This document provides an overview of the bexee system architecture, hoping to give a better understanding of its general design.
As opposed to the Engine Architecture or Solution Description documents, which specifically document individual parts of bexee, the System Architecture document focuses on the architecture of the entire application, and hence tries to give a general overview of the whole system.
bexee runs in a servlet container e.g. Apache Tomcat and thus ships ready to use in a web application archive (war) file. The war is divided into a number of components according to function that make up the entire application.
The accompanying illustration gives a rough overview of the main components that belong to bexee:
We will start from the inside out, explaining what the different components do and thus begin with the Engine Core component.
The Engine Core comprises all the business logic and knowledge about how to process a given BPEL document.
Most importantly this includes the BPELProcessFactory
for
creating a BPEL process given a BPEL document, the
ProcessController
for processing a BPEL process, the
Dispatcher
for looking up deployed BPEL processes and
executing instances as well as a number of other components.
As the name implies this is the core of the bexee engine, but of course there is a number of other supporting components that are needed, for making bexee a complete application.
The provider has a key role in bexee, because it is responsible for connecting Axis and bexee. How this works exactly will be explained further down in this document in the Providers section.
The Management component includes classes for deploying new BPEL processes to bexee and registering them as Web Services in Axis. It is foreseen that in a later release, there will also be some classes that can be used to administrate the engine.
It is important to note that management components are deployed as Web Services into Axis. This allows for an open interface available to a number of various clients; e.g. web application front-ends, Ant tasks, etc. (see Ant Tasks section)
As explained in the previous section we are using Apache Axis for processing SOAP messages. The Management and Engine Core components are deployed into Axis as Web Services.
The WebApp component includes Servlets, JSP's, HTML pages etc. offering more convenient access for querying or managing the engine. As shown in the deliverable structure diagram further up in this document, you can see that the engine is always accessed through its Web Service interfaces; be it for deploying or executing. More detailed information on this component can be found in the bexee WebApp section further down in this document.
The Axis framework is a Java-based, open source implementation of the SOAP specification from the Apache Group. Essentially Axis is a SOAP engine, i.e. a framework for constructing SOAP processors such as clients, servers, gateways, etc.
Axis provides a flexible messaging framework that includes handlers, chain, serializers, and deserializers. The latter provide encoding support for a wide variety of XML Schema data types.
In the following sections we will describe how we extended, used and integrated Axis in bexee. It is assumed that the reader has a basic understanding of the Axis architecture and how Axis works. More information on the Axis project can be found on the Apache Axis web site [Axis].
Every BPEL process has to expose itself as a Web Service in order to be triggered by clients who want to execute the process. We thus need to process incoming Web Service request, i.e. SOAP messages, transfer the request to the bexee engine for processing and after the process has finished executing, send a SOAP message containing the process result back to the client.
This led us to the decision to use Apache Axis for processing SOAP messages.
A provider is a special Axis Handler which handles incoming requests. Axis
makes available a number of different providers. A JavaProvider
for example handles a request by invoking a method on a given Java class
and then returns the result back to the response flow. Usually this is
the default behavior for Web Services deployed in Axis.
Which provider shall be used for a given Web Service can be specified upon deploying a new service. Axis' provider model is extensible, which means that you can plug in your own custom providers. Below you find a typical wsdd file used for deploying services into Axis. The service will be accessible under the name bexeeService and incoming requests will be handled by a custom provider.
Note that in Axis, providers are sometimes also refered to as pivot handlers.
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> <service name="bexeeService" provider="java:BexeeProvider" /> </deployment>
As the above deployment descriptor shows, we use a special provider
called BexeeProvider
, which we plug into the Axis engine.
Strictly speaking it is not the provider itself that is plugged into
Axis, but rather a custom factory which will then create the provider of
the given type.
Below you find an excerpt of the factory and provider class together with the methods they implement:
public class BexeeWSDDProvider extends WSDDProvider { public Handler newProviderInstance(WSDDService service, EngineConfiguration registry) throws Exception { return new BexeeProvider(); } public String getName() { return "BexeeProvider"; } }
public class BexeeProvider extends BasicProvider { public void initServiceDesc(SOAPService service, MessageContext msgContext) throws AxisFault { // init the service } public void invoke(MessageContext ctx) throws AxisFault { // process message and invoke target service } public void generateWSDL(MessageContext msgContext) throws AxisFault { // generate the web service description } }
This means that we are using our own custom provider for connecting Axis
and bexee: The provider takes the incoming SOAP message,
performs a number of checks (e.g. verifies whether the requested
operation can actually be performed by the process controller), puts all
the necessary information into a new BexeeMessage
and
passes it to the Dispatcher, the entry point to the bexee engine.
Note that the BexeeMessage
contains no SOAP specific data.
This allows for a decoupling of the bexee engine and thus
keeping it relatively independent from Axis and the SOAP protocol.
As soon as the provider receives the result back from the
Dispatcher
, it will create a new SOAP response and hand it
back to the Axis response flow, from where it will eventually be sent
back to the client that invoked the service.
The following illustration shows the connection between Axis and
bexee. If you've read the Axis architecture guide you may
notice that we've simply replaced the provider on the left side of the
picture with our own BexeeProvider
.
For an explanation of what happens after a new BexeeMessage
arrives at the Dispatcher refer to section Dispatching incoming messages in the Sequence Diagrams section of the Solution Description.
EngineConfigurationFactory
is an interface used to
construct concrete EngineConfigurationFactory
instances.
public interface EngineConfigurationFactory { public EngineConfiguration getClientEngineConfig(); public EngineConfiguration getServerEngineConfig(); }
Each EngineConfigurationFactory
implementation must also
(directly) implement the following static method:
public static EngineConfigurationFactory newFactory(Object param);
Which engine configuration is to be used can be specified with either a
system property or using
Jakarta Commons
Discovery
[Discovery]. In bexee the
later approach has been used. As to enable the Discovery mechanism
a file called org.apache.axis.EngineConfigurationFactory
must be created in the META- INF/services
directory in
bexee.jar
. Inside this file the fully qualified name of the
class implementing the EngineConfigurationFactory
must be
indicated.
Plugging our own BexeeEngineConfigurationFactory
into Axis
allows us to specify how the Axis server will be configured when it is
created.
We use this technique to make the bexee Manager Web Service available as soon as a new Axis server is created. For more information on this please refer to Deployment section further down in this document.
The BexeeEngineConfigurationFactory
extends the
EngineConfigurationFactoryServlet
in package
org.apache.axis.configuration
and basically doesn't do
anything else but making sure that the right server configuration file
is read in, when a new factory is created. The server configuration file
is stored as a wsdd file and includes - among other things - the
following service deployment information for deploying the Manager
Service.
<service name="Manager" provider="java:RPC"> <parameter name="allowedMethods" value="*"/> <parameter name="className" value="bexee.admin.Manager"/> </service>
The initial configuration is read from a default configuration file,
which is called bexee-config.wsdd
and is packaged into the
war file. Modified configurations will be stored inside the
WEB-INF
directory of the deployed bexee web application.
A design goal of bexee is to be easy to use in order to make it interesting for experiments with business processes and BPEL in general. We therefore decided to provide a hot-deployment mechanism in bexee. The main idea of such a mechanism is to ensure a simple way for the users to deploy business processes in bexee without requiring to have knowledge of the internal mechanisms of bexee. It will only be necessary for the user to describe the business process in BPEL and the necessary Web Service Descriptions (WSDL). The user then deploys these files to bexee and the process will be implemented as a Web Service and will be made available to be used by clients.
The contrary to such a hot-deployment mechanism would be requiring
a user to generate Java code for invokation of partner Web Services and
Web Service stubs for the invokation of the own Web
Service interface (as for all Receive
BPEL activities), to
compile generated code, package it and add it to the bexee classpath.
In our opinion an important purpose of the BPEL standard is to provide a language for business process modelling which is abstract enough to make it unnecessary for the modeller to know a programming languages like Java. The business process modeller needs certainly to have a good knowledge of the BPEL language, XPath and Web Services, but should not need to worry about how exactly the modeled processes will be represented or executed within a BPEL engine.
The main purpose of a hot-deployment mechanism is to shield the user from the implementation details of bexee. Providing a hot-deployment mechanism removes the necessity for a user to have an in-depth knowledge of technology specific aspects and maintains the advantages of decoupling the BPEL standard from the underlying technologies.
In order to deploy a business process, a number of documents are needed. The user has to prepare the BPEL document describing the process flow as well as define a WSDL document, specifying the process' Web Service interface. If other Web Services are to be invoked by the process, which of course is usually the case, the user also needs to provide the WSDL files of those partner services, possibly enriched with partner link information.
bexee provides a simple Manager Web Service which can be used to deploy the prepared documents. The Manager Web Service is responsible for deploying new BPEL processes to bexee and deploying them as Web Services to Axis.
Making the Manager Web Service available at Axis bootstrapping-time allows to use it as soon as bexee is deployed into the servlet container, i.e. Tomcat.
In this and the next section we will interchangeably refer to the deployed BPEL process either with BPEL process or BPEL service, depending which one is more appropriate in the context we are talking.
As already indicated above, alongside with the BPEL document itself, the user also needs to provide a Web Service descriptions (WSDL) for the process and all the partner Web Services. As soon as the user has collected or created all the necessary documents, he can send them to the Manager Web Service.
The Manager Web Service will create use a factory to create a new
BPELProcess
object, given the input of the BPEL document
the user provided. At the same time the input will also be validated
against syntactic errors.
Then another factory is used to parse the WSDL input documents, that is the WSDL describing the BPEL service as well as the WSDL documents describing the partner services. Again the input will be validated against syntactic errors.
The next step is to extract the necessary information out of the process' WSDL so that an Axis deployment descriptor can be created.
Once this has been done, the service will be deployed as a Web Service by adding it to the Axis engine configuration.
Finally, the BPEL and WSDL document object representations will be persisted to a data source. For that purpose the Manager uses bexee's Data Access Objects (DAOs) (see Persistence).
At the end, a response about the successful deployment will be send back to the user.
As already mentioned above, the modified Axis configuration will be
stored inside the WEB-INF
directory of the deployed bexee
web application.
As explained in the Hot-Deployment section, new BPEL processes will be deployed as Web Services into Axis at run- time. This means that as soon as the Manager has finished deploying a new BPEL process, it will immediately be available as a Web Service available for clients to use.
This section documents how a BPEL process that has been previously deployed to bexee (see section Deployment above) is executed inside bexee.
As already mentioned, deploying a BPEL process means also that the process will be implemented and exposed as a Web Service, according to the WSDL file that describes the Web Service interface of the process. The beauty of this is that a user can use this service just like any other service that is described in WSDL. The user doesn't necessarily need to know that the service she is using, basically is nothing else but a composition of existing services.
We will now describe, based on the following illustration, what happens inside bexee when a client invokes a deployed BPEL process or service to be precise.
The illustration and explanation relate to a synchronous BPEL process.
For asynchronous processes the execution flow is very similar, except
that the ProcessController
doesn't return the result back
to the client, but rather sends the result by invoking a call back Web
Service that has been provided upon deployment.
A client remotely invokes the deployed BPEL service. Because the service is described in WSDL a client can obtain information about the process (e.g. which operations can be executed) in a standardized manner.
The incoming SOAP message is processed by Axis (not shown in
illustration) and after running through all the Axis request handlers,
eventually arrives at the BexeeProvider
which is an
(Axis) provider or pivot handler and responsible for connecting Axis
with bexee (see Providers in Axis Integration section).
The BexeeProvider
first performs a number of checks (e.g.
operation existence / signature) and then disassembles the incoming
SOAP message in order to create a new BexeeMessage
. Using
our own independent message object allows for a decoupling of the
bexee engine and thus keeping it relatively independent from Axis and
the SOAP protocol. Once the BexeeMessage
has been created
and filled in with all the necessary values, it is send to the
Dispatcher
.
The Dispatcher
looks up the DAOs for a matching
BPELProcess
and ProcessContext
given the
information in the received BexeeMessage
. If no
ProcessContext
can be found (e.g. it is the first time
that a client invokes a service and thus has no running process yet) a
new ProcessContext
will be created. After that the
Dispatcher
will dispatch the message together with the
process and context to the ProcessController
. This will
either happen synchronously or asynchronously, depending wheter the
deployed process is synchronous or asynchronous.
Once the ProcessController
has received the necessary
input, it uses the Visitor pattern (see [Gamma95]) to start
processing the activities defined in the deployed process.
The main purpose of BPEL is to integrate existing Web Services ant
thus probably every meaningful BPEL process will at some point use
existing external Web Services, which will be invoked by the
ProcessController
.
After the ProcessController
has terminated its execution
it will return control to the Dispatcher
. Terminating
execution can mean two things here: Either the
ProcessController
terminates, because it has reached the
end of the deployed BPEL process and there are no more activities to
process or the controller reached a point in the process, where more
input from external sources is needed (e.g. user input or input from
asynchronously invoked partner services).
Depending wheter a result is available or more input is necessary, the
Dispatcher
will either wait for more input messages and
proceed as in the previously described steps or it will get the result
and return it back to the BexeeProvider
.
The BexeeProvider
takes the result and packs it into a
SOAP message, which will be given over to the Axis response flow.
Once the message has passed all the Axis response handlers, it will be sent back to the client.
The Dispatcher
dispatches inbound messages to the correct
process instances and thus has to maintain a store for them. A
ProcessInstance
is composed of a BPELProcess
and a ProcessContext
. Whereas there exists only one
instance of the BPELProcess
per deployed BPEL process,
there exists a multitude of ProcessContext
instances, as
new ProcessContext
s are created for each client that starts
a process. Hence it makes sense to store the two objects separately.
bexee uses the Data Access Object (DAO) pattern to encapsulate all
access to the BPELProcess
and ProcessContext
by providing a DAO for each one of them. The DAO manages the connection
with the data source to obtain and store data.
The DAO implements the access mechanism required to work with the data source. The data source could be a persistent store like an RDBMS, a File System or any other data source you can think of. The components that rely on the DAO use the simpler interface exposed by the DAO. The DAO completely hides the data source implementation details from its clients. Because the interface exposed by the DAO to clients does not change when the underlying data source implementation changes, this pattern allows the DAO to adapt to different storage schemes without affecting its clients or business components. Essentially, the DAO acts as an adapter between the component and the data source.
In the current version of bexee only an in-memory DAO is provided. In- memory means that data is only stored in memory and hence lost on server restarts etc.
Obviously this might not be enough for most applications and thus bexee provides the flexibility of adding new DAO implementations at a later time without having to modify code. (For an example on how a JDO DAO implementation could be added, refer to the Implementing DAOs section in the Developer's Guide).
This flexibility is achieved by using the Abstract Factory pattern as suggested in 'Design Patterns - Elements of Reusable Object-Oriented Software' [Gamma95].
In this case, an abstract DAO factory object (Abstract Factory) is provided, which can construct various types of concrete DAO factories, each factory supporting a different type of persistent storage implementation. Once you obtain the concrete DAO factory for a specific implementation, you use it to produce DAOs supported and implemented in that implementation.
The class diagram for the currently implemented DAOs in bexee shows a
base DAO factory (DAOFactory
), which is an abstract class
that is inherited and implemented by different concrete DAO factories to
support storage implementation-specific access.
The client can obtain a concrete DAO factory (e.g.
MemoryDAOFactory
) by calling the DAO factory's
getInstance()
method. Which DAOFactory
implementation will be returned, is determined by an application or
system property (bexee.dao.factory
) specifying the fully
qualified class name of the DAOFactory
implementation to be
used.
If you are interested in extending the model and writing your own store implementation, take at look at the Implementing DAOs section in the Developer's Guide.
For more information on the DAO pattern, please refer to Sun's Core J2EE Patterns catalog [J2EEPatterns].
Probably the most important component in the web application is the
AxisServlet
which was shamelessly copied from the Axis web
application and handles all the Web Service traffic for bexee.
The routing of an incoming http request containing a SOAP message is
handled by the AxisServlet
, which runs inside the bexee web
application. It is the main entry point for every incoming Web Service
request. The URL pattern that will invoke the AxisServlet
is configured to /bexee/services/*
.
The AxisServlet
's duty is to take on incoming http
requests, process them and deliver them to the Axis engine, which will
finally invoke the target service or the provider to be more precise.
The AxisServlet
is also responsible for creating a new
AxisServer
in case one has not already been created. To do
this, the AxisServlet
uses an
EngineConfiguratinoFactory
as described above and then uses
this information to create a new AxisServer
with the help
of a an AxisServerFactory
.
The AxisServer
is only created once by the
AxisServlet
during the life time of the web application.
This is done upon the first request to the AxisServlet
and
the AxisServer
is then put in to the web application
context from where it will be retrieved for every subsequent request.