Thursday, December 13, 2007

[Error ORABPEL-10902]: compilation failed, XML parsing failed because "".

Almost every body working with BPEL will run in the error:

Error:
[Error ORABPEL-10902]: compilation failed
[Description]: in "C:\projects\vijfhuizen.com\trunk\src\soa\bpel\HelloWorld\bpel\
HelloWorld",
XML parsing failed because "".
[Potential fix]: n/a.


The JDeveloper error message does not say more, especially the last one, "Potential fix: n/a". But it is possible to get some more in depth log info. This is done via build.xml file that JDeveloper creates for your bpel process.

Do the following steps:

Change the 'verbose' setting to true in the build.properties file.

# Set verbose to true if you want to
# see verbose output from deployment tasks

verbose = true


Right click on build.xml and then run ant task 'Compile'.
Detailed result is now shown in the log.

Friday, November 23, 2007

Dejavu: Concurrent Programming

Now I am doing SOA projects for a few years, I can still can rely on knowledge that I did on school. In the eighties I did some practices with concurrent programming. Building low-level applications what acts as processes and were handling information to each other.

When we were clearing the study room, I went trough a lot of books to look which can be thrown away. Then I saw the boook that I used during my study:
Looking into the book, it was a deja-vu. I saw that Business processing and the implementation in SOA/ESB/BPEL had much similarities with this book. While this book is rather technical, it also describes the principles about concurrent processing. The information in this book is very useful for implementing SOA application. It helps you to bridge from functional business processing to the technical implementation.

The difficult thing in business processing, is that all processes are running individual and in parallel. Furthermore, the processes are not in sync with each other, most of them are running at different points in time. Then there are processes that a waiting for other process for requesting or receiving information, all of these issue should be taken into account while designing SOA processes.

More info on the book can be found here.

Tuesday, November 20, 2007

Deploy single instances of XSD files

In most common project based on SOA we are using a lot of XSD file to specify the format of the message. The goal is often to design several common schema's that are used by the various processes in the SOA application (ESB/BPEL/Workflow).

By default, I mean, you just create BPEL or ESB processes, XSD files are generated by default or you import the XSD files in your project. Oracle JDeveloper just copies the XSD files to your local project. For development purposes this is nice, but for production environments (especially for maintenance), it is horrible to maintain all these files. Each project contains the WSDL and XSD files with the import statements:

<import namespace="http://www.vijfhuizen.com/Error"
schemaLocation="MyErrorMessage.xsd"/>

What you would like is to have one single source in your SOA project that holds all the common schema's.

You can enable this as follows, I suggest two solutions, but I prefer the last.

Let Apache keep the files.
On your Apache server you copy (ftp/scp) all your XSD files to the server. In the Apache configuration (httpd.conf), you create an 'Alias' that points to this directory. When you restart Apache, your could access these files via a normal http request.

Now you can change your XSD pointers to:

<import namespace="http://www.vijfhuizen.com/Error"
schemaLocation="http://www.vijfhuizen.com/commonfiles/MyErrorMessage.xsd"/>

De disadvantgae is that each time a change is made in the common XSD files, you must copy the files to the Apache server, using FTP/scp. This is different than the other SOA components.

Let BPEL keep the files.
You just create a dummy BPEL process, named CommonFiles. Add to this process all your XSD files. Just compile the project and deploy! Thats all.

Now you can change your XSD pointers to:

<import namespace="http://www.vijfhuizen.com/Error"
schemaLocation="http://www.vijfhuizen.com/orabpel/default/
CommonFiles/1.0/CommonFiles/MyErrorMessage.xsd"/>

Advantages: No changes at Apache level, no FTP/scp steps. the XSD files are under control by BPEL, you could use version functionality of BPEL.

Tuesday, October 09, 2007

Deploy depending BPEL processes

When designing and developing BPEL processes. It could result that process A call proccess B. But process B will also call process A. During development your start with process A, deploy it and later on you create process B. Then you add a partnerlink in process A to call B and vice versa.

You will not notice that these two processes are depending on each other until you create/deploy these processes in a new environment. It will not possible to deploy process A, while it depends on B. In the bpel.xml file process A will be compiled, but it will try to retrieve WSDL specification of B. While B is not there, it fails to compile. The other way arround, is the same. Process B does not compile because A does not exists.

This can be solved. The way I prefer is the following:
  • Copy the WSDL file and the XSD file of process B into your project of process A.
  • Copy bpel.xml into bpel_post.xml
  • Change all the WSDL locations, in bpel.xml, into local files: http://host/orabpel/default/HelloWorldB/HellowWorldB?wsdl
    into
    HelloWorldB.wsdl
  • Compile process A based on bpel.xml.
  • Deploy process A.
  • Deploy process B.
  • Compile process A based on bpel_post.xml.
  • Deploy process A.
Issue solved.

Wednesday, October 03, 2007

How to approach a SOA project

For our Dutch and Belgium audience, I wrote an article for Oracle University. This article tells you how to approach a SOA project. Here is the link:

http://www.oracle.com/global/nl/education/nieuws/Website_tips.html

Marc

Monday, October 01, 2007

Reinstall TaskManager / TaskActionHandler processes

Working with the BPEL process manager you deploy and undeploy processes from JDeveloper or via your own build system. Undeployment is mostly done via BPEL console, by selecting each process after each other, or select multiple processes at once.

But a mistake could be made, that you undeploy one of the two process that are supplied by default.
  • TaskActionHandler
  • TaskManager
After you undeploy these processes they can not be restored via the BPEL console. To restore these processes you do the following steps.

copy the two files from directory $ORACLE_HOME/bpel/install/extensions/ to the deployment directory of your domain.

cd $ORACLE_HOME/bpel/install/extensions
cp bpel_TaskActionHandler_1.0.jar
$ORACLE_HOME/bpel/domains/default/deploy
cp bpel_TaskManager_1.0.jar
$ORACLE_HOME/bpel/domains/default/deploy

Thursday, September 27, 2007

Using custom headers in BPEL

Sending messages to a BPEL process mostly done via the web service interface. In general the message is packed in a SOAP envelope in the body part. The header part of the SOAP envelope id not touch. This is mostly done automatically between the client and web service.

Sometimes you need information to send or retrieve information to the BPEL process that is not part of the message. This information is mostly technical and not functional related to the message in the SOAP body. In these cases you could manipulate the SOAP header to add your own message.

The next example describes a solution of retrieving headers from the SOAP request. The example is very simple it just an 'HelloWorld' application that reads the SOAP header. If the custom header exists it returns it, otherwise it does not. The BPEL process is show as follows:



Now this is simple. The trick is in the WSDL specification and the 'receive' step in the BPEL process. A few changes have been made in the default WSDL (after you create a default async BPEL process in jDeveloper).

The WSDL is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="HelloHeader"
targetNamespace="http://xmlns.oracle.com/HelloHeader"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:client="http://xmlns.oracle.com/HelloHeader"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing"
xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/">
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://xmlns.oracle.com/HelloHeader"
schemaLocation="HelloHeader.xsd"/>
<import namespace="http://schemas.xmlsoap.org/ws/2003/03/addressing"
schemaLocation="https://dvlp1.eurotransplant.nl/
orabpel/xmllib/ws-addressing.xsd"/>
</schema>
</types>
<!-- SOAP HEADER -->
<message name="RelatesToHeader">
<part name="RelatesTo" element="wsa:RelatesTo"/>
</message>
<message name="MessageIDHeader">
<part name="MessageID" element="wsa:MessageID"/>
</message>
<message name="ReplyToHeader">
<part name="ReplyTo" element="wsa:ReplyTo"/>
</message>
<message name="CustomHeader">
<part name="CustomHeader" element="client:HelloHeaderHeaderMessage"/>
</message>
<!-- EOF SOAP HEADER -->
<message name="HelloHeaderRequestMessage">
<part name="payload" element="client:HelloHeaderProcessRequest"/>
</message>
<message name="HelloHeaderResponseMessage">
<part name="payload" element="client:HelloHeaderProcessResponse"/>
</message>
<portType name="HelloHeader">
<operation name="initiate">
<input message="client:HelloHeaderRequestMessage"/>
</operation>
</portType>
<portType name="HelloHeaderCallback">
<operation name="onResult">
<input message="client:HelloHeaderResponseMessage"/>
</operation>
</portType>
<binding name="HelloHeaderBinding"
type="client:HelloHeader">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="initiate">
<soap:operation style="document" soapAction="initiate"/>
<input>
<soap:header message="client:MessageIDHeader"
part="MessageID" use="literal"/>
<soap:header message="client:ReplyToHeader"
part="ReplyTo" use="literal"/>
<soap:header message="client:CustomHeader"
part="CustomHeader" use="literal"/>
<soap:body use="literal"/>
</input>
</operation>
</binding>
<binding name="HelloHeaderCallbackBinding"
type="client:HelloHeaderCallback">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="onResult">
<soap:operation soapAction="onResult" style="document"/>
<input>
<soap:header message="client:RelatesToHeader"
part="RelatesTo" use="literal" required="false"/>
<soap:body use="literal"/>
</input>
</operation>
</binding>

<plnk:partnerLinkType name="HelloHeader">
<plnk:role name="HelloHeaderProvider">
<plnk:portType name="client:HelloHeader"/>
</plnk:role>
<plnk:role name="HelloHeaderRequester">
<plnk:portType name="client:HelloHeaderCallback"/>
</plnk:role>
</plnk:partnerLinkType>
</definitions>



In the WSDL we overwrite the binding of the web service. Here we specify the custom header. We should not forget to use the normal headers as MessageId and ReplyTo.

Note: In the XSD-file we added a message":
 <element name="
<complextype>
<sequence>
<element name="message" type="string">
</sequence>
</complextype>
</element>

Now the message and the WSDL are correct we could change the BPEL file to add the code to read the SOAP Header. In the variable declaration add:

<variable name="customHeader"
messageType="client:CustomHeader"/>
<variable name="messageID"
messageType="client:MessageIDHeader"/>
<variable name="replyTo"
messageType="client:ReplyToHeader"/>

Now change the receive task to add the "bpelx:headerVariable" statement.

<receive name="receiveInput"
partnerLink="client"
portType="client:HelloHeader"
operation="initiate"
variable="inputVariable"
createInstance="yes"
bpelx:headerVariable="customHeader messageID replyTo"
/>

After the receice step the headers, if the exist, are put into the variables. Now you could use normal assign/copy tasks to use this data.

You can download the example code here.

To test the BPEL process, use a tool as SoapUI.org (open source). Here is a SOAP request with a custom header:

<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:hel="http://xmlns.oracle.com/HelloHeader"
xmlns:add="http://schemas.xmlsoap.org/ws/2003/03/addressing">
<soapenv:Header>
<hel:HelloHeaderHeaderMessage>
<hel:message>This is the custom header</hel:message>
</hel:HelloHeaderHeaderMessage>
</soapenv:Header>
<soapenv:Body>
<hel:HelloHeaderProcessRequest>
<hel:input>Hello World</hel:input>
</hel:HelloHeaderProcessRequest>
</soapenv:Body>
</soapenv:Envelope>

Tuesday, September 18, 2007

Compile error BPEL against SSL

If you compile a BPEL proces that is using partner links based on SSL. You run into an compile error:

ValidatorException: PKIX path building failed

This can be solved by importing the certificate form the server into your local key store. This is the keystore from which JDeveloper is started.

Make sure that you apply this also on the SOA Suite server. The BPEL process is deployed and compiled again on the server.

cd [jdevhome]\jdk\jre\lib\security
..\..\bin\keytool.exe -import -file "Vijfhuizen.cer"
-keystore cacerts -storepass changeit -alias myRootCA

Owner: O=Vijfhuizen, C=Issuer: O=Vijfhuizen, C=com
Serial number: 1
Valid from: Mon Sep 21 08:00:00 CET 2007
until: Thu Feb 28 20:00:34 CET 2012
Certificate fingerprints:
MD5:
XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
SHA1: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
Trust this certificate? [no]: yes
Certificate was added to keystore


Tuesday, September 11, 2007

Cancel workflow / human-task

Work with human work flow in Oracle SOA Suite is very powerful. Within Oracle BPEL you can create a human task for a particular user or user-group. But as these tasks are assigned to users, the BPEL process is waiting on result. Depending on the task configuration, you could assign time-outs and escalation paths.

From business perspective, you could have a rule that says; reject all open task for a particular user or group. So how do we approach this issue? Oracle Suite has a rich Java API to control the human work flow. In this case you could create a java program that collects information from the work flow engine to cancel the tasks. This java program could be a:
  • A java client.
  • A web application, using the java api.
  • Embedded Java in the BPEL process.
But a closer look in the human task call in the BPEL process, shows another solution. Apart of initiating a human task you could also call various other operations:

The advantage to use BPEL code, you do not need any (embedded) Java API calls to fulfill this function. In our case we could invoke the human work flow via the 'updateTaskOutcome' operation. The are a few restrictions. Before you could set the outcome of an task (REJECT, APPROVED, DENIED, etc.) you must known the TaskID for that particular task and the session token of the task. This information is available in the BPEL process that creates this task. You could store this information in a database table to make it available for the process that wants to set the outcome.

A question was asked, how to obtain the TaskID and the session Token. This is easy. When a human-task is created, after the invoke in the human-task scope, a result is send back to BPEL. In this result you can retrieve information on this task. In our case you could read the TaskId and the Token. Saving this data in a table or file, you can use it by other processes to update the outcome.

Wednesday, August 15, 2007

Modifying XML records dynamically in BPEL

When you use an adapter to retrieve data from the database or reading records from a file, you will get a collection of XML records. Often you want to modify data within this list of XML records. This can be done like the the BPELX:InsertAfter/BPELX: and other functions. But there is another way to to this.

To dynamically change the value of element in a XML record you can manipulated the 'to:' element in the copy clause:

Normally you have:

<copy>
<from variable="InputVariable"
part="payload"
query="/ns1:HelloWorldRequest/ns1:input"/>
<to variable="OutputVariable"
part="payload"
query="/ns1:HelloWorldRequest/ns1:ListOfOrders
/ns1:Order:/ns1:Amount"/>
</copy>
This statement will fail if the the XML payload contains more than one row. Because the assigment is done on a single record. If we use a record counter that loops through this XML payload we are able to assign the specific record very easily. You can change copy in:

<copy>
<from variable="InputVariable"
part="payload"
query="/ns1:HelloWorldRequest/ns1:input"/>
<to variable="OutputVariable"
part="payload"
query="/ns1:HelloWorldRequest/ns1:ListOfOrders[$RecordCounter]
/ns1:Order:/ns1:Amount"/>
</copy>

The trick is to add the [$RecordCounter] directly in in the XPATH query of the copy activity. The BPEL PM will interprete this and translate this into the correct value.

Note: You must define the variable "RecordCounter" in your scope as an integer.

Wednesday, August 01, 2007

10.1.3.3 and the samples

This is an open door, but when you apply the patch of the 10.1.3.3 SOA Suite, keep in mind that not only the core code has been changed but also the samples. In my case I was struggling with the sample work list application. Later I found out that this sample was also updated. Verify also, when you are using 10.1.3.3 that the documentation could be out of sync on some detail steps.

Wednesday, June 06, 2007

Retrieve BPEL process instances with Java

As mentioned in a previous article calling a process from java can be done easy. From another perspective, you need in the application the state of a particular process or process-instance. In the next example the java code is searching for a particular process that is running and retrieves his status.

The status of running process is the name of the current scope the process is in. To test the Java program creat a BPEL process with some scopes. Each scope is waiting of a few minutes. Running the Java program multiple times, results that you see that the status of the process is chaning.
Note: The article is based on this article, using the properties file and libraries.

The program:

RMIListInstances.java

package nl.orasoa.bpel;

import com.collaxa.xml.XMLHelper;

import com.oracle.bpel.client.BPELProcessId;
import com.oracle.bpel.client.IBPELProcessHandle;
import com.oracle.bpel.client.IInstanceHandle;
import com.oracle.bpel.client.Locator;
import com.oracle.bpel.client.NormalizedMessage;
import com.oracle.bpel.client.delivery.IDeliveryService;

import com.oracle.bpel.client.util.WhereCondition;

import com.oracle.bpel.client.util.WhereConditionHelper;

import java.util.Map;
import java.util.Properties;

import org.w3c.dom.Element;

public class RMIListInstances
{
public static void main(String[] args)
throws Exception
{
IInstanceHandle[] instHandles;
IBPELProcessHandle[] procHandles;

IInstanceHandle instance = null;
BPELProcessId bpid = null;

WhereCondition cond;
WhereCondition cond1;
WhereCondition cond2;

try
{
// properties in the classpath
Properties props = new java.util.Properties();

// read the properties file
java.net.URL url =
ClassLoader.getSystemResource("context.properties");
props.load(url.openStream());
System.out.println(props);

// WhereCondition cond =
// WhereConditionHelper.whereInstancesClosed();
// WhereCondition cond =
// WhereConditionHelper.whereInstancesCompleted();
// Search only open instances
cond = WhereConditionHelper.whereInstancesOpen();

// append where clause to search for
// a specific process and version
cond1 = new WhereCondition( "process_id = ?" );
cond1.setString(1, "Wacht");
cond2 = new WhereCondition( "revision_tag = ?" );
cond2.setString(1, "1.0");

// append the whole where clause
cond.append("and").append(cond1).append("and").append(cond2);

// get a connection to the server
Locator locator = new Locator("default", "welcome1", props);

instHandles = locator.listInstances(cond);
for (int j = 0; j < instHandles.length; j++)
{
// get the instance
instance = instHandles[j];
// get the process for the instance
bpid = instance.getProcess().getProcessId();
System.out.print("Got process " + bpid.getProcessId()
+ "("+ bpid.getRevisionTag() + ") ");
System.out.println(instance.getConversationId() + " "
+ instance.getStatus() + " " + instance.getTitle());
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}


Calling BPEL/ESB Webservice from standalone java client

In this article a sample is give how we call BPEL/ESB process from a java standalone program. The example is based on the HelloWorld process that accepts a single string as input.

The reason why I wrote this example, is that I did not find a straight forward simple java program to do this. Examples are supplied with BPEL (no 102) but not exactly what I want.

To run the example, open in JDeveloper a new project and add the following java class into your project. Make sure you add the following libraries to your project to make to java program runnable.
Here is the property file, to make the connection to your SOA Server.

context.properties
orabpel.platform=ias_10g
java.naming.factory.initial=com.evermind.server.rmi.RMIInitialContextFactory
java.naming.provider.url=opmn:ormi://edison.eurotransplant.nl:6003:oc4j_soa/orabpel
java.naming.security.principal=oc4jadmin
java.naming.security.credentials=scanner1


Here is the class file.

RMIClient.java

package nl.orasoa.bpel;

import com.collaxa.xml.XMLHelper;
import com.oracle.bpel.client.Locator;
import com.oracle.bpel.client.NormalizedMessage;
import com.oracle.bpel.client.delivery.IDeliveryService;

import java.util.Map;
import java.util.Properties;

import org.w3c.dom.Element;

public class RMIClient
{
public static

void main(String[] args)
throws Exception
{
try
{
String who = "Marc";
System.out.println("Who is " + who);

// properties in the classpath
Properties props = new java.util.Properties();

java.net.URL url =
ClassLoader.getSystemResource("context.properties");
props.load(url.openStream());
System.out.println(props);

String xml =
"<HelloWorldProcessRequest
xmlns=\"http://bpel.eurotransplant.nl/HelloWorld\">";
xml = xml + "<input>" + who + "</input>";
xml = xml + "</HelloWorldProcessRequest>";

Locator locator = new Locator("default", "bpel", props);

IDeliveryService deliveryService =
(IDeliveryService)
locator.lookupService(IDeliveryService.SERVICE_NAME);

NormalizedMessage nm = new NormalizedMessage();
nm.addPart("payload", xml);

NormalizedMessage res =
deliveryService.request("HelloWorld", "process", nm);

Map payload = res.getPayload();

System.out.println("BPELProcess HelloWorld executed!<br>");
Element partEl = (Element) payload.get("payload");
System.out.println("The Result was " + XMLHelper.toXML(partEl));
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

Monday, May 21, 2007

Create a singleton process

This article is based on the one from Matt's blog.

Sometimes you do not want have a process invoked every time. It could have impact on performance, CPU usage or additional memory and derived from this, think about garbage collection. You would like to have a process instance that can be re-used each time. Think about that you want to reuse data that was already available in a process.

What is needed, is a process that 'runs' forever and wait for input to be processed. This can be shown in the next diagram.

The Singleton process is started and will then run forever. It waits until it is accessed from another process, in this case the SingletonAccessor. The Singleton process will increase a counter and return this to the calling process. The basic mechanism is using correlation. The Singleton process is running and is using two correlation sets. One set is used to set correlation on the Singleton process, based on identifier, and one is used to set to the calling process, the Singleton accessors.

Installing the Singleton Process
The demo, download at the end of the article, has been successfully tested with Oracle BPEL PM (for Developers) version 10.1.3.1/2 edition on Windows and Linux.

The Singleton.zip should be unzipped to a local directory (for convince it's suggested that you unzip it in the BPEL Samples directory), in order to be deployed your BPEL PM engine.
  1. Open Oracle JDeveloper
  2. Open the workspace Singleton.jws
  3. Deploy the Singleton process to the BPEL server.
  4. Deploy the SingletonAccessor process to the BPEL server.
note: that the SingletonAccessor process is using a partnerlink pointing to the Singleton process. Make sure the URL is set correct in the bpel.xml file.

<partnerLinkBinding name="Singleton"> <property name="wsdlLocation">
http://localhost:7777/orabpel/default/Singleton/Singleton?wsdl
</property> <property name="correlation">correlationSet</property> </partnerLinkBinding>

To run the demo, first initiate the Singleton process from the BPEL Console. ensure that you specify "Singleton/1.0" as the Singleton Id (note - this should be the default payload).

Then initiate as many instances of SingletonAccessor as you like. You should see that they all call the same process instance of Singleton.

Download the example file here.

Tuesday, May 15, 2007

Oracle SOA Suite: Reinstall repository (dehydration store)

During the installation of the SOA Suite, it depends on the installation, if it creates automatically the repository. The following schemas are created, by a default install.
  • orabpel
  • oraesb
  • orawsm
With the advanced install it expects that these three schemas are already there. But it can also be that for some reason you want to re-install the schemas. To (re)install the schemas or just one of these schemas, Oracle provides a script on the installation disk to peform this. This can be found at:

$SOASUITE_INSTALL_DISK/install/soa_schemas/irca

The following files can be used; there is a Windows and Unix flavour:
  • irca.bat
  • irca.sh
Make sure the database en the listener is started. Stop SOA components on the Oracle Application Server, if they are still running.

Start the script, in the example I assume you are running on Linux (as I do :-) ). First the script will ask the location of the database, then it will ask if you want to overwrite the schema.

sh irca.sh

Integration Repository Creation Assistant (IRCA) 10.1.3.1.0
(c) Copyright 2006 Oracle Corporation. All rights reserved.

Enter database "host port serviceName" [localhost 1521 orcl]:
Enter sys password:
Running IRCA for all product(s):
connection="localhost 1521 orcl", , orabpelUser=ORABPEL, esbUser=ORAESB, orawsmUser=ORAWSM

Validating database ...
Validating database character set ...

Running prerequisite checks for ORABPEL ...
WARNING: This script will overwrite the existing ORABPEL schema.
Do you wish to continue? (y/n) y
Enter password for ORABPEL:
Loading ORABPEL schema (this may take a few minutes) ...

Running prerequisite checks for ORAESB ...
WARNING: This script will overwrite the existing ORAESB schema.
Do you wish to continue? (y/n) y
Enter password for ORAESB:
Loading ORAESB schema (this may take a few minutes) ...

Running prerequisite checks for ORAWSM ...
WARNING: This script will overwrite the existing ORAWSM schema.
Do you wish to continue? (y/n) y
Enter password for ORAWSM:
Enter password for ORAWSM: Loading ORAWSM schema (this may take a few minutes) ...

INFO: ORABPEL schema contains 225 valid objects.
INFO: ORAESB schema contains 180 valid objects.
INFO: ORAWSM schema contains 90 valid objects.

IRCA completed.
Please check for any ERROR message above and also check the log file
/tmp/irca2007-05-15_12-22-05PM.log for any error or other information.

If you are using Oracle Managed Files, you must make some changes in the files. This is written in the following article.

Sometimes you ESB repository does not behaves as expected. In the $ORACLE_HOME/integration/esb/bin directory a script called 'reset.bat|sh' is available. This script will cleanup the ESB repository. Look in the config file, esbsetenv.bat|sh for the connection to the database.

Sunday, May 06, 2007

Human Tasks and Workflow

For a long time Oracle had a product called Oracle Workflow. This product (version 2..6.x) is a work flow product that was based on PL/SQL. It had it own GUI tool to develop and deploy work flow definitions. It is still be used in the Oracle E-Business Suite and some customers are using it in their applications.

Since Oracle has its own SOA product, there was an overlap on work flow functionality. In the statement of direction (SOD) Oracle explains that the Oracle BPEL will take over this functionality. This sounds strange why BPEL can take over workflow.

A few years ago, I was involved in projects based on Oracle Workflow. When I was looking into BPEL to find similarities with Oracle Workflow, if found out BPEL was just the right work flow tool, it covers all the functions I needed. Looking back now, when I doing only SOA related projects, it looks strange, from a SOA perspective, to see BPEL as a work flow product. But these two views can co-exists along this product. This is big advantage. Two worlds, SOA and Workflow, comes together in this product.

Projects that are completed related to SOA can be implemented for BPEL/ESB. But this also applies to projects that are completely based on work flow, including human-work flow. The functionality offered by Oracle SOA/BPEL covers almost all the functions the user requires.

For customers using Oracle Workflow and want to migrate to BPEL, for the work flow functionality, there is no migration path. A redesign of the OWF application to be taken into account.

There are a lot of advantages of the work flow functions in BPEL are:
  • The technology is based on Java/XML
  • Design en implementation is doen in JDeveloper (IDE)
  • A rich Java API exists for workflow and BPEL.
  • A default end-user application is supplied for work flow.

Friday, April 27, 2007

BPEL, Workflow and JHeadstart

Implementing SOA projects is not only designing processes and implementing them with Oracle SOA with BPEL, ESB or Human Workflow. In general there are still data-entry screens to be designed and maintained.

From the past customers were using 4GL tools, such as Oracle Designer/Forms tools to generate the data-entry screens. Nowadays, we are using tools such as Oracle ADF Faces to do the same.

I often hear, how does this fit in a SOA Architecture? For Forms/Designer applications there are migration paths to go to a web oriented approach with Oracle ADF Faces and JHeadstart. Applications that stay on the traditional technology stack, can implement another approach.

Customers that are already using or have migrated to this Oracle ADF technology stack must only implement SOA. It sounds simple but some work has to be done. There is a way to use JHeadstart to implement Oracle SOA Webservices (BPEL/ESB) or the Human Worflow into the web application. A nice article on this issue is written on the JHeadstart Blog.

The trick is as follows. With JDeveloper, create a Java wrapper arround your web services or use the Workflow API. With these java classes you create an Oracle ADF view object. This view object can be used in Oracle ADF, using drag and drop to create your screens or use JHeadstart to generate the screens.

Thursday, April 19, 2007

CDM Ruleframe and BPEL / ESB

What is wrong with technology that is working for ages without any troubles. Basically nothing. The disadvantage is that old-fashioned technology is passed by the latest and the greatest. For example SOA and Oracle CDM Ruleframe.

Nothing is wrong with CDM Ruleframe; it's stable, logical, sits in the database and based on good-old PL/SQL.

SOA is hot, using the newest technologies as SOAP, web services, BPEL, Rules, ESB etc.

But how do you combine them? Well that's look easy, but some issues to care about.

When you use CDM Ruleframe the business rules are defined on table level. The rules are fired at once when a user does a DML on the table and commits. CDM Ruleframe will create a list of erros that does not apply to the business rules. It will create a PL/SQL table with all CDM rules that have been failed. These stacked errors should be send back to the client that was initiating the database request.

Now comes the point with SOA. In BPEL or ESB it uses the database adapter to access the Oracle database. This goes over JDBC. If an error occurs it is catch as an exception. In the exception you get the oracle error, for example ORA-20998 and an error message text. In this message text, some text is related to CDM Ruleframe. But not all the business rules are mentioned. It is up to the BPEL instance to catch the error and parse the message text to obtain the error.

A solution for this is as follows. When you want to access the database for query only, use the normal select approach. When you do an update, delete or insert call a PL/SQL package to perform the appropriate action. In this PL/SQL package you can catch the exception and collect the CDM Ruleframe errors and descriptions. This collection is formatted as an XML string in the error message text. The BPEL or ESB instance can now catch the specific oracle eroror, for example ORA-20998, and get error message text, that can be parsed as XML.

Note that the error, in XML format, send back from the Database, can be picked up via the RemoteFault exception. The error message is in the summary element. The only issue is, that is wrapped in a string. A message"Exception occurred" is put in front of the XML message and a string is appended. This can be solved by using the substring-before() and substring-after() to extract the XML result.

Wednesday, April 04, 2007

Patches, Patching how to get the SOA Suite Working

A new patchset is out on top of 10.1.3.3.0, 10.1.3.3.1! You can obtain it from metalink.oracle.com as patch numer 6492514.

Note: At last it is there the patch 10.1.3.3! You can obtain it from
metalink.oracle.com as patch numer 6148874.


The current version of the Oracle SOA Suite, release 10.1.3.1.0 does install very easy. Alsmost out of the box and you ar eup and running. But, as you start working you will found out that not everything is working as expected. Therefore you must install some patches.
The patches can be obtained from Oracle Metalink, login and click on the tab patches and do an advanced search. Select the product BPEL.

You will found that more that patches are available. So which patch must I install? This is a difficult question. Some patches can not be installed while they are in conflict with others. While other patches contains a set of other patches. So how do you known which patches you need. This is hard to tell. Depeding on your requirement some patches are easy found, some not :-)

Here is a list of patches I use to install at customer projects. It is based on my own expierence, and are related to projects that are based on Advannced Queueing (AQ), Database access (tables, PL/SQL) and files.

Before you install the BPEL patches. You must install patch number "2617419". This patch is a patch for the tool "opatch", that you are using to install the patches. This patch must be unzipped under the $ORACLE_HOME directory.

The list of patches I use:
  • 5566761
  • 5659094
  • 5724766
  • 5729652
  • 5742242
  • 5747361
  • 5851215
  • 5855005
  • 5915792
  • 6082941
  • 6082193
  • 6053708
I hope it will help to run the SOA Suite successfully.

There is an patchset out for the application server to upgrade to 10.1.3.2. This patch is named "Oracle Application Server Release 3 (10.1.3) Patch Set 2 (10.1.3.2.0)" and can be downloaded from Oracle Metalink. The number of this patchset is 5906151. I applied it on my SOA installation, and everything looks working as expected.


The Oracle ESB product has now it's on product in the patches list of Metalink:

Search for "Product or Product Family" = "Oracle Enterprise Service Bus (oesb)"

Note: At last it is there the patch 10.1.3.3! You can obtain it from metalink.oracle.com as patch numer 6148874.

Marc

Thursday, March 22, 2007

Convert A-Synchronous proccess to Synchronous

Introduction

This article how to convert an Asynchronous to a Synchronous BPEL process. Since BPEL determines whether a process is async or sync by just some small settings in the .bpel file (and some dependency in the wsdl) it is rather easy to convert from one to another.

When creating BPEL processes, three files are created by default:
  1. bpel.xml
  2. .bpel
  3. .wsdl
To determine whether a BPEL process is Asynchronous or Synchronous, it looks at the second file: YourBPELProcess.bpel. Generally, when creating a process based on the Asynchronous template, the .bpel file look like this:

<process
name="BPELProcess1"
targetNamespace="http://xmlns.oracle.com/BPELProcess1"
xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
xmlns:client="http://xmlns.oracle.com/BPELProcess1"
xmlns:ora="http://schemas.oracle.com/xpath/extension"
xmlns:orcl="http://www.oracle.com
/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
xmlns:xp20="http://www.oracle.com
/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
xmlns:ldap="http://schemas.oracle.com/xpath/extension/ldap"
xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/">
<partnerLinks>
<partnerLink
name="client"
partnerLinkType="client:BPELProcess1"
myRole="BPELProcess1Provider"
partnerRole="BPELProcess1Requester"/>
</partnerLinks>
<variables>
<variable
name="inputVariable"
messageType="client:BPELProcess1RequestMessage"/>
<variable
name="outputVariable"
messageType="client:BPELProcess1ResponseMessage"/>
</variables>
<sequence name="main">
<receive
name="receiveInput"
partnerLink="client"
portType="client:BPELProcess1"
operation="initiate"
variable="inputVariable" createInstance="yes"/>
<invoke
name="callbackClient"
partnerLink="client"
portType="client:BPELProcess1Callback"
operation="onResult"
inputVariable="outputVariable"/>
</sequence>
</process>

The differences between a synchronous and asynchronous process lie in the steps of invoke callback vs. reply difference to return the response. In a synchronous process, the way a reply message is handed back is through a reply. The asynchronous process invokes a callback method to hand back the reply message.

<process … namespace definitions etc … >
<partnerLinks>
<partnerLink name="client"
partnerLinkType="client:BPELProcess3"
myRole="BPELProcess3Provider"/>
</partnerLinks>
<variables>
<variable name="inputVariable"
messageType="client:BPELProcess3RequestMessage"/>
<variable name="outputVariable"
messageType="client:BPELProcess3ResponseMessage"/>
</variables>
<sequence name="main">
<receive name="receiveInput"
partnerLink="client"
portType="client:BPELProcess3"
operation="process"
variable="inputVariable"
createInstance="yes"/>
<reply name="replyOutput"
partnerLink="client"
portType="client:BPELProcess3"
operation="process"
variable="outputVariable"/>
</sequence>
</process>
As shown in the .bpel xml examples, receive, invoke and reply refer to a portType and a partnerLink attribute. These are specified in the .wsdl and also show some differences.
<portType name="BPELProcess1">
<operation name="initiate">
<input message="client:BPELProcess1RequestMessage"/>
</operation>
</portType>
<portType name="BPELProcess1Callback">
<operation name="onResult">
<input message="client:BPELProcess1ResponseMessage"/>
</operation>
</portType>

<plnk:partnerLinkType name="BPELProcess1">
<plnk:role name="BPELProcess1Provider">
<plnk:portType name="client:BPELProcess1"/>
</plnk:role>
<plnk:role name="BPELProcess1Requester">
<plnk:portType name="client:BPELProcess1Callback"/>
</plnk:role>
An asynchronous process specifies two portTypes, each with its own variable. Also it specifies two partnerLinkTypes, because it uses the same client partnerlink to receive from and invoke to (the callback). A synchronous process only specifies one portType holding both the input aswell as the output variable. It requires just one definition of the client partnerlink, because it doesn’t need to be invoked separately. blok

There is also a difference in the operation names (ie. Initiate, onResult and process). Though these are just labels that are referred to, it is good practice to actually rename the to the labels as shown in the default generated code, when changing from async to sync (and vise versa). This makes the xml code better understandable later on.

Summary

In your Asynchronous BPEL process diagram:
  1. Remove the Invoke process step from the diagram
  2. Drag a Reply process step in that place
  3. Connect the Reply process step to the client partnerlink (on the left lane)
  4. In the Edit reply dialog change the name to replyOutput and click OK
  5. Ignore the yellow exclamation mark for now
Now go to the source view of the .bpel file (and auto indent xml):
  1. Within the sequence element find the receive and reply elements
  2. For both of them, set the operation attribute’s value to process
  3. To the reply element, add the attribute variable and assign as value the name of the output variable, by default this is outputVariable.
Open the .wsdl file in source view (and auto indent xml):
  1. Find the two portType definitions
  2. From the one with operation onResult and name Callback prefixed with your service name, copy the input element and paste it after the input element of the first portType (named your service name)
  3. Rename the element you just copy/pasted from input to output
  4. In the current portType, set the value for operation name to process
  5. Remove the element (including its child elements!) from which you copied the input element (the one that’s called Callback prefixed with the name of your process)
  6. Remove the partnerLink role element - plnk:role - (including its child elements!) that has a portType name equal to the earlier removed portType .
Now go back to your .bpel file and open it in diagram view. The yellow exclamation mark should now be gone. If not, open the Reply process step and click the Apply button. Recompile your project and deploy it.

Friday, March 16, 2007

Tuning BPEL with JVMStat

Since Java version 1.4 a nice tool is available to monitor the behavior of the JVM. This can also be applied on BPEL. While BPEL is running on top of the JVM. The tool is called JVMstat and is available via the Sun website.

It works as follows. On the application server a daemon program must be run. This program is collecting information from the running JVM's. Via a visual tool, supplied with JVMStat, the behavior of the JVM is shown in a graphical way.

We assume that the JVMStat daemon is running on your application server, on which SOA Suite 10.1.3 is running, and the JVMStat visual tool running from your workstation. This is shown in the following diagram.


Download JVMStat from the the Sun website, unzip the file into a directory on your workstation and copy the zip file to your server and unzip it there as well.

Create a policy file on the server. This file is needed to set the appropriate rights for JMVStat. Create a file named "jstatd.policy". The content of the file must be:

grant codebase "file:$ORACLE_HOME/jdk/lib/tools.jar"
{

permission java.security.AllPermission;
};

Replace $ORACLE_HOME with the full directory path.

On the server you can start the daemon process.

jstatd -J-Djava.security.policy=jstatd.policy

Note that the daemon process is using the policy file, we just created.

Now you can start the visual user interface. This is done by starting the program 'visualgc.cmd' on the workstation. Therefore you must known the process-id of the JVM on which the SOA Suite is running. Use, assuming you run a unix environment, the 'ps -ef | grep java' command to found the process id.

Start the visual tool as follows:

visualgc.cmd @

For example:

visualgc.cmd 3219@linuxmachine.local.site

Monday, March 05, 2007

Delete BPEL instances

Running a production environment generates a huge amount of BPEL instances. Unless you have specified that you do not use dehydration :-).

It is possible to purge the instances all at once, as described in the article here (It also describes how to reclaim your space). But this purges all the instances. This is nice during development. But in a production environment you want to have a controlled way. A nice way to do this is via good-old PLSQL. Use the package COLLAXA in the ORABPEL schema.

This package has some nice methods to call:

procedure delete_txs
Deletes all the transactions that belong to a particular cube instance.

procedure delete_ci
Deletes a cube instance and all rows in other Collaxa tables that reference the cube instance. Since we don't have referential integrity on the tables (for performance reasons), we need this method to help clean up the database easily.

You can make a query to select the BPEL instances to delete and call the package:

create or replace
PROCEDURE purge_instances
(
p_domain IN VARCHAR2 DEFAULT '%'
, p_process_name IN VARCHAR2 DEFAULT '%'
, p_revision IN VARCHAR2 DEFAULT '%'
, p_older_than IN NUMBER DEFAULT 999
)
IS
CURSOR c
(
b_domain IN VARCHAR2
, b_process_name IN VARCHAR2
, b_revision IN VARCHAR2
, b_older_than IN VARCHAR2
)
IS
SELECT
cie.cikey cikey
, dmn.domain_id domain_id
, cie.process_id process_id
, cie.revision_tag revision_tag
, cie.modify_date modify_date
, cie.domain_ref domain_ref
FROM
cube_instance cie
, domain dmn
WHERE cie.domain_ref = dmn.domain_ref
--
-- the name of the domain
AND dmn.domain_id LIKE b_domain
--
-- code 5 means completed
AND cie.modify_date < TRUNC(sysdate)-b_older_than
--
AND cie.process_id LIKE b_process_name
AND cie.revision_tag LIKE b_revision;
BEGIN
FOR r in c
(
p_domain
, p_process_name
, p_revision
, p_older_than
)
LOOP
DBMS_OUTPUT.PUT_LINE
(
'Purge '||r.process_id||'('||r.revision_tag||')'||
' at '||to_char(r.modify_date, 'YYYY-MM-DD HH24:MI:SS')
);
collaxa.DELETE_CI(r.cikey);
--
delete from wftask wfn where wfn.instanceid = r.cikey;
--
END LOOP;
--
-- delete invoke calls
-- invoked messages
DELETE FROM invoke_message_bin imn
WHERE EXISTS
(
SELECT 1
FROM invoke_message ime
, domain dmn
WHERE ime.message_guid = imn.message_guid
AND ime.domain_ref = dmn.domain_ref
AND dmn.domain_id LIKE p_domain
AND ime.state > 1
AND ime.process_id LIKE p_process_name
AND ime.revision_tag LIKE p_revision
AND ime.receive_date < TRUNC(sysdate)-p_older_than
);
--
DELETE FROM invoke_message ime
WHERE ime.domain_ref in
(
SELECT dmn.DOMAIN_REF
from domain dmn
WHERE dmn.domain_id LIKE p_domain
)
AND ime.state > 1
AND ime.process_id LIKE p_process_name
AND ime.revision_tag LIKE p_revision
AND ime.receive_date < TRUNC(sysdate)-p_older_than;
--
DBMS_OUTPUT.PUT_LINE ('-> #invoke msg '||SQL%ROWCOUNT);
--
--
-- delete callback calls
DELETE FROM dlv_message_bin dmb
WHERE EXISTS
(
SELECT 1
FROM dlv_message dme
, domain dmn
WHERE dme.message_guid = dmb.message_guid
AND dme.domain_ref = dmn.domain_ref
AND dmn.domain_id LIKE p_domain
AND dme.state > 1
AND dme.process_id LIKE p_process_name
AND dme.revision_tag LIKE p_revision
AND dme.receive_date < TRUNC(sysdate)-p_older_than
);
--
DELETE FROM dlv_message dme
WHERE dme.domain_ref IN
(
SELECT dmn.DOMAIN_REF
from domain dmn
WHERE dmn.domain_id LIKE p_domain
)
AND dme.state > 1
AND dme.process_id LIKE p_process_name
AND dme.revision_tag LIKE p_revision
AND dme.receive_date < TRUNC(sysdate)-p_older_than;
--
DBMS_OUTPUT.PUT_LINE ('-> #callback msg '||SQL%ROWCOUNT);
END;
/

Calling the Operating System (OS) from BPEL

Sometimes you would like to call a script on the operating system to perform some complex tasks that are not possible to do in BPEL. This is often seen in Unix environments, when you want to call some scripts to run batch program for example. The following code is an example that shows how to call the OS. Note that the 'command' contains the full path to the executable script.

<bpelx:exec name="CallOS"
language="Java" version="1.4">
<![CDATA[
Element inVarElem = (Element)getVariableData
( "inputVariable"
, "payload"
, "/CallOSRequest/client:command");
String inVar = inVarElem.getNodeValue();
String command = inVar;
String result;
InputStreamReader isr;
InputStream isForProcess;
String isResult;

try
{
Runtime myProcessRuntime = Runtime.getRuntime();
Process process = myProcessRuntime.exec(command);
int exitVal = process.waitFor();
isResult = new String();

if (exitVal > 0)
{
isForProcess = process.getErrorStream();
}
else
{
isForProcess = process.getInputStream();
}
isr = new InputStreamReader(isForProcess);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ( (line = br.readLine()) != null)
{
isResult = isResult + line;
}

addAuditTrailEntry("Input is: " + command);
addAuditTrailEntry("Output is: " + isResult);
result = "" + exitVal;
addAuditTrailEntry("Exit status: " + result);

setVariableData(
"outputVariable"
, "payload"
, "/client:CallOSResponse/client:result"
, result);

System.out.println("Executed (Input: " + inVar + ")");
}
catch (Exception ex)
{
ex.printStackTrace();
}]]>
</bpelx:exec>

Friday, February 16, 2007

Delete bulk BPEL instances

It can take a while to purge the BPEL instances from the dehydration store. It can be done faster, if you would like. The following step is usefull in a developement environement. First stop the BPEL instance via Enterprise manager.

BTW: If you do not want a bulk delete, but instance by instance for a particular date and domain and revision, look here.

Then in sqlplus orabpel/password (note: 10.1.3):
truncate table cube_instance;
truncate table cube_scope;
truncate table work_item;
truncate table wi_exception;
truncate table document_ci_ref;
truncate table document_dlv_msg_ref;
truncate table scope_activation;
truncate table dlv_subscription;
truncate table audit_trail;
truncate table audit_details;
truncate table sync_trail;
truncate table sync_store;
truncate table dlv_message;
truncate table invoke_message;
truncate table ci_indexes;

alter table cube_instance deallocate unused;
alter table cube_scope deallocate unused;
alter table work_item deallocate unused;
alter table wi_exception deallocate unused;
alter table document_ci_ref deallocate unused;
alter table document_dlv_msg_ref deallocate unused;
alter table scope_activation deallocate unused;
alter table dlv_subscription deallocate unused;
alter table audit_trail deallocate unused;
alter table audit_details deallocate unused;
alter table sync_trail deallocate unused;
alter table sync_store deallocate unused;
alter table dlv_message deallocate unused;
alter table invoke_message deallocate unused;
alter table ci_indexes deallocate unused;

alter table cube_scope enable row movement;
alter table cube_scope shrink space compact;
alter table cube_scope shrink space;
alter table cube_scope disable row movement;

alter table cube_instance enable row movement;
alter table cube_instance shrink space compact;
alter table cube_instance shrink space;
alter table cube_instance disable row movement;

exec dbms_utility.analyze_schema('ORABPEL', 'Compute');
Then in sqlplus orabpel/password (note: 10.1.2.0.2)
truncate table cube_instance;
truncate table cube_scope;
truncate table work_item;
truncate table wi_exception;
truncate table document;
truncate table scope_activation;
truncate table dlv_subscription;
truncate table audit_trail;
truncate table audit_details;
truncate table sync_trail;
truncate table sync_store;
truncate table tx_inferior;
truncate table tx_superior;
truncate table dlv_message;
truncate table dlv_message_bin;
truncate table invoke_message;
truncate table invoke_message_bin;

alter table cube_instance deallocate unused;
alter table cube_scope deallocate unused;
alter table work_item deallocate unused;
alter table wi_exception deallocate unused;
alter table document deallocate unused;
alter table scope_activation deallocate unused;
alter table dlv_subscription deallocate unused;
alter table audit_trail deallocate unused;
alter table audit_details deallocate unused;
alter table sync_trail deallocate unused;
alter table sync_store deallocate unused;
alter table tx_inferior deallocate unused;
alter table tx_superior deallocate unused;
alter table dlv_message deallocate unused;
alter table dlv_message_bin deallocate unused;
alter table invoke_message deallocate unused;
alter table invoke_message_bin deallocate unused;

alter table cube_scope enable row movement;
alter table cube_scope shrink space compact;
alter table cube_scope shrink space;
alter table cube_scope disable row movement;

alter table cube_instance enable row movement;
alter table cube_instance shrink space compact;
alter table cube_instance shrink space;
alter table cube_instance disable row movement;

exec dbms_utility.analyze_schema('ORABPEL', 'Compute');

Characterset conversion

Using the SOA Suite with the DBAdapter, even for Oracle EBunisses Suite (EBS), you must be ware of your character set you are using. The application server is running in Java and using XML, so it uses by default UTF-8.

If your database is configured not for UTF-8, it will convert the incoming payload to the character set of the database. Nine-out-of-ten it will run without any errors. But using special characters you could get errors when you insert data in the database.

This issue can be solved by using a PL/SQL function to convert the data from on characterset to another one.
PL/SQL using implicit the database character set. Using 'CONVERT()' function.
  • CONVERT(string, to-characterset, from-characterset);
Example:

SELECT CONVERT('Ä Ê Í Ó Ø A B C D E ', 'UTF8', 'WE8ISO8859P1') FROM DUAL;

Click here for more information in this function:

Wednesday, February 07, 2007

Migrate a monolithic application to SOA

More and more IT and business departments see the advantages of using SOA to make the business more efficient, adding more flexibility in their organisation, resulting in lower cost, thus making more profit. This can be in real money or in improvement of the employability or more satisfaction to the customer.

But most of the companies have already build and using their back-office systems. They run their business for several years and using these back-office applications. These applications are build or have evoluted into a monolithic application using one or more data sources and complex datamodels. These applications are build using technology that was state of the art during these days. But now it is hard to add SOA to these environments.

The Oracle SOA suite can help you to add SOA functionality to your back-office applications to start to migrate the monolithic application into an SOA application.

Type of monolithic applications
If we take a look in the Oracle world, there are various customers using their current applications and are happy with that. From business perspective they periodically add functionality to the application. But how longer they stay on their technology platform, it gets harder to implement additional functionality. The market is continuously moving forward, from business point as well as from technology point.

We define the following customers:
  • Oracle Forms and Oracle Reports.
  • PL/SQL based applications.
  • Applications with high interfacing.
  • Applications based on batch processing.
Oracle Forms and Oracle Reports.
Existing applications based on Forms and Reports can be enabled for SOA. There are some technical implications on this. Forms, and Reports support Java client side code. But the version of the Forms/Reports determines which Java can be accessed. An upgrade of the Forms/Reports environment can be a step in the migration to SOA. If the customer is already using Web based Forms/Reports, it will benefit of this, the migration can be carried more efficiently.

PL/SQL based applications.
Applications based on PL/SQL are completely running in the Oracle Database. To enable these applications for SOA, it depends of the version of the database the customer is using. The higher the version of the Oracle Database, the most benefit it will get to implement SOA. Customers on Oracle Database 9.0 or lower should think about migrating to a higher version.


Applications with high interfacing.
More and more applications are implemented in organizations for different reasons. By default it will have impact on the existing applications, because the application will communicate to other applications. This is implemented in various ways:
  1. Custom; end-user is typing data into the system.
  2. File based; files are read or written to a (remote)file system.
  3. Database schema; the application is reading/writing data of various schema's.
  4. Databases; the application is reading/writing data of various databases (via database links).
  5. Queues; the application is using queues to communication with the outside world.
This type of application will benefit most of SOA in short-term and is easy to implement. It will create a win-win situation for the IT-department as well the Business department.

Applications based on batch processing.
Applications are available to the end-users but they are using batch-processing to execute the business rules. Mostly this is done overnight. This is typically grown historically because the software and/or hardware were not able to perform these rules directly. Implementing SOA for these type of applications generates benefit to the end-user. The whole process is control and can be seen 'live'.

Project Approach
To migrate the monolithic application into a SOA environment we define some main points:
  • Use an evolution approach, no "big-bang".
  • Reuse what is good in monolithic environment.
  • The monolithic environment will not disappear (yet).
To prepare the organization for being SOA enabled execute the following steps:
  • Organize a meeting with IT and Business departments together for a SOA awerness session. What are the benefits for the organizations, the pitfalls, the quick-wins on short term and set the long-term approach. The result is a document/presentation how the SOA environment fits in the organization and how the organization can benefit it from, on short-term as well on long-term.
  • Together with IT start an analysis phase for creating the new technical architecture for the upcoming SOA environment. This architecture must fit in the current environment of the monolithic applications to enable the evolution approach. The result of this phase is a technical design of the SOA environment that fits in the current environment. The design describes the hardware components as well as the user components.
  • Based on the first step, the quick-wins of SOA for the organization is implemented. This means that the Oracle SOA suite is begin implemented. The quick-wins are analyzed and designed and implemented in the SOA environment.
  • Parallel to, or after the quick-win step a start is made with the analysis of the long-term benefits of SOA. This phase is crucial for SOA and the monolithic applications. Decisions are made which of the components/functionality/code is being reused or redesigned and when this is done. The result of this steps are a project plan, analysis/design document of the new SOA environment.
  • The last step is to implement the new SOA functionality based on on the project plan and the analysis documents.

Sunday, January 21, 2007

How to install and use the BpelConsole undeploy extension

Thanks to Michel Christianen for given me the input for this article.

Note: While this article is changing code in the original files of the product, there is no guarantee of support provided.

During development you deploy and undeploy process to the BPEL PM. Sometimes you want undeploy more than one process. This article describes a solutions that adds an option in the BPEL console to undeploy all the BPEL processes at onces.

Make a copy the of the files; bulkUpdateProcess.jsp and doBulkUpdateProcess.jsp.
These files are located in the directory

$ORACLE_HOME/j2ee/oc4j_soa/applications/orabpel/console

Add the following code in the the file bulkUpdateProcess.jsp.
Add the code after the label:

<label for="processStateOff">
<%= I18nUtil.getString("off", locale)%>
</label>



<p>
<b>Process Undeploy:</b><br>
Using this option all the selected processes
can be undeployed at once.
<br> The default for undeployment is <i><b>none
</b></i>, but you can enable this bulk undeployment
<br> by setting this value to <i><b>all
</b></i>.<br> Note that if this option is selected,
the other bulk update options (Process Lifecycle/State)
are ignored. <p>
<input type="radio" id="processDeployOff"
name="processDeploy" value="none" checked>
<label for="processDeployOff">None</label>
<input type="radio" id="processDeploy"
name="processDeploy" value="all">
<label for="processDeploy">All </label>

Replace the the code in the the file dobulkUpdateProcess.jsp.
The code can be found at the end of the article.

When you navigate to the BpelConsole after you have installed the undeploy extension files, you can now use the new feature. Select the BpelProcesses you want to undeploy or use the ‘Check_all’ option and press the ‘Bulk update’ button.


Now you see at the bottom of the page the new ‘Process Undeploy’ option which you can use to undeploy all the selected processes.

The doBulkUpdateProcess.jsp is here:

<%@page contentType="text/html; charset=UTF-8" %>
<%@page errorPage="reportError.jsp" %>
<%@page import="com.oracle.bpel.client.*" %>
<%@page import="com.oracle.bpel.client.ServerException" %>
<%@page import="com.oracle.bpel.client.util.*" %>
<%@page import="com.collaxa.cube.util.BuildInfo" %>
<%@page import="com.collaxa.cube.fe.util.ServletUtils" %>
<%@page import="com.collaxa.common.util.*" %>
<%@page import="com.collaxa.cube.rm.suitcase.*" %>
<%@page import="java.text.*" %>
<%@page import="java.util.*" %>
<%@include file="initI18n.jspf" %>

<%
int n0 = 0, n1 = 0;
Locator l = ServletUtils.getLocatorWithoutUrlRewrite(request, response);
request.setAttribute( "tab", "BPEL Processes" );

IBPELDomainHandle domain = l.lookupDomain();

String processIds = request.getParameter( "processIds" );
ArrayList list0 = CXStringUtils.split( processIds, ' ' );
n0 = list0.size();
ArrayList list1 = new ArrayList();
Iterator li = list0.iterator();

try {
String undeployMode = request.getParameter( "processDeploy" );
if (undeployMode.equalsIgnoreCase("all")) {
for( int size = list0.size(); size > 0; size-- )
{
list1.clear();
CXStringUtils.split( (String) li.next(), '~', list1 );
BPELProcessId pid = new BPELProcessId(domain.getDomainId(),
(String)list1.get(0), (String)list1.get(1));
domain.undeployProcess(pid);
n1++;
}
}
else {
int lifecycle = -1;
String processMode = request.getParameter( "processMode" );
if( ! CXStringUtils.isEmpty( processMode ) )
{
lifecycle = "open".equalsIgnoreCase( processMode )
? IBPELProcessConstants.LIFECYCLE_ACTIVE
: IBPELProcessConstants.LIFECYCLE_RETIRED;
}
int state = -1;
String processState = request.getParameter( "processState" );
if( ! CXStringUtils.isEmpty( processState ) )
{
state = "on".equalsIgnoreCase( processState )
? IBPELProcessConstants.STATE_ON
: IBPELProcessConstants.STATE_OFF;
}
for( int size = list0.size(); size > 0; size-- )
{
list1.clear();
CXStringUtils.split( (String) li.next(), '~', list1 );
BPELProcessHandle process = (BPELProcessHandle)
l.lookupProcess( (String) list1.get( 0 ),
(String) list1.get( 1 ) );
BPELProcessMetaData ri = process.getMetaData();

int i = 0;
if( lifecycle != -1 )
{
if( ( ri.isLifecycleActive() &&
lifecycle == IBPELProcessConstants.LIFECYCLE_RETIRED ) ||
( ! ri.isLifecycleActive() &&
lifecycle == IBPELProcessConstants.LIFECYCLE_ACTIVE ) )

{
ri.setLifecycle( lifecycle );
i++;
}
}
if( state != -1 )
{
if( ( ri.isStateOn() &&
state == IBPELProcessConstants.STATE_OFF ) ||
( ! ri.isStateOn() &&
state == IBPELProcessConstants.STATE_ON ) )
{
ri.setState( state );
i++;
}
}
if( i > 0 )
process.updateMetaData( ri );

n1++;
}
}
}
catch( Exception e )
{
e.printStackTrace();
}
%>

<html lang="en-US">
<style type="text/css">
<!--
.title {
font-size: 16px;
font-family: Verdana, Arial, Helvetica, sans-serif;
}
.note {
font-size: 12px;
font-family: Verdana, Arial, Helvetica, sans-serif;
}
-->
</style>
<head>
<title><%= I18nUtil.getString("title", BuildInfo.getVersion(), locale)%></title>
<jsp:include page="ngIncludes.jsp" />
</head>
<body bgcolor="#FFFFFF">
<form action="processes.jsp" method="get">

<table summary="" class="DefaultTable" cellspacing="0" cellpadding="0">
<tr height="20">
<td class="TabPane" colspan="2">
<jsp:include page="ngTabs.jsp" />
</td>
</tr>
<tr>
<td colspan="2" class="IViewerInstanceInfoPane">
<table summary="" class="DefaultTable" cellpadding="0" cellspacing="0">
<tr>
<td valign="middle" style="padding-left:15px"> </td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="IViewerTabControl">
<div class="IViewerTabPadding"><img src="images/iviewer/blank.gif" alt="" border="0" width="1" /></div>
</td>
<td class="IViewerRightPane">

<table summary="" class="DefaultTable" cellspacing="0" cellpadding="0" width="100%" height="100%">
<tr>
<td colspan="2" class="SViewerToolViewWrapper">
<div align="center" style="padding:10px">
<table width="80%" align="center" border="0" cellspacing="10" cellpadding="0" bgcolor="#f0f0f0">
<tr>
<td>
<b><label class="title"><%= I18nUtil.getString("bulk_update_processes_complete", locale)%></label></b>
<p>
<label class="note">
<%= n1 == 1 ? I18nUtil.getString("one_process_updated",
Integer.toString(n1), l.getDomainId(), locale) :
I18nUtil.getString("many_process_updated",
Integer.toString(n1), l.getDomainId(), locale) %>
<%
if( n0 > 0 && n0 != n1 )
{
String mesg = "";
if(n0 == 1 && ((n1 - n0) == 1) )
mesg = I18nUtil.getString("one_process_one_error",
Integer.toString(n0), Integer.toString((n1 - n0)), locale);
if(n0 != 1 && ((n1 - n0) == 1) )
mesg = I18nUtil.getString("many_process_one_error",
Integer.toString(n0), Integer.toString((n1 - n0)), locale);
if(n0 == 1 && ((n1 - n0) != 1) )
mesg = I18nUtil.getString("one_process_many_error",
Integer.toString(n0), Integer.toString((n1 - n0)), locale);
if(n0 != 1 && ((n1 - n0) != 1) )
mesg = I18nUtil.getString("many_process_many_error",
Integer.toString(n0), Integer.toString((n1 - n0)), locale);
%>
<%= mesg%>
<%
}
%>
</label>
<p>
<div style="text-align:right">
<input type="submit" name="home" value='<%= I18nUtil.getString("back_to_processes", locale)%>' />
</div>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td class="FooterPane" colspan="2">
<jsp:include page="ngFooter.jsp" />
</td>
</tr>
</table>
</form>
</body>
</html>