Exposing legacy applications: an apache soap framework that provides an excellent implementation

Exposing legacy applications: an apache soap framework that provides an excellent implementation – WSJ Feature

Adelene Ng

SOAP (Simple Object Access Protocol) is a wire protocol that is similar to CORBA’s Internet Inter-ORB protocol (IIOP) for communicating between applications running on different operating systems, with different technologies and programming languages. Unlike IIOP, which is binary in nature, SOAP is text based. This XML-based protocol lets you call an application, or even an individual object or method within an application, across the Internet via HTTP. HTTP does not pose any compatibility and security problems, unlike RPC, since all Internet browsers and servers support HTTP.

Typical applications for SOAP include:

* Business-to-Business Integration (B2Bi): Businesses can develop their applications and make these available to other companies via SOAP.

* Distributed applications: SOAP allows applications to be accessed and remotely managed via the Internet.

* Web applications: This typically allows a user to query a Web server through a Web browser and results are displayed to the user through the Web page. SOAP, on the other hand, allows a user to query the Web server and run a program on it through a SOAP client running on the user’s computer.

In this article, I propose a solution using SOAP that allows legacy client methods to be called from a SOAP client. A SOAP client is just like any program that can be run from the user’s computer. Even though other solutions are possible, for example using XML-RPC, SOAP offers the following advantages:

* Support for a richer set of data types

* Allowing users to specify a particular encoding

* Namespace aware

* Asynchronous

* Support for request routing and preprocessing of requests via SOAP headers

System Architecture

I’ve used a three-tier architecture in this implementation. Figure 1 shows the overall system architecture.

[FIGURE 1 OMITTED]

The first tier is the SOAP client, which accesses the legacy application through SOAP. The legacy application resides in another client/server application. The legacy client resides on the Web server–the middle tier. A wrapper layer is provided around the legacy client application. This allows for the clean separation of legacy calls from the wrapper class, and it isolates the legacy code to a single location, which makes for easy maintenance. The SOAP client accesses the legacy client application on the Web server through the wrapper class. The legacy client, in turn, communicates with the legacy server through ONC-RPC. The legacy server may reside on a different machine and is the third tier in our architecture.

Tools

The entire system was written in Java running on Win 2000 Professional. The tools used to build this system include:

* Java 2 Platform, Standard Edition (J2SE): http://java.sun.com/j2se

* ONC RPC for Java: A commercial ONC-RPC package: www.distinct.com

* Apache SOAP 2.3.1: http://xml.apache.org /soap/index.html

* JavaMail 1.3 (used for the SMTP transfer protocol support included in Apache SOAP): http://java.sun.com/products/java mail

* JavaBeans Activation Framework 1.0.2: http://java.sun.com/products/javabeans/ glasgow/jaf.html

* Java XML Pack Summer ’02 Update Release: http://java.sun.com/xml/downloads/javax mlpack.html. We are interested only in the JAXP for XML Processing Package.

* Apache Tomcat 3.2.4 (Servlet Engine): http://jakarta.apache.org/tomcat/index. html

Why SOAP?

SOAP was selected over other mechanisms such as XML-RPC because:

1. It’s a simple protocol to use.

2. The SOAP protocol is lightweight, incurring a minimal amount of overhead.

3. It runs over HTTP, making it easy to integrate SOAP-based applications with other Web-based applications.

4. It provides a better error handling mechanism through the SOAP Fault object.

5. It supports a variety of encodings that are governed by rules that determine how application-defined data type instances are exchanged.

6. Ease of handling of custom parameter types: Data exchange takes place via parameters passed to the SOAP remote service; and getting back a response from the remote service.

Developing a SOAP Application

Now let’s outline the steps necessary to develop a SOAP application:

Define a service class that is having its methods invoked remotely.

Define a deployment descriptor that tells the SOAP server:

* The URN of the SOAP service accessible to clients

* The list of methods available to the client(s): If the arguments and return types of these methods are simple types, then the deployment descriptor in suffices. If the arguments and return types of these methods are user-defined custom parameters, then the deployment descriptor will have to be augmented with a “mappings” element to tell the SOAP server how to handle custom parameters. The “mappings” element defines the serializer and deserializer to use. If your custom parameters are in the JavaBean format, then the BeanSerializer class provided by the Apache SOAP implementation will be used for the serialization and deserialization. In the example presented here (see Figure 3), the serializer and deserializer classes are part of the Apache SOAP framework, org.apache, soap.encoding.soapenc. Bean-Serializer.

[FIGURE 3 OMITTED]

* Serialization/deserialization handlers for custom classes (if any): This is required when the user-defined parameter is not a simple data type that can be handled by the Apache SOAP implementation nor does it conform to the JavaBean format. In this case, you will have to write your own serializer and deserializer. Any user-defined serializer and deserializer will have to implement the org.apache.soap.util.xml.Seria lizer and org.apache. soap. util.xml.De serializer interfaces. Since user-defined serialization and deserialization is beyond the scope of this article, this technique will not be discussed here.

The deployment descriptor is an XML file. In this example, it is called Accounting Service.xml. The contents are shown in Figure 2.

[FIGURE 2 OMITTED]

Before deploying the service, make sure that your Web server is up and running. Here we are using the Apache Tomcat Server, which has several scripts under the C:jakarta-tomcat-3.2.4 bin directory. To start the Apache Tomcat Server, go to the directory, C:jakarta-tomcat-3.2.4bin and type startup. Figure 4 shows the Tomcat 3.2 Console Window when the Tomcat Server is started.

[FIGURE 4 OMITTED]

Deploy the Service.

* Make your service class visible to your SOAP server. If you are using the Apache SOAP server, this service class is “Jarred” up and copied into the lib directory.

* Restart your servlet engine.

* Your service class can now be deployed by using the utility class, org.apache.soap. Server.ServceManager from Apache Soap. Deploy it by running the following command from the command line,

C:> java ServiceManagerClient

http://localhost:8080/soap/serverlet/rpcr

outer deploy AccountingService.xml

Check that your service has indeed been added via

C:> java ServiceManagerClient

http://localhost:8080/soap/serverlet/rpcr

outer list

This command should show the service that you have just added plus all the current services available on that server. Figure 5 shows the messages that are displayed when this command is run.

[FIGURE 5 OMITTED]

Run the legacy server application (if it is not currently running).

Run the SOAP client.

Once you are done with the service, you can undeploy it by running

C:> java ServiceManagerClient

http://localhost:8080/soap/serverlet/rpcr

outer undeploy urn: accounting-service

To make things simple, I have created batch files for the last five steps to facilitate the execution of these commands.

Developing a SOAP Client

For the purposes of this article, the SOAP client is invoked from the command line. The basic boilerplate steps involved in every SOAP call are:

1. Define the type mapping for the custom parameters. This is required only if the application uses custom parameters.

2. Build the call object.

3. Create a parameter list (for your method that you will be invoking).

4. Add the parameter list to the Call object.

5. Invoke it.

6. Error Handling.

Creating the SOAP Mapping Registry and Defining the Mapping Types

The following steps are required only if the application uses a custom or user-defined object and the user-defined object follows the JavaBean convention.

1. Create a user-defined object.

2. Create the SOAPMappingRegistry and Bean-Serializer objects.

SOAPMappingRegistry reg = new

SOAPMappingRegistry();

BeanSerializer b_serializer = new

BeanSerializer();

3. A QName object is also created to represent the user-defined type.

QName q_name = new QName(“urn:accounting-service”,

“x.y.z.UserDefinedClass”);

4. The type mapping is created by calling the method, mapTypes(), on the SOAPMap pingsRegistry object. This method takes in as arguments the encoding style, the QName object, the JavaBean class, and serializer and deserializer objects.

reg.mapTypes(Constants.NS_URI_SOAP_ENC,

q_name, x.y.z.UserDefinedClass, b_serializer,

b_serializer);

Building a Call Object

The first step is to create a new Call object:

Call call = new Call();

If the SOAPMappingRegistry was created previously, we have to tell the call object to set the type mapping to the SOAP mapping registry via:

call.setSOAPMappingRegistry(reg);

Next, set the URI of the SOAP Service to use:

call.setTargetObjectURI(“urn:accountingservice”);

Specify the method to call:

call.setMethodName(“GetNumberOfRecords_W”

);

Set the encoding style to use:

call.setEncodingStyleURI(Constants.NS_URI

_SOAP_ENC);

Creating a Parameter List

A new Vector object is created to store the parameter list:

Vector params = new Vector();

For each parameter in the method, create a new Parameter object and add that to the params vector list:

params.addElement(new Parameter(“filename”,

String.class, filename, null));

Finally, add the resulting Vector, params, to the Call object:

call.setParams(params);

Invoking the Call

The SOAP method is called:

Response response = call.invoke(url,””);

The Response object might contain the return value of the remote method that was invoked or the fault/error values as a result of the fault generated.

Error Handling

Errors are handled using the Fault object. The two main methods used are getFault String() and getDetailEntries(). The first method lets you know that an error has been encountered. However, it does not provide enough information to help you track down the root cause of the problem. The second method provides more details about the problem encountered. This call returns a vector of objects. Each element of this vector is a DOM element with detailed error information. The following code snippets show how the Fault object is used to obtain detailed error information.

Get the Fault object:

Fault fault = response.getFault();

Get the vector of DOM Elements:

Vector entries =

fault.getDetailEntries();

Iterate through this Vector and obtain the DOM elements for each entry:

for (Iterator i = entries.iterator();

i.hasNext(); ) {

org.w3c.dom.Element entry =

(org.w3c.dom.Element)i.next();

System.out.println(entry.getFirstChild().

getNodeValue());

}

Core Supporting Class and Methods

The core methods to support the SOAP Client are contained in the AccountingLog_ SC class. These are:

* public void BuildDOMTree(ArrayList al): Takes in an ArrayList and builds the DOM tree structure.

* public void TransformIt(String outputfilename): Takes the DOM tree produced by BuildDOMTree() and produces the resulting XML file.

The Web Server

The Web Service

The service to be deployed on the Web server is a Java class that exposes a number of methods callable from the SOAP client. In a two-tier application, this is typically the end point. However, in this article we show how in a three-tier application, the service residing on the Web server acts as a client to a legacy application that resides on a different server. The legacy client code that resides on the Web service has a wrapper layer over it. This will facilitate a clean separation from the legacy calls. Any future enhancements and fixes made to the legacy client application can be contained and isolated here.

The Wrapper Web Service

To expose the legacy client as a Web service, a wrapper class is built over the legacy client class. In this way, the legacy client code can be isolated. The two methods callable from the SOAP client are Get NumberOfRecords _W() and GetFileData _W(). Within each of these methods, calls are made to the legacy client methods.

The Legacy Client

In the legacy client implementation, calls are made to the stub methods, which in turn invoke the server functions. The underlying Distinct ONC/RPC runtime libraries and supporting framework handles all the marshalling/ unmarshalling of data. These data handling details are transparent to the user; each of the calls made to the stub methods are placed in separate methods–GetNumberOf Records() and GetFile Data() respectively. Separating these calls into different method calls will make it easier to integrate with the wrapper class.

The Legacy Server and Supporting Classes

The Legacy Applications

The legacy application is a typical client/server application. It uses ONC-RPC as a mechanism of communication between the two entities. RPC calls made by the client behave as if they were invoking a local procedure call. All the marshalling and unmarshalling of data is taken care of by the underlying ONC-RPC framework.

The X IDL file definition for the legacy application defines the interface between the client and server through a language-neutral construct, similar to the CORBA IDL definition.

The X IDL file definition contains two interface calls. One returns the number of records in the file. The other returns the data records, defined as GET_NUMBER_OF_ RECORDS() and GET_FILE_DATA() respectively. Listing 1 shows the contents of the X file.

[LISTING 1 OMITTED]

The Jrpcgen compiler translates the standard RPC/XDR (External Data Representation) interface definition files into Java classes that implement the client- and server-side stubs and the XDR conversions for the described interface. This means that Jrpcgen implements a certain Java language mapping for .x IDL files.

The Distinct ONC RPC/XDR for Java package contains the runtime libraries that conform to RFC 1831 and RFC 1832. The API consists of classes that allow you to write pure Java clients for standard RPC servers that can be embedded in applets and run by a standard Web browser. It also allows you to develop ONC RPC stand-alone servers. The package allows connections over TCP, UDP or encapsulated over HTTP.

Core Supporting Classes and Methods on the Legacy Server

The core methods required to support the legacy server are contained in the AccountingLog_ LS class. The supporting methods are:

* public int GetNumberOfRecords_LS(String filename): Opens the file specified as the argument, parses it, and returns the number of records read.

* public ArrayList BuildRecords(String filename): Opens the file specified, and returns all the records read as an ArrayList.

The Legacy Server

The legacy server implements the interface methods defined in the X IDL file. It makes use of the underlying core methods defined in AccountingLog_LS class to support the required behavior.

In the server implementation of get_ number_ of_records_1(), it calls the core method in the AccountingLog_LS class, GetNumberOf Records_LS(). This method opens the file specified in the argument list, counts the number of records, and returns the result to the caller.

Likewise, in the implementation of get_ file_data_1(), the core method, BuildRec ords(String filename), is called, again with the specified file as argument. The core method returns the records read as an array list (part of the Java Collections interface). Since XDR does not support Collections, the array list returned has to be converted into an array of strings, which is returned to the calling client.

Having the SOAP client invoke this call through the wrapper class results in the creation and storing of an XML file on the legacy server and may pose security problems. A better place to create the XML file is on the client end. After the records are read, the XML file can then be created and stored on the client.

“Chaining” and Interactions Between Tiers

“Chaining” can occur at the Web services or the legacy application level. In the former, the Web services on one Web server can act as a client accessing the Web services located on another Web server (see Figure 7). In Figure 8, the legacy client on the Web server accesses methods, objects, or even other applications on the legacy server. That legacy server in turn acts as a client to other servers on the system. For example, the legacy server could act as a database client querying the database server.

[FIGURES 7-8 OMITTED]

Flow Sequence

To show how the different pieces are tied together, Figures 9 and 10 illustrate the call sequence between the SOAP client, Web server (containing the wrapper class and legacy client), and legacy server. The sequence diagram summarizes the interactions between the different tiers and clearly shows which platform each of the classes reside on.

[FIGURES 9-10 OMITTED]

Future Enhancements

Let’s look at some of the possible enhancements to the application:

* Providing better GUI support for the application.

* Ability to perform “database-like” queries on the XML file. This will utilize the currently emerging “XML Query” technology.

* Transforming the resultant XML file into other formats using XSLT.

* Using XSL-FO to produce formatted reports.

Conclusion

This article has shown how legacy applications can be exposed as a Web service and accessed through the SOAP client. I’ve also discussed the possibilities of “chaining” on both the Web server and legacy application tiers. The Apache SOAP implementation provides an excellent framework in which to develop SOAP applications. The underlying mechanism (Call object) makes all the SOAP communications appear to work seamlessly together. The user does not need to be exposed to the nitty-gritty details of SOAP in order make a SOAP call.

References

* Srinivasan, R. “RPC: Remote Procedure Call Protocol Specification Version 2, RFC 1831” (Aug 1995). www.ietf.org/rfc/rfc18 31.txt

* Srinivasan, R. “XDR: External Data Representation Standard, RFC 1832” (Aug. 1995). www.ietf.org/rfc/rfc1832.txt

* SOAP Specification: www.w3.org/TR/SO AP

* McLaughlink, Java and XML, 2nd Edition. O’Reilly

* Englander, (2001). Java and SOAP, O’Reilly.

* Gupta, Samudra. “Using SOAP and Java, Parts 1, 2 & 3”. http://javaboutique.internet. com/tutorials/SOAP/index.html

Acknowledgements

I want to thank Tzu-Khiau Koh and Wen-Yun Chang for their invaluable feedback on the initial drafts of this article.

AUTHOR BIO:

Adelene Ng is a software architect with Xerox Corporation based in Rochester, NY. She holds a Ph.D. in computer science from the University of London, and an M.Sc. from the University of Manchester.

ADELENE.NG@XSSC.SGP.XEROX.COM

COPYRIGHT 2003 Sys-Con Publications, Inc.

COPYRIGHT 2003 Gale Group