Tuesday, December 30, 2008

How to Access BPEL Variables in a Java Embed Activity

In your embedded Java you can use:

javaVar = getVariableData("BPEL_Variable_Name");

and

setVariableData("BPEL_Variable_Name", javaVar);

Obviously, the types need to match up!

Also useful for debugging/logging purposes is:

addAuditTrailEntry("My Message Goes Here:",optionalJavaVarValueToLog);

Wednesday, October 29, 2008

How to Create A Multiple Entry Point BPEL Process Using Pick


In RIA development we want frequently want to consume web services. From a organizational point of view we typically want related methods to be provided by the same provider. If the web service is being provided via a BPEL process, how can we do that?

The answer is to use a BPEL process with a Pick activity.

Steps:

1) Create a normal synchronous BPEL process. Let the wizard create it's default input and output variables, as these won't be used.

2) Drop your custom input and output XSD files into the /bpel directory

3) Delete the the client partner link. When you do you'll be asked if you want to delete the Partner link -- answer Yes. You'll also be asked if you want to delete the WSDL file -- answer No to this.

4) Drop a Pick activity between the existing Receive and Reply activities. Now delete the Receive and Reply activities.

5) Edit the project WSDL file:
a) In the types section, delete the imports for the default XSD file, and add imports for your custom XSD files
b) Delete the existing messages and create a message for each request and response message you will be defining
c) Delete the existing portType definition. Add a new one, and under the portType add a new operation for each method you are implementing in this BPEL process via the Pick
d) Change the existing partnerLinkType to use your new portType

6) You will need to create an onMessage branch in the Pick for each operation being implemented:
a) Double click the message icon and select the partner link to associate with this message. On the first message you will need to create a new partner link.
b) Create the new input message variable, selecting the desired message type.
c) Select the appropriate operation type. This will bind the partner link message to this message branch.

7) You will need to add a sequence (or a scope/sequence combination) to each message branch and provide the rest of the activities within it.

8) If you are returning multiple return types (most likely), each branch will need a Reply activity at then end of it to return the output to the client.

Monday, October 27, 2008

Enable/Unlock OID User Account Using Java API

How to programmatically enable and/or unlock a user's OID account using the Java API? Let's take a step by step look:

First get a reference to the directory context:

ctx = oracle.ldap.util.jndi.ConnectionUtil.getDefaultDirCtx(ldapHost, ldapPort, ldapUserCN, ldapCred );

ldapUserCN will most likely be something like "cn=orcladmin" and ldapCred will be the password for that CN.

Next, we build an attribute set that we are going to update. This will do the account enable:

attrSet = new javax.naming.directory.BasicAttributes();
attrSet.put("orclIsEnabled", "ENABLED");
ctx.modifyAttributes(userDN, javax.naming.directory.DirContext.REPLACE_ATTRIBUTE, attrSet);

userDN here will be the full DN of the user we are modifying. We can also force a new password by putting the attribute "userpassword" in the attribute set and giving it the new password as its value.

Finally, we will do the unlock:

attrSet = new javax.naming.directory.BasicAttributes();
attrSet.put("orclpwdaccountunlock","1");
ctx.modifyAttributes(userDN, javax.naming.directory.DirContext.ADD_ATTRIBUTE, attrSet);

You should note that if you are modifying the user password programmatically, the password must adhere to all of the normal password rules set up for your OID instance.

The code can throw javax.naming.directory.InvalidAttributeValueException , which can be caused by a password not adhering to the OID policies.

Friday, September 12, 2008

Worklist Application Issue When Switching to OID Security Provider

In the Oracle 10.1.3.3.x BPEL server there is an issue with tasks disappearing from everyone's task list after the server has been switched to use OID as the security provider.

The issue is that along with user ID's, the worklist application maintains the user's identity context in several of the workflow data base tables, including: WFTASK, WFTASKHISTORY, WFUSERPREFERENCE, WFUSERTASKVIEW, WFUSERTASKVIEWGRANT, WFUSERVACATION, and WFNOTIFICATIONSTATUS. The column in each of these tables is IDENTITYCONTEXT

Oracle is working an active bug for the issue where the migration scripts do not change the identity context columns, but until then you may want to think about manually updating the column values. This is not recommended by Oracle support, but was the only way I found to get existing tasks to show in user's task lists and task history again....

Wednesday, September 10, 2008

Switch OC4J from OID back to File Based Security

The switch from file based security to OID (or LDAP) based security is well documented by Oracle, but what if you ever need to switch back?

The obvious thing to do it do go into Enterprise Manager and change all of the providers back to "File Based Security". This will get you close, but not quite there.

The next thing you need to do is to roll back the changes to the jazn.xml files that were made for each container during the original switch to OID. Hopefully, you saved a copy of these! Don't forget to roll back jazn.xml for each container.

The last thing, if you are using BPEL, is to check the is_config.xml file for the BPEL container. This file is in $SOA_HOME/bpel/system/services/config. If you didn't save a copy of this file, there should be a clean one present in is_config.xml.BPM.

Finally, restart the application serrver and you should be back to file based security.

Wednesday, July 30, 2008

Find the OPMN Port for Java BPEL API Calls

Frequently, you'll need the OPMN request port for doing Java BPEL API calls.

You can find this value by looking at the opmn.xml file on the mid tier application server. It is in the $ORACLE_SOA_HOME/opmn/conf directory. Around the 5th line down in the "port" tag, you'll need to use the port number specified in the "request" attribute.

Wednesday, July 16, 2008

Add attachment to BPEL Human Task at creation

Consider the sample BPEL flow below, which contains a Human Task activity. It may be useful at times to have BPEL attach data to the task as an attachment file. How can this be done?




















We can do this by expanding the human task activity and providing some custom initialization code in the first, the AssignTaskAttributes, assignment section.




By adding four additional Copy directives to the existing assignment block, we can effectively cause the file attachment to be created:


<copy>
<from>
<attachment xmlns="http://xmlns.oracle.com/bpel/workflow/task">
<name/>
<mimeType/>
<content/>
</attachment>
</from>
<to variable="initiateTaskInput" part="payload"
query="/taskservice:initiateTask/task:task/task:attachment"/>
</copy>

<copy>
<from expression="string('text/plain')"/>
<to variable="initiateTaskInput" part="payload"
query="/taskservice:initiateTask/task:task/task:attachment[1]/task:mimeType"/>
</copy>

<copy>
<from expression="string('Test.txt')"/>
<to variable="initiateTaskInput" part="payload"
query="/taskservice:initiateTask/task:task/task:attachment[1]/task:name"/>
</copy>

<copy>
<from expression="string('Some string of text content here...')"/>
<to variable="initiateTaskInput" part="payload"
query="/taskservice:initiateTask/task:task/task:attachment[1]/task:content"/>
</copy>


The first copy block, creates a new attachment element and adds to the task. The next three copies initialize the properties of that attachment including the mime type, file name, and content.

In the above example we will have attached a simple text document with the name of Test.txt to the human task. Mime type can be any type desired, one of the more useful being application/octet-stream. Using that type I will show in my next article how to send a file attachment from a JSP/Servlet to the BPEL process and have it attached to the Human Task.

Monday, July 14, 2008

Invoke BPEL Process with Java API

This is a frequently asked question on the Oracle BPEL Forums, so I thought I would address it here.

import com.oracle.bpel.client.Locator;

import com.oracle.bpel.client.NormalizedMessage;
import com.oracle.bpel.client.delivery.IDeliveryService;

public class InvokeBpel {

public static void main(String args[]) {
Properties props = new java.util.Properties();
Locator locator = null;
IDeliveryService svc = null;
NormalizedMessage msg = null;

try {

// load the propertiess object with the server info
props.put("orabpel.platform", "ias_10g");
props.put("java.naming.factory.initial",
"com.evermind.server.rmi.RMIInitialContextFactory");
props.put("java.naming.provider.url",
"opmn:ormi://ibp103.mascocs.com:6012:OC4J_BPEL/orabpel");
props.put("java.naming.security.principal", "oc4jadmin");
props.put("java.naming.security.credentials", "test123");

// get the reference to the locator object
locator = new Locator("default", "test123", props);

// get the service provider
svc = (IDeliveryService)locator.lookupService(IDeliveryService.SERVICE_NAME);

// create a normalized message with our xml string as the payload
String xmlString = "Your valid XML goes here";

msg = new NormalizedMessage();
msg.addPart("payload" , xmlString);

// async request so we post/initiate it
svc.post("TestBPELProcess", "initiate", msg);

// for a sync request we would request/process it like so:
//
// resp = svc.request("TestBPELProcess", "process", msg);
//
// our resp would be the NormalizedMessage response from the server

} catch (Exception e) {
e.printStackTrace();
}

} // end of main()

} // end of class

Monday, April 28, 2008

Including Task History from Previous Task in Oracle BPEL Human Workflow


Oracle BPEL allows the use of Human Task process activities, in conjunction with the Oracle Worklist Application, to allow human interaction with BPEL processes.

Sometimes, it would be desirable to have two human flows that include the same information. Consider a purchase request -- such a request may have a management approval flow, and then a flow for the purchasing department to actually obtain the item. If any comments or attachments are added during the management flow, the purchasers will probably need to see them.

The advanced tab of the human task process has a check box for including the task history from a previous human task process. Unfortunately, as of this writing, JDeveloper (10.1.3.3) does not correctly generate the BPEL copy operations for the new process. Compiling the process will generate several (usually 2 or more) errors relating to invalid XPATH expressions.

The problem usually lies in the copy blocks just prior to or just after the invoke for the new process. For example, the following code might be generated:

<copy>
<from variable="reinitiateTaskResponseMessage" part="payload"
query="/taskservice:initiateTaskResponse/wfcommon:workflowContext"/>
<to variable="workflowContext" query="/wfcommon:workflowContext"/>
</copy>

The problem here lies in the fact that the query should be changed to look like:

<copy>
<from variable="reinitiateTaskResponseMessage" part="payload"
query="/taskservice:reinitiateTaskResponse/wfcommon:workflowContext"/>
<to variable="workflowContext" query="/wfcommon:workflowContext"/>
</copy>

Notice, that the only change required was from initiateTaskResponse to reinitiateTaskResponse. That will be true for all of the errors, and by simply inserting a 're' you can fix them all.

One final note is that its easier to pick these out using the source editor view than the graphical view.

Saturday, March 22, 2008

Programatically controlling the length of expiration/escalation on BPEL Human Task

By default Oracle BPEL lets you expire or escalate tasks on a pre-determined duration basis. But consider the situation where you want the task duration to be 8 working hours before expiration, and working hours are only the time between 8 am an 5 pm, Monday through Friday -- how can you do this?

The options in the standard task dialog don't really accommodate this, but you can work around it. You can provide a variable to the task that has this information. Here are the five basic steps to making this work:

1) Create a BPEL variable of type string. For this example I use "strExpirationMinutes". This will hold the number of minutes to wait before expiring a task.

2) In your human task definition, define a parameter of type string. For this example let's call it "ExpirationTime"

3) In your human task block, assign the value of strExpirationMinutes ( bpws:getVariableData('strExpirationMinutes') ) to the parameter ExpirationTime

4) In your human task definition, set the expiration/escalation policy to be "By Expression" and provide the XPath to reference the passed in parameter. For this example the XPath would be: /task:task/task:payload/task:ExpirationTime

5) Prior to the human task block in the BPEL flow assign a value to strExpirationMinutes of the form "PTxM" where x is the number of minutes before expiration. I typically do this via a embedded Java block.

Here is the Java code for our example:

String tmp = "PT";   
int iMins = 0;
int hrs8 = 60*8;
int hrs23 = 60*23;
int hrs24 = 60*24;

java.util.Calendar calNow = java.util.Calendar.getInstance();

int hours = calNow.get( java.util.Calendar.HOUR_OF_DAY );
int minutes = calNow.get( java.util.Calendar.MINUTE );
int dow = calNow.get( java.util.Calendar.DAY_OF_WEEK );

// if a M-T
if (dow>=2 && dow<=5) {
// if starting before 8 am - add 8 hours plus the interval between now and 8 am
if (hours<8) {
iMins = (60-minutes) + ( (8-hours-1)*60 )+ hrs8;

// if starting between 8 am and 9 am - just add 8 hours
} else if (hours==8 || ( hours==9 && minutes==0) ) {
iMins = hrs8;

// if starting between 9 am and 5 pm - just add 23 hours
} else if (hours>=9 && (hours<17 || (hours==17 && minutes==0)) ) {

iMins = hrs23;

// if starting after 5 pm - add 8 hours plus the interval between now and 8 am
} else {
iMins = (60-minutes) + ( (24-hours-1)*60 ) + hrs8 + hrs8;
}

// if Fri
} else if (dow==6) {
// if starting before 8 am - add 8 hours plus the interval between now and 8 am
if (hours<8) {
iMins = (60-minutes) + ( (8-hours-1)*60 )+ hrs8;

// if starting between 8 am and 9 am - just add 8 hours
} else if (hours==8 || ( hours==9 && minutes==0) ) {
iMins = hrs8;

// if starting between 9 am and 5 pm - add 23 hours plus the two we days
} else if (hours>=9 && (hours<17 || (hours==17 && minutes==0)) ) {

iMins = hrs23 + hrs24 + hrs24;

// if starting after 5 pm - add 8 hours duration plus the interval between
// now and 8 am saturday, plus the 2 we days
} else {
iMins = (60-minutes) + ( (24-hours-1)*60 ) + hrs8 + hrs8 + hrs24 + hrs24;
}

// if Sat
} else if (dow==7) {
// add 8 hrs duration, plus the time between now and midnight sat, plus
// all of sunday, plus 8 hrs for monday before 8 am
iMins = (60-minutes) + ( (24-hours-1)*60 ) + hrs8 + hrs8 + hrs24;

// if Sun
} else {
// add 8 hrs duration, plus the time between now and midnight sun,
plus
// 8 hrs for monday before 8 am
iMins = (60-minutes) + ( (24-hours-1)*60 ) + hrs8 + hrs8;
}

// finish build the time string
tmp = tmp + iMins + "M";

// save the string to bpel proc and audit
setVariableData("strExpirationMinutes", tmp);
addAuditTrailEntry("strExpirationMinutes:",tmp);

Programmatically determining BPEL manual recovery status

It's been a while since I've written an article, and I hope no one has been waiting all this time for part 2 of my BAM/BPEL alert article. I promise to complete that write up soon.

Today, however, I'd like to talk about an interesting problem I ran across this week. If anyone has experience with Oracle's BPEL product you know that sometimes BPEL processes can go to manual recovery. The two most common issues are: 1) an issue on the invoke of the process (BPEL server Out of Memory error for example), and 2) an issue with the callback on an asynchronous BPEL process.

BPEL process manager has a nice UI for looking at and managing these, but what if we need to be alerted when a process goes into one of these states? Well, BPEL PM doesn't have that capability, so we need to write our own. Another useful thing might be to always clear the processes, especially those that are in manual recovery for callback. Typically in that situation the callback failed, most often because the original calling process is no longer around to receive the callback.

In the rest of the article we talk about finding processes in both invoke and callback manual recovery. For both cases, it will be necessary to get a reference to the Locator object via the BPEL Java API. I talk about that in an earlier post, so I've assumed that you've read up on that before continuing.

Getting process manual recovery for inoke:

            String Buffer buf = new StringBuffer();

WhereCondition where = new WhereCondition(buf.append(SQLDefs.IM_state).append( " = " ).append(IDeliveryConstants.STATE_UNRESOLVED ).toString() );

IInvokeMetaData imd[] = locator.listInvokeMessages(where);

String ids[] = new String[imd.length];

// print out the partial process information
// for processes in manual recovery status on invoke
for (i = 0; i <>
{
System.out.println("ConversationId=" +
imd[i].getConversationId());
System.out.println("ProcessId=" +
imd[i].getProcessId());
System.out.println("State=" + imd[i].getState());

ids[i] = imd[i].getConversationId();
}

// if we wanted to automatically recover these processes
// we would uncomment the following line:
// locator.lookupDomain().recoverInvokeMessages(ids);

That's it! For callbacks the code flow is the exact same. Instead of IInvokeMetaData, we get an array of ICallbackMetaData using the locator.listCallbackMessages(where) method. One other slight change is the where clause itself -- for callbacks the where clause should be built as:

WhereCondition where = new WhereCondition(buf.append(SQLDefs.DM_state).append( " = " ).append(
IDeliveryConstants.TYPE_callback_soap ).toString() );

The last change for callbacks is how they are recovered -- locator.lookupDomain.recoverCallbackMessages(ids) will do the trick!

Using the API's above you can see how we could build a custom notification process or an automatic or work flow based recovery method that does not involve the actual BPEL PM.

Oracle BAM - Calling an external web service as an alert - Part 1 - BAM Configuration

Oracle's BAM tool is very useful not only for reporting on enterprise data, but also in taking action on certain events.

For instance, suppose you have a BAM object defined and other processes are interested in the fact that the BAM object has been populated with a new row. In the SOA world, there are many ways we could notify another process -- via a message queue or simply by calling a web service. It is the second technique that we will be discussing in this and a follow up article.

In my example I have a BPEL process that needs to be called every time my BAM data object has a new row added to it. BAM doesn't know anything about using the BPEL Java API, but it can call a web service via an external action hooked to an alert. We'll talk about the BPEL process in the next post -- the rest of this post will described how to set up the external action and alert in BAM.

Step 1 - Creating an External Action in BAM


The external action will define the actual call to the web service. External actions are created using the BAM Architect module.

1) Select 'Data Objects' from the architect drop down
2) Expand the 'System' folder and then click the 'Alert' folder
3) Click on the 'External Actions' data object link
4) If you select the 'Layout' link you'll see that an external action has five fields that must be filled in:
  1. Name - The name that will appear in the alert's dialog
  2. Description - A description of the action
  3. Library Name - The library that contains the action class
  4. Class Name - The class which implements the external action
  5. Argument - Argument to pass to the action class
5) Click the 'Contents' link and then the 'Edit Contents' button.
6) Click the 'Add' button to add a new row. The name and description fields are self-explanatory. The library name field should be set to 'Internal' and the class name field should be set to 'WebServiceCaller'. Finally the argument field needs to be set to 'URL=' followed by the complete endpoint URL to the web service -- for example:
'URL=http://myhost:myport/orabpel/mydomain/bpelprocessname/1.0,SOAPAction=process'
7) Verify everything and click 'Save' to save your new row

Note: Once you have defined your new external actions, you should restart the BAM Event Engine service.

Step 2 - Creating the Alert in BAM to Call the Action

The alert will set up the conditions under which our alert is called. Alerts are created using the BAM Architect module.

1) Select 'Alerts' from the architect drop down
2) Click the 'Create a New Alert' link
3) A new window will pop up, click the 'Create Rule' button
4) Give the rule a meaningful name in the 'Rule Name' field
5) Select the trigger event. For my example I want to call the web service everytime a row is added to a data object, so I would select 'When a data field changes in a data object'
6) Click the 'Selet data field' link
7) Pick the appropriate data object and data field.
8) By default, BAM will add a frequency constraint that will launch your rule no more than once every 5 seconds. You can change this frequency constraint to any number of minutes, hours, or seconds, or you can disable the constraint by unchecking the 'Constraint Enabled' box. Make sure that you uncheck the box if you need the alert to fire on every single event (BAM will warn you about this and ask you to click 'OK' if you want the constraint disabled).
9) Click the 'Next' button
10) You can add any time conditions if required and most importantly you can now select the action to perform. If you restarted the event service after you created you external action, you should now see your external action as an option at the end of the list. Select it.
11) Click 'OK'. Your new alert will be created and appear in the alert list.

Note: You can enable and disable alerts, simply by checking or unchecking the 'Activate' box by the alert.

If you've filled in everything correctly, your alert should fire when you add a row to the data object that you selected. If you're reading this in anticipation of calling a BPEL process, here's an important point in advance of my next post -- BAM can only call synchronous BPEL processes.

JNDI URL in High Availability Environments

In high availability environments you'll want to specify more than one source for your JNDI provider. How can you do that?

With a simple URL change you can switch from only specifying one provider:

jndiProviderURL = "ormi://localhost/Service"

to a list of nodes which can serve as the provider:

jndiProviderURL = "opmn:ormi://host1:port1:oc4j/Service, opmn:ormi://host2:port2:oc4j/Service"

Debugging a failing BPEL process - How to force dehydration

Sometimes a failing BPEL process will fail without much trace, not even showing that an instance was ever created in Oracle process manager. In this case it may be useful to force dehydration to aid debugging.

You can try to force dehydration in your process by:

1) Adding a Java execution block to your process at the point you wish to dehydrate the process
2) Calling the checkpoint() method

You should not that this method should only be used for debugging purposes, and that future versions of Oracle BPEL may not support it.

Changing an Asynchronous Oracle BPEL process to be Synchronous

One of the top suggestions Oracle has for tuning BPEL processes is to make sure that processes that can be synchronous are. This is because synchronous processes can be considered transient within the BPEL engine -- and the BPEL engine has several tunable parameters for transient processes that determine if and when they are pushed to the dehydration store. Fewer dehydration trips means better performance.

An obvious question then becomes "I just created a bunch of BPEL processes and they are all asynchronous, do I have to recreate them?" The short answer is: NO!

If you take a look at an asynchronous process, you'll notice that the last step is typically a callback client, while for a synchronous process it is a reply. This is because the client of a synchronous process is blocking during the call and a simple reply response is made to that blocked client. An asynchronous process makes a callback to the non-blocking client using the partner link (although of using a different partnerLinkType).

To start modifying your process, open the process .bpel file in design mode using JDeveloper. Delete the callback client step at the end of the process, this will be an invoke block connected back to the client. Drag a new reply block to that space. Now connect the reply block to the client partner link. You should change the reply name to "replyOutput" or something similarly useful.

Next, we need to make some further changes to the process .bpel file, so switch to source view. Scroll down the file until you come to the sequence element. Find the receive and reply elements within the sequence and change the operation attribute value of each one to "process". You will also need to add variable attribute to the reply element. Set this to the value of the output variable - by default this would be "outputVariable". Sample receive and reply elements look like this:


<receive name="receiveInput" partnerLink="client"
portType="client:BPELProcess2" operation="process"
variable="inputVariable" createInstance="yes"/>


<reply name="replyOutput" partnerLink="client"
portType="client:BPELProcess2" operation="process"
variable="outputVariable"/>


For the last changes, you need to open up your process' .wsdl file in the source editor. The WSDL edits are a bit more involved so, follow closely....

First, find the two portType definitions. One of them, typically the second one, should have the name attribute set to something like <yourprocessname>Callback and the operation set to "onResult". Copy the input element and paste it under the existing input element in the first portType definition. Change the element you just copied from "input" to "output". Change the operation name of this portType to "process".

Going back to the Callback portType, delete the entire portType definition. If you'd rather you can simply comment it out.

Now find a the partnerLinkType element. You'll want to delete the plnk:role element within that has the same portType name attribute as the portType you just deleted. Make sure you remove the entire plnk:role element and not just the plnk:portType.

Here is an excerpt of my changed WSDL, with comments where I made changes:


<portType name="BPELProcess2">
<operation name="process">
<input message="client:BPELProcess2RequestMessage"/>
<!-- copied from old call back, change input to output -->
<output message="client:BPELProcess2ResponseMessage"/>
</operation>
</portType>

<!-- removed/comment out to make synchronous
<portType name="BPELProcess2Callback">
<operation name="onResult">
<input message="client:BPELProcess2ResponseMessage"/>
</operation>
</portType>
-->

<plnk:partnerLinkType name="BPELProcess2">
<plnk:role name="BPELProcess2Provider">
<plnk:portType name="client:BPELProcess2"/>
</plnk:role>

<!-- remove/comment out to make synchronous
<plnk:role name="BPELProcess2Requester">
<plnk:portType name="client:BPELProcess2Callback"/>
</plnk:role>
-->

</plnk:partnerLinkType>


You should now be able to save your changes and recompile the project -- see that was easy wasn't it?

Tips on the Oracle BPEL Java API - Part 2 - Using the Locator class to get a list of processes

In part 1, we saw how to use the Server class to connect to the BPEL server and get a list of BPEL domains configured on that server. The Server class is useful for performing administrative tasks on the BPEL server. If we want to perform process oriented tasks, we need to use the Locator class and it's methods.

First, you'll need to import several BPEL API classes:

import com.oracle.bpel.client.IBPELProcessHandle;
import com.oracle.bpel.client.Locator;

And, as in our discussion in part 1, next task is to configure a java.util.Properties object with the connection information for your BPEL server, as well as a String object containing the security credentials (password):

Properties props = new java.util.Properties();
props.put("orabpel.platform", "ias_10g" );
props.put("java.naming.factory.initial",
"com.evermind.server.rmi.RMIInitialContextFactory" );
props.put("java.naming.provider.url",
"opmn:ormi://bpelserver:6003:home/orabpel" );
props.put("java.naming.security.principal", "oc4jadmin" );
props.put("java.naming.security.credentials", "password123" );

String securityCredentials = "password123";

When we use the Locator class to search for processes, we need to specify which BPEL domain to look in. Here we initialize a String to use the default domain:

String selectedDomain = "default";

Now we can get our instance of the Locator. We'll need to pass it the domain we're interested in, the server password, and our Properties object to make the connection:

Locator locator = new Locator(selectedDomain, securityCredentials, props);

Once we have our Locator reference, we can lookup processes, instances, and services. For our example, we'll be getting a list of processes, represented as an array of IBPELProcessHandle objects, loaded in our default domain:

IBPELProcessHandle procs[] = locator.listProcesses();

We can now iterate through our array of process handles and print out the name of each one:

for (int i=0; i<procs.length; i++ ) {
System.out.println( "Process Name="+procs[i].getProcessId().getProcessId() );
}

You should note that calling locator.listProcesses() does not guarantee that an array of fully loaded process handle objects will be returned to the caller. If you intend to use the methods in the IBPELProcessHandle interface, you should first ensure that the process handle was loaded by calling the method isLoaded() first.

Sometimes Toplink's mergeEntity doesn't....

If you use JDeveloper and you want to use a JPA, odds are you'll pick Toplink. Toplink works well for me, but if you use a session facade bean to access your Toplink queries and objects you may have had a run in, like I have in the past, with the mergeEntity() method.

It seems like sometimes this method just will not save the data to the database, which can be very frustrating. I'll list some common causes and remedies below:

1) Toplink will not update values that compose the key pf an object. The only way I know around this is to delete the old object and create a new one.

2) You are calling mergeEntity() against objects created by a ReadAllQuery. In this case, in your session facade bean method you should make sure that you uncomment the code that detaches the results. It will be directly below a couple of comments that should look like these:
// Uncomment the following lines of code if the results from this query will be mutated.
// See SessionFactory.detach() for more information.

3) The read and the merge are using different transactions. Change the code to use the same transaction for reading/updating.

Tips on the Oracle BPEL Java API - Part 1 - Using the Server class to get a list of domains

In this post I'll describe some of the common things that need to be done to call the Oracle BPEL PM API from Java, and I'll show you how to put that to use to get a list of the current BPEL domains defined on you server. We'll be using the Server class, which is in the com.oracle.bpel.client package, and is useful for manipulating BPEL at the server level.

First, for this example, you'll need to import several BPEL API classes:

import com.oracle.bpel.client.BPELDomainStatus;
import com.oracle.bpel.client.Server;
import com.oracle.bpel.client.auth.ServerAuth;
import com.oracle.bpel.client.auth.ServerAuthFactory;

The next task is to configure a java.util.Properties object with the connection information for your BPEL server, as well as a String object containing the security credentials (password):

Properties props = new java.util.Properties();
props.put("orabpel.platform", "ias_10g" );
props.put("java.naming.factory.initial",
"com.evermind.server.rmi.RMIInitialContextFactory" );
props.put("java.naming.provider.url",
"opmn:ormi://bpelserver:6003:home/orabpel" );
props.put("java.naming.security.principal", "oc4jadmin" );
props.put("java.naming.security.credentials", "password123" );

String securityCredentials = "password123";

We are now ready to get a ServerAuth object from the ServerAuthFactory:

ServerAuth auth = ServerAuthFactory.authenticate(securityCredentials, null, props);


Next, we get an actual client connection to the server by creating a Server object and passing the constructor our ServerAuth object:


Server srv = new Server(auth);

Finally, we can get the list of domain status information by calling the getAllDomainStatus() method of the server:

BPELDomainStatus domainList[] = srv.getAllDomainStatus();

Now that you have the status information you can do any number of things, in our example we can print out the domain ID of each domain on the server with this code:

for (int i=0; i<domainList.length; i++ ) {
System.out.println( "Domain ID="+domainList[i].getDomainId() );
}

A short note about our new site home

This site contains the posts from my previous location for Charles' SOA Blog ( http://soablog.info ) through the end of 2007.

Additional posts will be made here as the other account is phased out.