Skip to main content

skip to main content

developerWorks  >  SOA and Web services  >

Implement and access stateful Web services using WebSphere Studio, Part 2

Managing the life cycle of WS-Resources

developerWorks
Document options

Document options requiring JavaScript are not displayed

Sample code


Rate this page

Help us improve this content


Level: Advanced

Hidayatullah Shaikh (hshaikh@us.ibm.com), Senior Software Engineer, IBM Corporation

04 May 2004

The Web Services Resource Framework proposes a model for accessing state using Web services. The WS-Resource Lifetime specification defines two ways of destroying a WS-Resource: immediate and scheduled destruction. These processes allow designers flexibility as to how their Web services applications can clean up resources that are no longer needed. This article illustrates how the two destruction mechanisms can be implemented in IBM® WebSphere® Application Server environment using WebSphere Studio Application Developer, Integration Edition 5.0.1.

The lifetime of a WS-Resource is the period between its creation and destruction. The life cycle of a resource can either be static or dynamic. Resources with a static life cycle are those that are created on or deployed to the system and remain there in a permanent or semi-permanent fashion. A hardware or software failure can unintentionally destroy a static life cycle resource, as opposed to a system management actor, which can intentionally destroy the resource. By contrast, dynamic life cycle resources are created and destroyed more frequently.

In many scenarios, it is appropriate for clients of a resource to explicitly destroy that resource. In such cases, the WS-Resource might support a message exchange pattern that allows a service requestor to request that resource's destruction. This is the immediate destruction mechanism identified in the WS-Resource Lifetime specification (see Resources).

However, in a distributed computing Web environment, a user might become disconnected from the service provider's endpoint and therefore might be unable to explicitly destroy the resource. The WS-Resource Lifetime specification standardizes the means by which a resource with a dynamic life cycle can be destroyed. This specification defines the means by which any client of a resource instance can establish and renew its interest in the resource instance for a specific period of time. If that time expires, the resource instance might self-destruct without the need for an explicit destroy request from a client. This time-based approach used for managing the destruction of a WS-Resource is also known as scheduled destruction.

In this article, I will use a simple Calculator service example to show how both immediate and scheduled destruction of WS-Resources can be implemented in IBM® WebSphere® Application Server environment.

Intended audience

You should have a basic understanding of J2EE technology, Web services, and WebSphere Application Server V5, Enterprise Edition. If you are hoping to familiarize yourself with these technologies, please consult the Resources section of this article for quality sources of introductory material. You might also consult additional resources available at IBM developerWorks.

You should also read the first article in this series, "Implement and access stateful Web services using WebSphere Studio, Part 1: Accessing resources through services" and become familiar with the Calculator example used in the article.



Back to top


Contents and requirements for the sample code

IBM® WebSphere® Studio Application Developer, Integration Edition, V5.0.1 was used to create the samples in this article. The samples also were unit-tested using the WebSphere Application Server Enterprise Edition V5.0.2 Built-in Test Environment.

The file ws-statefulws2code.zip contains the code samples that accompany this article. You can download it by clicking on the Code icon at the top or bottom of this paper. It contains the following files:

WASv5WSAExtensions.jarA JAR file containing the utility classes that WebSphere Application Server needs in order to create and access WS-Addressing message information headers in SOAP messages. Helper classes for manipulating WS-Addressing endpoint references are also included. These classes might be configured for use with WebSphere Studio applications.
WASvsWSAExtensions-javadoc.zipThe javadoc for the utility classes.
CalculatorService.earA sample stateful calculator service. A Web application is provided that allows the calculator service to be easily invoked.
WASv5WSRLExtensions.jarWSRL helper class for scheduled destruction support.



Back to top


The Calculator sample

You will use the Calculator sample that was in Part 1 of this series. The Calculator resource state is stored in the CalculatorState entity bean. You will also extend the Calculator Web service interface to support immediate destruction of the calculator state and alter some of the implementation to illustrate how scheduled destruction of the calculator state can be implemented. The instructions in this article will help you modify the sample code from the first part of this series; when you are done with these modifications, you should have the code that looks like the code in ws-statefulws2code.zip.



Back to top


Immediate destruction

To support immediate destruction, the Calculator WS-Resource has to support the destroy message exchange pattern so that a service requestor can request the resource's immediate destruction. This is done by adding the Destroy operation to the Calculator Web service WSDL. The signature of the Destroy operation is dictated by the WS-Resource Lifetime specification. The specification also defines the message definition for the request and the response for this operation. Listing 1 shows the relevant portion of this WSDL. For details, you can refer to the Calculator.wsdl file included in CalculatorService.ear.


Listing 1. The Destroy operation added to the Calculator WSDL
<wsdl:definitions targetNamespace="http://calculator.samples.ibm.com"
   ...
  xmlns:wsrl="http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceLifetime" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <wsdl:types>
 <xsd:schema xmlns="http://www.w3.org/2001/XMLSchema" 
     targetNamespace="http://www.ibm.com/xmlns/stdwip/web-services/WS-    
         ResourceLifetime">
 	<xsd:element name="Destroy">
 		<xsd:complexType />
 	</xsd:element>
 	<xsd:element name="DestroyResponse">
 		<xsd:complexType />
 	</xsd:element>
 </xsd:schema>
...
</wsdl:types>
...
<wsdl:message name="DestroyRequest">
  <wsdl:part name="DestroyRequest" element="wsrl:Destroy" /> 
  </wsdl:message>

 <wsdl:message name="DestroyResponse">
  <wsdl:part name="DestroyResponse" element="wsrl:DestroyResponse" /> 
  </wsdl:message>
...
  <wsdl:portType name="CalculatorService">
      ...
      <wsdl:operation name="Destroy">
         <wsdl:input message="intf:DestroyRequest" name="DestroyRequest"/>
         <wsdl:output message="intf:DestroyResponse" name="DestroyResponse"/>
      </wsdl:operation>

   </wsdl:portType>
...


Listing 2 shows the service endpoint interface that results when you run the updated WSDL through the WSDL2Java utility.


Listing 2. The service endpoint interface containing the destroy() method
public interface CalculatorService extends java.rmi.Remote 
{

    public javax.xml.soap.SOAPElement getCalculator(java.lang.String accountName)
              throws java.rmi.RemoteException;
    public float add(float value) throws java.rmi.RemoteException;
    public float getTotal() throws java.rmi.RemoteException;
    public float sub(float value) throws java.rmi.RemoteException;
    public void destroy() throws java.rmi.RemoteException;

}

Listing 3 shows the implementation of the destroy() method in the Calculator Web service. For your example, the values necessary for the service to identify the target implied resource are contained in the WS-Addressing reference properties, calcID. The calcID is first obtained from the reference properties and then used to find the right instance of the CalculatorState entity EJB component by calling the findByPrimaryKey method on the CalculatorState EJB home. You then destroy the WS-Resource by calling the remove() method on the CalculatorState bean.


Listing 3. The implementation of the destroy() method
public void destroy(){
	System.out.println("Destroy called in Service");
	try {
		CalculatorStateLocalHome home = getCalculatorStateHome();
		if (home != null) {
		  String calcID = EPRHelper.getReferencePropertyFromContext(
		  		      CALCULATOR_NS,
				      CALCULATOR_LOCALNAME_CALCID);

		  CalculatorStateLocal calculatorState =
                                         home.findByPrimaryKey(calcID);

		  if (calculatorState != null)   calculatorState.remove();
		}
	} catch (FinderException e) {
		e.printStackTrace();
	} catch (EJBException e) {
		e.printStackTrace();
	} catch (RemoveException e) {
		e.printStackTrace();
	}
}

The clients of the Calculator WS-Resource can now call the destroy() method to explicitly destroy it, as shown in Listing 4. For details, you can refer to the CalculatorTestExecute.jsp file included in CalculatorService.ear.

The destroy request follows the Implied Resource pattern: the identity values necessary for the service to identify the target implied resource are contained in the WS-Addressing reference properties and must appear as part of the destroy request message in the SOAP headers. Listings 5 and 6 show the SOAP encoding of the destroy message exchange.


Listing 5. Destroy request SOAP message
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<soapenv:Header xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing">         
<wsa:To>http://localhost:9080/CalculatorServiceWeb/services/CalculatorService</wsa:To>
<calcID xmlns="http://calculator.samples.ibm.com">1079046560736</calcID>
<dummyProp xmlns="http://calculator.samples.ibm.com">EXAMPLE PROPERTY</dummyProp>
</soapenv:Header>

<soapenv:Body>
   <Destroy xmlns=
   "http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceLifetime"/>
</soapenv:Body>

</soapenv:Envelope>




Listing 6. DestroyResponse SOAP message
<?xml version="1.0" encoding="UTF-8"?>
   <soapenv:Envelope 
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <soapenv:Body>
         <DestroyResponse 
         xmlns="http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceLifetime"/>
      </soapenv:Body>
   </soapenv:Envelope>




Back to top


Scheduled destruction

In the previous section, you saw how immediate destruction support can be added to the calculator WS-Resource. In this section, you will extend the Calculator sample to support time-based or scheduled destruction. For this, you are going to use the scheduler service of WebSphere Application Server V5, Enterprise Edition. The scheduler service enables tasks to execute at a requested time. The following tasks can be scheduled:

  • The invocation of a session bean method
  • The sending of a JMS message

For more information on enabling and configuring the scheduler service, please refer to the Resources section at the end of this article.

You will create the calculator resource and extend out to self-destruct in 30 seconds -- in other words, its lifetime is 30 seconds. To accomplish this, create a calculator resource and extend the Calculator service implementation. Make sure to schedule a life cycle task with the scheduler with a fire time of 30 seconds. When the scheduler fires the life cycle task, it calls the process() method of the life cycle bean. The implementation of the process() method contains the code to destroy the WS-Resource instance.

Now, let's take a look at the implementation of the life cycle task bean. You will perform the following steps:

  1. Create a stateless session bean, CalculatorResourceLifeCycleTask.
  2. In the bean's deployment descriptor, set the home and remote interfaces to com.ibm.websphere.scheduler.TaskHandlerHome and com.ibm.websphere.scheduler.TaskHandler, respectively.
  3. Implement the process() method in the TaskHandler remote interface. The process() method is called when the task fires. Listing 7 shows the process() method for this example. The primary key for the calculator resource state, calcID, is first obtained from the task status object and then used to find the right instance of the CalculatorState entity EJB component by calling the findByPrimaryKey() method on the CalculatorState EJB component home. You then destroy the WS-Resource by calling the remove() method on the CalculatorState bean instance. For details, refer to the CalculatorResourceLifeCycleTaskBean.java file included in CalculatorService.ear.

Listing 7. Implementing the process method of the life cycle task bean
public void process(TaskStatus status)
{
	CalculatorStateLocal calculatorState = null;
	try {
                        String calcID = status.getName();
		InitialContext ic = new InitialContext();

		Object o = ic.lookup("java:comp/env/ejb/CalculatorState");

		CalculatorStateLocalHome home =
			(CalculatorStateLocalHome) PortableRemoteObject.narrow(
					o,
					CalculatorStateLocalHome.class);

		calculatorState = home.findByPrimaryKey(calcID);

		calculatorState.remove();

		} catch (NamingException e) {
			e.printStackTrace();
		} catch (FinderException e) {
			e.printStackTrace();
		} catch (EJBException e) {
			e.printStackTrace();
		} catch (RemoveException e) {
			e.printStackTrace();
		}
	
	} 

Once the implementation of the life cycle bean is ready, you need to modify the getCalulator() method of the Calculator service so that the life cycle task is scheduled upon creation of a resource. To modify the getCalulator()method, add two lines of code shown in bold in Listing 8. The sample uses a WSRL Helper class (WSRLHelper), which I have included in the sample code. The scheduleResourceLifeCycleTask() method is called with the session bean context, expiry time, and identifier of the resource (calcID) as parameters.


Listing 8. Modifying the getCalculator() method to schedule the life cycle task
public javax.xml.soap.SOAPElement getCalculator(java.lang.String accountName)
{
    ...
    // Destroy the service after 30 seconds
    Date startDate = new Date(System.currentTimeMillis() + 30000);
    WSRLHelper.scheduleResourceLifeCycleTask(this.getSessionContext(), 
						         startDate, 
					                     calcID);
    ...
}

The WSRLHelper should be used only if you follow these naming conventions:

  • The life cycle bean should be named <ServiceName>ResourceLifeCycleTaskBean (such as CalculatorResourceLifeCycleTaskBean).
  • The remote interface of the service implementation bean should be <ServiceName>_RI.java (such as Calculator_RI.java).

The complete source code for the WSRL helper is included in the WASv5WSRLExtensions.jar.

This scheduleResourceLifeCycleTask() method walks through the following steps:

1. Looks up the home of the life cycle bean. Listing 9 illustrates this step.


Listing 9. Look up the lifecycle bean home
String taskId = null;
InitialContext ic = new InitialContext();
String className =
     stub.getEJBHome().getEJBMetaData().getRemoteInterfaceClass().getName();
		
// Lets remove the word Remote from the end
int index = className.lastIndexOf("Remote");
if(index != -1) className = className.substring(0, index);

index = className.lastIndexOf(".");
if(index != -1) className = className.substring(index + 1, className.length());

String lookupName = "java:comp/env/ejb/" 
                                +  className 
                                +  "ResourceLifeCycleTask";
		
// Get the Task handler home
TaskHandlerHome taskHandlerHome = getTaskHandlerHome(lookupName);


2. Gets a handle to the ResourceLifeCycleScheduler scheduler. Listing 10 illustrates this step.


Listing 10. Get the scheduler object
Scheduler scheduler = null;
try {
	InitialContext ic = new InitialContext();
	Object o = ic.lookup("java:comp/env/ResourceLifeCycleScheduler");
	scheduler =	
                  (Scheduler) PortableRemoteObject.narrow(o, Scheduler.class);
	} catch (NamingException e) {
		e.printStackTrace();
		}

3. Creates an instance of the BeanTaskInfo interface by using the createBeanTaskInfo() method on the scheduler. The TaskInfo interface contains various set methods that you can use to control aspects of the task's execution, including the time when the task will fire, and the work that the task will do when it fires. Listing 11 illustrates this step.


Listing 11. Populating the TaskInfo object

          // Create Task info	
          BeanTaskInfo taskInfo = scheduler.createBeanTaskInfo();
          taskInfo.setTaskHandler(taskHandlerHome);
taskInfo.setStartTime(startDate);	
taskInfo.setName(pKey);		


4. Submits the task to the scheduler instance for creation. Listing 12 illustrates this step.


Listing 12. Create the task
	
          // Schedule Task
TaskStatus status = scheduler.create(taskInfo);


You are finished. You have now seen how the scheduled destruction of a WS-Resource can be implemented using the scheduler service in WebSphere Application Server, Enterprise Edition. In this example, you have hard-coded the 30-second interval. You can also have the WS-Resource client set this interval by calling the SetTerminationTime operation, provided that the Calculator Web service implements the operation. The WS-ResourceLifetime specification defines the SetTerminationTime operation and message exchange.



Back to top


Conclusions

In a distributed computing environment with a large number of resources, it is important to make sure that these resources are destroyed in a controlled fashion, once they are no longer needed by service requestors. This article illustrates how two different WS-Resource destruction mechanisms can be implemented using existing tooling and runtime support in WebSphere Application Server, Enterprise Edition. It also provides minimal helper classes and documentation for building resources with life cycle support. While solutions that do not use the scheduler service are possible, this solution offers a clean and simple implementation by offloading the timer processing to the scheduler and making the Web service implementation agnostic to issues associated with threads in a J2EE environment. A new series of future articles will discuss programming model implementations of other WS-Resource specifications, such as WS-ResourceProperties, WS-ServiceGroup, and so forth. Watch for new developerWorks articles for this follow-on write-up.



Back to top


Get the tools used in this article

If you are a developerWorks subscriber, you have a single user license to use WebSphere Studio Application Developer, and other DB2®, Lotus®, Rational®, Tivoli®, and WebSphere products -- including the Eclipse-based WebSphere Studio IDE -- to develop, test, evaluate, and demonstrate your applications. If you are not a subscriber, you can subscribe today.




Back to top


Download

NameSizeDownload method
ws-statefulws2code.zip382.0 KBHTTP
Information about download methods


Resources



About the author

Hidayatullah H. Shaikh is a senior software engineer on the IBM Software Group's On Demand Architecture and Development Team. His areas of interest and expertise include business process modeling and integration, service-oriented architecture, grid computing, e-commerce, J2EE technology, and DBMSs. You can contact Hidayatullah at hshaikh@us.ibm.com.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top