Until now, supporting POSIX calls was quite difficult with JRuby. Using equivalent Java APIs is one way to go, but even if a Java equivalent of the functionality exists, it might not have the right semantics. And if the Java platform lacks the functionality, there remain only workarounds like launching command line programs to do the tasks.
Charles Nutter of the JRuby team reports the native code and POSIX on his blog:
I know, I know. It's got native code in it, and that's bad. It's using JNI, and that's bad. But damn, for the life of me I couldn't see enough negatives to using Java Native Access that would outweigh the incredible positives. For example, the new POSIX interface I just committed:The (not so) secret ingredient here is the Java Native Access (JNA) library, not to be confused with Java's JNI. While JNI provides access to native C code, it requires extra effort and glue code, such as JNI header definitions that need to be compiled, to access it.
import com.sun.jna.Library;
public interface POSIX extends Library {
public int chmod(String filename, int mode);
public int chown(String filename, int owner, int group);
}
For the given example, this code using JNA is all that's needed to load and access the library:
import com.sun.jna.NativeThis loads the standard C library, and gives access to chmod (for changing file access permissions) and chown (changing the owner of a file) functions. Of course, this approach is not limited to these two functions. Adding further functions to the
POSIX posix = (POSIX)Native.loadLibrary("c", POSIX.class);
POSIX
interface from the code sample would allow access to ever more functions of C stdlib. After all, Native.loadLibrary
simply tries to map the names from the Java interface methods to C functions in the library and make them accessible.JNA still uses JNI under the covers to access libffi which does all the magic. Using JNI brings along problems, for instance it's possible to run afoul of security managers that might not allow it or get into trouble with JEE containers.
Obviously, whenever native libraries are shipped, they need to fit the platform. The currently available JNA release ships with libraries compiled for Win32, Linux 32 and 64 bit x86 versions, Solaris SPARC and x86, FreeBSD, and Darwin (MacOS X) for PPC and x86, which covers quite a lot of the available spectrum.
Easy access to native libraries from JRuby is useful, but JNA opens another possibility: support for Ruby native extensions. These are shared libraries that are loaded in a Ruby process and can access the internals of the Ruby interpreter. Native extensions are widely used. For instance, the popular rcov tool, used to determine the test coverage of a piece of code, makes use of the Ruby API to see which code is actually executed in a test run.
Support for this is not as easy as the examples above, as it requires a full implementation of the Ruby C Language API that extensions use to interact with the Ruby runtime. This is a two way affair: native code can call this API, but the Ruby runtime also invokes callbacks for certain events. For more details on native extensions, see the Extending Ruby chapter of the online version of Programming Ruby.
Is the lack of POSIX functionality in JRuby a problem for you? What native extensions do you miss in JRuby?
Community comments
JNI required by JNA?
by Chris Morris,
Re: JNI required by JNA?
by Werner Schuster,
JNI required by JNA?
by Chris Morris,
Your message is awaiting moderation. Thank you for participating in the discussion.
Your article says, "JNA still uses JNI under the covers", but the jna home page says, "no JNI or native code is required". Are these statements compatible - does the JNA homepage mean only that JNI is not required in my code?
Re: JNI required by JNA?
by Werner Schuster,
Your message is awaiting moderation. Thank you for participating in the discussion.
JNA uses JNI to access libffi. I can't speak for the JNA guys, but I guess the "no JNI or native code required" means that, if you use JNA, you don't have to use JNI, instead you only use the JNA API calls and they do all the nasty JNI stuff in the background. One big problem with JNI is that if you want to access native code, you need to write a C library that needs to include JNI headers and compile and ship it with your product. This C library's functions area all you can call - nothing else. It's not possible to just load any old DLL or shared lib with plain JNI - JNA, on the other hand, can just take a DLL or shared lib, figure out what it provides and make these calls available.
Also: look into the jna.jar (that you can download at the JNA site) - it ships with native libs for various platforms.