Due to global networks, heterogeneous information systems, and the need for agility, conventional architectures have evolved. The tasks of building entirely new applications, making specific adaptors for legacy systems, or rewriting existing applications are now obsolete. Largely promoted by Web services connectivity, the service-oriented architecture (SOA) is now considered the preferred approach to designing an information system.
SOA proposes to provide existing functions of an information system as "services" that can be accessed in a loosely coupled way, independently from the technical platform. An application is seen as an orchestration of requests for those services. That is why an SOA generally comes with workflow or orchestration concepts.
An enterprise service bus (ESB) is an implementation of an SOA. It is middleware for connecting heterogeneous services and orchestrating them. Related to these concepts, the Java Business Integration specification (JBI, Java Specification Request 208) defines a standard framework for integration.
In this article, I use the Petals ESB, an open source JBI container, to illustrate how to connect existing heterogeneous services and put together an online travel agency Web application.
Java Business Integration
The Java Business Integration specification defines a standard means for assembling integration components. The goal is to create integration solutions that enable an SOA in an enterprise information system. These components are plugged into a JBI environment and can provide or consume services through it in a loosely coupled way. The JBI environment then routes the exchanges between those components.
Two kinds of components can be plugged into a JBI environment:
- Service engines provide logic in the environment, such as XSL (Extensible Stylesheet Language) transformations or BPEL orchestration (Business Process Execution Language).
- Binding components are "connectors" to external services or applications. They allow communication with various protocols, such as SOAP, Java Message Service (JMS), remote method invocation (RMI), or ebXML.
These configurable components enable communication between heterogeneous services. The JBI specification introduces the service assembly, which defines the configuration of these components and the links between them. The goal of the components (bindings or engines) is to expose external and internal services. Each service exposed in the JBI environment can be accessed through the service endpoint, the address of the service.
The messages exchanged between components are called message exchanges. The exchange pattern between the components is a send-accept message pattern.
An online travel agency application with JBI
This article's travel agency Website allows users to book flights and accommodations, and sends an email to users to confirm these reservations. To deliver this functionality, the Website sends to the workflow engine all the information provided by the user in XML. This workflow engine then connects to the airline to book the flight, then to the hotel chain to book the room. It sends a confirmation email to the user via the mail engine.
Even if the data exchanged during the process is XML, the XML schemas requested or provided by the various services differ. Thus, an XSLT (Extensible Stylesheet Language Transformation) engine is used to process transformations from XML to another format.
I discuss the business process later in this article. Let's first look at Figure 1, which shows how this application is built with the Petals ESB.
Now let's define the different parts that are key to this architecture.
A service assembly is a descriptor that configures a JBI component for integration with applications. A service assembly is deployed on the JBI container as a simple ZIP archive. The container analyzes all the content in this archive and configures the affected components. The configuration for a component is called a service unit. When we configure a component with a service unit, we say that we deploy an artifact on it. Note that the content of a service unit is opaque to the container and is just provided to the component.
If the service assembly contains link definitions between services (also called connections), the container creates them. Connections can be seen as aliases to real service endpoints.
The service assembly is a ZIP archive containing an XML descriptor file that defines to which component a service unit is provided and the connections between services. The service assembly also contains each service unit to deploy to components. These service units are also ZIP archives.
To recap, the role of a service assembly is to define the glue between a set of services to create an application in an SOA way. As multiple service assemblies are deployed on the container, multiple applications can run on and share the same services.
A service unit is a set of elements deployed to a JBI component. A service unit contains an XML descriptor that the component can read and any artifacts that the component can require. For instance, a service unit for an XSLT engine contains an XSL stylesheet, and the descriptor file tells the component that this stylesheet must be used when a message is received on a particular service endpoint.
The ESB explodes the service unit archive in a directory, calls the component's service unit manager (part of a JBI component) to inform it that a new service unit is available, and indicates the directory where the service unit has exploded. The component's service unit manager registers this new service in the JBI environment and configures the component to use the related artifact with the registered service endpoint.
When the component receives a message for a particular service endpoint, it knows which artifact to use.
A connection is defined in a service assembly's descriptor. It can be viewed as an alias for a real service endpoint. For example, a component can specify "I want to send a message to the service endpoint called My Endpoint," and a connection specifies that My Endpoint is in fact My Real Endpoint. Thus, when the component sends the message to My Endpoint, it is sent to My Real Endpoint.
The interest of using such a mechanism is to dynamically reconfigure the links between components. For instance, a component, such as the travel agency workflow engine, is configured to call a service where the service endpoint name is "airline service endpoint." Then, depending on the travel agency's partnership with the airline, the connection will link the airline service endpoint with, for instance,
AnotherAirlineCompanyEndpoint. The service's consumer needs no change to connect to the right service. By deploying various service assemblies containing different connections, the application will dynamically change the services used.
The travel agency application
The global process for our travel agency application proceeds as follows:
- The Website sends the user's reservation requests through a SOAP request to the SOAP binding component. This information is called Website XML content. Note that this communication is external to JBI.
- Now, we enter the JBI environment. The SOAP binding component is configured to send the Website XML content via a message exchange to the endpoint
BookingWorkflowEndPoint(hosted by the BPEL engine).
- The BPEL engine sends the Website XML content to the
XSLT_1_Endpoint(hosted by the XSLT engine).
- The XSLT engine transforms the Website XML content to a format recognized by the airline service and returns it as the flight-request XML.
- The BPEL engine sends the Website XML content to the
XSLT_2_Endpoint(hosted by the XSLT engine).
- The XSLT engine transforms the Website XML content to a format recognizable by the hotel service and returns it as the hotel-request XML.
- The BPEL engine sends the flight-request XML to the
AirLineEndpoint, resolved as
MyAirLineCompanyEndpoint(hosted by the SOAP binding component).
- The SOAP binding component is configured to send the fight-request XML through a SOAP request to the MyAirLineCompany Web service (external to JBI). The result is the confirmed flight-response XML and is returned to the BPEL engine.
- The BPEL engine sends the hotel-request XML to the
HotelEndpoint, resolved as
MyHotelEndpoint(hosted by the RMI binding component).
- The RMI binding component is configured to send the hotel-request XML through an RMI call to the MyHotel RMI server (external to JBI). The result is the confirmed hotel-response XML and is returned to the BPEL engine.
- As the result of the two reservations, the BPEL engine concatenates the flight-response XML and hotel-response XML to flight-and-hotel-response XML. Then it sends this XML to the
XSLT_3_Endpoint(hosted by the XSLT engine).
- The XSLT engine transforms the flight-and-hotel-response XML to text that summarizes the reservations. This email XML returns to the travel agency workflow engine.
- The BPEL engine sends the email XML to the
EmailEndpoint(hosted by the email binding component).
- The email binding component sends an email with the email XML to the user (external to JBI). The process is now complete.
The JBI components needed for the application are the SOAP binding component (communication with the Website and the airline Web service), the JMS binding component (communication with the hotel JMS service), the XSLT engine (XML transformation), the email engine (send confirmation email to the user), and the BPEL engine. These JBI components are distributed with the Petals JBI container.
To create our application, we just install those components in the JBI container. (See Resources for more about JBI component installation.)
At this point, the architecture looks like this:
Note that the mail engine natively exposes its single service endpoint to the JBI environment, as it requires no configuration and always performs the same task (which is, in fact, to send email).
When the components are installed, we must configure them. Thus, we need to create the service assembly that links these elements together. The service units described below make up this service assembly.
Website service unit
A service unit is created to be deployed on the SOAP binding component (SOAP BC). This service unit defines an http://travel.com/workflowService Web service that will map to the internal service endpoint
With this service unit, the SOAP BC consumes the
WorkflowEndpoint service endpoint:
<jbi version="1.0" xmlns='http://java.sun.com/xml/ns/jbi' ...> <services binding-component="true"> <consumes service-name =" BookingWorkflowService " endpoint-name =" BookingWorkflowEndpoint " /> <petals:address> http://travel.com/workflowService </petals:address> </services> </jbi>
When the service unit deploys, the SOAP BC exposes a new Web service, called http://travel.com/workflowService. When an external call to this Web service is performed (from the Website, for instance), the SOAP BC transfers it to the
BookingWorkflowEndpoint service endpoint, that is, the application workflow engine.
Booking process service unit
A service unit is created for deployment on the BPEL engine. This service unit contains a BPEL definition of the booking process. This definition lists the different service endpoints that must be called by the workflow engine. This process definition maps to the internal service endpoint, the
<jbi version="1.0" xmlns='http://java.sun.com/xml/ns/jbi' ...> <services binding-component="false"> <provides service-name =" BookingWorkflowService " endpoint-name =" BookingWorkflowEndpoint " /> <petals:address> file://travel-booking.bpel </petals:address> </services> </jbi>
The travel-booking.bpel file is contained in this service unit and describes the process.
Service unit for the airline Web service
Another service unit is created for deployment on the SOAP BC. This service unit defines a
MyAirlineCompanyEndpoint that will map to the external Web service http://myairline.com/flightBookingService.
With this service unit, the SOAP BC provides the
MyAirlineCompanyEndpoint service endpoint:
<jbi version="1.0" xmlns='http://java.sun.com/xml/ns/jbi' …> <services binding-component="true"> <provides service-name =" MyAirLineCompanyService " endpoint-name =" MyAirLineCompanyEndpoint " /> <petals:address> http://myairline.com/flightBookingService </petals:address> </services> </jbi>