 | Level: Intermediate Hidayatullah Shaikh (hshaikh@us.ibm.com), Senior Software Engineer, IBM Corporation
08 Jun 2004 The Web Services Resource Framework proposes a model for accessing state using Web services. The WS-Resource Properties specification defines how you can use Web services technologies to query and change data associated with a stateful resource. This allows a standard means by which clients can access data associated with a WS-Resource. This article illustrates how you can use IBM® WebSphere® Studio Application Developer V5.1 to implement WS-Resource properties in a WebSphere Application Server environment.
The WS-Resource Properties specification describes the means by which service requestors can view and modify the type and values of a WS-Resource’s state through a Web services interface. The WS-Resource state is expressed as an XML resource property document using XML schema. The WS-Resource Properties specification standardizes the means by which the definition of a resource's properties may be declared as part of the Web service interface. It also defines a standard set of message exchanges that allow a requestor to query or update the property values of the implied resource instance.
In this article, I use a simple Calculator service example to show how you can specify and access WS-Resource properties in an IBM WebSphere Application Server environment.
Intended audience
You should have a basic understanding of J2EE technology, Web services, and WebSphere Application Server V5.1. 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 Part 1 and Part 2 in this series, "Accessing resources through services" and "Managing the lifecycle of WS-Resources," and become familiar with the Calculator example used in these articles (see Resources).
Contents and requirements for the sample code
The samples referenced in this article were created with WebSphere Studio Application Developer V5.1.1 GM Version. The samples were also unit tested using the WebSphere Application Server V5.1 Built-in Test Environment. The WSDLs in the samples have been configured to use the tcpmon utility that comes with Apache Axis for monitoring the SOAP messages being exchanged. Configure the tcpmon utility to listen on port 81 (listenPort) and forward the requests to a target port of 9080 (targetPort). For more information on tcpmon refer to the Resources section of this article.
The file ws-statefulws3code.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.jar
| A JAR file containing the utility classes that WebSphere Application Server V5.1 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 may be configured for use with WebSphere Studio applications. |
WASvsWSAExtensions-javadoc.zip
| The javadoc for the utility classes. |
CalculatorService.ear
| A sample stateful calculator service. A Web application is provided that allows the calculator service to be easily invoked. |
The calculator sample
The calculator sample introduced in Part 1 of this series provided a simple calculator service to client programs via a standard WSDL v1.1 interface. The service interface allowed clients to create instances of a calculator and subsequently add and subtract from the calculator total. Calculator instances are treated as WS-Resources in the sample. Also note that the Calculator Web service implementation was able to use existing J2EE best practices with the service interface implemented as a stateless session bean and the state maintained in a CMP entity bean.
This article takes you through the steps to selectively expose pieces of the calculator state as properties using the techniques described in the WS-Resource Properties specification. Specifically, you will:
- Add an additional attribute
request to the CalculatorState bean.
- Create an XML Schema to represent the properties that are to be exposed from the WS-Resource.
- Associate the resource properties with the Calculator service by attaching the schema to the Calculator service WSDL.
- Update the Calculator service WSDL to include the WS-Resource property access operations that you plan to implement.
- Extend the Calculator service implementation to support the new operations.
The instructions in this article help you modify the sample code in 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-statefulws3code.zip.
Modifying the CalculatorStateBean
For this example, the CalculatorState bean is modified to keep track of how many times the resource is accessed via the add, sub, and getTotal operations. To do this, you add an attribute called request to the CalculatorState bean. Further, you modify the add, sub, and getTotal methods to increment the request counter every time they are called. Listing 1 includes a code sample of the Calculator service's modified add method. For details, refer to the CalculatorServiceSoapBindingImpl.java file included in the CalculatorService.ear.
Listing 1. Implementation of add method
public float add(float value) {
float _newTotal = 0f;
try {
CalculatorStateLocalHome home = getCalculatorStateHome();
if (home != null) {
String calcID = getPrimaryKeyFromContext();
CalculatorStateLocal calculatorState =
home.findByPrimaryKey(calcID);
if (calculatorState != null) {
_newTotal = calculatorState.getTotal() + value;
calculatorState.setTotal(_newTotal);
}
//Increment the request counter
int request = calculatorState.getRequest();
calculatorState.setRequest(++request);
}
} catch (FinderException e) {
e.printStackTrace();
}
return _newTotal;
}
|
Defining resource properties document for the Calculator WS-Resources
The WS-Resource Properties specification defines the resource properties document as the XML document representing a logical composition of resource property elements. The resource properties document defines a particular view or projection of the state data implemented by the WS-Resource. The Calculator WS-Resource has three resource properties: calcid, request, and value. In the sample, you expose these as properties of the WS-Resources exposed via the Calculator service. You should be aware that I arbitrarily picked properties to expose from the Calculator service to illustrate the mechanics of implementing this. The WS-Resource Properties specification does not dictate what properties you are required to expose from a service. It is expected that over time, higher level, domain-specific specifications will emerge that define a style and best practice pattern for exposing resource properties. You can find early examples of this in the WS-Manageability specifications being produced by the OASIS WSDM Technical Committee (see Resources for more information on WS-Manageability and WSDM).
As per the WS-Resource Properties specification, the schema for resource properties should be added to the WSDL definition of the Web service through which the WS-Resource is exposed. Listing 2 shows this for the Calculator service WSDL. For details, you can refer to the CalculatorService.wsdl file included in the CalculatorService.ear.
Listing 2. Schema for the Calculator resource properties
...
<!-- Resource property element declarations -->
<element name="calcId" type="string"/>
<element name="total" type="float"/>
<element name="request" type="int"/>
<!-- Resource properties document declaration -->
<element name="GenericCalculatorProperties">
<complexType>
<sequence>
<element ref="intf:calcId"/>
<element ref="intf:total"/>
<element ref="intf:request"/>
</sequence>
</complexType>
</element>
...
|
The WS-Resource Properties document declaration is associated with the WSDL portType definition via the use of the ResourceProperties attribute, as Listing 3 shows. For details, you can refer to the CalculatorService.wsdl file included in the CalculatorService.ear.
Listing 3. Associating resource property document with portType
...
<wsdl:portType name="CalculatorService" wsrp:ResourceProperties=
"intf:GenericCalculatorProperties">
...
|
Adding WS-Resource Properties operations to the Calculator service
The WS-Resource Properties specification defines a collection of message exchanges that standardize the means by which a requestor can retrieve values of resource properties, update values of resource properties, and issue queries against resource properties. The WS-Resource Properties specification defines four operations:
GetResourceProperty: This operation allows a requestor to retrieve the value of a single resource property of a WS-Resource. A Web service implementing a portType that includes the resources properties document type declaration MUST support this operation.
GetMultipleResourceProperties: This operation allows a requestor to retrieve the values of multiple resource properties of a WS-Resource. Support for this operation is optional.
SetResourceProperties: This operation allows a requestor to modify the values of multiple resource properties of a WS-Resource. There are three types of changes that this operation allows -- insert, update, and delete. Support for this operation is optional.
QueryResourceProperties: This operation allows a requestor to query the resource properties document of a WS-Resource using a query expression such as XPath. Support for this operation is optional.
In this example, you extend the Calculator sample to support GetResourceProperty and the GetMultipleResourceProperties. A future article will discuss the implementation of the SetResourceProperties and QueryResourceProperties operations. Listing 4 shows the modification to the Calculator service WSDL to support the GetResourceProperty operation. Do the following to support the GetResourceProperty operation in the WSDL (repeat these steps for other WS-ResourceProperties operations):
- Paste the WS-ResourceProperties schema into the WSDL document. This schema contains the definition for the
BaseFaultType and the GetRequestProperty request and response.
- Add WSDL messages for the various faults and the
GetRequestProperty request and response as defined by the WS-Resource Properties specification.
- Add the
GetResourceProperty operation to the CalculatorService portType.
- Add binding information for the
GetResourceProperty operation to the soap binding of the CalculatorService.
Note that you only include the operations that you intend to implement in the WSDL. This ensures that any service requestor will have the ability to determine what operations are supported, as well as the properties that are accessible by introspecting the WSDL either manually or programmatically. For details on changes needed to support other operations, you can refer to the CalculatorService.wsdl file included in the CalculatorService.ear.
Listing 4. The GetResourceProperty operation added to the Calculator service WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://calculator.samples.ibm.com" ...>
<wsdl:types>
<xsd:schema targetNamespace=
"http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties" xmlns:wsrp=
"http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties" ...>
<!-- ======= Global Attribute Declaration for WSDL 1.1 portType==== -->
<xsd:attribute name="ResourceProperties" type="xsd:QName"/>
<!-- ==== Common fault information to carry in all fault messages ==== -->
<xsd:complexType name="BaseFaultType">
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="Timestamp" type=
"xsd:dateTime"/>
<xsd:element maxOccurs="1" minOccurs="0" name="Originator" type=
"wsa:EndpointReferenceType"/>
<!--
<xsd:element name="ErrorCode"
minOccurs="0" maxOccurs="1">
<xsd:complexType>
<xsd:complexContent mixed="true">
<xsd:extension base="xsd:anyType">
<xsd:attribute name="dialect" type="xsd:anyURI"
use="required"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
-->
<xsd:element maxOccurs="unbounded" minOccurs="0" name=
"Description" type="xsd:string"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" name=
"FaultCause" type="wsrp:BaseFaultType"/>
</xsd:sequence>
</xsd:complexType>
<!-- ========== Message Types for GetResourceProperty ============ -->
<xsd:element name="GetResourcePropertyRequest" type="xsd:QName"/>
<xsd:element name="GetResourcePropertyResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:any maxOccurs="unbounded" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="ResourceUnknownFaultType">
<xsd:complexContent>
<xsd:extension base="wsrp:BaseFaultType"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="ResourceUnknownFault" type="wsrp:ResourceUnknownFaultType"/>
<xsd:complexType name="InvalidResourcePropertyQNameFaultType">
<xsd:complexContent>
<xsd:extension base="wsrp:BaseFaultType"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="InvalidResourcePropertyQNameFault" type=
"wsrp:InvalidResourcePropertyQNameFaultType"/>
...
<wsdl:message name="InvalidResourcePropertyQNameFault">
<wsdl:part name="InvalidResourcePropertyQNameFault" element=
"wsrp:InvalidResourcePropertyQNameFault"/>
</wsdl:message>
<wsdl:message name="GetResourcePropertyResponse">
<wsdl:part name="GetResourcePropertyResponse" element=
"wsrp:GetResourcePropertyResponse"/>
</wsdl:message>
<wsdl:message name="GetResourcePropertyRequest">
<wsdl:part name="GetResourcePropertyRequest" element=
"wsrp:GetResourcePropertyRequest"/>
</wsdl:message>
<wsdl:message name="ResourceUnknownFault">
<wsdl:part name="ResourceUnknownFault" element=
"wsrp:ResourceUnknownFault"/>
</wsdl:message>
...
<wsdl:portType name="CalculatorService" wsrp:ResourceProperties=
"intf:GenericCalculatorProperties">
<wsdl:operation name="GetResourceProperty">
<wsdl:input name="GetResourcePropertyRequest" message=
"impl:GetResourcePropertyRequest"/>
<wsdl:output name="GetResourcePropertyResponse" message=
"impl:GetResourcePropertyResponse"/>
<wsdl:fault name="InvalidResourcePropertyQNameFault" message=
"impl:InvalidResourcePropertyQNameFault"/>
<wsdl:fault name="ResourceUnknownFault" message=
"impl:ResourceUnknownFault"/>
</wsdl:operation>
...
</wsdl:portType>
<wsdl:binding name="CalculatorServiceSoapBinding" type="impl:CalculatorService">
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetResourceProperty">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="GetResourcePropertyRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="GetResourcePropertyResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
<wsdl:fault name="InvalidResourcePropertyQNameFault">
<wsdlsoap:fault name="InvalidResourcePropertyQNameFault" use="literal"/>
</wsdl:fault>
<wsdl:fault name="ResourceUnknownFault">
<wsdlsoap:fault name="ResourceUnknownFault" use="literal"/>
</wsdl:fault>
</wsdl:operation>
...
</wsdl:binding>
...
</wsdl:definitions>
|
Listing 5 shows the service endpoint interface (SEI) that results when you run the updated WSDL through the WSDL2Java utility.
Listing 5. The service endpoint interface containing the WS-ResourceProperties methods
public interface CalculatorService extends Remote
{
public GetResourcePropertyResponse
getResourceProperty(QName getResourcePropertyRequest)
throws RemoteException,
InvalidResourcePropertyQNameFaultType,
ResourceUnknownFaultType;
public GetMultipleResourcePropertiesResponse getMultipleResourceProperties(
GetMultipleResourcePropertiesRequest getMultipleResourcePropertiesRequest)
throws RemoteException,
InvalidResourcePropertyQNameFaultType,
ResourceUnknownFaultType;
public SOAPElement
getCalculator(String accountName)
throws RemoteException;
public float
add(float value)
throws RemoteException;
public float
sub(float value)
throws RemoteException;
public float
getTotal()
throws RemoteException;
}
|
Implementing and invoking the WS-Resource Properties operations
Listing 6 shows the implementation of the GetResourceProperty method in the Calculator Web service. For details, refer to the CalculatorServiceSoapBindingImpl.java file included in the CalculatorService.ear.
Listing 6. Implementation of the GetResourceProperty method in the Calculator Web service
001 public com.ibm.samples.wsrp.GetResourcePropertyResponse
002 getResourceProperty(javax.xml.namespace.QName
003 getResourcePropertyRequest)
004 throws com.ibm.samples.wsrp.
InvalidResourcePropertyQNameFaultType,
005 com.ibm.samples.wsrp.ResourceUnknownFaultType
006 {
007 GetResourcePropertyResponse resourcePropertyResponse = null;
008
009 if((getResourcePropertyRequest != null)&&
010 011(getResourcePropertyRequest.getNamespaceURI().equals
011 (CALCULATOR_NS)))
012 {
013 try {
014 CalculatorStateLocalHome home =
015 getCalculatorStateHome();
016 if (home != null) {
017 String calcID = getPrimaryKeyFromContext();
018 CalculatorStateLocal calculatorState =
019 home.findByPrimaryKey(calcID);
020
021 String name =
022 getResourcePropertyRequest.getLocalPart();
023 SOAPFactory sf = new SOAPFactory();
024 SOAPElement[] se = new SOAPElement[1];
025 se[0] = (SOAPElement)
026 sf.createElement(name,
027 "calc",
028 CALCULATOR_NS);
029
030 if(name.equals("calcId"))
031 {
032 se[0].addTextNode(calcID);
033 resourcePropertyResponse = new
034 GetResourcePropertyResponse();
035 resourcePropertyResponse.set_any(se);
036
037 }
038 else if(name.equals("total"))
039 {
040 float total = calculatorState.getTotal();
041 se[0].addTextNode(
042 (new Float(total)).toString());
043 resourcePropertyResponse = new
044 GetResourcePropertyResponse();
045 resourcePropertyResponse.set_any(se);
046
047 }
048 else if(name.equals("request"))
049 {
050 int request = calculatorState.getRequest();
051 se[0].addTextNode(
052 (new Integer(request)).toString());
053 resourcePropertyResponse = new
054 GetResourcePropertyResponse();
055 resourcePropertyResponse.set_any(se);
056 }
057 else
058 {
059 String[] description
060 = {"Cannot find resource property"};
061 throw new
062 InvalidResourcePropertyQNameFaultType
063 (Calendar.getInstance(),
064 null,
065 description,
066 null);
067
068 }
069
070 }
071 } catch (FinderException e) {
072 e.printStackTrace();
073 String[] description = {"Cannot find resource"};
074 throw new ResourceUnknownFaultType
075 (Calendar.getInstance(),
076 null,
077 description,
078 null);
079 } catch (SOAPException e) {
080 e.printStackTrace();
081 }
082
083 }
084 else
085 {
086 String[] description
087 = {"Cannot find resource property"};
088 throw new InvalidResourcePropertyQNameFaultType
089 (Calendar.getInstance(),
090 null,
091 description,
092 null);
093 }
094 return resourcePropertyResponse;
095 }
096
|
Take a look at the above code sample in detail.
- In lines 9 through 11 you check to make sure that the
getResourcePropertyRequest object is not null and that the namespace URI contained in it matches the namespace URI of the Calculator service.
- In lines 14 through 19, 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.
- In lines 23 through 29 you create a SOAP element using the Calculator service namespace. This SOAP element will be sent in the response object (
resourcePropertyResponse).
- In lines 30 through 37 you see if the name contained in the
getResourcePropertyRequest is calcId. If so, you set the value of the SOAP Element node (instantiated in step 3) to calcID (obtained in step 2). You further set the SOAP element in the resourcePropertyResponse response object.
- In lines 38 through 47 you see if the name contained in the
getResourcePropertyRequest is total. If so, you get the value of total from the CalculatorState EJB instance (obtained in step 2) and set it in the SOAP element. You further set the SOAP element in the resourcePropertyResponse response object.
- In lines 48 through 56 you see if the name contained in the
getResourcePropertyRequest is request. If so, you get the value of request from the CalculatorState EJB instance (obtained in step 2) and set it in the SOAP element. You further set the SOAP element in the resourcePropertyResponse response object.
- In lines 57 though 93 you throw different exceptions (defined in the WS-Resource Properties specification).
- In line 94 you return the
resourcePropertyResponse object.
Listing 7 shows how a client invokes the GetResourceProperty operation provided by the Calculator Web service. For details, you can refer to the CalculatorTestExecute.jsp file included in the CalculatorService.ear. In this example, the client is interested in the resource property of the Calculator WS-Resource called total.
Listing 7. A sample client that wants to access a property of the calculator resource
com.ibm.samples.calculator.CalculatorService calculatorService = null;
// Initial Context
javax.naming.InitialContext ic = new javax.naming.InitialContext();
// Lookup calculator SI
// Returns object support javax.xml.rpc.Service
com.ibm.samples.calculator.CalculatorServiceService calculatorServiceSI
= (com.ibm.samples.calculator.CalculatorServiceService) ic.lookup(
"java:comp/env/service/CalculatorServiceService");
// Get the calculator SEI
// Object that supports CalculatorService remote interface
//
calculatorService =
(com.ibm.samples.calculator.CalculatorService)
calculatorServiceSI.getPort(com.ibm.samples.calculator.CalculatorService.class);
if(calculatorService != null)
{
try
{
String acctName = request.getParameter("acctName");
float add
= (new Float(request.getParameter("add"))).floatValue();
float sub
= (new Float(request.getParameter("sub"))).floatValue();
javax.xml.soap.SOAPElement SE
= calculatorService.getCalculator(acctName);
com.ibm.samples.wsa.wsaddr.EndpointReference epr
= com.ibm.samples.wsa.wsaddr.EndpointReference.fromSOAPElement(SE);
// Call JAXRPCHelper to associate EPR with account and
// make it stateful
com.ibm.samples.wsa.utils.JAXRPCHelper.setEPR(
(javax.xml.rpc.Stub) calculatorService ,
epr);
// Call a couple of other methods on calculator SEI
calculatorService.add(add);
calculatorService.sub(sub);
javax.xml.namespace.QName rpQName
= new javax.xml.namespace.QName("http://calculator.samples.ibm.com",
"total");
com.ibm.samples.wsrp.GetResourcePropertyResponse getResourcePropertyResponse
= calculatorService.getResourceProperty(rpQName);
javax.xml.soap.SOAPElement[] se1
= getResourcePropertyResponse.get_any();
...
|
The GetResourceProperty 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. They must appear as part of the GetResourceProperty request message in the SOAP headers. Listing 8 and Listing 9 show the SOAP encoding of the GetResourceProperty message exchange.
Listing 8. GetResourceProperty request SOAP
<?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 ...>
1083949184296
</calcID>
<dummyProp...>
EXAMPLE PROPERTY
</dummyProp>
</soapenv:Header>
<soapenv:Body>
<GetResourceProperty xmlns="">
<GetResourcePropertyRequest xmlns:ns-1495319864=
"http://calculator.samples.ibm.com" xmlns=
"http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties">
ns-1495319864:total
</GetResourcePropertyRequest>
</GetResourceProperty>
</soapenv:Body>
</soapenv:Envelope>
|
Listing 9. GetResourceProperty response 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>
<GetResourcePropertyResponse xmlns="">
<GetResourcePropertyResponse xmlns=
"http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties">
<calc:total xmlns:calc="http://calculator.samples.ibm.com">5.0</calc:total>
</GetResourcePropertyResponse>
</GetResourcePropertyResponse>
</soapenv:Body>
</soapenv:Envelope>
|
Listing 10 shows the implementation of the GetMultipleResourceProperties method in the Calculator Web service. For details, refer to the CalculatorServiceSoapBindingImpl.java file included in the CalculatorService.ear. The implementation involves calling the getResourceProperty operation N number of times, where N is equal to the size of the QName array contained in the getMultipleResourcePropertiesRequest. The result of each invocation is collected into an array of SOAP elements and is then set in the resourcePropertiesResponse, which is returned to the client.
Listing 10. Implementation of the GetMultipleResourceProperties operation
public com.ibm.samples.wsrp.GetMultipleResourcePropertiesResponse
getMultipleResourceProperties
(com.ibm.samples.wsrp.GetMultipleResourcePropertiesRequest
getMultipleResourcePropertiesRequest)
throws com.ibm.samples.wsrp.InvalidResourcePropertyQNameFaultType,
com.ibm.samples.wsrp.ResourceUnknownFaultType
{
QName[] resourceProperty
= getMultipleResourcePropertiesRequest.getResourceProperty();
int size = resourceProperty.length;
SOAPElement[] se = new SOAPElement[size];
GetMultipleResourcePropertiesResponse resourcePropertiesResponse
= null;
if((resourceProperty != null)&&( size!= 0))
{
for(int i=0; i<size; i++)
{
SOAPElement[] _se
= getResourceProperty(resourceProperty[i]).get_any();
se[i] = _se[0];
}
resourcePropertiesResponse
= new GetMultipleResourcePropertiesResponse();
resourcePropertiesResponse.set_any(se);
}
return resourcePropertiesResponse;
}
|
Listing 11 shows how a client invokes the GetMultipleResourceProperties operation provided by the Calculator Web service. For details, refer to the CalculatorTestExecute.jsp file included in the CalculatorService.ear. In this example, the client is interested in two resource properties of the Calculator WS-Resource -- total and request.
Listing 11. A sample client that wants to access multiple properties of the calculator resource
com.ibm.samples.calculator.CalculatorService calculatorService = null;
// Initial Context
javax.naming.InitialContext ic = new javax.naming.InitialContext();
// Lookup calculator SI
// Returns object support javax.xml.rpc.Service
com.ibm.samples.calculator.CalculatorServiceService calculatorServiceSI
= (com.ibm.samples.calculator.CalculatorServiceService) ic.lookup(
"java:comp/env/service/CalculatorServiceService");
// Get the calculator SEI
// Object that supports CalculatorService remote interface
//
calculatorService =
(com.ibm.samples.calculator.CalculatorService)
calculatorServiceSI.getPort(com.ibm.samples.calculator.CalculatorService.class);
if(calculatorService != null)
{
try
{
String acctName = request.getParameter("acctName");
float add
= (new Float(request.getParameter("add"))).floatValue();
float sub
= (new Float(request.getParameter("sub"))).floatValue();
javax.xml.soap.SOAPElement SE
= calculatorService.getCalculator(acctName);
com.ibm.samples.wsa.wsaddr.EndpointReference epr
= com.ibm.samples.wsa.wsaddr.EndpointReference.fromSOAPElement(SE);
// Call JAXRPCHelper to associate EPR with account and
// make it stateful
com.ibm.samples.wsa.utils.JAXRPCHelper.setEPR(
(javax.xml.rpc.Stub) calculatorService ,
epr);
// Call a couple of other methods on calculator SEI
calculatorService.add(add);
calculatorService.sub(sub);
...
com.ibm.samples.wsrp.GetMultipleResourcePropertiesRequest
getMultipleResourcePropertiesRequest =
new com.ibm.samples.wsrp.GetMultipleResourcePropertiesRequest();
javax.xml.namespace.QName[] resourceProperty
= new javax.xml.namespace.QName[2];
resourceProperty[0] = new javax.xml.namespace.QName(
"http://calculator.samples.ibm.com",
"total");
resourceProperty[1] = new javax.xml.namespace.QName(
"http://calculator.samples.ibm.com",
"request");
getMultipleResourcePropertiesRequest.setResourceProperty(
resourceProperty);
com.ibm.samples.wsrp.GetMultipleResourcePropertiesResponse
getMultipleResourcePropertiesResponse =
calculatorService.getMultipleResourceProperties(
getMultipleResourcePropertiesRequest);
javax.xml.soap.SOAPElement[] se
= getMultipleResourcePropertiesResponse.get_any();
...
|
The GetMultipleResourceProperties request also follows the implied resource pattern. Listing 12 and Listing 13 show the SOAP encoding of the GetResourceProperty message exchange.
Listing 12. GetMultipleResourceProperties 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 ...>
1083949184296
</calcID>
<dummyProp...>
EXAMPLE PROPERTY
</dummyProp>
</soapenv:Header>
<soapenv:Body>
<GetMultipleResourceProperties xmlns="">
<GetMultipleResourcePropertiesRequest xmlns=
"http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties">
<ResourceProperty xmlns:ns-1495319864=
"http://calculator.samples.ibm.com" xmlns=
"">ns-1495319864:total</ResourceProperty>
<ResourceProperty xmlns:ns-1495319864=
"http://calculator.samples.ibm.com" xmlns=
"">ns-1495319864:request</ResourceProperty>
</GetMultipleResourcePropertiesRequest>
</GetMultipleResourceProperties>
</soapenv:Body>
</soapenv:Envelope>
|
Listing 13. GetMultipleResourceProperties response 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>
<GetMultipleResourcePropertiesResponse xmlns="">
<GetMultipleResourcePropertiesResponse xmlns=
"http://www.ibm.com/xmlns/stdwip/web-services/WS-ResourceProperties">
<calc:total xmlns:calc="http://calculator.samples.ibm.com">5.0</calc:total>
<calc:request xmlns:calc="http://calculator.samples.ibm.com">4</calc:request>
</GetMultipleResourcePropertiesResponse>
</GetMultipleResourcePropertiesResponse>
</soapenv:Body>
</soapenv:Envelope>
|
Conclusions
This article provided a basic introduction of how service requestors define and access WS-Resource properties. It showed that the base service implementation which leverages J2EE best practices was easily extendible to support these new accessor operations. In particular, it showed you how to do a simple mapping of the QName defined in the properties document to an EJB Entity bean field containing that state. Similarly, you were able to leverage existing tooling to easily provide this implementation.
I expect that the optional operations introduced by WS-Resource properties will be increasingly easier to implement as other technologies emerge in this space. In particular, combining WS-transactions with Set Operation will give more structure and definition to update semantics. Similarly, some of the emerging technologies such as XMLBeans (see Resources) and Service Data Objects (see Resources) will allow us to better utilize the expressive power of XPATH. Using these structures as a construct to implement the query operation is an interesting item to prototype in the near future.
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.
Acknowledgements
The author wishes to thank Sonny Fulkerson for reviewing this article and for providing technical guidance.
Download | Name | Size | Download method |
|---|
| ws-statefulws3code.zip | | HTTP |
Resources
- Read the other parts of the series "Implement and access stateful Web services using WebSphere Studio:"
- Download WebSphere Studio Application Developer Trial Version.
- Get the JAX-RPC specification from the Java Community Process.
- For more information on J2EE Web services, check out Part 1 and Part 2 of Greg Flurry's series, "Support for J2EE Web Services in WebSphere Studio Application Developer V5.1" (developerWorks, October 2003).
- Check out JSR 109, which covers Web services for J2EE environment.
- Download the WS-Addressing specification from IBM developerWorks. WS-Addressing is an XML serialization and standard SOAP binding for representing network-wide pointers to services.
- Get the specifications related to the WS Resource Framework, which are:
WS-Notification,
WS-ResourceProperties,
WS-ResourceLifetime.
- Find the family of WS-Notification specifications, which include: WS-BaseNotification, WS-BrokeredNotification, and WS-Topics.
- Check out the OASIS Web site for more information on the OASIS WSDM Technical Committee. Also refer to the documents section.
- Check out Apache XMLBeans.
- Obtain more information on tcpmon from the Axis User’s Guide.
- Download the Service Data Objects specification from IBM developerWorks.
- For more on the Implied Resource pattern, see "Modeling stateful resource with Web services," by Ian Foster, Jeffrey Frey, Steve Graham, Steve Tuecke, Karl Czajkowski, Don Ferguson, Frank Leymann, Martin Nally, Tony Storey, William Vambenepe, and Sanjiva Weerawarana (Whitepaper, developerWorks, January 2004)
- Access Web services knowledge, tools, and skills with Speed-start Web services, which offers the latest Java-based software development tools and middleware from IBM (trial editions), plus online tutorials and articles, and an online technical forum.
- Browse for books on these and other technical topics.
- Want more? The developerWorks SOA and Web services zone hosts hundreds of informative articles and introductory, intermediate, and advanced tutorials on how to develop Web services applications.
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
|  |