YOUR FEEDBACK
Craig Balding wrote: Bruce I read your comment and couldn't quite understand how it related to the p...


2008 East
DIAMOND SPONSOR:
Data Direct
Frontiers in Data Access: The Coming Wave in Data Services
PLATINUM SPONSORS:
Red Hat
The Opening of Virtualization
Intel
Virtualization – Path to Predictive Enterprise
Green Hills
IT Security in a Hostile World
JBoss / freedom oss
Practical SOA Approach
GOLD SPONSORS:
Software AG
The Art & Science of SOA: How Governance Enables Adoption
PlateSpin
Effective Planning for Virtual Infrastructure Growth
Fujitsu
Automated Business Process Discovery & Virtualization Service
Ceedo
Workspace Virtualization
Click For 2007 West
Event Webcasts

2008 East
PLATINUM SPONSORS:
Appcelerator
Think Fast: Accelerate AJAX Development with Appcelerator
GOLD SPONSORS:
DreamFace Interactive
The Ultimate Framework for Creating Personalized Web 2.0 Mashups
ICEsoft
AJAX and Social Computing for the Enterprise
Kaazing
Enterprise Comet: Real–Time, Real–Time, or Real–Time Web 2.0?
Nexaweb
Now Playing: Desktop Apps in the Browser!
Sun
jMaki as an AJAX Mashup Framework
POWER PANELS:
The Business Value
of RIAs
What Lies Beyond AJAX?
KEYNOTES:
Douglas Crockford
Can We Fix the Web?
Anthony Franco
2008: The Year of the RIA
Click For 2007 Event Webcasts
SYS-CON.TV
TOP THREE LINKS YOU MUST CLICK ON


Interfacing with Legacy Libraries Using RMI
Interfacing with Legacy Libraries Using RMI

The assignment was enough to make any neophyte Java developer bolt for the door: to provide a remote method for use by an applet that invokes a native method that wraps a function in an existing legacy library. Mentally calculating the odds of making it to the parking lot, I discarded that option and indicated my willingness to assume responsibility for the task with an air of cautious confidence. The purpose of the remote method is to return an instance of a class object whose contents reflect the data structure returned by the legacy function. Little did I know what I was getting myself into.

Perhaps the most significant hurdle I had to overcome was the lack of useful documentation to help direct my efforts. While embroiled in implementation, I spent an entire day poring through the RMI usergroup archive on Sun's Web site searching for guidance ­ to no avail. I would've spent a lot of time wading through their JNI usergroup archive as well, but I couldn't seem to locate one. Subsequently I made the decision to document my findings so as to assist others.

Before we start on the class design, let's look at what the existing legacy code (Get_Legacy_Data) does. An ASCII file is read from the local disk, then its contents are parsed into a Legacy_Type structure whose address is passed as an argument by the caller (see Listing 1). Not much to it, really. The legacy code was compiled into a shared object library, legacy.so, using the IRIX 6.2 compiler and then loaded onto the Web server, a Silicon Graphics Indy station loaded with the IRIX 6.4 operating system.

The first requirement for class design is a class that acts as a template for the data structure that's returned by the legacy function. This class, JLegacy, declares a series of public instance variables that correspond to the members of Legacy_Type and provides a constructor that has no parameters (see Listing 2). This constructor is never called, not even by the native method that allocates the object for return to the remote method.

Next, the remote interface declaration for the remote object must be defined. The remote interface is a Java interface that extends java.rmi.Remote, used exclusively to identify remote objects. The remote method getJLegacy, which is defined by JLegacyIF, returns a JLegacy instance and throws java.rmi.RemoteException, which provides a mechanism to handle any failures (see Listing 3).

Now that the remote interface has been defined, let's look at the design of the remote object, JLegacyRO (see Listing 4). For JLegacyRO to implement getJLegacy, it must interface with the existing legacy code through a native method, getN. This method is declared in the JLegacyRO class but implemented in C, just like the legacy code. It returns a JLegacy instance and is declared static since its implementation is the same for all instances of the JLegacyRO class. It's implemented in a native shared-object library, libJLEG.so, which is loaded into the Java Virtual Machine at runtime using a static initializer in the JLegacyRO class. Static initializers are executed once by the JVM when the class is first loaded. If JLegacyRO doesn't load the native library, an UnsatisfiedLinkError exception is thrown when getN is called. Failure to load libJLEG.so is established only by catching one of the exceptions thrown by System.loadLibrary. The JVM qualifies the library name, assigns the prefix lib and appends the library extension .so for UNIX and .dll for Microsoft Windows.

JLegacyRO calls getN and returns the JLegacy object returned by it to implement the method defined by JLegacyIF. Nothing to it, right? Well, let's finish the JLegacyRO class before we call this one complete.

The JLegacyRO class exports itself by extending UnicastRemoteObject and calling the constructor of its superclass in its own constructor. In addition, UnicastRemoteObject redefines the equals, hashCode and toString methods inherited from java.lang.Object for remote objects.

The first thing the main method provided by the JLegacyRO class does is install RMISecurityManager to protect its resources from remote client stubs during transactions. The RMISecurityManager is the equivalent of the applet security manager for remote object applications. Next, the main method creates an instance of the JLegacyRO class and a remote object registry listening on a port number, which is declared static final. The JLegacyRO class is the only application that will use this registry. Finally, the main method binds the instance of the JLegacyRO class to a unique name in the remote object registry, making the object available to clients on other virtual machines. The name bound to the object is formed using the port number and the name of the remote object's host, which is passed to the application as a command line argument and the String "JLegacyRO".

Before delving into the details of the native method, let's look at the last class ­ the client-side class that invokes the method on the remote object, JLegacyC (see Listing 5). JLegacyC provides a constructor without parameters, which is never intended to be called, and a static method, get, which looks up the remote object in the registry created by JLegacyRO. This static method also retrieves a reference to JLegacyIF through which the remote method, getJLegacy, is invoked. The get method returns the JLegacy object that was returned by the remote method invocation.

These three classes and the interface are all compiled into the same package. All classes, including the stub and skeleton created from the JLegacyRO class using the rmic compiler, are served from the Indy Web server. The environment settings are explained at the conclusion of this article. The native method is also relatively straightforward.

Before we can discuss the details, however, we must establish its C prototype. The C header file, which defines the prototype for the native method, is generated using the javah tool with the -jni option on the compiled JLegacyRO class (see Listing 6). Since the JLegacyRO class has been compiled into a package, the package name must be appended to the class name when javah is executed (e.g., javah -jni my.jlegacy.classes.JLegacyRO). The resulting header file will be prefixed with the package name (e.g., my_jlegacy_classes_JLegacyRO.h).

If you've read the Java Native Interface specification, you're already familiar with the method used by javah in composing native method names. If you haven't, I must warn you it's not pretty. A native method name has the following signature: Java_<mangled fully qualified class name>_<mangled method name>. The term mangled is actually used in the JNI specification. If the native method is an overloaded method, the name is further appended with __<mangled argument signature>. There's that word again. For further information on the JVM's type signatures, I recommend reading the JNI specification.

The JNI interface (or JNIEnv) pointer is always the first argument to a native method. The interface pointer points to a table of function pointers, each a JNI function. In standard C, all JNI functions are called via this pointer (e.g., (env)->FindClass(env,"java/lang/String") ). The JNIEnv structure is defined in C++ with inline functions that ultimately resolve to the same references as the standard C functions. Since the sole purpose of the JNIEnv pointer is to invoke the JNI functions, and because it has a well-defined syntax, I wrapped all the JNI functions so as to promote greater readability and easy maintenance.

The second argument to a native method varies depending on whether or not the method is declared static. If the method is nonstatic, the argument is type jobject and is a pointer to the Java object that invoked the method. If the method is declared static, the argument is type jclass and is a pointer to the Java class that declared the method (i.e., the remote object class JLegacyRO). Any arguments passed to the native method in its Java declaration follow the second argument in the function prototype. In this case the method is declared with no arguments.

Remember about getN being declared as returning an instance of the JLegacy class? This is the jobject returned by the function in the C prototype. Briefly, the native method will retrieve the required data using the existing legacy function, instantiate the jobject to be returned and populate it with the retrieved data (see Listing 7).

First the native method calls Get_Legacy_Data, passing it a pointer to the Legacy_Type structure to be populated. Then the fun begins. Using the JNI AllocObject function, the native method allocates an object of the JLegacy class. The jclass must be established first, using the JNI FindClass function, because the native method is declared static in the JLegacyRO class. This means that the jclass argument passed to it isn't the class to which an object is to be allocated. The FindClass function requires a fully qualified class name (i.e., my/jlegacy/classes/JLegacy).

The JLegacy object is an example of a local reference, meaning its scope is for the lifetime of the native method and it's automatically freed by the JVM upon return. All objects passed into or returned from native methods are local references. Global references remain visible until they're freed.

Once the JLegacy object is returned, the native method must establish the field IDs for the public instance (nonstatic) variables within the Java object in order to access the variables or fields. Fields are identified by the JNI, using their symbolic names and type signatures.

Finally, the instance fields are set to the contents of the Legacy_Type structure returned by Get_Legacy_Data using the JNI Set<type>Field family of accessor routines, and the populated JLegacy object is returned to the interface implemented by JLegacyRO. Former C programmers should note that the Set<type>Field routines are provided only for the following primitives: boolean, byte, char, short, int, long, float and double; everything else is an object of some sort.

In this case a series of the members in the Legacy_Type structure returned by Get_Legacy_Data are char arrays or UTF-8 format in Java. The UTF-8 format encodes nonnull ASCII characters in the range 0x01 to 0x7F (hexadecimal) in a single byte. Characters above 0x7F are encoded using up to 3 bytes of storage. The JNI SetObjectField function requires a native type for the value of the indicated field, so the char arrays must be converted to java.lang.String objects before their instance fields can be set in the Java object. This translation may be performed using the JNI NewStringUTF function. Since a series of these instance fields have to be set, the steps needed to do this are generalized into another function, JL_SetStringField.

If an error condition arises during execution of the native method, the method will delete the local reference that the JLegacy object pointed to and then return a null object to the interface implemented by JLegacyRO. Freeing the local reference is a habitual practice of mine when I write C code, though it's not required in Java; I just think it's good programming style.

Now let's make everything talk to each other. First let's discuss compiling getN into the native shared-object library, libJLEG.so. In the makefile for libJLEG.so, legacy.so must be supplied as an argument to the link editor in order to resolve the symbol supplied by Get_Legacy_Data's object module for getN. In addition, Java 3.1 (Sun 1.1.5) assumes the runtime linker to load n32 libraries. If you attempt to load an o32 native library from the JLegacyRO class, a fatal error will be returned by rld. It can't successfully map the shared object name to the LD_LIBRARY_PATH despite the presence of the native library located at a path specified by the environment variable.

To facilitate loading an o32 library, two options are available. The first is to set the environment variable SGI_ABI to "-32" before starting JLegacyRO. The second is to pass the "-32" argument to the Java interpreter when starting JLegacyRO. On the Indy Web server the LD_LIBRARY_PATH variable must include the path for libJLEG.so and legacy.so, as well as <yourJAVA_HOMEpath>/lib/sgi/green_threads.

Apparently the JVM for the Silicon Graphics platform uses the default Green threads package as its user threading model. The Green threads package maps all Java threads into a single native thread, prohibiting concurrent execution of multiple threads in a Java application. In addition, the CLASSPATH variable on the Indy Web server must include the path that precedes the directory structure, defined by the package the classes were compiled in, so the Java interpreter can locate them. Finally, the applet class is served from the Indy Web server by setting the CODEBASE attribute accordingly in the HTML file.

I hope this article answers more questions than it raises. I know I learned a lot while working on this task and even more while writing about it. I hope you did, too.

Although all of these classes were served from a single Indy Web server, a summary illustrating the client and server classes running on different platforms might be useful to make clear on which platform each class belongs and each command-line step takes place (see Table 1).

In this context client refers to the process (i.e., applet) invoking a method defined by a remote object and server refers to the remote object process. The rmic compiler is used on the server platform to create the stub and skeleton classes; the stub class is copied to the client platform before runtime. In addition, javah is used on the server platform to generate the header file that defines the C prototype for the native method declared by the remote object class; development of the source file that implements the C function is left to the user. The make of the native shared-object library on the server platform isn't illustrated, nor is browser startup on the client platform.

About Scott Howard
Scott Howard, a staff analyst for New Technology, Inc., in Huntsville, Alabama, has developed software for private industry and the aerospace community for 13 years using FORTRAN 77, C and now Java. He's also a contributor to the Enhanced Huntsville Operations Support Center System Web infrastructure and Java Common User Interface designs at Marshall Space Flight Center.

LATEST JAVA STORIES & POSTS
Furthering its dedication to providing Java developers productivity with choice, Oracle announced the Oracle Enterprise Pack for Eclipse, a new component of Oracle Fusion Middleware. This release marks the first free Eclipse 3.4 environment to support Oracle WebLogic Server 10g R...
Two of the biggest launches in Rich Internet Application history took place in 2007/2008 when Adobe launched AIR 1.0 in February '08 and Microsoft launched Silverlight (September '07). At the 6th International AJAXWorld RIA Conference & Expo in October SYS-CON Events is delighted...
Red Hat CTO Brian Stevens, Citrix CTO Simon Crosby, Egenera CTO Pete Manca, Allen Stewart, Group Manager, Windows Virtualization at Microsoft, and Brian Duckering, Sr. Director of Products and Alliances at Symantec were the top industry executives who joined Jeremy Geelan in the ...
Government intervention and direction has long been critical to the development of the computer industry. The Internet, after all, was derived from the ARPANET, developed in the early 1970s from a U.S. government-sponsored research project by the Advanced Research Projects Agency...
Commercial systems are developed with a huge range of performance requirements and we are concerned in this article with the small number of systems where absolute maximum performance is demanded either in terms of execution speed or available memory. We'll discuss the role of be...
Genuitec announced the availability of MyEclipse Enterprise Workbench 7.0 milestone 1. This milestone release delivers advanced AJAX tooling for Java EE and full Application Lifecycle Management (ALM) capabilities for Eclipse 3.4 Ganymede, among other enhancements.
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS
SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


SYS-CON FEATURED WHITEPAPERS

SPONSORED BY INFRAGISTICS
There are many forces that influence technological evolution. After a decade of building enterprise ...
2008 is going to be an important year for Rich Internet Applications. Most organizations are deliver...
The OpenAjax Alliance is developing an Ajax industry wishlist for future browsers, using a dedicated...
In every field of design one of the first things students do is learn from the work of others. They ...
Infragistics announced the availability of two Community Technology Preview (CTP) User Interface (UI...
The YUI development team has released version 2.5.2; you can download the new release from SourceFor...
ADS BY GOOGLE
BREAKING JAVA NEWS

SpringSource, a leading provider of infrastructure software and the company behind ...