Using Web Services for Interoperability


Web services are the recommended interoperability technique, unless performance or other considerations require a binary solution. This section looks at how you can use Web services to implement interoperability. It covers the data format choices, how to build the service interface for the Web service in Java using GLUE, from The Mind Electric (recently acquired by webMethods, Inc.) and how to build the .NET interoperability adapters.

Deciding on a Data Format

With a Web service interface, the temptation is to use the service interface to return complex types, allowing the adapters to create proxies of these complex types and consume them. However, because of the issues of handling XSD-based complex types in Web services, not all Web services stacks are compatible. Experience shows that what works for one Web service stack may break another. To solve this problem, you should look at exchanging only primitive data types, such as strings, integers and so on. All Web service stacks support these data types, and these provide the greatest levels of flexibility and client access.

If you use primitive data types and need to return something more complex, like an order, you have to package the data as a string. The best solution for this is to populate a string with an XML representation of the data. This XML encoding should follow an agreed schema.

Note

There is little performance difference between passing Java data types directly and serializing them and passing them as strings, because the Web service has to serialize the Java data into XML anyway.

In the XBikes application, the J2EE and .NET developer teams decided upon a common data format for the Web services. They created an XSD Schema from this design, which both teams then used to create the appropriate classes and mapping files.

Building the Service Interface in J2EE

You now need to create a service interface that exposes the J2EE Business tier fa ade through Web services. This becomes the J2EE Web service service interface. This publication refers to these as WS service interfaces.

Building the Java Web service is a fairly straight forward process. First, create Java data classes based upon the XSD schemas for the messages. Then you need to create Java helper classes that parse the data classes based upon the XSD schema and convert the data to and from XML formatted strings. The Java data classes can then be serialized in to XML formatted strings and back again using the helper classes.

You then build a Java class that exposes the correct methods for the Web service. This class accepts and returns primitive data types, performs any data conversion between what the Web service uses and what the Business tier service fa ade(s) expect, and calls the correct method on the service fa ade. Once you create this Java class, you can expose this as a Web service using whatever techniques your Web service stack provides.

To build your Java Web service, complete the following tasks:

  1. Create the XSD-based data types and XML mapping for serialization.

  2. Create a Java Helper Class

  3. Create and expose the Java class as a Web service.

Creating the Data Types and XML Mapping

The first part in creating the WS service interface is to create any data manipulation code you need. Since you should have an XSD Schema to work with, you can use one of the many Java XML products to generate a Java class from this schema.

Many Java XML products contain mapping files, which map a field in the class to an element or attribute in the XML Schema. Sometimes your existing classes map to the correct Schema without needing an intermediary. If this is the case, create mapping files for you existing classes, as this removes the step of taking the data from the existing Java classes into the Schema-based Java classes.

The XBikes developers used GLUE as the Java Web services stack. GLUE also contains Electric XML in the same package. Electric XML includes tools for building Java classes from an XSD. Electric XML also produces a mapping file which GLUE uses when reading or writing the XML data to or from Java classes.

The developers used these tools to build the Java classes from the XSD files. Conveniently, the generated classes were almost the same as the existing Java data classes. In these cases, the developers modified the created mapping files and then serialized the existing classes.

The following steps illustrate how to create the Java class from the CustomerData XSD files, which the developers implemented in the AuthenticateCustomer use case using the GLUE tools:

  1. The XBikes developers designed the CustomerData XSD file using the XSD Designer in Visual Studio .NET 2003. For more information about XSD Designer and XSD files, see Chapter 3.

    Note

    These steps assume the computer has a licensed copy of GLUE installed and a valid Java path configured.

  2. The developers created the Java classes based on the CustomerData.xsd file. GLUE provides a schema2java tool, which the developers used to create the Java class in the correct package for the project by running the following command.

     schema2Java CustomerData.xsd -g -p xbikes.common.dataconverters.customers 

This command generated two classes, Customers_TYPE.Java and CustomerData_TYPE.Java. The tool also generated a CustomerData.map which the serializer uses to map the fields to the correct XML elements.

Creating the Java Helper Class

After you have these XSD-based classes, you should move the data from the original Java data classes into the XSD-based classes. After you populate the XSD classes, you need to serialize them to an XML formatted string. It makes sense to put this serialization code into a method in a helper class, and this is what the XBikes developers did.

The following steps illustrate how the developers created the Java helper class for the CustomerData XSD based classes:

  1. The Developers created a helper class containing two methods to read and write the data to and from a string. The methods accepted a single parameter for the type of data you want to convert, and returned a single value of the converted type. The following method signatures show this.

     public static String orderToString(Order o);
    public static Order StringToOrder(String o);

  2. The developers then added the files created in steps 1 and 2 to the Java project, placing them in the common package for easy access. As you can see from the schema2Java command line in step 1, the package destination was xbikes.common.dataconverters.customers.

  3. As GLUE is the chosen environment, the team added Glue.jar to the build path.

  4. Next the developers generated the helper class to perform the conversion to and from the Java classes into the strings. They added a new class called CustomerConverter to the xbikes.common.dataconverters package.

  5. The developers added two methods to the CustomerConverter class, one to convert the Java data into a string, and the other to convert a string into the Java data. These methods use the GLUE serializer to read and write the XML. Because the existing Java CustomerData class is not compatible with the schema, this requires population of the CustomerData_TYPE and Customers_TYPE classes as part of the conversion. This code listing shows the completed CustomerConverter class.

     public final class CustomerConverter {     private static final String WRITER = "CustomerData";     private static final String NAMESPACE = 
    "http://tempuri.org/CustomerData.xsd"; public static CustomerData stringToCustomerData(String xml)
    throws XBikesInteropException { try { // Need to convert the string into xml Document d = new Document(xml); IReader reader = new LiteralReader(d); CustomerData_TYPE myCustomer = (CustomerData_TYPE) reader.readObject(CustomerData_TYPE.class); Customers_TYPE customer = myCustomer.getCustomers(); CustomerData cd = new CustomerData(); cd.setAddress(customer.getEmailAddress()); cd.setCustomerID(customer.getCustomerID()); cd.setName(customer.getFullName()); cd.setPassword(customer.getPassword()); cd.setZip(customer.getZipCode()); return cd; } catch (Exception e) { System.out.println(e.getMessage()); throw new XBikesInteropException(e.getMessage()); } } public static String customerDataToString(CustomerData cd)
    throws XBikesInteropException { try { // Move the data from the internal Java classes into those
    // generated by the schema tool Customers_TYPE customer = new Customers_TYPE(); customer.setCustomerID(cd.getCustomerID()); customer.setEmailAddress(cd.getAddress()); customer.setFullName(cd.getName()); customer.setPassword(cd.getPassword()); customer.setZipCode(cd.getZip()); CustomerData_TYPE customerData = new CustomerData_TYPE(); customerData.setCustomers(customer); // Write the object to a string, via the LiteralWriter / Document
    // and StringBuffer IWriter writer = new LiteralWriter(WRITER); writer.writeObject(customerData); writer.writeNamespace("", NAMESPACE); Document d = writer.getDocument(); String sCustomerData = ""; StringWriter sw = new StringWriter(); d.write(sw); sCustomerData = sw.getBuffer().toString(); return sCustomerData; } catch (Exception e) { System.out.println(e.getMessage()); throw new XBikesInteropException(e.getMessage()); } }

Creating and Exposing a Java Class as a Web Service

Your final task is to build and expose the Java Web service. The exact mechanics of this depend on which Web service stack you have decided to use. The XBikes developers used GLUE, so there may be steps that you do not need to carry out in your chosen stack.

The Mind Electric, like many other Java Web service vendors, implements Web services in GLUE through a servlet. Therefore you need a Web application to host this component. The Web service needs to contain all the methods that you want to expose from the BusinessServiceFacade, but rather than return the Java data types, you should return strings. The Web service therefore should convert any Java data types into strings containing XML, that has been formatted according to the XSD files. In the following example, you already have the code for this in a helper, so you simply need to make a method call. The flow of logic in any of the Web service methods is as follows:

  1. Application calls the Web service method.

  2. Web service passes any data that requires converting to the helper class.

  3. The Web service creates the home interface for the BusinessServiceFacade session bean.

  4. The Web service calls the appropriate method on the BusinessServiceFacade, passing the converted data.

  5. If the BusinessServiceFacade returns data, use the helper class to convert this to a string.

  6. Return the string representation of the data back to the calling application.

Figure 7.3 shows this in action.

click to expand
Figure 7.3: Using the Data Helper class in a Web service

You now have all the pieces you need to build the Web service. Because GLUE implements the Web service stack as a servlet, you need to create a Web project in the XBikes solution to host this servlet.

Note

GLUE also provides its own container to run GLUE Web services if you are not using an application server.

The XBikes developers carried out the following steps to implement the Web service:

  1. The developers created a new Web Project called XBikesBLLServiceInterface within IBM WebSphere Studio. They then added this project to the existing Enterprise Application Project called SingleTierXBikes.

  2. The Web service needs to call objects within both the XBikesCommon and XBikesBiz projects, so the developers added these as module dependencies.

  3. GLUE provides a template application that you can use. This template contains all the files required to run a GLUE Web service on an application server. You should find these files in the C:\Tme\Glue\App-Template folder. The developers copied these files into the project to get the basic GLUE files and the required folder structure. They also added the Glue.jar file to the build path.

  4. The developers then built the class that the application exposes as the Web service. This class has the same methods as BusinessServiceFacade, but uses strings as the data type, rather than the existing Java classes.

  5. The team created a new interface and class based upon the methods in BusinessServiceFacade, replacing the data types with strings. They added these classes to the xbikes.bll.serviceinterface.j2ee.ws package. The following code sample shows the methods added to IBLLWSServiceInterface.

     public String authenticateCustomer(String email, String password)         throws XBikesInteropException; public String getCategories() throws XBikesInteropException; public String getProductsByCategory(int categoryID)         throws XBikesInteropException; public String getSearchResults(String keyword)         throws XBikesInteropException; public String placeOrder(String order) throws XBikesInteropException; public String getCustomerOrders(int customerID)         throws XBikesInteropException; 

  6. The following code shows the implementation of the AuthenticateCustomer method in the XBikesBLLServiceInterface class.

     package xbikes.bll.serviceinterface.j2ee.ws; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.rmi.PortableRemoteObject; import xbikes.bll.facade.BusinessServiceFacade; import xbikes.bll.facade.BusinessServiceFacadeHome; import xbikes.common.data.CustomerData; import xbikes.common.dataconverters.CustomerConverter; import xbikes.common.exceptions.XBikesInteropException; public class BLLWSServiceInterface implements IBLLWSServiceInterface {     private static final String BUSINESS_FACADE_JNDI = 
    "ejb/xbikes/bll/facade/BusinessServiceFacadeHome"; /** * @see
    xbikes.bll.serviceinterface.j2ee.ws.IBLLWSServiceInterface#authenticate
    Customer(String, String) */ public String authenticateCustomer(String email, String password) throws XBikesInteropException { try { BusinessServiceFacade facade = getFacadeHome().create(); CustomerData cd = facade.authenticateCustomer(email, password); String sCustomerData = CustomerConverter.customerDataToString(cd); // We now have a string that contains the xml.
    // We shall return that! return sCustomerData; } catch (Exception e) { throw new XBikesInteropException(e.getMessage()); } } }

    Note

    In this class the developers created a helper method to allow easy access to the BusinessServiceFacade session bean.

  7. As you have now created the class that provides the functionality for the Web service, you simply need to tell GLUE about it. In XBikes, the developers went to the XBikesBLLServiceInterface\Web Content\WEB-INF\services folder, then copied and renamed the sample configuration file Sample.xml to make the new BLLWSServiceInterface.xml file.

  8. The developers modified this file, changing the constructor tag with xbikes.bll.serviceinterface.j2ee.we.BLLWSServiceInterface. They altered the description tag to Bikes Unsecure Web Service, the publish tag to yes and the style to document. They also amended the interface tag, replacing electric.util.sample.ISample with xbikes.bll.serviceinterface.j2ee.ws.IBLLWSServiceInterface and the targetNamespace to http://www.xbikes.com/.

  9. They then copied the maps created earlier into the Web Content\WEB-INF\Maps folder.

  10. To test the Web service, the developers compiled and started the server. They opened a browser and pointed it to http://localhost:9080/XBikesBLLServiceInterface/Console before using the GLUE console to invoke the authenticateCustomer method.

Creating the Interoperability Adapters in .NET

You have now created the Web service service interface in Java, so you can proceed to build the .NET interoperability adapters. The procedures to do this are as follows:

  • Build the .NET data classes based on the XSD schema.

  • Build a Web service proxy using the tools in Visual Studio .NET.

  • Create an adapter for either the entire service interface, or one for each use case.

    Note

    In XBikes, the developers created an adapter for each use case.

The interoperability adapter calls the proxy, which then calls the Web service. The adapter also has to convert any .NET data to and from the correct string/XML format based on the XSD schema.

The logic flow for an adapter is as follows:

  1. The application calls the adapter method.

  2. The adapter converts any complex data to an XML string representation.

  3. The adapter creates an instance of the Web service proxy.

  4. The application calls the appropriate method in the Web service proxy.

  5. If the proxy returns data, convert it into the correct .NET format if necessary.

  6. Return the data back to the calling application.

Figure 7.4 shows this in operation.

click to expand
Figure 7.4: Web service proxy operation with .NET Framework applications

Creating the XSD based Data Classes

To enable .NET Framework applications to consume data from the Java Web service, you need to have a .NET class that you can populate with the returned XML string. Again you can use a tool that converts the schema into a class, which is the XSD.EXE tool.

XSD.EXE accepts the /dataset switch to generate a sub-classed dataset. If you are building the .NET Framework application from scratch, it may be worth considering using the datasets that XSD generates in your .NET Framework application. This removes the need to convert from the XSD-based classes into a differently formatted or structured .NET class.

The XBikes developers used the XSD tool with the /dataset switch to generate the .NET dataset classes. They then used these datasets throughout the entire .NET Framework application to remove the need to convert between data that the Java Web service returns and proprietary .NET classes.

Note

An alternative technique would be to use a graphical tool such as XML Schema Designer in Visual Studio .NET 2003.

To create the CustomerData data type in .NET the developers opened a Visual Studio .NET 2003 command prompt and executed the following command.

 xsd CustomerData.xsd /dataset /namespace:xbikes.common.schemas 

They then copied the generated file into the XBikes-Common project.

Creating the .NET Web Service Proxies

The next task is to build the proxy classes for the Web service. You can use Visual Studio .NET or the wsdl.exe command line tool depending on your preference. If you use Visual Studio .NET, add a Web reference to the project that contains your interoperability adapters. When you create the Web reference, enter the URL to the Java WSDL file. If you prefer the wsdl.exe command line tool, you should specify switches to create the proxy class in the correct namespace.

Note

When you add a Web reference to your project in Visual Studio .NET, it will have a default name which is the same as the server name portion of the URL where the Web service’s WSDL is located. The proxy class generated by the Web reference belongs to a namespace which is the default namespace for the project suffixed with the name of the Web reference. It is good practice to give the Web reference, and thus the proxy namespace, a name other than the default name.

Because XBikes consumes a simple Web service, the developers used the Add Web Reference functionality of Visual Studio .NET to create the proxy. They added this proxy to the XBikes-UseCaseInteropAdapters project. The URL to the Java WSDL was http://localhost:9080/XBikesBLLServiceInterface/services/BLLWSServiceInterface.wsdl. The developer team renamed the Web Reference from its default value of localhost to J2EE.BLLWSSI. This new name reflects that this Web reference is for the J2EE business logic layer WS service interface. The proxy class generated by this Web reference then belongs to the XBikes.UseCaseInteropAdapters.J2EE.BLLWSSI namespace.

Creating the .NET Interoperability Adapters

Now that you have the data classes and Web service proxy, you can build the interoperability adapters. As discussed earlier in this chapter, you may choose to have a single adapter per Web service, or create an adapter for each use case, depending upon the level of fine control you require. The XBikes developers created an adapter for each use case to give maximum flexibility.

The XBikes use cases follow the command pattern, providing an execute and initialise method, and implement an interface called IUseCaseCommand. The adapters take names from the command they adapt, so AuthenticateCustomerInteropAdapter links to the AuthenticateCustomerCommand.

Creating the interoperability adapter for the AuthenticateCustomer use case was straight forward. In the XBikes-UseCaseInteropAdapters project the developers added a new class called AuthenticateCustomerInteropAdapter to the J2EE\WS folder. Next they changed the class to implement the IUseCaseCommand interface. This required them to implement both execute and initialise methods and to add code to the class constructor. The following code listing illustrates the Constructor and Initialise methods.

 public AuthenticateCustomerInteropAdapter() {     try     {         // Instantiate the BLL service interface proxy.         // Creates a J2EE-side BLL service interface         _facade = new BLLWSServiceInterface();     }     catch (Exception e)     {         throw new XBikesInteropException("[AuthenticateCustomer]:
J2EE WS Interop Adapter error: ", e); } } private string _email; private string _password; public void Initialise(object[] parameters) { _email = (string) parameters[0]; _password = (string) parameters[1]; }

The execute method needs to create an instance of the Web services proxy generated earlier. The returned string data then needs packaging up into a dataset before being returned. The next code listing shows the execute method.

 public DataSet Execute() {     try     {         //Retrieve customer data as an XML Document in a string format.         StringReader sr = new 
StringReader(_facade.authenticateCustomer(_email,_password)); CustomerData ds = new CustomerData(); //Load result string back into CustomerData typed DataSet. ds.ReadXml(sr); return ds; } //soap error catch (System.Web.Services.Protocols.SoapException soapExp) { string soapFaultMsg = soapExp.Message; //Parse SoapException message to get exception type. string ExceptionType = ExceptionHelper.GetSoapExceptionType(soapFaultMsg); //Throw the appropriate exception type based on the //exception type found in the SoapException. switch (ExceptionType) { case "Interop": throw(new XBikesInteropException(soapFaultMsg)); case "Application" : throw(new XBikesApplicationException(soapFaultMsg)); default: throw(new XBikesApplicationException(soapFaultMsg)); }//switch } //general error catch (Exception e) { //Wrap in Interop Exception XBikesInteropException intExp = new
XBikesInteropException("AuthenticateCustomer WS Interop
Adapter error.",e); //Throw up the stack to client for logging. throw (intExp); } }

When implementing this procedure, the string data that the Web service returns should be in the correct format according to the common XML Schema for CustomerData. Since the CustomerData typed DataSet is based on the common schema, you can load the XML string that the Web service returns into the DataSet using the ReadXML() method.

Note

The code example assumes the XML string returned matches the correct schema format, as the application generates an exception if this is not the case. You may wish to run the returned XML string through a validation process against the XSD schema file in order to confirm this before attempting to use the ReadXML() method to load the string into the typed DataSet.

In this section you saw how to create interoperability adapters and service interfaces in Java and .NET that use Web services to interoperate. In the next sections you look at how to implement interoperability adapters and service interfaces using JNBridgePro and Ja.NET to provide higher performance interoperability solutions.




Application Interoperability. Microsoft. NET and J2EE
Application Interoperability: Microsoft .NET and J2EE: Microsoft(r) .Net and J2ee (Patterns & Practices)
ISBN: 073561847X
EAN: 2147483647
Year: 2003
Pages: 104

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net