Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

Web Services and Sessions
by Sergey Beryozkin | Pages: 1, 2, 3

Using SOAP Metadata

Possibly the strongest side of SOAP, which can swing the decision on how to do web services in its favor, lies within its extension mechanism, which makes it possible to carry out metadata related to a message body's content. It allows for building sophisticated, extremely distributed web services, which is more difficult to achieve with pure XML content alone.

Using SOAP metadata presents another alternative to the way session identification tokens are passed around. Systinet, a company emerging as one of the major players on the web services market, was the first to add remote references into its line of WASP Servers. For example, consider the following two Java interfaces :

//this interface is implemented by a CounterFactoryImpl class
public interface CounterFactory {
Counter createCounter();
}
public interface Counter extends java.rmi.Remote {
int getCount();
void increment();
}

At deployment time, only a WSDL for a CounterFactoryImpl service is generated:

<wsdl:definitions ...>
<wsdl:types>
<schema targetNamespace="http://idoox.com/interface" ...>
<complexType name="serviceReference">
<sequence>
<!-- first two elements are not shown -->  
<element name="wsdl" type="anyURI"/>
<element name="instanceID" type="string"/>
</sequence>
</complexType>
<element name="instance">
<complexType>
<choice>
<element name="id" type="string"/>
<!-- last two elements are not shown --> 
</choice>
</complexType>
</element>
</schema>
</wsdl:types>
<wsdl:message name="createCounterRequest"/>
<wsdl:message name="createCounterResponse">
<!-- serviceRef_res is declared in a separate schema -->
<wsdl:part element="ns0:serviceRef_res" name="response"/>
</wsdl:message>
<wsdl:portType name="CounterFactoryImpl">
<wsdl:operation name="createCounter">
<wsdl:input message="tns:createCounterRequest"/>
<wsdl:output message="tns:createCounterResponse"/>
</wsdl:operation>
</wsdl:portType>
<!-- binding and service elements are not shown for brevity -->
</wsdl:definitions>

When a client sends a createCounter request, an instance of a serviceReference type is returned, which includes an identifier of a Counter service instance and a URI of its automatically generated WSDL. This eventually results in a client stub being created (this is an example of a static runtime binding). Using an <instance> extension, the instance ID can then be passed as a value of its <id> child element during communication with a specific Counter service.

<e:Envelope xmlns:e="http://schemas.xmlsoap.org/soap/envelope/">
 <e:Header>
   <n0:instance xmlns:n0="http://idoox.com/interface">
     <id>localhost:2002.07.17 03:57:09 GMT:16A26A3EC87D818A:9</id>
   </no:instance> 
 </e:Header> 
 <e:Body>
  <n0:getCount 
  xmlns:n0="http://localhost/RemoteReferencesDemo/wsdl
            /demo.remote_references.CounterE9A7C2Counter"/> 
 </e:Body>
</e:Envelope>

Related Reading

Programming Web Services with SOAP
By James Snell, Doug Tidwell, Pavel Kulchenko

The lifecycle of a newly created service can be managed either explicitly, for example, by calling an endCounter method on a Counter service, or implicitly, using an instance of LifeCycleService which can decide when a particular instance should time out, for example, when it has not been called for a limited period of time.

In general, this approach is a fairly serious attempt to apply a remote references idiom to web services design. Using SOAP headers for passing state data is guaranteed to work for all SOAP-based web services, irrespective of whether a message is sent within an application protocol, such as HTTP, or directly over transport protocols. An initial sender can also send such data to a receiver separated from it by multiple hops.

However, being a proprietary solution, it also bears some drawbacks. It requires a client to understand the semantics of the underlying server application and to use the same toolkit as is used on the server side. It would be great if it were possible for a client to get all the required knowledge from a WSDL description only, which then can be processed by a client's SOAP environment when required.

On the Grid

The Globus Project, led by Argonne National Laboratory and the University of Southern California's Information Sciences Institute is a research and development project focused on defining and building Grid middleware standards and software that can be applied to a broad range of scientific and technical computing applications. Open Grid Services Architecture (OGSA), the result of an ongoing collaboration between the Globus Project and IBM, is an effort to define a Grid system architecture based on an integration of Grid and Web services concepts and technologies.

OGSA defines a Grid service as an instance-based Web Service that conforms to a set of conventions (interfaces and behaviors) that define, in terms of WSDL, mechanisms required for creating and composing sophisticated distributed systems. It standardizes on a factory/instance pattern for managing stateful service instances, and deals with such issues as the instances identification, discovery, lifetime management, and soon, provisioning of resources.

The Grid Services specification introduces the notion of a handle and a reference. A handle is a permanent globally unique identifier to a Grid service instance and is represented as a URI. It is returned by a factory and must be resolved using a URI-specific protocol (for example, HTTP GET for an HTTP URI) to a reference to the service instance. It is possible to discover what type of service instances a factory creates before asking it to create an instance.

While references can take a variety of forms specific to the binding mechanism of a service, a standard form defined by OGSA that is expected to be used widely is a WSDL document. It is recommended to contain only a <service> element which can be used to discover what port types a service instance implements and get required port and binding details. Resolving a service handle into such a minimal WSDL fragment is likely to lead to a more efficient and type-safe static (and possibly dynamic) runtime binding, especially when a client chooses between different instances of the same service. Depending on the definition of the selected binding, a service instance can be actually identified in a number of ways, for example, by passing the handle in a SOAP header.

A reference is transient, that is its lifecycle may be independent from the lifecycle of the service instance it refers to. An important thing is that the same handle to a specific instance can be resolved to a new reference after the original one becomes invalid (for example, after the service port or binding has changed), which provides for an enhanced load-balancing and scalability.

The specification defines a flexible lifecycle management scheme, by allowing clients to destroy service instances by either explicitly invoking a destroy operation or using a soft-style approach.

The "Business" Way

Good examples of a coarse-grained, service-oriented approach toward building stateful services can be found in today's B2B integration solutions.

Consider the following simplified fragment of a purchase order service definition.

<definitions ...>
<types ...>
 <schema ...>
  <complexType name="PurchaseOrder">
    <element name="orderId" type="xsd:int">
    <!-- other elements are not shown --> 
  </complexType> 
 </schema>
</types>
<message name="PORequest"/>
  <part name="PurchaseOrder" type="xsd1:PurchaseOrder"/>
</message>
<!-- POResponse message is not shown -->
<portType name="PurchaseOrderPortType">
 <operation name="submitOrder">
  <input message="tns:PORequest"/>
  <!-- output is not defined for asynchronous responses --> 
  <output message="tns:POResponse"/>
</operation>
</portType>
</definitions>

This service can process purchase order requests from its clients synchronously or asynchronously. An initial request can lead to a multi-step conversation between a service and a client. The service needs to maintain a conversational state per each individual request and is instance (or session) based.

A value of a simple token orderId, which is part of a business document instance, is associated with an implicitly created session and is used during the following conversation regarding a specific purchase order. In this example, it is the responsibility of a buyer to initialize an orderId field. A token may also be passed within a SOAP header.

The BPEL4WS specification, which allows the exposure of a business process as a stateful compound service, generalizes this approach by introducing message correlation sets. These are named groups of abstract properties that are mapped by XPath selections to fields within the message data. A correlation set is instantiated within the scope of a business process instance as part of some initial operation and uniquely identifies this instance during an application-level conversation afterwards. For a good and clear explanation of how it all works please read the relevant parts of the specification.

BPEL4WS 1.1 uses endpoint references defined by WS-Addressing specification. These references may include the qualified name of a wsdl:service element, which itself can be inlined within the service reference if it's not already known. It may also contain instance-specific properties, such as an instance identifier, however, they're not strictly required to be present when a reference refers to another BPEL4WS-enabled service due to the fact that correlation sets can identify specific instances.

A client typically can not directly affect the lifecycle of an individual session, unless some custom conversational protocol is used or a close operation is added. For example, BPEL4WS says that a business process instance can die after an activity it executes has ended normally or as a result of an exception, etc.

Using a single monolithic service is good for supporting peer-to-peer interactions between business partners, but it may not be ideal in other situations.

For example, consider a banking web service which allows the opening of an account and retrieval of the balance. An open request (possibly conversational) is orthogonal to debit/credit messages, so making them belong to a single interface, or opening an account implicitly as part of some update requires the service to build a state machine. So, it might make sense to have one service to open an account and another account service to accept update requests:

Account a = bankManager.openAccount();  (1)
a.debit(getAmountFromUser());
showBalanceToUser(a.getBalance());

New account details (number, sort code, etc) and an account service reference may be returned in an open response. A BPEL4WS-like client runtime can privately use the account details for correlating future interactions with the account service. However, it all can become quite complex, as the runtime may need to interact with a user during an open request and has to make only part of the response (a service reference converted to an Account proxy ) available to the user application, so that a programmer does not have to write :

AccountResponse response = bankManager.openAccount();
Account a = Runtime.getProxy(response.serviceReference);
a.debit(response.accountNumber, getAmountFromUser());

While it may not be applicable in the above scenario, a returned standardized service reference containing both an instance handle and a WSDL service definition can make this work without a BPEL4WS or a proprietary toolkit's support, especially when such a reference is all a client needs to start talking to an associated service instance when it wants to. Passing handles like URLs within headers for a session identification can be preferable to using application-specific tokens in such cases.

While maintaining a state machine may not be a major problem with a single interface to a stateful service, handling a heavy load of client requests may become the one. By returning session service references it is not only possible to redirect clients to different physical nodes but also to balance the load effectively.

Pages: 1, 2, 3

Next Pagearrow