There are two groups of people in CS who want to control your program’s interaction with the outside world–the operating system people and programming language people–and they are always fighting over who will have this honor. The operating system people want to provide a set of functionality that is available to any programming language, and the programming language people (generally) want to provide a set of functionality that is available on any operating system.
The OS people made POSIX, and mostly adhere to it and it is available on most any system you would use. The language people made java, the clr, common lisp, and a variety of other platforms, none of which really work together.
I like Java. It is a simple, statically compiled language with great performance and solid garbage collector implementations; but unfortunately it was made by the language people. This means a lot of basic functionality available on every platform you could reasonably run on, isn’t available to you when your program is written in java.
Want to move a file across volumes, figure out what user you are, get your process id, send a signal, interact with pipes, etc? Too bad. Sun has decided you shouldn’t, so you can’t.
The motivation for this is to allow java to be used in set-top boxes or something like that, but it presents a bit of a problem for server-side software development when the code needs to get anywhere near the operating system.
You are supposed to be able to fix this with JNI. JNI is a standard that lets you wrap native code with java interfaces and call it from java. The problem is it is a massive pain to write, so people rarely do.
We have seen a number of problems that this causes. We have seen a couple of problems caused by attempts to use Runtime.exec to run a unix command to collect basic file information. This is a major problem since it forks a huge java process to run an itsy bitsy unix command, then attempts to parse the output. Who could be so stupid, you would ask? Well one was buried in an apache commons library, the other was Hadoop (which tries to execute whoami). The later, in addition to forking a large namenode process, is actually quite non-portable in comparison to getuid().
I didn’t know this existed, but it turns out there is a library called jna that does transparent native access for java using dynamic proxies. Here is an example of using it to implement kill() to send a signal to a process in java using jna.
public class Kill {
public static void main(String[] args) {
Posix posix = (Posix) Native.loadLibrary("c", Posix.class);
int pid = Integer.parseInt(args[0]);
int signal = Integer.parseInt(args[1]);
posix.kill(pid, signal);
}
public interface Posix extends Library {
public int kill(int pid, int signal);
}
}
The only downside of this that I have found is that JNI bound native libraries (whether using JNA or not) cannot be reloaded. This means that if you are writing something deployed in a servlet container like tomcat that expects to be able to reload various sub-applications this will not work. The work around is to add the JNA jar to the tomcat system classloader, but this breaks the ability to package the application as a war that works in an container. (Special thanks to a coworker who pointed this out to me before we started converting things right and left.)