Introduction
This article introduces a design blueprint for implementing a homegrown, lightweight Enterprise Service Bus (ESB) that leverages commonly used Integrated Development Environments (IDEs) and middleware. The scenario uses IBM® WebSphere® Application Server V8, a robust deployment environment for Java EE applications, and IBM Rational® Software Architect, which provides tooling to design, develop, test, and package Java EE applications for deployment to an application server.
Business scenario Challenge
In order to meet business demands, a service provider is
required to deliver multiple releases of its application within a year. Each
release results in updating the existing service contract and deploying a new
version of the web service into a production environment.
The most cost-effective
solution would typically be a single instance of the service deployed in
production to reduce maintenance costs. However, due to budget restrictions or
maintenance schedules, service consumers are not always in a position to adopt
new versions as soon as they are released. This scenario forces the service
provider to host multiple versions of the service to support client needs.
Solution
WebSphere
Enterprise Service Bus (WebSphere ESB) and WebSphere DataPower® Appliances both
provide robust ESB capabilities that enable dynamic routing and transformation
of requests between service consumers and providers. These capabilities enable
the decoupling of service consumers from the instance of the service that
processes the request. By leveraging an ESB, service providers can honor
multiple service contracts without hosting multiple instances of the service in
production.
When only a subset
of the capabilities provided in WebSphere ESB and WebSphere DataPower are
required, customers have the option of building lightweight ESB capabilities
into their Java EE applications to meet their project-specific needs.
Blueprint for
implementing a lightweight ESB:
A blueprint for implementing
a lightweight ESB should consist of several layers to handle the different
functions needed to receive, route, transform, and respond to requests from a
client. The blueprint outlined in this article includes the following four
layers:
Ø Routing
Layer -- A Java API for RESTful Web Services (JAX-RS) RESTful endpoint for URL
pattern matching and request routing.
Ø Mediation
Layer -- Mediation and mapping modules for managing requests at the data
content level between a client and a specific service version.
Ø Service
Invocation Layer -- Manager for the services contract that builds the required
request, invokes a physical service endpoint, and returns the content with the
response.
Ø Multi-Protocol
Listener Layer -- A listener service such as WebSphere MQ, Java Message Service
(JMS), or another service for non-JAX- RS client applications to participate in
the lightweight ESB.
Templates and
guidelines for implementation
The following sections provide details about
the templates and guidelines for each layer in the blueprint.
Routing Layer
The Routing Layer is the entry point into the
lightweight ESB. The primary purpose of the Routing
Layer is to provide clients
with well-known service endpoints and routing of client requests to the
appropriate mediation logic. In doing so, the Routing Layer decouples the
service consumers from the physical location of the service provider's endpoint.
The solution template provided for the Routing Layer is a JAX-RS
RESTful web service. This layer intercepts client requests and reroutes them,
based on URL, to the appropriate Mediation Layer entry point. Below Figure
shows the following functions of the Routing Layer:
Ø Two
service consumers -- MyService version A client and MyService version B client
-- which use different URLs when invoking the ESB.
Ø Routing
components for MyService version A client and MyService version B client which
route requests based on URL to the appropriate mediation component.
The JAX-RS Routing Layer provides two URLs – one for MyService
version A clients and one for MyService version B clients. Each URL refers to a
method in the URL Routing Resource class that handles the routing of the client
request to the appropriate mediation logic:
URL Routing Resource class
public
class URL_Routing_Resource {
private URLRouterImpl urlRouterImpl = new
URLRouterImpl();
// Constructor
public URL_Routing_Resource() {}
@GET
@Path
(value="myService/versionA/")
@Produces("application/xml")
public Response
invokeMyServiceVersionA(String payload)
{
String content = null;
System.out.println("");
content =
urlRouterImpl.myServiceVersionA(payload);
return Response.ok(content).build();
}
@GET
@Path
(value="myService/versionB/")
@Produces("application/xml")
public Response
invokeMyServiceVersionB(String payload)
{
String content = null;
System.out.println("");
content =
urlRouterImpl.myServiceVersionB(payload);
return Response.ok(content).build();
}
@GET
@Path
(value="otherService/versionX/")
@Produces("application/xml")
public Response
invokeOtherServiceVersionX(String payload)
{
String content = null;
System.out.println("");
content =
urlRouterImpl.otherServiceVersionX(payload);
return Response.ok(content).build();
}
Listener Layer
(optional)
The Listener Layer is an optional component of the blueprint and is dependent on the need for batch or non-HTTP type interfaces. The primary purpose of the Listener Layer is to provide ESB access to a broader range of clients that leverage common non-HTTP based transport mechanisms, such as WebSphere MQ, JMS, File Transfer Protocol (FTP), and Remote Method Invocation (RMI). You can create the Listener Layer to intercept an inbound non-HTTP request, build an HTTP request from the incoming data, invoke the Routing Layer via HTTP, and build a non-HTTP client response. Technologies to implement the Listener Layer can include an MQ Listener, JMS Listener, FTP Listener, or EJB Listener. Figure 3 shows the following functions of the Listener Layer:
The Listener Layer is an optional component of the blueprint and is dependent on the need for batch or non-HTTP type interfaces. The primary purpose of the Listener Layer is to provide ESB access to a broader range of clients that leverage common non-HTTP based transport mechanisms, such as WebSphere MQ, JMS, File Transfer Protocol (FTP), and Remote Method Invocation (RMI). You can create the Listener Layer to intercept an inbound non-HTTP request, build an HTTP request from the incoming data, invoke the Routing Layer via HTTP, and build a non-HTTP client response. Technologies to implement the Listener Layer can include an MQ Listener, JMS Listener, FTP Listener, or EJB Listener. Figure 3 shows the following functions of the Listener Layer:
Ø Two non-HTTP clients -- An MQ service consumer for MyService version A client, and an FTP service consumer for MyService version B client.
Ø Two
Listener Layer mapping modules that map the incoming request to an HTTP JAX- RS
request and invoke the Routing Layer. In addition, the response is also mapped
as required by the client and the appropriate response returned to the client.
Mediation Layer
The Mediation Layer
serves as the central data content mapping point for all incoming and outgoing
service requests. The primary purpose of the Mediation Layer is to provide
mapping capabilities between client-aware versions of a service and physical
service endpoint versions. In addition, the Mediation Layer ensures that
adequate data-related content required by a specific service version is present
prior to calling the Service Invocation Layer.
The solution template provided for the Mediation Layer leverages Java
classes to programmatically determine a service version, and perform inbound
mapping to fill in missing data content required to call a physical service
endpoint. This layer invokes the Service Invocation layer and performs
outbound-related mapping for the client-specific response based on version. The
Mediation Layer could also use XSLT or other mapping technologies or products,
such as WebSphere Transformation Extender, to provide data content mapping.
Figure 4 shows the following functions of the Mediation Layer:
Ø An inbound mapping module for clients of MyService that supports versions A and B.
Ø An outbound mapping module for clients of MyService that supports versions A and B.
Ø An additional example of a mapping module for clients that would support multiple versions of a future service (depicted as OtherService).
Ø An inbound mapping module for clients of MyService that supports versions A and B.
Ø An outbound mapping module for clients of MyService that supports versions A and B.
Ø An additional example of a mapping module for clients that would support multiple versions of a future service (depicted as OtherService).
The Mediation Layer provides an invocation entry point for MyService
(version A clients and version B clients), in addition to an entry point for
OtherService. The Invoke method uses the incoming service name to call the
service-specific mediation logic:
Invoke method in Mediation Layer
/*
* Entry point into Mediation Layer for all
services
*/
public MediationObject
invoke(MediationObject mo)
{
if(mo.getServiceName().equalsIgnoreCase("myService"))
return invokeMyService(mo);
else
if(mo.getServiceName().equalsIgnoreCase("otherService"))
return invokeOtherService(mo);
else
return null;
}
The logic within the service-specific mediation determines which
version of client made the request, and executes mapping logic to transform the
incoming message content prior to passing the message to the Service Invocation
Layer. When the response is returned from the Service Invocation Layer,
outbound mapping logic is performed to transform the message content into the
format expected by the requesting client:
Mediation logic for MyService
/*
* Mediation logic for MyService
*/
private MediationObject
invokeMyService(MediationObject mo)
{
Mapper mapper = new Mapper();
MediationObject outgoingMO = new
MediationObject();
// 1. Determine service version
if
(mo.getVersion().equalsIgnoreCase("A"))
{
// 2. Invoke the Mapping Layer to
perform any required outbound mapping
ServiceInvocationObject sio = mapper.serviceRequestMapper(mo);
// 3. Call the Invocation Layer to
physically invoke the service
InvocationLayer invoke = new
InvocationLayer();
ServiceInvocationResponse sir =
invoke.callService(sio);
// 4. Invoke the Mapping Layer to
perform any required inbound mapping
outgoingMO =
mapper.serviceResponseMapper(sir);
}
else
if(mo.getVersion().equalsIgnoreCase("B"))
{
// Repeat Steps 2 - 4 above
}
else
return null;
return outgoingMO;
}
Service
Invocation Layer
The Service Invocation Layer serves as the
entry point for calling a physical service. The primary purpose of the Service
Invocation Layer is to implement the client code to invoke a physical service
endpoint. The Service Invocation Layer takes the data content from the
Mediation Layer and constructs the request required by the physical service
endpoint. The physical service is then invoked, and the Service Invocation
Layer constructs a response object that is returned to the Mediation Layer.
The solution template provided for the Service Invocation Layer leverages
Java classes to implement the client code, which constructs the service
endpoint request from the data content provided by the Mediation Layer. This
Layer constructs the physical service request object, invokes the physical
service endpoint, and converts the response object back to the format required
by the Meditation Layer. Figure 5 shows the following functions of the Service
Invocation Layer:
Ø A
module to construct the request object, invokes the physical service endpoint,
and converts the response to the format required by the Mediation Layer.
Ø An
additional example of a module to construct the request object, invoke the
physical service endpoint, and convert the response to the format required by
the Mediation Layer for a future service (depicted as Other Service).
The Service Invocation Layer provides an invocation entry point for
MyService and an entry point for OtherService. The callService method uses the
incoming service name to call the service-specific invocation logic:
The
callService method in the Service Invocation Layer
/*
* Entry point for Service Invocation Layer
*/
public ServiceInvocationResponse
callService(ServiceInvocationObject sio)
{
if(sio.getServiceName().equalsIgnoreCase("myService"))
return callMyService(sio);
else
if(sio.getServiceName().equalsIgnoreCase("otherService"))
return callOtherService(sio);
else
return null;
}
The logic within the Service Invocation Layer determines which
version of a service is being requested by a client, constructs the
endpoint-specific request, submits the request to the endpoint, and then converts
the endpoint response to the format expected by the Meditation Layer:
/*
* Service Invocation logic for myService
*/
private ServiceInvocationResponse
callMyService(ServiceInvocationObject sio)
{
ServiceInvocationResponse sir = new
ServiceInvocationResponse();
// 1. Build physical service endpoint
specific object from SIO payload
// 2. Call physical service endpoint
// 3. Build SIR payload from endpoint
specific response object
// 4. Return SIR to Mediation Layer
return sir;
}
Conclusion
This article
introduced a design blueprint for implementing a homegrown, lightweight ESB.
The blueprint consists of four layers that outline the different functionalities
needed to receive, route, transform, and respond to requests from a client. To
illustrate the use of the blueprint, the article described a business scenario
and provided code templates and guidelines for implementing a lightweight ESB.
You can use this article to design and implement your own lightweight ESB to
meet your specific project requirements.
Downloads
Downloads
File Name
|
Description
|
Size
|
Download
|
Design
blueprint to implement a lightweight ESB
|
Document
|
480 KB
|
0 comments :
Post a Comment