Level: Introductory Greg Adams (Greg_Adams@ca.ibm.com), Distinguished Engineer, IBM Richard Gregory (gregoryr@ca.ibm.com), Staff Software Developer, IBM Jane Fung (jcyfung@ca.ibm.com), Advisory Software Developer, IBM Randy Giffen (Randy_Giffen@ca.ibm.com), Advisory Software Developer, IBM
23 Mar 2006 This second article in a series explains the service oriented architecture (SOA) programming model and describes how to create a simple SOA application in WebSphere® Integration Developer.
From the IBM WebSphere Developer Technical Journal.
Building applications the service-oriented way
Part 1 of this series gave you a driver's view of IBM® WebSphere® Integration Developer by telling you what the product is and by showing you the various tools that it offers. In this second article, you will learn the programming model and the context in which the tools are used. To put things into perspective, we will describe a simple application and show you how you would build it using WebSphere Integration Developer.
Unless you are a hermit living in the woods, you have
probably heard the phrase service-oriented architecture
(SOA). But what is SOA, and more importantly, why is it
of interest to the business integration space?
We're glad that you asked. WebSphere Integration
Developer applications are implemented using a
service-oriented architecture, so let's start by looking
at what SOA is and what it means for your application to
follow this architectural pattern.
Ideally, you want to be able to reuse your existing IT
assets as building blocks or components for new
applications. Each building block is a service, which
means you can access each one in a standard way without
regard to its implementation or location. In an SOA, the
business logic is separated from the infrastructure, or
"plumbing," so that developers can focus on the
implementation and not worry about how the service will
be accessed.
Put in simplest terms, services are black boxes; you
don't care what goes on inside as long as they perform
as advertised. Once you have the black boxes, the next
key step is to connect them together into an overall
integrated application. The boxes can be Java™
technology, Business Process Execution Language (BPEL),
connections or adapters to your legacy systems, or
connections to Web services provided by your business
partners. These black boxes are your service building
blocks.
Services generally are stateless, which means you do not
have to worry about calling them in a certain order or
in a specific context. Furthermore, you might want to
incorporate the services of your business partners and
access those in the same way that you access your own
services. You might also want your partners to be able
to access your services. With SOA, you can adapt or
respond easily to a changing business environment by
swapping one service for another, or by calling new
services as needed. This makes it easy for transactions
to occur between businesses.
What is a standard way to access services? Services have
published interfaces, which serve as a contract
between the service and the caller. An interface can be
described with Web Services Definition Language (WSDL),
for example, as in the case of Web services. The
interface includes the specification of the data that is
to be passed to and from the service. The interface
doesn't specify how or with what language the service is
implemented. So, you could have a service implemented
with Java that makes calls to another service that is
implemented with BPEL.
All that is a high level, generic view that sounds nice,
but we should get down to how you can realize a
service-oriented architecture with WebSphere Integration
Developer. In the last article, we described all of the
different ways to implement services, but we didn't say
much about how the services work together. This article
dives a bit further into the details of service interaction.
The building blocks of an application
The building block metaphor is a useful way to think of
a service-oriented architecture. Normally you would
stack or snap the blocks together to build a bigger
application, which could become yet another one of the
blocks. When you look at services this way, it is easy
to grasp the WebSphere Integration Developer programming
model of Service Component Architecture (SCA). SCA is a
realization of SOA, and WebSphere Integration Developer
is a workbench where you have the tools to not only
visually assemble the blocks into a complete solution,
but also to build the inner workings of each block.
There is a standardization effort for SCA that is part
of the Apache Tuscany open-source project. The next
sections provide a primer in using the Service Component
Architecture to lay out the groundwork for any solution
that you will build with WebSphere Integration
Developer.
Modules
A module is a container for your services and is both a
project in the WebSphere Integration Developer workbench,
and the unit of deployment to the WebSphere Process
Server. That means that any solution that you build will
be deployed to the server as one or more modules. For
those who are familiar with J2EE, a module is packaged
and deployed as an enterprise archive (EAR) file. One of
the advantages of the Service Component Architecture is
that you don't have to be concerned with the underlying
packaging. A module provides services that can be used
by other modules and that can be accessed by external
clients used by your partners or customers. A module is
a collection of components,
imports and exports, as we
explain in the following sections.
You create modules by right-clicking in the Business
Integration view and selecting New - Module. A new
assembly diagram is created for each module you create,
which you work with using the assembly editor. The
Business Integration view shows all of your project's
artifacts, which appears to the left of the assembly
editor (if you haven't moved the view). Figure 1
shows a newly created module.
Figure 1. A new module
Components
A module is one of the bigger, course-grained building
blocks that is composed of smaller, fine-grained blocks
known as components, A component is the part of a module
that is the actual service. On the inside, it is
implemented using one of the implementation types
described in the first article (we'll recap those
shortly). For example, suppose that you have an
order-processing module. Within the module, you might
have an inventory component that updates the inventory
information system and another component that checks
customer credit.
You create components in the assembly editor by
selecting the component icon on the palette and then
dropping it on the assembly editor canvas. You can also
drag an implementation
or an interface from the Business
Integration view to the canvas to create a new
component. This means that you can either create your
components/services by using the top-down approach of
defining the contracts first and then the
implementation, or you can use a bottom-up approach by
pulling in an existing surface.
If you are playing along at home and have dropped a new
component from the palette, it is displayed in the
assembly diagram, as shown in Figure 2. The blue
exclamation mark indicates that an implementation hasn't
been created yet. When you create a component, you need
to give it at least one interface, which we'll talk
about in the next section. Remember the interface
(contract) is what other services will be able to see
and talk to; they will not see or care about how you
implement the service/component.
Figure 2. A service component
Interfaces
To users of a service component, all that matters is its
interface, which dictates how to use it. An interface is
a specification of a component's operations. An
operation is a business function or query that is
provided by a service component. As an example, suppose
you have an EmployeeData component, which is a service
that provides employee information. It might provide
just one operation, such as getEmployee, where you give
it an employee ID, and it returns the data for that
employee. It might have other operations such as
getRetiredEmployees or getCurrentEmployees that return a
set of employee data. These operations are the queries
that the EmployeeData service provides.
An operation contains inputs, outputs, and faults. In
the employee example, getEmployee would specify that its
input is a string and its output is employee data. The
other two operations might not require any input
(although you might pass in data that specifies some
restrictions, for example) and return a collection of
employee data. The interface can optionally specify any
faults that the operation might throw because of an
error condition during the service call. For example,
getEmployee might be defined to throw an
InvalidEmployeeID fault when the internal mechanism
cannot locate any records with that ID. In some cases,
an operation might not have any inputs, outputs, or
faults, such as in the case where an operation is simply
used to trigger an action.
You can define interfaces for your components using
either WSDL or Java. Note that in Java parlance,
operations are method signatures and faults are
exceptions. Creating WSDL interfaces using a text editor
can be tedious. WebSphere Integration Developer provides
the interface editor to simplify creating interfaces for
your components, as Figure 3 shows.
You will at some point want to call external services
such as Web services, so you can also import existing
WSDL interfaces from your partners into the workspace.
Figure 3. A component interface
References
So, you've declared what interface your service
component will support. OK, that's great, but what
happens when you want your component's implementation to
call another service. Well, you need two things. First,
the other service component has to have declared its own
interfaces, and your own component has to say what
interfaces it will be calling. This way, when you
connect the black boxes together, the system can make
sure that what one service wants is what is provided by
the service that you are connecting it to. Let's make
this a bit drier with some technical details.
A component has one or more references. When you write
your implementation for your service component, you will
never directly call another service component; that
would be bad because it builds a dependency into your
code on the other component. Instead, your
implementation will call a reference. A reference has a
name and indicates what interfaces the other service
should ultimately have. Eventually, when you wire your
black boxes together, you will wire that reference to
another box. Presto, your implementation only knows
about references and doesn't depend on any specific
component. As you assemble your modules, you have
complete flexibility to assemble reusable parts,
provided the references match the interfaces of the
destination component.
For example, Figure 4 shows a call from within a
business process implementation to the Travel Agency
Partner reference, and Figure 5 shows the definition and
wiring of the reference in the SimpleProcess component.
This means that when a call is made to Travel Agency
Partner, the service at the other end of the wire will
be used.
In the assembly editor, you can right-click on a
component, and select Add - Reference to add new
references. A dialog box opens that lets you select the
appropriate interface for the reference.
Figure 4. A service call using a reference
Figure 5. A component reference
Wires
When we used the building block metaphor earlier, we
mentioned snapping or stacking blocks together. To be
more precise, with the Service Component Architecture
you use wires to connect the blocks. A wire is simply a
connection in the assembly diagram that indicates which
reference is connected to which component. For example,
in Figure 5 the Travel Agency partner reference of the
SimpleProcess component is wired to the TravelAgency
component. The interface of the reference at the source
of the wire must match the interface of the target
component. As we will explain in the "Imports and
exports" section of this article, the source of a wire
can also be an export and the target can also be an
import.
Implementations
An implementation of a service component is the internal
business logic that carries out the service's function.
Remember, callers of your service don't know how you
choose to implement your service. In fact, they don't
even know if your pet hamster is secretly in there doing
the work. If you are using a top-down approach, that is,
if you are creating components and interfaces first, you
can create an implementation by right-clicking on a
component in the assembly diagram and selecting Generate
Implementation. This gives you a sub-menu where you can
select the appropriate implementation type, such as a
business process. You can also create an implementation
first by selecting File - New, and then selecting an
implementation type, such as business process or human
task. You can then drag the implementation from the
Business Integration view to the assembly diagram to
create a component automatically.
Table 1. Component implementation types
| Implementation type | Purpose |
|---|
| Business process |
Describes a series of activities to accomplish a
business task. Coordinates services and subprocesses
that are part of the overall task.
| | Business state machine |
An event-driven business process that defines a
set of states for a given part of the
application. The state machine moves from one
valid state to another, based on external events
that it receives. It can perform tasks or call
services as it moves from one state to another.
| | Business rule group |
Captures and implements business policies and
practices based on a set of rules or decision
tables that can be changed dynamically after
deployment.
| | Human task |
A unit of work that is done by a person instead
of a program.
| | Java |
Describes business logic at a lower level than
with the visual implementations such as business
processes.
| | Selector |
Uses the date and time to determine
which component to use. It is a slightly
different type of component because it doesn't
have references to the components that it
selects. The components, and the times to use
them, are encoded within the selector
| | Map |
An interface map translates from one interface
to another, and a business object map translates
from one business object to another.
|
Imports and exports
At some point, you will want to delegate some of your
module's work to another module or even to a partner's
service. The challenge is that in the assembly editor,
you can only wire components to other components that
are in the same module. The solution is to use an
import. An import is the same as a component, but
without an implementation. Instead, an import contains a
binding, which is the information on how to connect to
the actual service. The import is essentially saying
that, at this point, you will be going outside of your
module and relying on a service elsewhere to do the
work. The binding helps to identify where and what that
other service is. The following bindings are available:
-
SCA for binding to other WebSphere Integration
Developer components
- JMS for binding to Java message services
-
Stateless session bean for binding to Enterprise
JavaBeans
- Web Service for binding to Web services
The other components in the module use imports in the
same manner as they would any other component (that is,
to create references to it). An import must have the
same interface as the component to which it is bound. In
English, that means that if the import indicates it will
be calling a service (wherever it may be) that has
interface 1, then ultimately, that service better play
nice and actually implement interface 1.
Exports come into play when you want to expose any of
your module's components as services externally or to
other modules. Again, since you can't wire into your
module from outside, you need to use an export. Like
imports, exports must have an interface matching the
component to which they are wired. Exports can also
contain the same bindings as imports (with the exception
of the stateless session bean). With an SCA binding,
components from other modules can make service calls to
your module's components. The other bindings let other
applications call your components as though they were
just another Web service or JMS.
As an example, suppose you had a credit history service
and you anticipate that your business partners will need
to access it. You would create an export, give it a Web
Service binding and wire it to your credit history
component, as Figure 6 shows.
Figure 6. Exporting a component as a Web service
Business objects
As we covered in the previous article, a business object
is a container for the data that flows within and
between components. Business objects are often referred
to as the currency of your application. Business objects
are created using the business object editor, and are built
on the Service Data Object framework
(SDO), which lets you access business data within your
implementations in a standard way. When you define the
inputs and outputs for the operations of an interface,
you can select business objects.
Business graphs are an extension of business objects.
They contain additional metadata as well as change
summary and event summary information that is required
by various enterprise information system resource
adapters. Figure 7 shows an EmployeeInfo business graph
that we used as the output of the getEmployee operation
back in Figure 3. The verb attribute is for commands
such as "Create" or "Delete," which some information
systems require. For example, a verb value of "Create,"
would tell the back-end system to take the employee
business object and create an entry in its database for
it.
Figure 7. An employee business object and business graph
Using the building blocks
Now let's put the above concepts to use
and build an application using a service-oriented
architecture with WebSphere Integration Developer. The
general steps of building an application are:
-
Create the modules to hold all of the
application artifacts.
-
Create libraries (a library is another kind of
WebSphere Integration Developer project) to
hold artifacts that will be shared between
modules. For example, if you have several
modules sharing the same currency (business
object) you can put those business objects into
a shared library.
-
Create the generic business objects that hold
the data that will be used in each component, or
passed between components.
-
Create interfaces to act as contracts between
the components.
- Create components and add their interfaces.
-
Add references to components that will use the
services of other components.
-
Add imports for service references that exist
outside each module, and add exports to make the
services of each module available to other
components.
-
Wire each reference to a component or import.
-
Implement the components using business
processes, business rules, mediations, and so
on.
These steps are intentionally not numbered; depending on
the situation, you can do the steps in a different order
than in the preceding list. For example, there is no
reason you couldn't create interfaces that use business
object types that you will define later. As we have
pointed out, there are two general ways to build an
application, a top-down approach and a bottom-up
approach. The order in the preceding list is just one
example of a top-down approach. Which route you take
depends on whether you already have pieces of your
application ready, or you are building it from scratch.
Most likely, you will do some parts of an application
with a top-down approach and others with a bottom-up
approach. Furthermore, you might choose to use shortcuts
such as dragging the interface of a component to add a
wire between two components and letting the assembly
editor create the reference for you.
A simple order processing application
Let's consider how we might construct a simple
application that handles order processing. We will
conclude this article with the general outline of how to
build the application and, in the next article, we will
list all of the steps to build and test it.
For the purpose of illustration, we assume that the
order processing system works as follows: when the
system receives an order, it uses a customer check
component to determine whether the account is in good
standing. If it is, then the system sends a message to
the shipping department with information on the order
that is to be shipped. Or, if the account is not in good
standing, nothing happens. The system waits for a
response from the shipping department confirming that
the order was sent. This isn't much of an application,
but it should suffice to provide a quick tour of the
development process.
The application requires three components:
OrderProcessing, Shipping, and CustomerCheck, as Figure
8 shows. The components will be contained in the
OrderProcessing module. The CustomerCheck component
relies on an enterprise information system to obtain
customer status. The actual order shipping is a manual
process, so there is one additional component to let
employees see what must be shipped, and then let them
indicate when the order has been shipped. The numbers in
Figure 8 show the order of execution after an order is
received, assuming the customer is in good standing. A
more detailed description of each component and how it
works is shown after the next section. The next section
shows the business object type required by the
components.
Figure 8. A simple order processing application
The Order business object
Figure 9 shows the Order business object. When an
instance of this type is passed to the OrderProcessing
module, it will contain all of the data necessary to do
a customer check and ship an order. In a real
application, you would probably create a separate
Customer business object type to hold additional
customer information in addition to the customer ID
string that we have here.
Figure 9. The Order business object data type
The OrderProcessing component
The OrderProcessing component is the entry point to the
system when an order is received from a client
application and is the driver for the OrderProcessing
module. This component receives an Order business
object, which contains the order information along with
the customer account number. The OrderProcessing
component uses the account number to determine from the
CustomerInformation component whether the account is in
good standing. If so, it sends a message to the Shipping
component to ship the order. If the account is not in
good standing, the process simply terminates.
Figure 10 shows the interface for the ProcessOrder
component. A client calls the placeOrder operation to
begin the ordering process. The operation takes an Order
business object as input. We want the client to be able
to just place the order and continue with other work, so
the operation is one-way. Note that an external client
cannot call the placeOrder operation directly because
only components in the same module can be wired to it.
So the external client must use a stand-alone reference
that is wired to the OrderProcessing component. The
orderShipped operation is called by the ShippingProcess
component when it needs to send a message that the order
was shipped.
Figure 10. OrderProcessing component interface
Because the OrderProcessing component is event-driven
and the allowable operations are determined by the state
of the order being processed, we will implement it using
a business state machine, as Figure 11 shows. The events
consist of:
-
Receipt of an order (a client calls the
placeOrder operation)
-
Notification that the order was shipped (the
shipping system calls the orderShipped
operation)
The states are:
- Waiting for an order
- Customer being checked
- Order being shipped
- Order complete
Figure 11. The OrderProcessing business state machine
There are various ways to model this application in a
state machine, but we have chosen this approach because
we assume that, when an order is received, it
automatically triggers a customer check as it moves to
the CustomerBeingChecked state. The result of the check
automatically triggers a transition to either the
OrderBeingShipped or the OrderComplete states, depending
on the value of the result of a call to the
CustomerCheck service while in the CustomerBeingChecked
state. When in the OrderBeingShipped state, the shipping
component makes a call to the shipOrder operation of the
ShippingProcess component. A transition to the
OrderComplete state occurs when notification is received
from the Shipping component that the order was shipped.
The CustomerInformation component
Figure 12 shows the interface for the CustomerInformation component.
This component determines whether
the customer with the given customerID is in good
standing.
Figure 12. The CustomerInformation interface
We use a simple rule to determine standing: if the
customer ID starts with "gold," then the customer is
automatically considered "good." Otherwise, the customer
information system is checked and his status is
retrieved. This rule can be changed. Additional rules
can be added after application deployment, in which case
this component would be implemented using a rule group.
We assume that the information is stored in an external
enterprise information system, and that another module
will contain the components necessary to access that
system. Therefore, this module will use an import
instead of defining an implementation. An export for a
component in that module will contain the same
CustomerInformation interface as the import..
The Shipping and ShippingTask components
Figure 13. The Shipping interface
Figure 13 shows the Shipping interface. This component
is implemented as a business process because the
activities are executed sequentially. The first activity
sends notification to the ShippingTask component, whose
interface is shown in Figure 14, that an order is to be
shipped. The ShippingTask component is implemented as a
human task because someone must physically ship the
order. The ShippingTask component forwards the order
information to a Web portal where an employee can view
the order information, ship the order, possibly change
some of the order information such as the quantity, and
then indicate that the order was shipped.
You could use IBM Rational® Application Developer to
create the Web portal, or, for starters, just use the
Business Process Choreographer Explorer that ships with
WebSphere Process Server to stand in for your own
portal. When the component receives notification from
the portal that the order was shipped, it returns the
updated Order business object to the shipping business
process.
Figure 14. The ShippingTask interface
When the ShippingTask component completes its work, the
next activity in the Shipping process sends a message
back to the OrderProcessing component via a call to the
orderShipped operation.
The complete OrderProcessing module
Figure 15 shows how the components are wired together in
the OrderProcessing module.
Figure 15. The assembled components in the OrderProcessing module
Summary
In this article, we introduced you to the Service
Component Architecture programming model for WebSphere
Integration Developer. We put the concepts into use by
showing how a simple order processing module could be
built. In the next article, we will show you the exact
steps in building the module, and provide explanations
for each step that will help you fully understand
development with WebSphere Integration Developer.
More articles in this series
Resources Learn
Get products and technologies
Discuss
About the authors  | 
|  | Greg Adams was the lead architect for the user interface
in the award-winning Eclipse platform, and more
recently, has been the lead architect and development
lead in the core WebSphere Business Integration Tools,
including WebSphere Studio Application Developer Integration Edition
and WebSphere Integration Developer. Greg led the delivery of
IBM's first complete services oriented architecture
(SOA) tools stack and the first BPEL4WS standards
supporting Business Process Editor; both critical
deliverables in support of IBM's On Demand strategy. |
 | 
|  |
Richard Gregory is a software developer at the IBM
Toronto Lab on the WebSphere Integration Developer team.
His responsibilities include working on the evolution
and delivery of test tools for WebSphere Integration
Developer.
|
 | 
|  | Jane Fung is an Advisory Software Developer at IBM Canada
Ltd, where she is responsible for developing the Business
Process Execution Language (BPEL) and Business Rules
debuggers in WebSphere Integration Developer. Prior to
that, she was the team lead of the WebSphere Studio
Technical Support team.
|
 | 
|  |
Randy Giffen is an advisory software developer at the
IBM Ottawa Lab on the WebSphere Integration Developer
team. He was responsible for WebSphere Integration Developer's business state
machine tools and the visual snippet editor. Prior to to
this he was a member of user interface teams for
WebSphere Studio Application Developer Integration Edition,
Eclipse, and VisualAge for Java.
|
Rate this page
|