4
Roadmap for Developing Reliable Web Services and Clients 4-1
4
Roadmap for Developing Reliable Web Services and Clients
The following sections present best practices for developing Web services and clients.
■
Section 4.1, Roadmap for Developing Reliable Web Service Clients
■
Section 4.2, Roadmap for Developing Reliable Web Services
■
Section 4.3, Roadmap for Accessing Reliable Web Services from Behind a Firewall MakeConnection
■
Section 4.4, Roadmap for Securing Reliable Web Services
4.1 Roadmap for Developing Reliable Web Service Clients
Table 4–1 provides best practices for developing reliable Web service clients, including
an example that illustrates the best practices presented. These guidelines should be used in conjunction with the guidelines provided in
Chapter 2, Roadmaps for Developing Web Service Clients.
.
Note: It is assumed that you are familiar with the general concepts
for developing Web services and clients, as described in Getting Started With JAX-WS Web Services for Oracle WebLogic Server.
See also Section 6.2, Roadmap for Configuring Web Service
Persistence. .
Table 4–1 Roadmap for Developing Reliable Web Service Clients
Best Practice Description
Always implement a reliability error listener.
For more information, see Section 5.8, Implementing the Reliability
Error Listener. Group messages into units of work.
Rather than incur the RM sequence creation and termination protocol overhead for every message sent, you can group messages into business
units of work—also referred to as batching. For more information, see Section 5.11, Grouping Messages into Business Units of Work
Batching .
Note : This best practice is not demonstrated in
Example 4–1 .
4-2 Programming Advanced Features of JAX-WS Web Services for Oracle WebLogic Server
The following example illustrates best practices for developing reliable Web service clients.
Example 4–1 Reliable Web Service Client Best Practices Example
import java.io.; import java.util.;
import javax.servlet.; import javax.xml.bind.JAXBContext;
import javax.xml.ws.; import weblogic.jws.jaxws.client.ClientIdentityFeature;
import weblogic.jws.jaxws.client.async.AsyncClientHandlerFeature; import weblogic.jws.jaxws.client.async.AsyncClientTransportFeature;
import weblogic.wsee.reliability2.api.ReliabilityErrorContext; import weblogic.wsee.reliability2.api.ReliabilityErrorListener;
import weblogic.wsee.reliability2.api.WsrmClientInitFeature; import com.sun.xml.ws.developer.JAXWSProperties;
Example client for invoking a reliable Web service asynchronously. public class BestPracticeAsyncRmClient
extends GenericServlet { private BackendReliableServiceService _service;
private BackendReliableService _singletonPort; private WebServiceFeature[] _features;
private static int _requestCount; private static String _lastResponse;
private static final String MY_PROPERTY = MyProperty; Override
public void init throws ServletException {
_requestCount = 0; _lastResponse = null;
Only create the Web service object once as it is expensive to create repeatedly. Set the acknowledgement interval to a
realistic value for your particular scenario.
The recommended setting is two times the nominal interval between requests. For more information, see
Section 5.7.9, Configuring the Acknowledgement Interval.
Note
: This best practice is not demonstrated in Example 4–1
. Set the base retransmission interval to a
realistic value for your particular scenario.
The recommended setting is two times the acknowledgement interval or nominal response time, whichever is greater. For more information, see
Section 5.7.4, Configuring the Base Retransmission Interval.
Note
: This best practice is not demonstrated in Example 4–1
. Set timeouts inactivity and sequence
expiration to realistic values for your particular scenario.
For more information, see Section 5.7.7, Configuring Inactivity Timeout
and Section 5.7.6, Configuring the Sequence Expiration.
Note
: This best practice is not demonstrated in Example 4–1
.
Table 4–1 Cont. Roadmap for Developing Reliable Web Service Clients
Best Practice Description
Roadmap for Developing Reliable Web Services and Clients 4-3
if _service == null { _service = new BackendReliableServiceService;
} Best Practice: Use a stored list of features, per client ID, to create client instances.
Define all features for the Web service port, per client ID, so that they are consistent each time the port is called. For example:
_service.getBackendServicePort_features; ListWebServiceFeature features = new ArrayListWebServiceFeature;
Best Practice: Explicitly define the client ID. ClientIdentityFeature clientIdFeature =
new ClientIdentityFeatureMyBackendServiceAsyncRmClient; features.addclientIdFeature;
Best Practice: Always implement a reliability error listener. Include this feature in your reusable feature list. This enables you to determine
a reason for failure, for example, RM cannot deliver a request or the RM sequence fails in some way for example, client credentials refused at service.
WsrmClientInitFeature rmFeature = new WsrmClientInitFeature; features.addrmFeature;
rmFeature.setErrorListenernew ReliabilityErrorListener { public void onReliabilityErrorReliabilityErrorContext context {
At a minimum do this System.out.printlnRM sequence failure: +
context.getFaultSummaryMessage; _lastResponse = context.getFaultSummaryMessage;
And optionally do this... The context parameter conveys whether a request or the entire
sequence has failed. If a sequence fails, you will get a notification for each undelivered request if any on the sequence.
if context.isRequestSpecific { Single request failure possibly as part of a larger sequence failure.
Retrieve the original request. String operationName = context.getOperationName;
System.out.printlnFailed to deliver request for operation + operationName + . Fault summary: +
context.getFaultSummaryMessage; if DoSomething.equalsoperationName {
try { String request = context.getRequestJAXBContext.newInstance,
String.class; System.out.printlnFailed to deliver request for operation +
operationName + with content: + request;
MapString, Serializable requestProps = context.getUserRequestContextProperties;
if requestProps = null { Retrieve the request property. Use MyProperty
to describe the request that failed and print this value during the simple error recovery below.
String myProperty = StringrequestProps.getMY_PROPERTY; System.out.printlnGot MyProperty value propagated from request: +
myProperty; System.out.printlnmyProperty + failed;
}
4-4 Programming Advanced Features of JAX-WS Web Services for Oracle WebLogic Server
} catch Exception e { e.printStackTrace;
} }
} else { The entire sequence has encountered an error.
System.out.printlnEntire sequence failed: + context.getFaultSummaryMessage;
} }
}; Asynchronous endpoint.
AsyncClientTransportFeature asyncFeature = new AsyncClientTransportFeaturegetServletContext;
features.addasyncFeature; Best Practice: Define a port-based asynchronous callback handler,
AsyncClientHandlerFeature, for asynchronous and dispatch callback handling. BackendReliableServiceAsyncHandler handler =
new BackendReliableServiceAsyncHandler { public void onDoSomethingResponseResponseDoSomethingResponse res {
... Handle Response ... try {
Show getting the MyProperty value back. DoSomethingResponse response = res.get;
_lastResponse = response.getReturn; System.out.printlnGot reliable async response: + _lastResponse;
Retrieve the request property. This property can be used to remember the context of the request and subsequently process
the response. MapString, Serializable requestProps =
MapString, Serializable res.getContext.getJAXWSProperties.PERSISTENT_CONTEXT;
String myProperty = StringrequestProps.getMY_PROPERTY; System.out.printlnGot MyProperty value propagated from request: +
myProperty; } catch Exception e {
_lastResponse = e.toString; e.printStackTrace;
} }
}; AsyncClientHandlerFeature handlerFeature =
new AsyncClientHandlerFeaturehandler; features.addhandlerFeature;
Set the features used when creating clients with the client ID MyBackendServiceAsyncRmClient.
_features = features.toArraynew WebServiceFeature[features.size]; Best Practice: Define a singleton port instance and initialize it when
the client container initializes upon deployment. The singleton port will be available for the life of the servlet.
Creation of the singleton port triggers the asynchronous response endpoint to be published and it will remain published until our container Web application is undeployed.
Note, we will get a call to destroy before this. _singletonPort = _service.getBackendReliableServicePort_features;
Roadmap for Developing Reliable Web Services and Clients 4-5
} Override
public void serviceServletRequest req, ServletResponse res throws ServletException, IOException {
TODO: ... Read the servlet request ... For this simple example, echo the _lastResponse captured from
an asynchronous DoSomethingResponse response message. if _lastResponse = null {
res.getWriter.write_lastResponse; _lastResponse = null; Clear the response so we can get another
return; }
Set _lastResponse to NULL in order to make a new invocation against BackendService to generate a new response
Best Practice: Synchronize use of client instances. Create another port using the exact same features used when creating _singletonPort.
Note, this port uses the same client ID as the singleton port and it is effectively the same as the singleton from the perspective of the Web services runtime.
This port will use the asynchronous response endpoint for the client ID, as it is defined in the _features list.
NOTE: This is DEFINITELY not best practice or ideal because our application is incurring the cost of an RM handshake and sequence termination
for every reliable request sent. It would be better to send multiple requests on each sequence. If there is not a natural grouping
for messages a business unit of work, then you could batch requests onto a sequence for efficiency. For more information, see
Section 5.11, Grouping Messages into Business Units of Work Batching. BackendReliableService anotherPort =
_service.getBackendReliableServicePort_features; Set the endpoint address for BackendService.
BindingProvideranotherPort.getRequestContext. putBindingProvider.ENDPOINT_ADDRESS_PROPERTY,
http:localhost:7001BestPracticeReliableServiceBackendReliableService; Make the invocation. Our asynchronous handler implementation set
into the AsyncClientHandlerFeature above receives the response. String request = Protect and serve;
System.out.printlnInvoking DoSomething reliablyasync with request: + request;
Add a persistent context property that will be returned on the response. This property can be used to ’remember’ the context of this
request and subsequently process the response. This property will not get passed over wire, so the properties can change independent of the
application message. MapString, Serializable persistentContext =
MapString, SerializableBindingProvideranotherPort. getRequestContext.getJAXWSProperties.PERSISTENT_CONTEXT;
String myProperty = Request + ++_requestCount; persistentContext.putMY_PROPERTY, myProperty;
System.out.printlnRequest being made reliably with MyProperty value: + myProperty;
anotherPort.doSomethingAsyncrequest;
4-6 Programming Advanced Features of JAX-WS Web Services for Oracle WebLogic Server
Return a canned string indicating the response was not received synchronously. Client needs to invoke the servlet again to get
the response. res.getWriter.writeWaiting for response...;
Best Practice: Explicitly close client instances when processing is complete. If not closed, the port will be closed automatically when it goes out of scope.
This will force the termination of the RM sequence we created when sending the first doSomething request. For a better way to handle this, see
Section 5.11, Grouping Messages into Business Units of Work Batching. NOTE: Even though the port is closed explicitly or even if it goes out of scope
the reliable request sent above will still be delivered under the scope of the client ID used. So, even if the service endpoint
is down, RM retries the request and delivers it when the service endpoint available. The asynchronous resopnse will be delivered as if the port instance was
still available. java.io.CloseableanotherPort.close;
} Override
public void destroy { try {
Best Practice: Explicitly close client instances when processing is complete. Close the singleton port created during initialization. Note, the asynchronous
response endpoint generated by creating _singletonPort remains published until our container Web application is undeployed.
java.io.Closeable_singletonPort.close; Upon return, the Web application is undeployed, and our asynchronous
response endpoint is stopped unpublished. At this point, the client ID used for _singletonPort will be unregistered and will no longer be
visible from the Administration Console and WLST. } catch Exception e {
e.printStackTrace; }
} }
4.2 Roadmap for Developing Reliable Web Services