Using a design blueprint to implement a lightweight Enterprise Service Bus

Follow this design blueprint to implement a homegrown, lightweight ESB. The scenario leverages commonly used Integrated Development Environments (IDEs) and middleware, such as Rational Software Architect and WebSphere Application Server. The framework consists of a routing layer with a JAX-RS RESTful endpoint, a mediation layer with mediation and mapping modules, and a service invocation layer. 

Tendai Chinoda (tendai@us.ibm.com), IT Specialist and Senior Software Engineer, IBM

Photo of Tendai ChinodaTendai Chinoda is an IBM Certified IT Specialist and Senior Software Engineer in IBM Software Services for WebSphere (ISSW). He provides consulting and enablement services to IBM customers for the WebSphere family of products. His expertise and interests include application architecture, design and development for cloud computing, Java EE, SOA, and web services.


developerWorks Contributing author
        level

Harry L. Hoots, III (hlhoots@us.ibm.com), IT Specialist, IBM

Photo of Harry L. HootsHarry L. Hoots, III is an IT Specialist working on the IBM Account. He serves in senior roles and is a Web Services Development Lead on a major internal project. His expertise and interests include application architecture, design and development of Java EE, web services, and WebSphere MQ.



16 January 2013

Also available in Chinese

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. For more information on these and other relevant products, see the Resources section at the bottom of the article.

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.

Figure 1 shows the high-level design and interface points for the four layers of the lightweight ESB blueprint:

Figure 1. Design and interface points for lightweight ESB blueprint
Design and interface points for lightweight ESB blueprint

Applying the lightweight ESB blueprint in a real-world example

The following example shows a real-world usage scenario of the blueprint:

  1. A service provider updates their current production instance of MyService version A to version B.
  2. The installation of MyService version B results in the sunsetting of MyService version A, and thus only a single instance of MyService version B is supported by the service provider.
  3. The service provider works with the ESB design team to define the necessary routing, mediation, and service invocation logic to provide continued support of both new and existing clients.
  4. The ESB design team leverages the blueprint to implement a solution that supports clients of either version of MyService.

For templates and guidelines used by the ESB design team to implement their lightweight ESB, see the Downloads section at the bottom of the article.

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. Figure 2 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.
Figure 2. Routing Layer
Routing Layer

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:

  • 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.
Figure 3. Listener Layer
Listener Layer

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).
Figure 4. Mediation Layer
Mediation Layer

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, invoke the physical service endpoint, and convert 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 OtherService).
Figure 5. Service Invocation Layer
Service Invocation Layer

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:

Logic for the Service Invocation 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.


Download

DescriptionNameSize
RSA project for the design blueprintLightWeightESBWorkspace.zip28 KB

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=855240
ArticleTitle=Using a design blueprint to implement a lightweight Enterprise Service Bus
publish-date=01162013