ServiceLocator for Web Service Clients: Design Details
This solution is illustrated by the Java[TM] 2 Platform, Enterprise
Edition (J2EE[TM] platform) component as a client of a web
service
application available under the bpcatalog project hosted at
java.net. This
application illustrates how J2EE components can call web
services. The application was enhanced to apply the Service Locator
pattern in its design. This application shows a Servlet component
accessing a web service that is deployed as part of another
application. The concepts are basically the same for any J2EE
component (Servlet, JSP[TM] page, EJB[TM] component that needs to
access a web service.
The key parts of this application are
- Servlet: this component that needs to access a purchase
order web service. It delegates the work to other classes which will
call the purchase order web service application
- SchemaPOServiceBD.java: this class implements the Business
Delegate pattern and handles the code to call the web service. This
class uses the ServiceLocator.java class
- ServiceLocator.java: this class implements the service locator
pattern
- ServiceLocatorException.java: this class is an exception that
occurs when an
error occurs trying to look up a service reference in the naming
directory.
This application accesses a deployed web service (another application).
Because this client is a J2EE application, in this case a web
application war file, it must specify a service reference in its
web.xml file. Here is a code snippet for its web.xml:
<service-ref>
<description>Schema defined Purchase Order
Service Client</description>
<service-ref-name>service/SchemaDefinedPurchaseOrderService</service-ref-name>
<service-interface>
com.sun.j2ee.blueprints.docoriented.client.objectposervice.SchemaDefinedPurchaseOrderService
</service-interface>
<wsdl-file>WEB-INF/wsdl/SchemaDefinedPurchaseOrderService.wsdl</wsdl-file>
<jaxrpc-mapping-file>WEB-INF/schemadefinedpurchaseorderservice-mapping.xml</jaxrpc-mapping-file>
<service-qname
xmlns:servicens="urn:SchemaDefinedPurchaseOrderService">servicens:SchemaDefinedPurchaseOrderService</service-qname>
</service-ref>
Code Example 1: Service Reference in a web.xml Deployment Descriptor
In addition to including a service reference, the application
would need to bind that service-ref to a JNDI name at deployment time
so that the client code could look it up. Now lets take a look at some
of the key classes which use and implement the service locator pattern.
SchemaPOServiceBD.java
Let's start by looking at the code for the SchemaPOServiceBD.java
class. This class uses the service locator. This class just has a
single method, which is called and acts as
a delegate to access the web service. This class implements the
Business
Delegate pattern. The key part of this submitPO
method
is that it uses the service locator. It uses the service locator to get
a reference to the web service, and then calls the web service.
public class SchemaPOServiceBD {
private ServiceLocator serviceLocator;
public SchemaPOServiceBD(){
serviceLocator = new
ServiceLocator();
}
public String
submitPO(com.sun.j2ee.blueprints.docoriented.client.PurchaseOrder po)
throws RequestHandlerException {
try {
SchemaDefinedPurchaseOrderServiceSEI
port =
(SchemaDefinedPurchaseOrderServiceSEI)
serviceLocator.getServicePort(JNDINames.SCHEMA_SERVICE_REF,
SchemaDefinedPurchaseOrderServiceSEI.class);
//convert po object into object for
service type of order
// that is to be sent to the endpoint
...
String ret =
port.submitPO(order);
return ret;
}
catch ...
....
}
}
ServiceLocator.java
Now let's take a look at the ServiceLocator.java class. As you can see,
the implementation is like a service locator for other resources,
except
in this case, we have added support to get references to web services.
Since the service locator contains all the lookup code to obtain a
service reference, classes can use this service locator and avoid
copying and pasting this lookup code into a lot of different places.
This helps clean up the code in your application.
import javax.naming.*;
import java.rmi.Remote;
import javax.xml.rpc.*;
/**
* Implements Service Locator pattern for Web services
*/
public class ServiceLocator {
private transient InitialContext ic;
public ServiceLocator() throws
ServiceLocatorException {
try {
setInitialContext();
} catch (Exception e) {
throw new ServiceLocatorException(e);
}
}
private void setInitialContext() throws
javax.naming.NamingException {
ic = new InitialContext();
}
/**
* Service class acts as a factory of the
Dynamic proxy for the target service endpoint.
* @see java.xml.rpc.Service.java
* @return the Service instance
*/
public Remote getServicePort(String jndiName, Class
className) throws ServiceLocatorException {
try {
if
(ic == null) setInitialContext();
Service service = (Service) ic.lookup(jndiName);
return service.getPort(className);
} catch (Exception e) {
throw new ServiceLocatorException("ServiceLocator can not lookup
jndiName=" + jndiName + " and className=" + className, e);
}
}
}
ServiceLocatorException.java
Now let's take a look at the ServiceLocatorException.java class. Notice
that we chose to have this exception extend a RuntimeException. Because
an exception occurring while looking up a resource in a naming
directory is an unrecoverable exception for the user, we chose to treat
this an unchecked system exception. Also note that we used exception
chaining. In the J2EE client example application that uses the service
locator, we had the main servlet use the servlet error page mapping
mechanism in web.xml to map this exception and all Runtime exceptions
to a JSP error page which prints out a system error message.
package com.sun.j2ee.blueprints.docoriented.client;
public class ServiceLocatorException extends RuntimeException {
public ServiceLocatorException() {}
public ServiceLocatorException(String msg) {
super(msg); }
public ServiceLocatorException(String msg, Throwable
cause) { super(msg, cause); }
public ServiceLocatorException(Throwable cause) {
super(cause); }
}
© Sun Microsystems 2005. All of the material in The
Java BluePrints Solutions Catalog is copyright-protected
and may not be published in
other works without express written permission from Sun Microsystems.