5.4. General Considerations

There are some general considerations that Web service client developers might want to keep in mind. In particular, developers need to be aware of the issues regarding conversational state. Also included in this section are some guidelines for improving or enhancing the user experience, and a short discussion of server-side design considerations. Last, there is an explanation of how to package client applications.

5.4.1. Managing Conversational State

Clients should view Web services as stateless and should assume that a service endpoint retains no knowledge of previous client interactions. However, some use cases may require a client to make a sequence of calls to a service to accomplish a given operation.

It is best if the client application maintains state when circumstances require this. The client may manipulate this retained state when not online. There are ways for a client to identify itself across multiple calls to a service and manage its state to keep it in sync with state on the server.

5.4.1.1. Coordinating State with a Service Endpoint

There are certain situations where the client may want to have its conversational state managed by the service endpoint. A client application, for example, may have only minimal processing capabilities and insufficient memory resources to adequately store its conversational state during a session interaction with a service. For a service endpoint to maintain conversational state with its clients, the endpoint must be designed with this in mind.

Often, such endpoints are designed to use a unique, nonreplicable token to identify communication from a specific client, much like browsers use the cookie mechanism. The service endpoint and the client application pass the token between them with each call during their conversation. Code Example 5.18 shows the definition of an order management service endpoint's methods for retrieving and updating a purchase order. Each method includes a token parameter, clientToken, that identifies the specific client. The client application creates a unique token and passes it to the service endpoint when invoking these methods. When it receives the method invocation, the service endpoint identifies the client and persists its state. In this example, notice that the endpoint can identify the purchase order because the same client token is passed when retrieving and updating the purchase order.

Code example 5.18. Service Endpoint Interface Methods with Unique Tokens
public interface OrderManagementSEI extends Remote {
   public void updatePurchaseOrder(PurchaseOrder po,
          String clientToken) throws RemoteException;
   public PurchaseOrder getPurchaseOrder(String id,
          String clientToken) throws RemoteException;
}

When an EJB component is the basis for a service endpoint, the EJB component can persist conversational state to a data store during the session. The service endpoint may still be designed to use tokens, and such tokens may represent the primary key of an entity bean. In this case, the endpoint designer must be sure to clean up stale session data from the persistent store. This can be done using a time stamp on the entity bean holding the conversational state and a timer bean to track elapsed time. An endpoint that does not properly clean up stale session data might eventually persist a large amount of data.

A client developer whose application interacts with an endpoint that stores conversational state needs to have detailed knowledge of the endpoint's token requirements and the state maintained by the endpoint. In addition, the developer needs detailed knowledge of the timeout, if one exists. This coordination between the client and endpoint makes them tightly coupled. As such, developers should use this approach only when a tightly coupled situation is acceptable or required, or when the client and service endpoint responsibilities are clearly documented.

5.4.1.2. Synchronizing Shared State among Clients

There are times when multiple Web service clients share state among themselves. Such shared state may be read only or it may be state that is updated. Read-only state does not require synchronization—since clients are retrieving data only, they may poll the service at intervals and obtain current data. However, it is possible for other Web clients to concurrently update shared data. Data consistency is an issue when one or more clients may be manipulating the same data at the same time.

An example use case that illustrates sharing modifiable state among Web service clients might be purchase order management client application. The application accesses a set of purchase orders that require manual approval. After the user manually processes these orders offline, the application uploads them to the service. It is conceivable that two such client applications may each download some of the same purchase orders, and some of these orders may be changed independent of each other. After the first client application uploads its changed data to the service, there is a data consistency problem if the second application tries to upload its modified data.

To prevent such inconsistencies, the client developer should keep certain considerations in mind. The developer can detect data inconsistency using techniques such as time-stamp checking or checksum analysis before uploading modified data, and this may require cooperation from the service endpoint. Data locking is another technique to avoid simultaneous changes to the same data. A service endpoint could throw a service-specific exception indicating that data has been modified by another client and might be out of sync. The client application can be designed to overwrite the service endpoint copy, or it can ask the user to re-enter the data. Both client and service endpoint developers need to ensure that their respective applications handle such inconsistencies properly.

5.4.2. Enhancing User Experience

The dynamics of the user interface play a large role in determining the quality of a user's experience. J2SE clients have the advantage of drawing on a rich set of APIs, in particular the Swing APIs, to make the user experience the highest quality possible. These APIs give J2SE clients the ability to query a Web service in the background, by invoking the Web service in a different thread, and then updating the user interface when the information is received. The client is able to continue its interaction with the user until the service returns the information. With other types of clients, the user is often left with what appears to be a frozen screen or a nonfunctional or locked application, since the client application blocks during the call to the Web service. In short, the user does not know whether the application is still alive.

A J2SE client can use the SwingUtilities.invokeLater method to make the call to the service in a separate thread, and thus to achieve a better user experience. (See Code Example 5.19.) This method takes a single argument of an object implementing the Runnable interface. When the invokeLater method is invoked, the J2SE platform creates another thread to run in background mode by invoking the run method on the Runnable class.

Code example 5.19. J2SE Client Using SwingUtils.invokeLater
private void trackOrder() {
   setStatus("Tracking Order " + getOrderId());
   GetOrderDetails gd = new GetOrderDetails(this);
   SwingUtilities.invokeLater(gd);
}

class GetOrderDetails implements Runnable {
   private OTClientGUI gui;
   private String orderId;
   boolean done = false;

   GetOrderDetails(OTClientGUI gui) {
       this.gui = gui;
       this.orderId = gui.getOrderId();
   }

public void run() {
   if (!done) {
      try {
         gui. setStatus("Looking for Order " + orderId);
         OrderDetails od = WSProcessor.getOrderDetails(orderId);
         if (od != null) {
            gui.setDetails(od);
         }
      } catch (OrderNotFoundException ex) {
         gui.clearDetails();
         gui.setStatus("");
         JOptionPane.showMessageDialog(gui,
            "Order Not found with Order ID " + orderId,
            "Error",
             JOptionPane.ERROR_MESSAGE);
      } catch (Exception ex) {
         // do nothing for now
      }
      gui.setStatus("Completed lookup for order ID " + orderId);
      SwingUtilities.invokeLater(this);
      done = true;
      }
   }
}

This example illustrates how a J2SE client can use the J2SE platform APIs to enhance the user experience. In this example, the user has selected an option to track an order currently being handled by the Web service. That option calls the invokeLater method, which in turn invokes a class implementing the Runnable interface. This class, using a callback mechanism, updates the user with messages indicating the status of the Web service call and details pertaining to the order being tracked. If the order is not found, the code handles displaying to the user a suitable error message indicating the exception.

Note: More information is available on the SwingUtilities API, along with using threads and GUIs with J2SE clients. You can find this information at http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html.

5.4.3. Server-Side Design Considerations for Clients

It should be clear by now that client developers and service endpoint providers do not operate in a vacuum. When it is known that the target client environment is based on JAX-RPC, the service endpoint developer can provide prepackaged libraries and server-side documentation. These libraries should contain all files, such as the client-side representation of the service endpoint interface and its dependent classes, that are necessary to access the service. The library can include additional façade classes that simplify the client view of the service and potentially shield the client from some future changes to the service. These façade classes help a client developer to not only access the service in a standardized manner, but may also improve their understanding of the service endpoint so as to develop better clients.

More extensive HTML documentation of a service covering parameters required by the service, return values, and exceptions helps developers better interact with the service. This information should go beyond what is included in the WSDL document.

5.4.4. Packaging

To access a service, a stand-alone client requires a runtime environment. For J2SE clients, the runtime must be packaged with the application. J2EE clients rely on the JAX-RPC runtime.

J2ME clients do not need to package the JAX-RPC runtime with the applications. Although stubs do need to be packaged with an application, the stubs are portable across JAX-RPC runtimes. The portability of stubs is critical because J2ME clients cannot generate or compile stub implementation code, and thus must rely on more dynamic provisioning.

This section discusses packaging issues for the different types of clients.

5.4.4.1. J2EE Clients

Web service clients running in a J2EE environment require some basic artifacts, as follows:

  • Service reference— A service-ref element in the deployment descriptor

  • Mapping file— A JAX-RPC mapping file

  • WSDL document

  • Service endpoint interface— A stub or dynamic proxy

  • Generated classes

The service-ref element, part of the general J2EE 1.4 schema, contains information about a service. Web, EJB, and J2EE application client module deployment descriptors use this element to locate the JAX-RPC mapping files as well as the service's WSDL file. The service reference element maps a service to a JNDI resource name and also specifies the service endpoint interface for those clients using stubs and dynamic proxies. (Clients using DII do not need to specify the service endpoint interface.) It also specifies the WSDL file for the service (its location is given relative to the root of the package) and the qualified name for the service in the WSDL file. If a WSDL file is required, the element specifies a JAX-RPC mapping file. The mapping file's location is also relative to the package root. Code Example 5.20 is an example of a service reference:

Code example 5.20. web.xml Fragment for Web Service Reference
<service-ref>
   <description>OPC OT Service Client</description>
   <service-ref-name>service/OpcOrderTrackingService
   </service-ref-name>
   <service-interface>
      com.sun.j2ee.blueprints.adventure.web.actions.
         OpcOrderTrackingService
   </service-interface>
   <wsdl-file>WEB-INF/wsdl/OpcOrderTrackingService.wsdl
   </wsdl-file>
   <jaxrpc-mapping-file>WEB-INF/opc-ot-jaxrpc-mapping.xml
   </jaxrpc-mapping-file>
   <service-qname
      xmlns:servicens="urn:OpcOrderTrackingService">
         servicens:OpcOrderTrackingService
   </service-qname>
</service-ref>

The JAX-RPC mapping file specifies the package name containing the generated runtime classes and defines the namespace URI for the service. (See Code Example 5.21.)

Code example 5.21. JAX-RPC Mapping File
<java-wsdl-mapping xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee ht
    tp://www.ibm.com/webservices/xsd/j2ee_jaxrpc_mapping_1_1.xsd"
version="1.1">
<package-mapping>
   <package-type>com.sun.j2ee.blueprints.adventure.web.actions
</package-type>
<namespaceURI>urn:OpcOrderTrackingService</namespaceURI>
</package-mapping>
</java-wsdl-mapping>

WSDL files, including partial WSDL files, are packaged within clients. Their location is dependent on the type of module. Since clients using DII do not require a WSDL file, they leave the wsdl-file element portion of the service-ref element undefined and they must not specify the jaxrpc-mapping-file element.

For a web application archive (WAR) file, the WSDL file is in the WEB-INF/wsdl directory. (See Figure 5.8.) For an EJB endpoint as well as a J2EE application client, the WSDL file is in the directory MET-INF/wsdl. (See Figure 5.9.) Both directories are relative to the root directory of the application module.

Figure 5.8. Web Application Module Packaging


Figure 5.9. EJB Module Packaging


For Web tier clients, a service-ref element in the web.xml file contains the location of the JAX-RPC mapping file, client-jaxrpc-mapping-file.xml. The service endpoint interface (if provided) is either a class file in the WEB-INF/classes directory or it is packaged in a JAR file in the WEB-INF/lib directory. Generated classes are located in the same directory.

For EJB tier client components, the service-ref element is defined in the deployment descriptor of the ejb-jar.xml file and the client-jaxrpc-mapping-file.xml mapping file. The WSDL files are in a META-INF/wsdl directory. The service endpoint interface as well as generated class files are stored in the module's root directory.

The client developer should ensure that the resource-ref definition in the client deployment descriptor is correct and that the JAX-RPC mapping file is packaged in the correct module.

5.4.4.2. J2SE Clients

J2SE clients using stubs or dynamic proxies should package the service endpoint interface with the application client, and they should be referenced by the class path attribute of the package's manifest file. J2SE clients also must provide a JAX-RPC runtime. For example, a J2SE client is packaged along with its supporting classes or with references to these classes. (See Figure 5.10.) The service endpoint interface as well as the necessary generated files may be provided in a separate JAR file.

Figure 5.10. Packaging a J2SE Client with Web Service Library


Figure 5.10 shows how to package a J2SE client in a modular manner. The classes specific for Web service access are kept in a separate JAR file referenced via a class path dependency. Packaged this way, a client can swap out the service endpoint access without having to change the core client code. The service access classes may also be shared by different application clients accessing the same service. A developer utilizing a prepackaged service interface may also be able to develop a Web service client with less knowledge of a service.

5.4.4.3. J2ME Clients

Two optional packages, both of which are extensions of the J2ME platform, enable Web services in the J2ME platform by providing runtime support for XML processing and JAX-RPC communication. (Note that although XML processing capabilities are not provided in the J2ME platform, they are required for JAX-RPC communication.)

A J2ME client application developer must package certain resources with a J2ME application. First, J2ME applications are packaged in a MIDlet format. A MIDlet is a Java Archive (JAR) file that contains class files, application resources, and a manifest file (manifest.mf), which contains application attributes.

A developer may also provide an external Java Application Descriptor (JAD) file for the MIDlet. A JAD file provides the J2ME environment with additional information about the application, such as the location of the application's MIDlet file. A JAD file's attributes mirror those found in the manifest file, but the JAD file takes precedence over the manifest file. Furthermore, a developer or deployer may override application attributes in the JAD file. Figure 5.11 describes the packaging for a Web service MIDlet client application.

Figure 5.11. Packaging a MIDlet Web Service Client Application


The foo.jar MIDlet file contains the client application classes and the respective artifacts generated by the J2ME Web service development tools, as well as a manifest file. A foo.jad file describes the foo.jar MIDlet. Similar to the J2EE platform, the J2ME platform with the optional Web service packages provides the resources required for Web service communication.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset