Skip to main content

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

Managing the life cycle of WS-Resources

Hidayatullah Shaikh (hshaikh@us.ibm.com), Senior Software Engineer, IBM Corporation
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.

Summary:  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.

Date:  04 May 2004
Level:  Advanced
Activity:  1012 views

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.


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.

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.


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>



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.


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.


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.



Download

NameSizeDownload method
ws-statefulws2code.zip382.0 KB HTTP

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.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and Web services
ArticleID=10412
ArticleTitle=Implement and access stateful Web services using WebSphere Studio, Part 2
publish-date=05042004
author1-email=hshaikh@us.ibm.com
author1-email-cc=

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers