ServiceLocator for Web Service Clients
Sean Brydon
Problem Description
Many applications use the Service
Locator pattern. Now that web services are becoming more
common in applications, there is a need to update your service locator
code to support web services. Also, if your application does not
currently
apply the service locator pattern, you should consider doing this.
Enterprise applications require a way to look up the references
that provide access to distributed components and web services.
Java[TM]
2 Platform, Enterprise Edition (J2EE[TM])
applications use Java Naming and Directory Interface (JNDI) to look up
enterprise bean home interfaces, Java Message Service (JMS) components,
data sources, connections, connection factories, and now web
services. Repetitious lookup code makes code difficult to read and
maintain. The Service Locator pattern
centralizes this code into one class and eliminates redundant code that
otherwise gets scattered around the application.
This solution is applicable in the following circumstances:
- The client application is using the J2EE1.4 platform.
- The client application has J2EE components that act as clients
calling
the target web services.
Solution
The service locator pattern has been around for a while, and many J2EE
applications use a service locator class to lookup J2EE resources. Now
that there are web services that can be looked up and a service
referenced obtained, we need to consider how to do this to support web
services.
This solution will do the following:
- Provide a brief review of the service locator pattern. If you are
familiar
with the service locator pattern, then you can skip this section and
jump right into the solution
strategies
sections.
- Provide a strategy to add suppport for clients looking up web
services, and provide an example to refactor application code to
introduce
a service locator for web services. Then we will present some
strategies as solutions in different circumstances.
- Briefly show how to apply the caching strategy which is popular
with the service locator
Review of ServiceLocator Pattern
Let's look at an older example
from the Java Adventure Builder of a service locator with web services
support
added. As you can see from the code below, there are methods to get
references to different kinds of J2EE resources, such as EJBHomes, JMS
ConnectionFactories, or Data Sources such as databases.
public class ServiceLocator {
private transient InitialContext ic;
public ServiceLocator() throws ServiceLocatorException {
try {
ic = new InitialContext();
} catch (Exception e) {
throw new ServiceLocatorException(e);
}
}
/**
* @return the EJB Home factory corresponding to the homeName
*/
public EJBHome getRemoteHome(String jndiHomeName, Class
className)
throws ServiceLocatorException {
try {
Object objref = ic.lookup(jndiHomeName);
return (EJBHome)
PortableRemoteObject.narrow(objref, className);
} catch (Exception e) {
throw new ServiceLocatorException(e);
}
}
/**
* @return the factory for the factory to get JMS connections from
*/
public ConnectionFactory getJMSConnectionFactory(String
jmsConnFactoryName)
throws ServiceLocatorException {
try {
return (ConnectionFactory)
ic.lookup(jmsConnFactoryName);
} catch (Exception e) {
throw new ServiceLocatorException(e);
}
}
/*
* @return the DataSource corresponding to the name parameter
*/
public DataSource getDataSource(String dataSourceName) throws
ServiceLocatorException {
try {
return
(DataSource)ic.lookup(dataSourceName);
} catch (Exception e) {
throw new ServiceLocatorException(e);
}
}
...//and other J2EE resources
}
Code Example 1: Service Locator for J2EE Resources, With No
Support For Web Services
Let's look at some of the main participants in the Service Locator
pattern:

On the client that will use a business object or service it
first needs to look up and get a reference to the service. In using the
service locator pattern you
have the following key participants:
- Client Object: This is a Servlet/JSP[TM]/EJB[TM] or Java object
that is going to call
the target web service. This uses the service locator to lookup a
service.
- ServiceLocator: This is the implementation of the service
locator.
- InitialContext: This the initial context used to look up
references in JNDI naming directory .
- Resouce Factory: This is a resource factory such as EJB Home.
- Component or Resource: This is the reference that will be used to
access the service or resource or component containing the business
logic. For example, it could be an EJB session bean.
Now that we have some idea about the service locator, let's look at how
to add the web service support.
Adding Web
Service Support to a Service Locator
Now let's look at what methods you need to add to your service
locator to support web services.
For this example, let's assume there is a deployed application with
a
running service, and your application is a war file with a servlet that
will access that service. In J2EE, components such as a Servlet in a
web app that wants to access a web service application would need to
write code to call a service and also in the web.xml deployment
descriptor include a reference to a service (see Code Example 2).
<service-ref>
<description>Client of Some
Service</description>
<service-ref-name>service/
SomeService
</service-ref-name>
<service-interface>
com.sun.j2ee.blueprints.myclientapplication.
SomeService
</service-interface>
<wsdl-file>WEB-INF/wsdl/SomeService.wsdl</wsdl-file>
<jaxrpc-mapping-file>WEB-INF/someservice-mapping.xml</jaxrpc-mapping-file>
<service-qname
xmlns:servicens="urn:
SomeService
">servicens:
SomeService
</service-qname>
</service-ref>
Code Example 2: Service Reference in a web.xml Deployment Descriptor
When your client application is deployed and a JNDI name is
bound for
this service-ref, then the application can just access the naming
service to
get access to the service. For this example, let's assume that the
service reference is bound in the naming directory as
"java:comp/env/service/SomeService"
. The code in the left
side
of Table 1 shows the code without using a
service locator class. Now,
this code needs to be refactored to use the service locator, as shown
in the right side of the table.
Without Using
a Service Locator |
Refactored to
Use a Service Locator |
String s=
"java:comp/env/service/SomeService";
try {
Context ic = new InitialContext();
Service myService =(Service)ic.lookup(s);
SomeServiceSEI port =(SomeServiceSEI)
myService
.getPort(SomeServiceSEI.class);
//now just call the web service method
port.someMethod(someParameter);
} catch(Exception exe){
...
}
|
String s=
"java:comp/env/service/SomeService";
try
{
ServiceLocator sLoc = new ServiceLocator();
SomeService SEI port = ( SomeService SEI)
sLoc .getServicePort( s , SomeService SEI.class);
//now just call the web service method
port.someMethod(someParameter);
}
catch(ServiceLocatorException sle){
...
} catch(Exception exe){
...
}
|
Table 1: Refactoring to Use the Service Locator Pattern
As you can see, it's just a simple change to update your service
locator
for web services. Although this is just a small change to the code, it
is very useful since this code is often repeated in many places in the
application. And over time, if you have repeated code in many places,
it starts to get a bit inconsistent, messy, and hard to maintain. So
the usage of a service locator can clean up the code a bit.
Additionally,
the service locator class needs to be updated to support the lookup of
a web service. Code Example 3 shows the service locator with support
to look up web service references.
/**
* Implements Service Locator pattern for Web services
*/
public class ServiceLocator {
private transient InitialContext ic;
public ServiceLocator() throws
ServiceLocatorException {
try {
ic =
new InitialContext();
} catch (Exception e) {
throw new ServiceLocatorException(e);
}
}
public Remote getServicePort(String jndiHomeName,
Class className) throws ServiceLocatorException {
try {
Service service = (Service) ic.lookup(jndiHomeName);
return service.getPort(className);
} catch (Exception e) {
throw new ServiceLocatorException(e);
}
}
}
Code Example 3: ServiceLocator With Support for J2EE Components to
Act as Web Service Clients
That's it. Its easy to use this pattern. It does add an extra class
to
your application, but it can clean up your code a bit.
Strategy: Adding Web Service Support to a Service Locator
Implementing the Caching Strategy
Some applications design the service locator using the caching
strategy. This is to avoid unnecessary JNDI initial context creation
and service object lookups. A service
locator that applies this caching strategy for web service lookup
is shown below in Code Example 4.
public class ServiceLocator {
private InitialContext ic;
//used to hold references to resources
private Map cache = Collections.synchronizedMap(new
HashMap());
private static ServiceLocator instance = new
ServiceLocator();
public static ServiceLocator getInstance() {
return instance;
}
private ServiceLocator() throws
ServiceLocatorException {
try {
ic =
new InitialContext();
} catch (Exception e) {
throw new ServiceLocatorException(e);
}
}
public Remote getServicePort(String jndiHomeName,
Class className) throws ServiceLocatorException {
Remote servicePort = (Remote)
cache.get(jndiHomeName);
if
(servicePort ==
null) {
try {
Service service = (Service) ic.lookup(jndiHomeName);
servicePort =
service.getPort(className);
cache.put(jndiHomeName, servicePort);
} catch
(Exception e) {
throw new ServiceLocatorException(e);
}
}
return
servicePort;
}
}
Code Example 4: ServiceLocator for Web Service References, With
Caching Strategy
As you can see from these code examples, an application that
needs to look up web services can leverage the service locator pattern
in much the same way as it can to look up other J2EE resources.
References
For more information about this topic, refer to the following:
- Core J2EE Patterns: Best
Practices and Design Strategies, Second Edition. D Alur, D.
Malks, and J. Crupi. Copyright 2003, Prentice Hall PTR.
- The design
document for the example application using the service locator has
a more detailed explanation.
- The Service
Locator pattern is explained for more general purposes
with other examples on the
Java BluePrints web site.
© 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.