he hype during the mid-to-late 1990’s over Java’s utility to run swarms of autonomous applets was greatly exaggerated. This early enthusiasm (and marketing) for Java as a language with which developers could develop cross-platform applets was doubly unfortunate. Not only did it fail to deliver the applets promise because of weaknesses in the platform’s technology, but these failures also shifted Java development away from applet-rich “thick” clients and toward server-centric, thin-client solutions, even in relatively homogenous intranet environments. Developers seemed to forget the fact that because Java is very portable across multiple platforms it is very suitable for developing distributed thick clients.
Today, in addition to client portability considerations, the need for platform-independent protocols is growing. The increasing use of XML-based technologies such as SOAP allows the developer to concentrate on the representation of data without worrying as much about the underlying hardware or network. Additionally, the text-based nature of XML-based protocols allows simpler debugging, although this comes with a speed tradeoff.
Because most of my work involves interfacing rather closely with the machine, my first inclination for addressing portability typically is to use Perl. Although Perl is a good all around language that offers portability to a wide variety of platforms, Java has advantages. It offers a well-defined set of graphical widgets, digital signatures, and a mechanism to deploy applications across multiple clients, namely Java Network Launching Protocol (JNLP).
When my database server vendor added a SOAP-based API to what had been a purely PHP-based interface, I decided to take the plunge into Java thick-client development with SOAP. I developed a small client to interface with the underlying database via documented SOAP methods. This enhanced functionality also enabled me to develop some much-needed administrative tools and explore intranet-deployed clients using Java Web Start.
|Figure 1. The Apache Axis
I began by combining Java Web Start and SOAP (using JAX-RPC) to develop a centrally deployed proof-of-concept client. I designed a client that connected to the SOAP server and then authenticated, retrieved, deserialized, and displayed an array of data structures from the server. Other developers could then use this program as a template, adding more general-purpose features as needed.
Laying the Groundwork
XML-based messaging has been a hot topic for several years now, and a lot of effort has been made to develop classes and libraries to facilitate the uniform deployment of XML-related technologies. The developers at Sun have been hard at work adding new features to Java—version 1.4 of the Java Standard Edition SDK comes in at about 93 megabytes uncompressed. It should come as no surprise that Java includes a fairly complete toolset to simplify program development. Included among these tools is JAX-RPC (Java API for XML-based Remote Procedure Call). Additionally, I downloaded the Apache Axis toolkit, another SOAP RPC API, which provides important extras such as the
tcpmonitor utility (See Figure 1).
Apache Axis or JAX-RPC: Which API Should I Use?
As with most standards, you have several choices among libraries that support XML-based messaging. Fortunately, the two I chose, Apache Axis and JAX-RPC, have classes that share many similar methods, and they create objects that are very compatible. Many of these objects, such as qualified names (Qnames), are largely portable between APIs, so one can choose to use pieces of each library where it is useful to do so. The Axis library is fairly large, including the axis.jar, commons-discovery.jar, commons-logging.jar, Jaxrpc.jar, log4j-1.2.8.jar, and saaj.jar.
tcpmonitor utility is one very strong reason to use the Axis API instead of JAX-RPC. Since I likely would be using the
tcpmonitor utility fairly frequently, I decided to wrap it up in a jar file that I could call from the command line. I unzipped the Apache Axis toolkit into a suitable location and altered the package declaration to allow compilation in the current directory. Next, I compiled it and placed the necessary files in a single jar file. This software came in handy for monitoring other TCP-based traffic (see Sidebar 1. Compiling and Packaging the “tcpmon” Utility).
The second reason to download the Apache Axis toolkit is the Apache Axis WSDL2Java emitter, a utility that can read the server side Web services deployment descriptor and generate JavaBeans-compliant “stubs”, which serve as containers for the deserialized SOAP objects (see Sidebar 2. Generating Java “Stubs”).
A final reason to opt for Apache Axis over JAX-RPC is that interfacing with the Axis BeanSerializer (which allows unmarshalling of complex data structures) is easier. So much so in fact that several Java gurus a the University where I work had no luck deserializing the SOAP structures when they used a purely JAX-RPC-based approach. The Apache Axis classes simply worked as we expected.
Initiating a Connection
Since this was my first experience working with the SOAP protocol, I started out with some trivial applications that merely established a connection and displayed intermediate results to standard output.
The documentation typically discussed deploying both a client and a server concurrently, so it was not directly applicable to my situation. I was attempting to connect to a preexisting server, and I had only the following resources available:
- The documentation that I had regarding the procedure calls
- Traffic the
- Some example perl code
- Reference material I found on the Web
Since the connection uses standard HTTP and does not use an encrypted channel, some precautions are necessary to avoid sending an unencrypted password over the network. The client first requests a challenge string from the server. This string is then used to encrypt the password. The resulting encrypted password is then sent to the server to validate the client. So the first step in establishing that this service is available is to request a challenge string (see Listing 1. Challenge.java).
Retrieving The Data
After developing the initial code to exchange handshakes and establish a session, I had to actually extract account information from the server. Up to this point, the data returned consisted of simple types such as strings and integers, but the listing of user projects (which is returned by the
getProjectStruct() remote method) returns in a more complex structure. At this point, I faced the process of converting the SOAP data structures into an equivalent Java class (not much more than a data structure with
get/set methods). This process is known as data unmarshalling or deserialization.
Most of the documentation on unmarshalling SOAP assumed I had ready access to a client-side Web services deployment descriptor (WSDD). Unfortunately, I did not, but I did have access to the API reference. The server-side WSDD and the Axis library provided the missing pieces that I could not find in the JAX library, the
BeanSerializerFactory() and the
BeanDeSerializerFactory() methods. These methods register deserializers with objects of class
TypeMapping, all within the
connect() method in the
At first blush, JNLP deployment of jar files may seem as simple as repackaging the working program, writing a JNLP deployment file (not the same as a WSDD), and dropping the entire package on a friendly Web server. In actuality, it was not that easy. Because JNLP-deployed programs may not have access to standard output, all I/O must be done via the GUI. Furthermore, the interpretation rules for CLASSPATH values were not always obvious. It may be necessary to edit the JNLP file to either reference the necessary support libraries or unpack these libraries and re-roll them up into the deployed Java archive. The simple application that I wrote used standard output and relied on six other jar files.
Creating a Deployable Jar File
The JNLP file can include references to the associated Java archives needed to run the deployable applet. However, it was easier for me to include all the necessary classes in a single archive. In order to do that, I needed to extract all the required Apache Axis libraries into the base directory of a Java archive that contains the necessary libraries.
Deploying the Resulting Jar File
A deployable jar file can be placed on a Web server almost like any other file. The complication is that any Web page that launches this file cannot do so directly. The Web page instead references a JNLP file, which contains details such as security settings and necessary libraries to support the application. So any deployable jar file must be launched by an associated JNLP file.
I also needed to edit the MIME configuration for Apache so that it sent the correct application type to the browser, which would then in turn pass the JNLP file to a client-side JVM (a Java Web Start application launcher). For the Apache Web server, I needed to add the following directive to the
/etc/mime.types file, then restart or reload Apache:
Other Web servers differ in this configuration detail. If your browser does not receive the correct application type, it will either attempt to download the JNLP file or provide you with an XML parse error.
Bumps in the Road
Deploying a JNLP-enabled application presented an entirely new set of problems, most obvious to me was the lack of STDOUT and STDERR for debugging. I am considering just wrapping all future JNLP-based applications in a main frame with some sort of optional “console”, which could be used to redirect display and debugging messages. JNLP directives could be used to toggle this on and off as necessary.
Lastly, I developed this application using Java 1.4.2, which has been superseded by version 1.5. So I should upgrade my compiler and test everything using the newest version of Java—as should you.
JNLP and SOAP: A Natural Mix
As is typical with learning a new language, class library, or network communications protocol, the process can alternate between being totally fascinating and maddeningly frustrating. JNLP deployment of SOAP applications is perhaps an ideal way to become familiar with other ancillary technologies such as XML, digital signatures, and thick-client deployment via an intranet. Developing centrally deployed (and automatically updated) client applications allows the programmer to add features without orphaning users who neglect to check for newer versions. At the same time, leveraging the cross-platform features of SOAP provides a greater deal of freedom in deploying application servers. Combining these two technologies seems like a natural mix.