Almost every body working with BPEL will run in the error: |
Wednesday, May 9, 2012
[Error ORABPEL-10902]: compilation failed, XML parsing failed because "".
Writing a 'Singleton' BPEL Process
A typical use case in BPEL is connecting to an external resource / system which only support a single connection at a time. In such a case we need to protect against parallel BPEL instances submitting concurrent requests to that resource.
This implies that we need some way to serialize requests for that resource (probably on a first in first out basis). A common design pattern for achieving this is the Singleton, first documented in the Gang of Four's patterns book (where they use a print spooler as an example).
Now BPEL doesn’t explicitly support the notion of a Singleton, however it does allow you to simulate one, which for the purpose of what we are trying to achieve is good enough.
The basic idea is to have an explicit initiateSingleton operation which is used to instantiate a single process instance, and then have a separate invokeSingleton operation which is used to submit each actual request. The invoke operation is then placed in a loop, so as soon as it’s processed one request it loops back round for the next one.
For this example, I’ve just created a simple process which keeps track of the number of times it’s been called. It takes a single parameter, name and returns a string of the following format:
Hello |
Labels: BPEL
Top 5 Insights for Maximizing Returns with SOA
Oracle
are hosting a live webcast on some of the key insights gained by
customers who have successfully implemented SOA based solutions within
their organization.
|
Labels: SOA
Downloading the SOA Design Time for JDeveloper 11G
racle
Fusion Middleware 11G Release 1 was officially launched by Oracle on
the 1st July 2009; included in this release are the 11G version of
WebLogic, SOA Suite, WebCenter and Identity Management. You can download
all of the required components from http://www.oracle.com/technology/software/products/middleware/index.html. Saturday, 13 June 2009Arch2Arch PodcastsTheir latest podcast, is part one of a two part interview by Bob Rhubart (the host of Arch2Arch) with Antony Reynolds and myself about our book the Oracle SOA Suite Developer's Guide. The interview is truly international with Bob carrying out the interview based in California, Antony in the UK and myself from a hotel room in Sydney, Australia (about 8am in the morning). It's quite strange hearing yourself speak, but what struck me is how English Antony sounded! Have a listen and see what you think (and whether I’ve picked up an Aussie twang) and whilst you’re their check out some of the other excellent podcasts as well. |
Labels: SOA
SOA Down Under
Well it's been a while since I posted my last blog, and since then a lot has happened!! |
Labels: SOA
Invoking EJB's from Oracle ESB using WSIF
A common requirement with the Oracle ESB is to use it to invoke one or
more EJBs; one way to do this is to create a standard SOAP service from
an existing EJB using the wizards in JDeveloper.
Creating the WSIF WSDL File
Before
you can invoke an EJB via WSIF you need to create a WSDL file which
contains the appropriate binding information required by the WSIF
framework to invoke the EJB.There are two basic approaches you can take:
Define Abstract WSDL File
The
first step is to define a simple abstract WSDL file to describe your
services, for our purpose we have defined the following:At first glance there is nothing here to indicate that the WSDL is for a service to be implemented using an EJB. The only thing worth mentioning is that we have defined our XML schema elements for our input and outputs parameters in a separate file, which we have imported into our WSDL document. The reason for doing this it that at a later stage we will need to generate Java classes based on the XML Schema, and separating out the schema makes this process slightly simpler, especially if you need share the Schema between multiple EJBs. The schema for Person.xsd is as follow: Note: We have defined all our parameters as elements and NOT complexTypes since the Oracle ESB will complain if you try and use a WSDL which uses complexTypes in its message definitions.
Implement Session EJB
The next step is to implement a corresponding stateless session EJB to implement our Greeting service. The simplest way to do this in JDeveloper is right click your Greeting project and select New. This will bring up the ‘Gallery’ as shown below. Browse to the Business Tier-> EJB section and select Session Bean (as shown below) and click OK.Figure 1 - Creating a Session Bean This will launch the Create Session Bean Wizard. In Step 1, select ‘Enterprise Java Beans 3.0(J2EE 5.0)’ as the version of EJB you wish to use and click next. In step 2; specify the EJB Name, i.e. Greeting, Keep the default settings for the Session EJB 3.0 options (as shown below) and click ‘Next’.
Figure 2 – Specify EJB Name and Options
Next specify the bean class name. This will have already been defaulted based on the EJB Name you specified in the previous step (i.e. it will have appended bean to it). Leave the class name as is, but specify the package name as appropriate. In our case we set the package name to com.bpelpeople.ejb and then click next.
Figure 3 – Specify Class Name
Finally specify that you want the EJB to implement a remote, local and web service endpoint interface (as shown below). Then hit ‘Finish’ to generate your EJB.
Figure 4 – Specify EJB Interfaces
For each operation defined in our WSDL file we should create the equivalent method in our EJB. For each method we need to define its input and return parameters. For operations or method that return simple XML types (e.g. xsd:string, xsd:integer) we can use the equivalent type in Java. However for complex types, such as our Person element we need to implement the appropriate classes required for serialization/de-serialization between java and xml.
Using schemac to generate serialization/de-serialization classes
As
part of the SOA Suite, Oracle provides the schemac utility (bundled
with BPEL PM) which you can use to generate the
serialization/de-serialization classes. To use this utility open the
BPEL Developer Prompt and then run the following command:schemac –noCompile –sourceOut < dir=""> < file=""> This will generate the source Java for serialization/de-serialization classes for the specified schema file (e.g. Person.xsd in our case) and places these within the specified source directory. Within JDeveloper you will need to import these classes into you project containing your EJB. You will notice that for each element, schemac will generate three classes (e.g. Person, IPerson and PersonFactory); we will use the actual concrete class (i.e. Person) for the input parameter to our method. So for our Greeting EJB we have defined the following method:
Setting Project Classpath
Once
you have imported the generated Java classes into your project, in
order to compile them you will need to add the orabpel.jar file to your
project classpath, this is located at:$SOA_HOME/bpel/lib/orabpel.jar
Create Deployment Descriptor
Finally
we need to create a deployment descriptor for our EJB, within the
Application Navigator right click on our Greeting project and select
‘New’. From the gallery, browse to General -> Deployment Profiles and
select ‘EJB Jar File’. This will bring up the Create Deployment Profile
window.Figure 7 – Specify Deployment Profile Name Specify a profile name, i.e. ‘Greeting’ in our example and click ‘OK’. This will launch the ‘EJB JAR Deployment Profile Properties’ window, as shown below. Figure 8 – EJB JAR Deployment Profile Properties Specify a name for the application, in our case we have chosen ‘GreetingApp’ (note: you will need to make a note of this value as you will use it when defining the WSIF Binding for your service) and click ‘OK’. Note: you will need to define an Application Server connection to the OC4J instance to which you want to deploy your EJB first.
Deploying the EJB
You can now use JDeveloper to deploy your EJB, however before doing this you should define an Application Server connection with JDeveloper to the oc4j instance on which the SOA Suite is deployed (e.g. oc4j_soa). You are now ready to deploy your EJB. You can now use the deployment file you just created to deploy your EJB. Right click on this file and select deployTo-> oc4j_soa (where oc4j_soa is the name of your application server connction). As part of the deployment process, JDeveloper will bring up the Configure Application window. However if you click ‘OK’ and follow the standard deployment process, you will need to include the orabpel.jar within your .ear file. This can be a bit cumbersome, particularly if you have several EAR files to deploy. The other option is to deploy your application as a child of the orabpel application. By designating orabpel as the parent application, your EJB will inherit the set of shared libraries imported by the parent including orabpel.jar. To do this select ‘GreetinApp’ within the ‘Configure Application’ window and then select orabpel as the parentApp as show below in figure 9. Figure 9 – Setting the Parent Application Then click ‘ok’ and JDeveloper will complete the deployment of our EJB.
Adding WSIF Bindings
Now that we have written and deployed our EJB we are ready to add the WSIF bindings to our abstract WSDL file to enable it to be called from the ESB.
Modify Definitions Element
Within the <definitions> element of your WSDL file you need to add the following namespaces:
Add Bindings Element
This
is where we bind our service to an EJB rather than a standard SOAP
service. For our example, the WSDL <binding> element is defined as
follows:
Ejb Binding
<ejb:binding> should be the first element within our <bindings> tag and identifies that this is service is bound to an EJB rather than a SOAP service.
Type Definitions
Next,
you need to map the XML Schema elements used within the WSLD message
definitions to the Java types used in the method invocations for your
EJB.The <format:typemapping> element will contain one <format:typemap> for each xml schema element that we need to map, it has two attributes encoding and style both of which should be set to ‘Java’ to indicate that we are mapping to Java classes. The <format:typemap> element has two attributes, typeName which hold the name of the xml schema element that we are mapping and formatType which contains the class name of the Java class to which we are mapping it. In our example, we have specified two type mappings one between our Person element and the corresponding class that we generated using schemac, and the other between the Return element and the java.lang.String class.
Method Mapping
The final step is now to map the EJB method calls onto the WSDL operations. This is done using the <ejb:operation> tag to identify which EJB method should be used to support a given operationThis element has the following attributes:
Add Services Binding
Finally we have to add the
element to our WSDL to specify where to locate the service. This looks
pretty normal, except that instead of a <soap:address> element, we
need to specify an <ejb:address> element.This contains one attribute jndiName; which specifiec the JNDI Name of the deployed EJB. In our example the <service> element is defined as follows:
Calling your EJB from ESB
We
are now ready to invoke our EJB from within our ESB. To do this, create
a SOAP Service based on our WSDL file within your ESB project in the
normal way (note you will need to import the Schema into your ESB
project first).However before registering your ESB project you will need to define the following endpoint properties on your service:
This is so that the ESB is able to locate and invoke the EJB at run time.
java.naming.provider.url
Specifies the URL for the provider (or application) which contains our EJB, this takes the form:opmn:ormi://<hostname>:<opmn request port>:<oc4j container>/<application> Where
To do this first close down JDeveloper (otherwise you can get sync issues) and then open the appropriate .esbsvc file in your favourite text editor and specify the endpoint properties at the end of this file as follows: Once done, you can open up JDeveloper and deploy your ESB project.
Deploy EJB Classes to ESB Engine
Before we can call the EJB from the ESB, we must first deploy the remote interface class of our EJB (Greeting.class)
and our Java serialization/de-serialization classes to the ESB engine,
the simplest way to do this is to copy the java classes into the
directory:<soa_home>\bpel\system\classes Once done you will need to re-start the SOA Suite so that it picks up the classes.
Deploy Patch to ESB
Finally if you are using 10.l.3.3 of Oracle SOA Suite you will need to install patch 6314009 which is available at metalink.oracle.com. |
Monitoring SOAP Messages between BPEL Processes
When debugging BPEL processes it can sometime be very useful to see the actual messages flowing between processes.
Configuring the BPEL Server to use obtunnel as a Proxy
Oracle
BPEL PM can easily be configured to use a proxy; typically this is for
such scenrios as placing an HTTP Gateway in front of a BPEL Server.
However we can use the same approach to set up obtunnel as the proxy.To achieve this we need to set two properties; soapServerUrl and soapCallbackUrl in the server configuration file.
soapServerUrl
This URL is published as part of the SOAP address of a process in the WSDL file.The hostname and port for this URL should be customized to match the Host and the Listen Port of your instance of obtunnel. Assuming you are running obtunnel on the same host as your BPEL Server, you just need to change the port number.
soapCallbackUrl
This
URL is sent by the process (using WS-Addressing) as part of the
asynchronous callback address to tell the recipient of the request where
to send the response to.Again the hostname and port for this URL should be customized to match the hostname and listen port of your instance of obtunnel; so should have the same value as soapServerUrl. The simplest way to set these properties is on the configuration tab from BPEL Admin (to access this on the BPEL Console login screen select goto BPEL Admin). Once set you will need to restart your BPEL Server. Note: You will need to re-deploy any processes currently deployed to your server in order for them to be re-compiled (e.g. generate WSDL) with the correct addresses.
Configuring the BPEL Domain
Once
we have configured the server, any external caller of a process will
now access both the WSDL and the service via the proxy URL.However the default behaviour for a process is to by-pass this proxy, why? Well really for reasons of performance; it simply doesn’t make sense for a process to call another process via SOAP as the overhead would be to big, rather a process simply calls another process via a direct in memory Java call which is far more performant. However for our purpose, we can turn this off by setting the property optSoapShortcut to false. The simplest way to set this is in the BPEL Console, click on Manage BPEL Domain (top right hand corner), and then update the property in the configuration tab. Note: In version 10.1.3.0.1, this property is not actually specified in the domain configuration file, so you will need to add it manually to the domin config file, located at: [bpel_home]/domains/[domain]/config/domain.xml Once added you will need to re-start the engine for it to pick up the change (from then on you can modify it as normal in the domain configuration tab).
Running obtunnel
The simplest way to
run obtunnel, is to launch the BPEL Developer Prompt, this simply
launches a Command Prompt with all the appropriate environment
varaiables set. From here simply type the command obtunnel.Once launched simply specify the port you want to listen on, and then the host name and port of your BPEL Server.
Summary
Using
this approach you can easily monitor the various SOAP messages between
processes, without the need to make any actual changes to the
configuration of the process. All that is required is to deploy them to a
version of the BPEL PM Server configured to use the proxy.Note: If you develop your BPEL Processes against the “Proxy BPEL PM Server”, then the WSDL locations in the PartnerLinks will contain the Host and Port No of the Proxy of the service. This is typically not a problem as you re-configure these as part of the process of deploying the processes to a test / production BPEL PM Server. |
Using nested Schemas within BPEL
When developing any BPEL based solution, you soon find that you are
defining a common set of data objects that are used across multiple
processes. |
Using Email to initiate a BPEL Process
The notification service in Oracle BPEL Process Manager allows you to
send a notification by email (as well as voice message, fax, pager, or
SMS) from a BPEL process.
Configure Email Account
To
configure the email account which the BPEL Server should connect to, we
need to place a MailAccount xml configuration file (in our example
BpelMailAccount.xml) into the following directory:<soa_home>\bpel\domains\default\metadata\MailService Note: You will need to create the metadata and MailService directories. The file itself can have any name (though must end with .xml) as you can define multiple accounts. However make a note of the name as you will need it to link your BPEL Process to the actual mail account. Here’s our sample file: The outgoing SMTP service doesn’t need to be configured (as we use the notification service to send outgoing emails). However the incoming account is defined by the following tags: <incomingServer> <protocol>[protocol pop3 or imap]</protocol> <host>[imap or pop3 server]</host> <email>[imap or pop3 account]</email> <password>[imap or pop3 password]</password> <folderName>[imap only, inbox folder ]</folderName> </incomingServer> Note: When defining the account name, be careful to use the actual account name not the email address as they are not always the same.
Creating BPEL Process
The
first step is to use JDeveloper to create an Asynchronous process
initiated by a request message with a payload containing an element of
type mailMessage (defined in Mail.xsd installed as part of BPEL PM).To do this use the BPEL Project Creation wizard to create a BPEL Process in the normal way. After entering the process name and specifying the process template to be asynchronous, select "Next". This will take you to the next step in the wizard where you specify the Input and Output Schema Elements, click on the flash light for the input schema and select Mail.xsd (located in <SOA_HOME>\bpel\system\xmllib) as shown in the figure 1 below.
Figure 1 - Specify Input and Output Element
This will then open the type chooser window to select the element to use from the imported schema. Select the mailMessage element as shown in figure 2 below.
Figure 2 - Type Chooser
Once the process has been created you can remove the callBackClient activity as we won’t need this.
Import Common Schema
If
you now try and compile your process, you will find it fails with an
error message. Thus is because the Mail.xsd itself imports a schema
(common.xsd), so you need to import this schema as well. To import the Mail Schema into your BPEL Process, ensure the diagram view for your BPEL process is open and selected in JDeveloper. Then within the BPEL Structure window, right click on the Project Schemas node and select "Import Schemas" (as shown in figure 3 below).
Figure 3 - Import Schema
Note: Once imported, manually update the WSDL file to ensure the import statements for both the Mail.xsd and common.xsd are contained within the same <schema> element or it will still fail to compile. See previous blog - Using Nested Schemas with BPEL for details.
Define Mail Activation Agent
The
process itself is now ready for deployment. However we need to complete
one final activity, which is to tie the BPEL Process to a mail
activation agent for the Email account that we defined earlier.The Activation Agent will poll the defined mail box for emails and then for each email it receives invoke an instance of the process to handle it. To do this you need to add the following definition to the bpel.xml file, after the <partnerLinkBindings> element: <activationAgents> <activationAgent className=”com.collaxa.cube.activation.mail.MailActivationAgent” heartBeatInterval=”60”> <property name=”accountName">BpelMailAccount</property> </activationAgent> </activationAgents> Where heartBeatInterval is how often we want to poll the email account for new emails, and the accountName corresponds to the name of the account configuration file we defined earlier. Finally deploy the process and send an email to the appropriate account. Gotcha!! - If you modify the BPEL process in JDeveloper, the bpel.xml file may lose its changes (i.e. the activationAgent definition), and as a result the process will never get initiated - so always check the bpel.xml file is correctly defined just before deploying the process.
Email Server
To
make testing easier, I installed my own local mail server. For this I
used James (which is an Open Source Java Mail Server from Apache).Installation of James is very straight forward you just download it and unzip it to a convenient location. To start it, use the script run.bat or run.sh, depending on your operating system in the james-2.3.0/bin directory. To configure James just bring up a telnet session (on port 4555) to bring up the Remote Administration Tool from which you can create the required accounts. For example, to create the accounts bpel and jsmith (where the password is welcome1) enter the following: JAMES Remote Administration Tool 2.3.0 Please enter your login and password Login id: root Password: root Welcome root. HELP for a list of commands adduser bpel welcome1 User bpel added adduser jsmith welcome1 User jsmith added listusers Existing accounts 2 user: bpel user: jsmith quit |
Using Analytics to Modify In-Flight Processes
I recently had the pleasure of presenting the Oracle Key Note at the
Butler Business Process Management & Integration symposium. The
subject of the keynote was to look at how we can use business analytics
to enable us modify processes already in-flight.
Collecting Real Time Business Analytics
Business
Activity Monitoring (BAM) provides us with the tool to collect the near
time analytics on which we can base our decision on how we wish to
modify our in-flight processes.For those of you who are not familiar with Oracle BAM, it enables the business to gain a real-time view of what’s happening with the business. To achieve this it provides the following key components:
Modifying In-Flight Processes
Once we have the real time analytics, the next challenge here is to use the data to modify the processes already in flight.Now when we talk about modifying In-Flight Processes; most people assume that this involves quickly writing a new version of the process, testing it, deploy it, and then migrating the existing in-flight processes to this new improved version. The reality is that is rarely as quick as required!!! Rather what’s really required from a business perspective is to be able to modify the flow through a process (and its sub-processes) in order to obtain the desired business outcome. There are three basic patterns here which provide a way of achieving this, these are:
Modify Process Flow
With
this approach we are not looking to modify the actual process, rather
modify the “path” through the process. If we look at any process, then
at various points the process will hit a decision point which will
determine which route it should take the through the process. Rather
than building these decision points directly into the process we can
externalise them in a rules engine such as Oracle Business Rules or iLog
JRules, as illustrated below.This then enables the business to modify the rules based on what’s currently happening within the business (as indicated through BAM) and thus get the process to take a different route. An excellent case study for this is Cattles (a UK company which lends money to the secondary market), which uses a combination of BPEL, BAM and Rules for this purpose.
Exception Management
BPEL already
provides a comprehensive way to handle exceptions, within the context of
a process. However on some occasions we want to take a more holistic
view to managing exceptions. This is certainly the case where we are
suddenly “hitting” a common exception across multiple processes.For example, if we have a loan flow process that’s going out to an external credit rating agency, and for some reason that credit rating check fails. Within the individual process BPEL process, we could have built in a simple re-try mechanism that simply waits a period of time before re-trying the service. However if we start having a high number of failures (e.g. we may 1000’s of these processes running at any time), rather than handle the same exception multiple times (at least the same root cause) we can use BAM to detect that we have an issue and kick-off a single process to handle that exception (as illustrated below).
Dynamic Process Assembly
Rather
than use BAM to feed a Dashboard, we can use it as a real time data
source. A BPEL process can then query this real time data and pass this
to the rules engine; enabling us to evaluate rules based on real time
data.At this point we could just use the result from the rules engine to dictate the flow through a process (as we did with the first example – Modify Process Flow). However (as the title implies) we can take it a step further and dynamically assemble the process. The trick here is to have multiple “sub” processes all with the same WSDL definition. The rules engine rather than returning a “decision” now returns the end-point of the sub process to call, which the main BPEL process can then call dynamically (as illustrated below). For more details on how to implement dynamic routing, see my previous blog; Using BPEL to Implement Dynamic Content Based Routing. |
Writing a Recursive BPEL Process
Recently I was working with a client who wanted to implement a recursive
process (i.e. one that calls itself). Now Recursion is a classic
programming pattern, and in theory it should be pretty straight forward
for a process to call itself. However at first sight it’s not so
obvious.
Example
I’ve created a simple example process, based of course on the classic Factorial example. You can download this here.
Deployment Considerations
The
one drawback with this approach is that the WSDL file will now contain
the Endpoint location for the service within in it. Thus is you were to
deploy the process on a different server it would fail at run-time.So you need to modify the WSDL file at deployment time so that the endpoint reflects the hostname and port number of where the process is actually being deployed. The simplest way to do this is update your build script so that ant will automatically do this for you.
Final Thought
Now
in theory you could have incredibly nested processes using this
approach, however I would advise is bad practice and is likely to have
performance implications.For example; if we ran the Factorial process to work out 50 Factorial, that would result in 50 process instances. Now if we expected to handle 1000 process running in parallel, this would result in 50,000 process instances – so the actual number of process instance could increase very dramatically. So I would recommend using this approach with caution to ensure that it doesn’t result in a dramatic increase in the overall number of process instances. |
Labels: BPEL
Querying BPEL Process Instances
The Oracle BPEL Console provides a great tool for monitoring the status of in-flight and completed process.
However it is often a requirement to present this information to a business user within a business specific view. One way of achieving this is to use the Oracle BPEL Portlets.
This is fine where you want to give the user a specific list of process instances, for example a list of all currently running Purchase Order processes. But what about when you need to give them a list more filtered to their specific business requirements, for example:
How do I find all open purchase order processes for a specific customer?
How do I find all help desk processes being managed by a specific customer service representative?
How do I find all open expense processes that are waiting approval?
In addition once you’ve located a process instance, how do I provide the user with access to relevant data contained within the process? Again the BPEL Console provides a mechanism for drilling into the process and looking at the audit trail for the data. But often we want to provide this data in a summarised business view designed specifically for the needs of the business user.
The Oracle BPEL PM Server provides a series of API’s that enable you to meet these requirements.
In fact what is not often realised is that the BPEL Console itself makes use of these API’s, giving you the flexibility to completely re-write the console if that is what’s required!!!
In reality this is rarely if ever the case, typically the requirement is to provide business users with a simplified view tailored to their specific needs. A simple way of achieving this is through the use of these API’s; this is the subject of this article.
Locating a Process Instance
The Oracle BPEL PM Client API provides a Locator class for enabling a client application to search for processes, instances and activities. The Locator class provides a number of constructors, which enable you to connect to a BPEL domain hosted on either a local or remote J2EE Server.
For the purpose of locating specific process instances it provides two very useful methods:
listInstances(WhereCondition wc)
listInstancesByIndex(WhereCondition wc)
Each method returns an array of objects of type InstanceHandle, which can then be used to perform operations on the corresponding process instance.
The key parameter for each of these methods is the WhereCondition, which is used to build up a query to restrict which instances are returned by the method.
Note: Where condition objects may be concatenated together to form a larger query. The methods append and prepend allow the user to add a clause (in String format) or even a whole WhereCondition object to the beginning or end of the current where condition.
The following code snippet shows how to construct a WhereCondition to return all running process instances for the “LoanFlowProcess” where it’s current status is “CheckingCredit”.
String pProcessId = "LoanFlowProcess";
String pStatus = "CheckingCredit";
// Constructs a where condition that searches for open instances
WhereCondition where = WhereConditionHelper.whereInstancesOpen();
// Extend the where condition to filter on process id
WhereCondition whereProcessId = new WhereCondition( "process_id = ?" );
whereProcessId.setString(1, pProcessId);
where.append(whereProcessId);
// Extend the condition to filter on processes with the status ‘CheckingCredit’
WhereCondition whereStatus = new WhereCondition( "status = ‘" + pStatus + " );
whereStatus.setString(1, pStatus);
where.append("and").append(whereStatus)
// Find Instances
IInstanceHandle[] instanceHandles = locator.listInstances( where );
In the final step, the actual locator class is performing a query against the BPEL Dehydration store, similar to the one illustrated below:
“select cikey from cube_instance where " + whereCondition.getClause();
We use the WhereCondition (which wraps a SQL prepared statement where condition), in order to restrict the result set returned by the query.
It’s worth exploring in a bit more detail the various parts of the WhereCondition.
For the first we use the WhereConditionHelper class to restrict the query to only currently running processes. This is a simple utility class which provides a variety of Static methods for creating various query fragments (e.g. return process instance whose state is open, completed, aborted, stale, etc) which can then be appended to additional where conditions to create the required query.
For our second condition we are literally adding the condition
cube_instance.process_id = “LoanFlowProcess”
to our prepared statement. Here you can specify pretty much any of the columns in the database table cube_instance (e.g. Process_Id, Revision_Tag, Priority, Status).
In reality, rather than naming this column explicitly, we should use the appropriate constants defined in com.oracle.bpel.client.util.SQLDefs (e.g. SQLDefs.CI_process_id for our example).
The final statement is similar to the second in that we are querying on the process status. But what is the process status? Well it shouldn’t be confused with process state, which we queried on in the first WhereCondition.
Rather the process status is a variable that keeps track of where in the process a particular process instance is. When the process is first initiated, this value is set to ‘initiated’. This value is then updated every time you enter a new scope within a process to contain the name of the scope.
Note: When you have nested scopes, it will contain the name of the lower most nested scope that the process is in, i.e. it contains the last scope that was entered. Also when a process leaves a scope the status value is NOT reset, i.e. it will still contain the name of the previous scope until it enters a new scope.
Process Indexes
The listInstances method is very useful but it still doesn’t allow us to perform a query based on actual data held in the process instance, e.g. just return the loan flow process for ‘Dave’.
To solve this problem, BPEL allows for a process to have up to 6 indexes and to create a where condition across one or more of these indexes.
Essentially there are two steps to this; first you need to set the index values on the actual process instance; secondly you use the index values in a query to pull back all processes for a particular index value in a similar fashion to above.
Setting the Index Value
The simplest way to achieve this is to embed a piece of Java (using the Java Embed Task) at the start of the process to call the setIndex API to set the index value based on a value in the initial message, as shown in the example below:
// Set Index1 for Customer Name
String customerName = ((com.collaxa.cube.xml.dom.CubeDOMText)
getVariableData("input", "payload", "/auto:loanApplication/auto:customerName/text()")).getText();
setIndex(1, customerName);
Note: The getVariableData method is used to retrieve the customerName from the “input” variable; the syntax of the parameters is similar to the “from” component within an assign construct.
Querying Processes
The following code snippet shows how to construct a WhereCondition to return all running process instances where index_1 is equal to ‘Dave’.
String pCustomerName = "Dave";
// Constructs a where condition that searches on index 1
WhereCondition where = new WhereCondition(SQLDefs.CX_index_1 + " = ?");
where.setString(1, pCustomerName);
// Find Instances
IInstanceHandle[] instanceHandles = locator.listInstancesByIndex( where );
However there is one minor issue with this; under the covers the listInstances method is performing a query on the cube_instance database table, whilst the listInstancesByIndex is performing a query on the ci_indexes database table.
The issue here is if we want to perform a query that is a join across these two tables, i.e. show me all LoanFlow process for Dave. The WhereCondition API doesn’t (naturally) allow for joins; however there are two possible workarounds:
The first is to set the index values to hold the additional data required by the query, e.g. set index_1 to hold the process name and index_2 to hold the customer id.
The second is to extend the where condition passed to the listInstance method to have an IN condition that queries against the ci_indexes database table, as show below:
// Extend the where condition to only return open processes with the
WhereCondition whereIndex = new WhereCondition( "cikey in (select cikey from ci_indexes where index_1 = ?");
whereIndex.setString(1, pCustomerName);
where.append("and").append(whereIndex)
Note: I’ve used table and column names for clarity, but in reality you should use the constants defined by SQLDefs.
Using an Index to set status
Earlier in the article we looked ay how we can use process status to keep track of where we currently are in a process (remember status contains the name of the last scope that we entered).
However, whilst this is useful it has a couple of drawbacks; one is that if we use the listInstancesByIndex method to locate a process, we can’t actually filter on the state of the process. However the other is that we rely on insuring that the scopes are correctly named, designed, etc to keep track of where we are in the process. However in reality we may only have a few key milestones that we are interested in, and these may span several scopes or we may have more than one milestone contained within the same scope.
An alternative is to use an Index to hold the status of the process, and just update the status of the process using the setIndex method at appropriate points within the process.
Accessing Process Data
Once we have our list of processes instances, the final stage is to actually access the relevant data contained within the instance to display to the business user.
This is simply the case of iterating through our array of instance handles. Once you have the instanceHandle for a process, you can then use this to access process variables contained within the process instance using the getField method.
However you need to take care that whatever variable you are trying to access is currently visible within the active scope of the process. I find the simplest way to do this is to define a global variable (i.e. define the variable at the process level) and initialise it at the beginning of the process based upon the content of the initial message received by the process. Then during the lifetime of the process update the variable as required to reflect the true state of the process.
The following code snippet shows how we can process each instance returned by the locator and access the variable “LoanApplicationSummary” defined in the BPEL process.
// Find Instances
IInstanceHandle[] instanceHandles = locator.listInstancesByIndex( where );
// Process each instance
for (int i = 0; i < instanceHandles.length; i++ )
{
IInstanceHandle instanceHandle = instanceHandles[ i ];
// Get Loan Application Summary Variable
Element loanApplicationElement = (Element) instanceHandle.getField(“LoanApplicationSummary”);
// Create Loan Application Bean
LoanApplication loanApplication = LoanApplicationFactory.createFacade(loanApplicationElement);
// Process Loan Application Bean as required
…
}
To access the variable you use getField method on your instance Handle, as show below:
// Get Loan Application Summary Variable
Element loanApplicationElement = (Element) instanceHandle.getField(“LoanApplicationSummary”);
This will return a DOM (Document Object Model) representing the XML contained within the process variable. You can use the actual DOM API to parse and manipulate the XML content but for any complex structure this can be quite tricky.
To make this simpler, Oracle BPEL Process Manager provides a lightweight JAXB-like Java object model on top of XML; a so called XML façade. The façade provides a Java bean-like front end for an XML document/element. Façade classes have a corresponding Factory class which parse the XML document/element to create the façade, as show in the code snippet below:
// Create Loan Application Bean
LoanApplication loanApplication = LoanApplicationFactory.createFacade(loanApplicationElement);
Once the façade has been created, you can use its getter methods to access the required data.
Note: Façades are generated using the schemac tool shipped with Oracle BPEL Process Manager. You can use schemac to generate the façades from WSDL or XSD files (see the Oracle BPEL PM Developer guide for further details).
Summary
As we have seen Oracle BPEL PM provides a powerful Client API that makes it relatively simple to build a business specific “console” tailored to the needs of the user.
For further information on the API you should see the Oracle BPEL Process Manager Client API Reference
Posted by Matt Wright at 14:51 10 comments
Wednesday, 14 February 2007
"Private" BPEL Processes
When developing any BPEL based solution, good practice dictates that you take a modular approach to process design, which allows the sharing of sub-processes among higher level processes. For example a payment process may be used by both the Expenses Process and Order Process.
As a result you will often end up with BPEL processes that you only intend to be called by other BPEL processes, and typically BPEL processes with at least some knowledge about the underlying process. So how do you prevent other ‘clients’ from directly invoking these processes?
Now initially this may sound like a security issue, and Oracle BPEL Process Manager provides a number of ways of securing BPEL Processes; in addition Oracle Web Services Manager provides a comprehensive solution for adding policy-driven security to all Web services (not just BPEL Processes).
However security is typically intended for enabling controlled secured access to a BPEL Process (or Web Service) by authorized clients. However in this case we don’t actually want any client directly accessing the process. Now admittedly we could take a standard based security approach to this, but is there a simpler way?
Now many programming languages such as Java provide the concept of private or protected methods that control what has access to them. For example, in Java a class may declare some of its methods as being protected; indicating that only other classes in this package can access these methods. The great thing about this approach is that the developer is actually signalling a level of intent, i.e. this method should not be called directly except by related classes (or sub-classes) that can be trusted to use the method correctly.
Ideally it would be great if BPEL provided similar functionality, however unfortunately it doesn’t. So is there a way of achieving something similar?
Well it turns out there is a fairly straight forward way of getting close to the desired effect. The approach makes use of the Oracle HTTP Server embedded within the Oracle Application Server (as such this won’t work for the Developer install) to prevent access to a specific URL pattern, plus the use of domains with Oracle BPEL PM to enable us to create a simple URL pattern for all “private” processes.
Configuring Oracle HTTP Server
Oracle HTTP Server is the Web server component of Oracle Application Server and is based on the Apache infrastructure.
Any one familiar with Apache administration is aware that it provides Allow and Deny directives which let you either allow or deny access to a particular URL (or pattern) based on the host name, IP address (or partial IP address) or a fully qualified domain name (or partial domain name).
By specifying a |
Labels: BPEL
Oracle BPEL and ESB
Hi, |
BPEL Correlation
Labels: BPEL, Correlation
Deploying BPEL processes in a High Available Application Cluster
Introduction
This article describes how to deploy BPEL processes to a clustered application server environment. In this scenario we will have three (3) instances of Oracle Application Server 10g. On each of the server an Oracle BPEL is installed. This is shown as example in the next diagram. Each application server is added to a logical cluster. The cluster can be defined via Oracle Enterprise Manager 10g. This applies also for adding the application server instances to this cluster. It is assumed that the application servers are using the Oracle Database 10g for retrieving and storing their data. This database is made high available via Oracle Real Application Clusters. Solution Define a logical application cluster and add each application server to this cluster. This can be done via Oracle Enterprise Manager 10g.
After creating the OC4J instance, each application server will now have a local OC4J instance. The power of the OC4J instance, in other words a J2EE environment, is that it can deploy EAR and WAR files. Creating an EAR or WAR file and deploy this to the application server, results that this file will be unpacked in each OC4J instance. Using this mechanism for BPEL processes, it confirms to the industry standard of J2EE deployment. Create an EAR file that contains all the BPEL jar files that must be deployed. For example, create an EAR file with an application name “bpel_deploy” containing a web application named “files”. The names must be conforming to the EAR/WAR structure. In this example the EAR file contains a WAR file that contains the BPEL jar files. bpel_deploy.ear meta-inf/application.xml files.war files.war web-inf/web.xml bpel_ProcessTaks_1.0.jar bpel_HelloWorld_1.0.jar bpel_CreditRatingService_1.0.jar Deploy the EAR file to the OC4J_BPEL_DEPLOY instance of the cluster. The trick is that the EAR file will be deployed to each OC4J instance on each application server! This results that all BPEL jar files are copied to all servers. The deployment of the EAR file is done via Oracle Enterprise Manager 10g or via Oracle JDeveloper. After this deployment the BPEL servers must me made aware that BPEL jar files have been deployed. Making the BPEL servers aware of these jar files is done once, only during the initial setup. This is done by replacing the temporary directory for BPEL processes on the server to point to the directory where the BPEL jar files are extracted from the EAR file. This can be done as follows (UNIX example): rm ${ORACLE_HOME}/integration/orabpel/domains/default/tmp ln –s ${ORACLE_HOME}/j2ee/ OC4J_BPEL_DEPLOY /applications/bpel_deploy/files ${ORACLE_HOME}/integration/orabpel/domains/default/tmp Each time a new EAR file is deployed, with all the BPEL jar files, the BPEL servers are aware that new BPEL processes are ready to apply in the BPEL server environment. Conclusion Using the EAR/WAR mechanism of J2EE for deployment of BPEL jar files, results in a more industry standard compliancy. The deployment is less complex to maintain in a high available environment. The risks of faults during deployment are reduced. Deploying the BPEL files is done in the same way as normal J2EE application. Deployment is done via HTTP or HTTPS protocol, making no need of special configuration in the network. Multiple BPEL processes are deployed at once. |
Labels: BPEL