by David H. Boydston
The fact that Java has been accepted more quickly than any programming language in history is a reflection of the excellence of the language. Java is an ideal solution for both Internet and standalone applications.
Because of Java's phenomenal growth and its developer base, it's sometimes easy to forget how young the language really is. When you use Java to build extensive applets or applications, you'll sooner or later need to complete a task for which the language currently has no solution.
What should you do when you can't find a class or method that provides the functionality you need? Should you wait for Sun or Microsoft to provide a solution for you? You could, but the wait may be a long one.
Instead, you might want to consider native methods. In this article, we'll explore the power of native methods and how you can use them to accomplish nearly anything you may need to do with Java.
Suppose you want to determine the amount of available disk space on a particular drive or volume. Such a task appears to be a simple enough; therefore, you might expect that Java would have a method for measuring disk space. However, if you examine the Visual J++ documentation, you'll find that J++ doesn't provide this particular functionality. And, if you look closely at Sun's Java, you'll find that this functionality doesn't exist in Java 1.1, either.
Before discussing the implementation of our native methods, let's reflect briefly on how Java provides one of its major strengths. Java (in theory at least) gives you the ability to write your application once and run it without modification on any number of platforms. This promise is often billed as "Write-Once-Run-Anywhere." Let's take a look at what's actually required to fulfill this promise.
Java is based on a Virtual Machine (VM) technology. This VM technology allows the language to leave the platform-dependent details to those who provide a port of the VM to a particular platform. But make no mistake, code at some level is controlling the video card, sound card, network-interface card, etc. The code that provides this functionality is typically part of the standard shared library set that ships with Java.
From the developer's perspective, this functionality is provided as a feature of the port of the VM. This means that when Java x.y is ported to platform z, you know your Java code written for x.y will run on platform z.
This model works well if your application needs only classes that are provided as part of Java version x.y, and version x.y is ported to each platform you want your application to run on. Unfortunately, this isn't always the case.
To provide functionality that "standard" Java doesn't include, you can use native methods. When writing native methods, you're providing the port to each platform your application is to run on. Thus, you'll typically write the same native functionality many times (once for each platform), and it will run only on the platforms for which you've written the native implementation. The bottom line: Multiple platform support requires multiple shared libraries or DLLs, one for each platform.
Currently, there are several native method interface implementations. Microsoft developed the RNI (Raw Native Interface) for its VM implementation, RNI is also used in the Microsoft JDK and J++.
When using RNI, note that Microsoft modified RNI beginning with JDK 2.0PR. As a result, RNI DLLs developed for use with JDK 1.0 and 1.5 are inoperable with JDK 2.0PR and later. Also note that you can't run DLLs built using JSDK 2.0 with SDK 1.0 or 1.5.
Other native interfaces include the "classic" native method interface that appeared with Sun's JDK 1.0 and the JNI (Java Native Interface) that appeared with Sun's JDK 1.1. According to Sun, the company plans to support only JNI in the future; therefore, the classic interface will probably be phased out. Currently, Sun's JDK 1.1 supports both JNI and classic interfaces.
By the time you read this article, Microsoft may have released J/Direct, which promises to allow you to call Win32 functions directly from Java. You may want to consider this option if you only plan to run your Java application on Windows. Depending on how Microsoft implements J/Direct, you may be better off using RNI, since this interface should allow simpler translation to other vendors' VMs. The point is that when you decide to use native methods, the details are a bit more complex than choosing to use "pure" Java.
Security is another issue you need to consider when working with native methods. The ability to access native methods from Java provides a great amount of power and flexibility, but not without some security risk. If Java didn't provide security when calling native methods, nothing would stop a malicious programmer from using native methods to do destructive things (like erasing every file on your hard disk).
Fortunately, part of Java's security design controls access to native methods. When Java calls your native methods, it does something similar to these lines of code:
SecurityManager security = System.getSecurityManager();if (security == null) {
someClass.someNativeMethod(...);
}
else {
security.checkAccess(+)
}
When your class files run as an application--or as an applet loaded from the local hard disk--the getSecurityManager call returns a null. This response indicates you're running in a trusted environment. Therefore, Java won't restrict the call to your native method(s).
On the other hand, if your code were to run as a downloaded applet, the security manager would control the calling of the native methods. In this case, the native method(s) would be allowed if the applet were digitally signed and the certificate used to sign the applet had been granted the access to run native methods. For more details on Java security and applets, see the October 1997 issue of Visual J++ Developer's Journal.
As we've shown, native methods involve significantly more detail and effort than using "pure" Java. However, when you need some functionality that Java doesn't deliver, native methods can do the job, and are well worth the effort.
David H. Boydston is a principal consultant for Solutions Consulting. He's currently working on several Java and electronic commerce projects. You can reach him at daveb@sc-systems.com.