CONTENTS | PREV | NEXT | INDEX Designing Web Services
with the J2EETM 1.4 Platform



3.4 Designing a Service's Interaction Layer

A service's interaction layer has several major responsibilities, and chief among them is the design of the interface the service presents to the client. Since clients access the service through it, the interface is the starting point of a client's interaction with the service. The interaction layer also handles other responsibilities, such as receiving client requests, delegating requests to appropriate business logic, and creating and sending responses. This section examines the responsibilities of the interaction layer and highlights some guidelines for its design.


3.4.1 Designing the Interface

There are some considerations to keep in mind as you design the interface of your Web service, such as issues regarding overloading methods, choosing the endpoint type, and so forth. Before examining these issues, decide on the approach you want to take for developing the service's interface definition.

Two approaches to developing the interface definition for a Web service are:

  1. Java-to-WSDL--Start with a set of Java interfaces for the Web service and from these create the Web Services Description Language (WSDL) description of the service for others to use.
  2. WSDL-to-Java--Start with a WSDL document describing the details of the Web service interface and use this information to build the corresponding Java interfaces.

How do these two approaches compare? Starting with Java interfaces and creating a WSDL document is probably the easier of the two approaches. With this approach, you need not know any WSDL details because you use vendor-provided tools to create the WSDL description. While these tools make it easy for you to generate WSDL files from Java interfaces, you do lose some control over the WSDL file creation.

With the Java-to-WSDL approach, it may be hard to evolve the service interface without forcing a change in the corresponding WSDL document, and changing the WSDL might require rewriting the service's clients. These changes, and the accompanying instability, can affect the interoperability of the service itself. Since achieving interoperability is a prime reason to use Web services, the instability of the Java-to-WSDL approach is a major drawback. Also, keep in mind that different tools may use different interpretations for certain Java types (for example, java.util.Date might be interpreted as java.util.Calendar), resulting in different representations in the WSDL file. While not common, these representation variations may result in some semantic surprises.

On the other hand, the WSDL-to-Java approach gives you a powerful way to expose a stable service interface that you can evolve with relative ease. Not only does it give you greater design flexibility, the WSDL-to-Java approach also provides an ideal way for you to finalize all service details--from method call types and fault types to the schemas representing exchanged business documents--before you even start a service or client implementation. Although a good knowledge of WSDL and the WS-I Basic Profile is required to properly describe these Web services details, using available tools helps address these issues.

After you decide on the approach to take, you must still resolve other interface design details, which are described in the next sections.

3.4.1.1 Choice of the Interface Endpoint Type

In the J2EE platform, you have two choices for implementing the Web service interface--you can use a JAX-RPC service endpoint (also referred to as a Web tier endpoint) or an EJB service endpoint (also referred to as an EJB tier endpoint). Using one of these endpoint types makes it possible to embed the endpoint in the same tier as the service implementation. This simplifies the service implementation, because it obviates the need to place the endpoint in its own tier where the presence of the endpoint is solely to act as a proxy directing requests to other tiers that contain the service's business logic.

When you develop a new Web service that does not use existing business logic, choosing the endpoint type to use for the Web service interface is straightforward. The endpoint type choice depends on the nature of your business logic--whether the business logic of the service is completely contained within either the Web tier or the EJB tier:

When you add a Web service interface to an existing application or service, you must consider whether the existing application or service preprocesses requests before delegating them to the business logic. If so, then keep the following guideline in mind:

If the existing application or service does not require preprocessing of the incoming request, choose the appropriate endpoint that is present in the same tier as the existing business logic. Besides these major considerations for choosing an endpoint type, there are other, more subtle differences between an EJB service endpoint and a JAX-RPC service endpoint. You may find it helpful to keep in mind these additional points when choosing a Web service endpoint type:

3.4.1.2 Granularity of Service

Much of the design of a Web service interface involves designing the service's operations, or its methods. You first determine the service's operations, then define the method signature for each operation. That is, you define each operation's parameters, its return values, and any errors or exceptions it may generate.

For those Web services that implement a business process, the nature of the business process itself often dictates the service's granularity. Business processes that exchange documents, such as purchase orders and invoices, by their nature result in a Web service interface that is coarse grained. With more interactive Web services, you need to carefully choose the granularity of these operations.

You should keep the same considerations in mind when designing the methods for a Web service as when designing the methods of a remote enterprise bean. This is particularly true not only regarding the impact of remote access on performance but also with Web services; it is important with Web services because there is an underlying XML representation requiring parsing and taking bandwidth. Thus, a good rule is to define the Web service's interface for optimal granularity of its operations; that is, find the right balance between coarse-grained and fine-grained granularity.

More coarse-grained service operations, such as returning catalog entries in sets of categories, keep network overhead lower and improve performance. However, they are sometimes less flexible from a client's point of view. While finer-grained service operations, such as browsing a catalog by products or items, offer a client greater flexibility, these operations result in greater network overhead and reduced performance.

For example, consolidating logically different operations is inefficient and should be avoided. It is much better to consolidate similar operations or operations that a client is likely to use together, such as querying operations.

If you are planning to expose existing stateless session beans as Web service endpoints, remember that such beans may not have been designed with Web services in mind. Hence, they may be too fine grained to be good Web service endpoints. You should consider consolidating related operations into a single Web service operation.

Good design for our airline reservation Web service, for example, is to expect the service's clients to send all information required for a reservation--destination, preferred departure and arrival times, preferred airline, and so forth--in one invocation to the service, that is, as one large message. This is far more preferable than to have a client invoke a separate method for each piece of information comprising the reservation. To illustrate, it is preferable to have clients use the interface shown in Code Example 3.1.

public interface AirlineTicketsIntf extends Remote {
	public String submitReservationRequest(
			AirReservationDetails details) throws RemoteException;
}
Code Example 3.1 Using Consolidation for Greater Efficiency (Recommended)

Code Example 3.1 combines logically-related data into one large message for a more efficient client interaction with the service. This is preferable to receiving the data with individual method calls, as shown in Code Example 3.2.

public interface AirlineTicketsIntf extends Remote {
	public String submitFlightInformation(FlightDetails fltInfo)
						throws RemoteException;
	public String submitPreferredDates(Date depart, Date arrive)
					throws RemoteException;
	// other similar methods 
}
Code Example 3.2 Retrieving Data with Separate Method Calls (Not Recommended)

However, it might not be a good idea to combine in a single service invocation the same reservation with an inquiry method call.

Along with optimal granularity, you should consider data caching issues. Coarse-grained services involve transferring large amounts of data. If you opt for more coarse-grained service operations, it is more efficient to cache data on the client side to reduce the number of round trips between the client and the server.

3.4.1.3 Parameter Types for Web Service Operations

A Web service interface exposes a set of method calls to clients. When invoking a service interface method, a client may have to set values for the parameters associated with the call. When you design an interface's methods, choose carefully the types of these parameters. Keep in mind that a method call and its parameters are sent as a SOAP message between the client and the service. To be part of a SOAP message, parameters must be mapped to XML. When received at the client or service end, the same parameters must be mapped from XML to their proper types or objects. This section describes some guidelines to keep in mind when defining method call parameters and return values.

Note: Since each call potentially may return a value, the discussion in this section about parameter values applies equally to return values.

Figure 3.3 Binding Parameters and Return Values with JAX-RPC

Parameters for Web service method calls may be standard Java objects and types, XML documents, or even nonstandard types. Whether you use the Java-to-WSDL approach or the WSDL-to-Java approach, each type of parameter must be mapped to its XML equivalent in the SOAP message. Figure 3.3 shows how the binding happens for various types of parameters.

3.4.1.3.1 Java Objects as Parameters

Parameters for Web service calls can be standard Java types and objects. If you use the Java-to-WSDL approach, you specify the parameter types as part of the arguments of the method calls of your Java interface. If you use the WSDL-to-Java approach, you specify the parameter types as the type or element attributes of the part element of each message in your WSDL. The type of a parameter that you use has a significant effect on the portability and interoperability of your service.

The platform supports the following Java data types. (Refer to the JAX-RPC specification at http://java.sun.com/xml/jaxrpc/ for the equivalent WSDL mappings for these Java data types.)

As Figure 3.3 shows, parameters that have standard type mappings are bound implicitly. However, the developer must do more work when using parameters that do not have standard type mappings. See Handling Nonstandard Type Parameters for more details on using nonstandard Java types and possible side effects of such use.

Here are some additional helpful points to consider when you use Java objects with standard type mappings as parameters.

  1. Many applications and services need to pass lists of objects. However, utilities for handling lists, such as ArrayList and Collection, to name a few, are not supported standard types. Instead, Java arrays provide equivalent functionality, and have a standard mapping provided by the platform.
  2. JAX-RPC value types are user-defined Java classes with some restrictions. They have constructors and may have fields that are public, private, protected, static, or transient. JAX-RPC value types may also have methods, including set and get methods for setting and getting Java class fields.
  3. However, when mapping JAX-RPC value types to and from XML, there is no standard way to retain the order of the parameters to the constructors and other methods. Hence, avoid setting the JAX-RPC value type fields through the constructor. Using the get and set methods to retrieve or set value type fields avoids this mapping problem and ensures portability and interoperability.
  4. The J2EE platform supports nested JAX-RPC value types; that is, JAX-RPC value types that reference other JAX-RPC value types within themselves. For clarity, it is preferable to use this feature and embed value type references rather than to use a single flat, large JAX-RPC value type class.
  5. The J2EE platform, because of its support for the SOAP message with attachment protocol, also supports the use of MIME-encoded content. It provides Java mappings for a subset of MIME types. (See Table 3.1.)

    Mapping of MIME Types

    MIME Type

    Java Type

    image/gif

    java.awt.Image

    image/jpeg

    java.awt.Image

    text/plain

    java.lang.String

    multipart/*

    javax.mail.internet.MimeMultipart

    text/xml or application/xml

    javax.xml.transform.Source

Since the J2EE container automatically handles mappings based on the Java types, using these Java-MIME mappings frees you from the intricacies of sending and retrieving documents and images as part of a service's request and response handling. For example, your service, if it expects to receive a GIF image with a MIME type of image/gif, can expect the client to send a java.awt.Image object. A sample Web service interface that receives an image might look like the one shown in Code Example 3.3:

import java.awt.Image;
public interface WeatherMapService extends Remote {
	public void submitWeatherMap(Image weatherMap)
					throws RemoteException, InvalidMapException;
}
Code Example 3.3 Receiving a java.awt.Image Object

In this example, the Image object lets the container implementation handle the image-passing details. The container provides javax.activation.DataHandler classes, which work with the Java Activation Framework to accomplish the Java-MIME and MIME-Java mappings.

3.4.1.3.2 XML Documents as Parameters

There are scenarios when you want to pass XML documents as parameters. Typically, these occur in business-to-business interactions where there is a need to exchange legally binding business documents, track what is exchanged, and so forth. Exchanging XML documents as part of a Web service is addressed in a separate section--see Handling XML Documents in a Web Service for guidelines to follow when passing XML documents as parameters.

3.4.1.3.3 Handling Nonstandard Type Parameters

JAX-RPC technology, in addition to providing a rich standard mapping set between XML and Java data types, also provides an extensible type mapping framework. Developers can use this framework to specify pluggable, custom serializers and deserializers that support nonstandard type mappings.

Vendors currently can provide their own solutions to this problem. It must be emphasized that if you implement a service using some vendor's implementation-specific type mapping framework, then your service is not guaranteed to be portable and interoperable.

Instead, a better way is to pass these parameters as SOAP document fragments represented as a DOM subtree in the service endpoint interface. (See Figure 3.3.) If so, you should consider binding (either manually or using JAXB) the SOAP fragments to Java objects before passing them to the processing layer to avoid tightly coupling the business logic with the document fragment.

3.4.1.4 Interfaces with Overloaded Methods

In your service interface, you may overload methods and expose them to the service's clients. Overloaded methods share the same method name but have different parameters and return values. If you do choose to use overloaded methods as part of your service interface, keep in mind that there are some limitations, as follows:

Let's see how this applies in the weather service scenario. As the provider, you might offer the service to clients, letting them look up weather information by city name or zip code. If you use the Java-to-WSDL approach, you might first define the WeatherService interface as shown in Code Example 3.4.

public interface WeatherService extends Remote {
	public String getWeather(String city) throws RemoteException;
	public String getWeather(int zip) throws RemoteException;
}
Code Example 3.4 WeatherService Interface for Java-to-WSDL Approach

After you define the interface, you run the vendor-provided tool to create the WSDL from the interface. Each tool has its own way of representing the getWeather overloaded methods in the WSDL, and your WSDL reflects the particular tool you use. For example, if you use the J2EE 1.4 SDK from Sun Microsystems, its wscompile tool creates from the WeatherService interface the WSDL shown in Code Example 3.5.

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="WeatherWebService" .......>
	<types/>
	<message name="WeatherService_getWeather">
		<part name="int_1" type="xsd:int"/>
	</message>
	<message name="WeatherService_getWeatherResponse">
		<part name="result" type="xsd:string"/>
	</message>
	<message name="WeatherService_getWeather2">
		<part name="String_1" type="xsd:string"/>
	</message>
	<message name="WeatherService_getWeather2Response">
		<part name="result" type="xsd:string"/>
	</message>
	...
</definitions>
Code Example 3.5 Generated WSDL for WeatherService Interface

Notice that the WSDL represents the getWeather overloaded methods as two different SOAP messages, naming one getWeather, which takes an integer for the zip code as its parameter, and the other getWeather2, which takes a string parameter for the city. As a result, a client interested in obtaining weather information using a city name invokes the service by calling getWeather2, as shown in Code Example 3.6.

...
Context ic = new InitialContext();
WeatherWebService weatherSvc = (WeatherWebService)
		ic.lookup("java:comp/env/service/WeatherService");
WeatherServiceIntf port = (WeatherServiceIntf)
		weatherSvc.getPort(WeatherServiceIntf.class);
String returnValue = port.getWeather2("San Francisco");
...
Code Example 3.6 Using Weather Service Interface with Java-to-WSDL Approach

For example, to obtain the weather information for San Francisco, the client called port.getWeather2("San Francisco"). Keep in mind that another tool may very likely generate a WSDL whose representation of overloaded methods is different.

If instead you choose to use the WSDL-to-Java approach, your WSDL description might look as follows. (See Code Example 3.7.)

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="WeatherWebService" ...>
	<types/>
	<message name="WeatherService_getWeatherByZip">
		<part name="int_1" type="xsd:int"/>
	</message>
	<message name="WeatherService_getWeatherByZipResponse">
		<part name="result" type="xsd:string"/>
	</message>
	<message name="WeatherService_getWeatherByCity">
		<part name="String_1" type="xsd:string"/>
	</message>
	<message name="WeatherService_getWeatherByCityResponse">
		<part name="result" type="xsd:string"/>
	</message>
	...
</definitions>
Code Example 3.7 WSDL for Weather Service with Overloaded Methods Avoided

Since the messages in a WSDL file must have unique names, you must use different message names to represent methods that you would otherwise overload. These different message names actually convert to different method calls in your interface. Notice that the WSDL includes a method getWeatherByZip, which takes an integer parameter, and a method getWeatherByCity, which takes a string parameter. Thus, a client wishing to obtain weather information by city name from a WeatherService interface associated with the WSDL in Code Example 3.7 might invoke the service as shown in Code Example 3.8.

...
Context ic = new InitialContext();
WeatherWebService weatherSvc = (WeatherWebService)
		ic.lookup("java:comp/env/service/WeatherService");
WeatherServiceIntf port = (WeatherServiceIntf)
		weatherSvc.getPort(WeatherServiceIntf.class);
String returnValue = port.getWeatherByCity("San Francisco");
...
Code Example 3.8 Using Weather Service with WSDL-to-Java Approach
3.4.1.5 Handling Exceptions

Just like any Java or J2EE application, a Web service application may encounter an error condition while processing a client request. A Web service application needs to properly catch any exceptions thrown by an error condition and propagate these exceptions. For a Java application running in a single virtual machine, you can propagate exceptions up the call stack until reaching a method with an exception handler that handles the type of exception thrown. To put it another way, for non-Web service J2EE and Java applications, you may continue to throw exceptions up the call stack, passing along the entire stack trace, until reaching a method with an exception handler that handles the type of exception thrown. You can also write exceptions that extend or inherit other exceptions.

However, throwing exceptions in Web service applications has additional constraints that impact the design of the service endpoint. When considering how the service endpoint handles error conditions and notifies clients of errors, you must keep in mind these points:

A Web service application may encounter two types of error conditions. One type of error might be an irrecoverable system error, such as an error due to a network connection problem. When an error such as this occurs, the JAX-RPC runtime on the client throws the client platform's equivalent of an irrecoverable system exception. For Java clients, this translates to a RemoteException.

A Web service application may also encounter a recoverable application error condition. This type of error is called a service-specific exception. The error is particular to the specific service. For example, a weather Web service might indicate an error if it cannot find weather information for a specified city.

To illustrate the Web service exception-handling mechanism, let's examine it in the context of the weather Web service example. When designing the weather service, you want the service to be able to handle a scenario in which the client requests weather information for a nonexistent city. You might design the service to throw a service-specific exception, such as CityNotFoundException, to the client that made the request. You might code the service interface so that the getWeather method throws this exception. (See Code Example 3.9.)

public interface WeatherService extends Remote {
	public String getWeather(String city) throws 
				CityNotFoundException, RemoteException;
}
Code Example 3.9 Throwing a Service-Specific Exception

Service-specific exceptions like CityNotFoundException, which are thrown by the Web service to indicate application-specific error conditions, must be checked exceptions that directly or indirectly extend java.lang.Exception. They cannot be unchecked exceptions. Code Example 3.10 shows a typical implementation of a service-specific exception, such as for CityNotFoundException.

public class CityNotFoundException extends Exception {
	private String message;
	public CityNotFoundException(String message) {
		super(message);
		this.message = message;
	}
	public String getMessage() {
		return message;
	}
}
Code Example 3.10 Implementation of a Service-Specific Exception

Code Example 3.11 shows the service implementation for the same weather service interface. This example illustrates how the service might throw CityNotFoundException.

public class WeatherServiceImpl implements WeatherService {
	public String getWeather(String city)
								throws CityNotFoundException {
		if(!validCity(city))
			throw new CityNotFoundException(city + " not found");
		// Get weather info and return it back
	}
}
Code Example 3.11 Example of a Service Throwing a Service-Specific Exception

Chapter 5 describes the details of handling exceptions on the client side. (In particular, refer to "Handling Exceptions" on page 230.) On the service side, keep in mind how to include exceptions in the service interface and how to throw them. Generally, you want to do the following:

Although they promote interoperability among heterogeneous platforms, Web service standards cannot address every type of exception thrown by different platforms. For example, the standards do not specify how Java exceptions such as java.io.IOException and javax.ejb.EJBException should be returned to the client. As a consequence, it is important for a Web service--from the service's interoperability point of view--to not expose Java-specific exceptions (such as those just mentioned) in the Web service interface. Instead, throw a service-specific exception. In addition, keep the following points in mind:

As a result, you should avoid directly throwing java and javax exceptions to clients. Instead, when your service encounters one of these types of exceptions, wrap it within a meaningful service-specific exception and throw this service-specific exception back to the client. For example, suppose your service encounters a javax.ejb.FinderException exception while processing a client request. The service should catch the FinderException exception, and then, rather than throwing this exception as is back to the client, the service should instead throw a service-specific exception that has more meaning for the client. See Code Example 3.12.

...
try {
	// findByPrimaryKey
	// Do processing
	// return results
} catch (javax.ejb.FinderException fe) {
	throw new InvalidKeyException(
		"Unable to find row with given primary key");
}
Code Example 3.12 Converting an Exception into a Service-Specific Exception

You should avoid defining service-specific exceptions that inherit or extend other exceptions. For example, if CityNotFoundException in Code Example 3.10 extends another exception, such as RootException, then when the service throws CityNotFoundException, methods and properties inherited from RootException are not passed to the client.

The stack trace for an exception is relevant only to the current execution environment and is meaningless on a different system. Hence, when a service throws an exception to the client, the client does not have the stack trace explaining the conditions under which the exception occurred. Thus, you should consider passing additional information in the message for the exception.

Web service standards make it easier for a service to pass error conditions to a client in a platform-independent way. While the following discussion may be of interest, it is not essential that developers know these details about the J2EE platform's error-handling mechanisms for Web services.

As noted previously, error conditions are included within the SOAP messages that a service returns to clients. The SOAP specification defines a message type, called fault, that enables error conditions to be passed as part of the SOAP message yet still be differentiated from the request or response portion. Similarly, the WSDL specification defines a set of operations that are possible on an endpoint. These operations include input and output operations, which represent the request and response respectively, and an operation called fault.

A SOAP fault defines system-level exceptions, such as RemoteException, which are irrecoverable errors. The WSDL fault denotes service-specific exceptions, such as CityNotFoundException, and these are recoverable application error conditions. Since the WSDL fault denotes a recoverable error condition, the platform can pass it as part of the SOAP response message. Thus, the standards provide a way to exchange fault messages and map these messages to operations on the endpoint.

Code Example 3.13 shows the WSDL code for the same weather Web service example. This example illustrates how service-specific exceptions are mapped just like input and output messages are mapped.

<?xml version="1.0" encoding="UTF-8"?>
<definitions ...>
	...
	<message name="WeatherService_getWeather">
		<part name="String_1" type="xsd:string"/>
	</message>
	<message name="WeatherService_getWeatherResponse">
		<part name="result" type="xsd:string"/>
	</message>
	<message name="CityNotFoundException">
		<part name="CityNotFoundException"
						element="tns:CityNotFoundException"/>
	</message>
	<portType name="WeatherService">
		<operation name="getWeather" parameterOrder="String_1">
			<input message="tns:WeatherService_getWeather"/>
			<output message=
					"tns:WeatherService_getWeatherResponse"/>
			<fault name="CityNotFoundException"
						message="tns:CityNotFoundException"/>
		</operation>
	</portType>
	...
</definitions>
Code Example 3.13 Mapping a Service-Specific Exception in WSDL
3.4.1.6 Use of Handlers

As discussed in Chapter 2, and as shown in Figure 3.1, JAX-RPC technology enables you to plug in SOAP message handlers, thus allowing processing of SOAP messages that represent requests and responses. Plugging in SOAP message handlers gives you the capability to examine and modify the SOAP requests before they are processed by the Web service and to examine and modify the SOAP responses before they are delivered to the client.

Handlers are particular to a Web service and are associated with the specific port of the service. As a result of this association, the handler's logic applies to all SOAP requests and responses that pass through a service's port. Thus, you use these message handlers when your Web service must perform some SOAP message-specific processing common to all its requests and responses. Because handlers are common to all requests and responses that pass through a Web service endpoint, keep the following guideline in mind:

You cannot store client-specific state in a handler: A handler's logic acts on all requests and responses that pass through an endpoint. However, you may use the handler to store port-specific state, which is state common to all method calls on that service interface. Note also that handlers execute in the context of the component in which they are present.

Also note that handlers work directly on the SOAP message, and this involves XML processing. You can use handlers to pass client-specific state through the message context. (See "Passing Context Information on Web Service Calls" on page 366.)

Use of handlers could potentially affect the interoperability of your service. See the next section on interoperability. Keep in mind that it takes advanced knowledge of SOAP message manipulation APIs (such as SAAJ) to correctly use handlers. To avoid errors, Web service developers should try to use existing or vendor-supplied handlers. Using handlers makes sense primarily for writing system services such as auditing, logging, and so forth.

3.4.1.7 Interoperability

A major benefit of Web services is interoperability between heterogeneous platforms. To get the maximum benefit, you want to design your Web service to be interoperable with clients on any platform, and, as discussed in Chapter 2, the Web Services Interoperability (WS-I) organization helps in this regard. WS-I promotes a set of generic protocols for the interoperable exchange of messages between Web services. The WS-I Basic Profile promotes interoperability by defining and recommending how a set of core Web services specifications and standards (including SOAP, WSDL, UDDI, and XML) can be used for developing interoperable Web services.

In addition to the WS-I protocols, other groups, such as SOAPBuilders Interoperability group (see http://java.sun.com/wsinterop/sb/index.html), provide common testing grounds that make it easier to test the interoperability of various SOAP implementations. This has made it possible for various Web services technology vendors to test the interoperability of implementations of their standards. When you implement your service using technologies that adhere to the WS-I Basic Profile specifications, you are assured that such services are interoperable.

Apart from these standards and testing environments, you as the service developer must design and implement your Web service so that maximum interoperability is possible. For maximum interoperability, you should keep these three points in mind:

  1. The two messaging styles and bindings supported by WSDL
  2. The WS-I support for attachments
  3. The most effective way to use handlers

WSDL supports two types of messaging styles: rpc and document. The WSDL style attribute indicates the messaging style. (See Code Example 3.14.) A style attribute set to rpc indicates a RPC-oriented operation, where messages contain parameters and return values, or function signatures. When the style attribute is set to document, it indicates a document-oriented operation, one in which messages contain documents. Each operation style has a different effect on the format of the body of a SOAP message.

Along with operation styles, WSDL supports two types of serialization and deserialization mechanisms: a literal and an encoded mechanism. The WSDL use attribute indicates which mechanism is supported. (See Code Example 3.14.) A literal value for the use attribute indicates that the data is formatted according to the abstract definitions within the WSDL document. The encoded value means data is formatted according to the encodings defined in the URI specified by the encodingStyle attribute. Thus, you can choose between an rpc or document style of message passing and each message can use either a literal or encoded data formatting.

Code Example 3.14 shows a snippet from the WSDL document illustrating how the sample weather service specifies these bindings.

<?xml version="1.0" encoding="UTF-8"?>
<definitions .......>
<binding name="WeatherServiceBinding" type="tns:WeatherService">
	<operation name="getWeather">
		<input>
			<soap:body use="literal"
						namespace="urn:WeatherWebService"/>
		</input>
		<output>
			<soap:body use="literal"
						namespace="urn:WeatherWebService"/>
		</output>
		<soap:operation soapAction=""/></operation>
		<soap:binding style="rpc"
				transport="http://schemas.xmlsoap.org/soap/http" />
		</binding>
		<service .....>
</definitions>
Code Example 3.14 Specifying WSDL Bindings

It is important to keep in mind these message styles and bindings, particularly when you design the interface using the WSDL-to-Java approach and when you design the WSDL for your service. When you use the Java-to-WSDL approach, you rely on the vendor-provided tools to generate the WSDL for your Java interfaces, and they can be counted on to create WS-I-compliant WSDL for your service. However, note that some vendors may expect you to specify certain options to ensure the creation of a WS-I-compliant WSDL. For example, the J2EE 1.4 SDK from Sun Microsystems provides a wscompile tool, which expects the developer to use the -f:wsi flag to create the WS-I-compliant WSDL for the service. It is also a good idea to check the WSDL document itself to ensure that whatever tool you use created the document correctly.

Regarding the second issue, you should note that the WS-I Basic Profile 1.0 (which is the profile supported by the J2EE 1.4 platform) does not address attachments. The section, Parameter Types for Web Service Operations, which discussed Java-MIME type mappings provided by the J2EE platform, advised that an efficient design is to use these mappings to send images and XML documents within a completely Java environment. Because the WS-I Basic Profile, version 1.0 does not address attachments, a Web service that uses these mappings may not be interoperable with clients on a non-Java platform.

Since most Web services rely on an exchange of business documents, and interoperability is not always guaranteed, it is important that you properly understand the options for handling XML documents. The section, Exchanging XML Documents, explains the various options available to Web services for exchanging XML documents in an interoperable manner. It should also be noted that the next version of the WS-I Basic Profile specification addresses a standard way to send attachments, and later versions of the J2EE platforms will incorporate this.

Last is the issue of handlers. Handlers, which give you access to SOAP messages, at the same time impose major responsibilities on you.

This ends the discussion of considerations for designing a Web service interface. The next sections examine other responsibilities of the interaction layer, such as receiving and delegating requests and formulating responses.


3.4.2 Receiving Requests

The interaction layer, through the endpoint, receives client requests. The platform maps the incoming client requests, which are in the form of SOAP messages, to method calls present in the Web service interface.

As noted in Parameter Types for Web Service Operations and elsewhere, Web service calls are basically method calls whose parameters are passed as either Java objects, XML documents (javax.xml.transform.Source objects), or even SOAP document fragments (javax.xml.soap.SOAPElement objects).

You may have to undertake additional steps to handle XML documents that are passed as parameters. These steps, which are best performed in the interaction layer of your service, are as follows:

  1. The service endpoint should validate the incoming XML document against its schema. For details and guidelines on how and when to validate incoming XML documents, along with recommended validation techniques, refer to "Validating XML Documents" on page 139.
  2. When the service's processing layer and business logic are designed to deal with XML documents, you should transform the XML document to an internally supported schema, if the schema for the XML document differs from the internal schema, before passing the document to the processing layer.
  3. When the processing layer deals with objects but the service interface receives XML documents, then, as part of the interaction layer, map the incoming XML documents to domain objects before delegating the request to the processing layer. For details and guidelines on mapping techniques for incoming XML documents, refer to "Mapping Schemas to the Application Data Model" on page 143.

A design such as this helps to catch errors early, and thus avoids unnecessary calls and round-trips to the processing layer. Figure 3.4 shows the recommended way to handle requests and responses in the Web service's interaction layer.

The Web service's interaction layer handles all incoming requests and delegates them to the business logic exposed in the processing layer. When implemented in this manner, the Web service interaction layer has several advantages, since it gives you a common location for the following tasks:

Figure 3.4 Web Service Request Processing

It is generally advisable to do all common processing--such as security checks, logging, auditing, input validation, and so forth--for requests at the interaction layer as soon as a request is received and before passing it to the processing layer.


3.4.3 Delegating Web Service Requests to Processing Layer

After designing the request preprocessing tasks, the next step is to design how to delegate the request to the processing layer. At this point, consider the kind of processing the request requires, since this helps you decide how to delegate the request to the processing layer. All requests can be categorized into two large categories based on the time it takes to process the request, namely:

Note: When referring to request processing, we use the terms synchronous and asynchronous from the point of view of when the client's request processing completes fully. Keep in mind that, under the hood, an asynchronous interaction between a client and a service might result in a synchronous invocation over the network, since HTTP is by its nature synchronous. Similarly, SOAP messages sent over HTTP are also synchronous.

Figure 3.5 Weather Information Service Interaction

The weather information service is a good example of a synchronous interaction between a client and a service. When it receives a client's request, the weather service must look up the required information and send back a response to the client. This look-up and return of the information can be achieved in a relatively short time, during which the client can be expected to block and wait. The client continues its processing only after it obtains a response from the service. (See Figure 3.5.)

Figure 3.6 Synchronous Interaction Between Client and Service

A Web service such as this can be designed using a service endpoint that receives the client's request and then delegates the request directly to the service's appropriate logic in the processing layer. The service's processing layer processes the request and, when the processing completes, the service endpoint returns the response to the client. (See Figure 3.6.)

Code Example 3.15 shows the weather service interface performing some basic parameter validation checks in the interaction layer. The interface also gets required information and passes that information to the client in a synchronous manner:

public class WeatherServiceImpl implements 
						WeatherService, ServiceLifecycle {

	public void init(Object context) throws JAXRPCException {....}

	public String getWeather(String city)
							throws CityNotFoundException {

		/** Validate parameters **/
		if(!validCity(city))
			throw new CityNotFoundException(....);

		/** Get weather info form processing layer and **/
		/ **return results **/
		return (getWeatherInfoFromDataSource(city));
	}

	public void destroy() {....}
}
Code Example 3.15 Performing a Synchronous Client Interaction

Now let's examine an asynchronous interaction between a client and a service. When making a request for this type of service, the client cannot afford to wait for the response because of the significant time it takes for the service to process the request completely. Instead, the client may want to continue with some other processing. Later, when it receives the response, the client resumes whatever processing initiated the service request. Typically in these types of services, the content of the request parameters initiates and determines the processing workflow--the steps to fulfill the request--for the Web service. Often, fulfilling a request requires multiple workflow steps.

The travel agency service is a good example of an asynchronous interaction between a client and a service. A client requests arrangements for a particular trip by sending the travel service all pertinent information (most likely in an XML document). Based on the document's content, the service performs such steps as verifying the user's account, checking and getting authorization for the credit card, checking accommodations and transportation availability, building an itinerary, purchasing tickets, and so forth. Since the travel service must perform a series of often time-consuming steps in its normal workflow, the client cannot afford to pause and wait for these steps to complete.

Figure 3.7 shows one recommended approach for asynchronously delegating these types of Web service requests to the processing layer. In this architecture, the client sends a request to the service endpoint. The service endpoint validates the incoming request in the interaction layer and then delegates the client's request to the appropriate processing layer of the service. It does so by sending the request as a JMS message to a JMS queue or topic specifically designated for this type of request.

Validation ensures that a request is correct. Delegating the request before validation may result in passing an invalid request to the processing layer, making error tracking and error handling overly complex. After the request is successfully delegated to the processing layer, the service endpoint may return a correlation identifier to the client. This correlation identifier is for the client's future reference and may help the client associate a response that corresponds to its previous request. If the business logic is implemented using enterprise beans, message-driven beans in the EJB tier read the request and initiate processing so that a response can ultimately be formulated.

Figure 3.7 Asynchronous Interaction Between Client and Service

Figure 3.8 shows how the travel agency service might implement this interaction, and Code Example 3.16 shows the actual code that might be used.

Figure 3.8 Travel Agency Service Interaction

In Figure 3.8, the vertical lines represent the passage of time, from top to bottom. The vertical rectangular boxes indicate when the entity (client or service) is busy processing the request or waiting for the other entity to complete processing. The half arrow type indicates asynchronous communication and the dashed vertical line indicates that the entity is free to work on other things while a request is being processed.

public class ReservationRequestRcvr {
	public ReservationRequestRcvr() throws RemoteException {....}

	public String receiveRequest(Source reservationDetails) throws
							RemoteException, InvalidRequestException{

		/** Validate incoming XML document **/
		String xmlDoc = getDocumentAsString(reservationDetails);
		if(!validDocument(xmlDoc))
			throw new InvalidRequestException(...);

		/** Get a JMS Queue and delegate the incoming request **/
		/** to the queue **/
		QueueConnectionFactory queueFactory = 
			serviceLocator.getQueueConnectionFactory(....);
		Queue reservationRequestQueue = 
						serviceLocator.getQueue(...);
		QueueConnection connection =
			queueFactory.createQueueConnection();
		QueueSession session = connection.createQueueSession(false,
							Session.AUTO_ACKNOWLEDGE);
		QueueSender queueSender = session.createSender(queue);
		TextMessage message = session.createTextMessage();
		message.setText(xmlDoc);
		queueSender.send(message);
		/** Generate and return a correlation identifier **/
		return generateCorrelationID();
	}
}
Code Example 3.16 Implementing Travel Agency Service Interaction

One question remains: How does the client get the final result of its request? The service may make the result of the client's request available in one of two ways:

Often this is decided by the nature of the service itself. For example, if the service runs a business process workflow, the workflow requires the service to take appropriate action after processing the request.


3.4.4 Formulating Responses

After you delegate the request to the business logic portion of the application, and the business logic completes its processing, you are ready for the next step: to form the response to the request.

This permits having a common location for response assembly and XML document transformations, particularly if the document you return to the caller must conform to a different schema from the internal schema. Keeping this functionality near the endpoint lets you implement data caching and avoid extra trips to the processing layer. (See Figure 3.9.).

Consider response generation from the weather information service's point-of-view. The weather information service may be used by a variety of client types, from browsers to rich clients to handheld devices. A well-designed weather information service would render its responses in formats suitable for these different client types.

Figure 3.9 Web Service Response Processing

However, it is not good design to have a different implementation of the service's logic for each client type. Rather, it is better to design a common business logic for all client types. Then, in the interaction layer, transform the results per client type for rendering. It is thus important to consider the above guidelines, especially when your service has a common processing logic but potentially has different response rendering needs to fit its varied client types.



CONTENTS | PREV | NEXT | INDEX
Copyright © 2004 Sun Microsystems, Inc. All Rights Reserved.