views:

37

answers:

2

I'm trying to port a piece of code, written in Java (see below), from Linux to Windows and struck at a point.

                String sh = "/bin/sh";
                String cop = "-c";
                String cmd = "netstat -a | grep 9000 | wc -l";
                String[] exe = new String[] {sh, cop, cmd};
                Process FindConns = Runtime.getRuntime().exec(exe);

This actually builds up a command and passes it to shell for execution and collects the result.
Now in Windows, the equivalent command would be

netstat -a | find /c "9000"

However, I'm not sure about the following:-

  • For Windows port, what command string should be passed to 'Runtime.getRuntime().exec()'. I tried with

    String cmd = "netstat -a | find /c 9000";
    //and String cmd = "netstat -a | find /c \"9000\""; Process FindConns = Runtime.getRuntime().exec(cmd);

But it fails. It seems, on debugging, that Windows messes up at | (pipe) character. Since the following works alright.

String cmd = "netstat -a";
Process FindConns = Runtime.getRuntime().exec(cmd);
  • Secondly, (being new to java programming) what is the best way to do conditional compilation like #ifdef WIN32 etc in Java.

Thanks.

+1  A: 

The | is actually processed by the command line interpreter, and no other program knows to do that.

If you want to process a command line (containing stuff like redirection) in Windows, you should pass that line as an argument to cmd /c. I've had fairly good success with that in the past.

EDIT: (In case that was less than clear)

exec() runs a program, it does not explicitly call the command line interpreter (cmd.exe) to do so.

The program you need to execute is cmd.exe, and all the other stuff needs to be passed to it as a command line. I'm not quite sure if you need the arguments as a single string or they should be separated... give that a try!

Carl Smotricz
+1  A: 

As a separate answer: The equivalent of conditional compilation in Java.

(It might have been better for you to ask this as a separate question).

As you probably know, Java doesn't really have conditional compilation, certainly not in the sense of C's preprocessor.


For some cases, it's easy enough to put each coding alternative into an if block controlled by constants, err, static final fields. If those fields can be evaluated at compile time so their values are effectively constants, then the compiler is smart enough to completely remove code in if blocks controlled thereby. However, the code inside those blocks is still compiled (unlike the preprocessor) and subject to syntax checks. I sometimes find it annoying that #imports used by constant-commented-out code are declared (in my Eclipse IDE) to be unused, yet if I leave out the #import then my coding will be incorrect if I change the constants.

Note that this "constant" can be defined in a separate class, so changing your "configuration" could be accomplished by changing a value in a single file.


A more higher-level answer to your question involves run-time configuration, dependency injection, that kind of thing. The basic idea is to have your system-dependent code contained in separate classes (one for each target system), all of which implement the same interface(s).

At run time, about two different mechanisms come to mind for selecting the correct code:

  • Your code has a field whose type is that of the common interface; at startup, your program reads the name of the appropriate class from a configuration file, instantiates an object of that class using Class.forName() or something similar, assigns that object to the field and then uses the methods on that instance to do whatever configuration-specific things need to be done.

  • If you're deploying your program as Jar files, you can create separate Jar files containing one each of your config-dependent classes, and when you deploy your program, you deploy a "main" jar file and one jar file with the config-dependent stuff. Then when your program runs it can search its classpath for any of the candidate classes (perhaps by doing trial-and-error with Class.forName()) and then it works similarly to the other mechanism.


EDIT

Thinking about this, I thought of a "Zen Buddhist meta-answer":

In the gluttonous boundlessness of memory occupied by a Java program, why worry about a few bytes of superfluous code? If you really only want to code two alternative approaches to executing a system-dependent command, then heck, code and compile separate methods for each one:

private void windowsProcess();
private void linuxProcess();

...and then call whichever one is appropriate:

public void independentProcess() {
    if (runningOnWindows()) {
        windowsProcess();
    } else {
        linuxProcess();
    }
}

...and be done with it.

Separate Jars, runtime resolution and so forth are solutions aimed at exchanging significant parts of code machinery, whole libraries perhaps... if it's just a few hundred lines or so, I personally would not worry about the unused code in my program. It's not Java-like to be fastidious about small or even medium amounts of memory. What's the memory overhead of every object? 16 bytes? 32?

Carl Smotricz