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>

Saturday, January 20, 2007

Overule the BPEL instance name

When running BPEL processes, the BPEL consolse is showing the status of the process. This is nice, but when you have hundreds or even thousands process instances, is hard to known for which payload the process instance is running.

A nice feature is to manipulate the title of the process. The maximum length of the title is 50 characters.

Note: in 10.1.3 they change the underlying XML parser. It is now using the Oracle XML parsers. This means that the returned object from getVariableDataI() is not returning a Dom Element but an oracle.xml.parser.v2.XMLElement object.

http://www.oracle.com/technology/tech/xml/xdk/doc/production10g/doc/java/javadoc/index.html

Create a Java step after the first step in your process. You can use the data of the payload to put this in the title:

<bpelx:exec name="JavaSetTitle" language="java" version="1.4">
<![CDATA[
Element inVarElem = (Element)getVariableData("inputVariable"
, "payload"
, "/client:HelloWorldProcessRequest/client:input");
try
{
String inputdata = inVarElemOrpsId.getNodeValue();
String title = "HelloWorld " + inputdata;
setTitle(title);
addAuditTrailEntry("New Title is: >" + title + "<");
}
catch (Exception ex)
{
ex.printStackTrace();
}]]>
</bpelx:exec>


10.1.3 example:

String inputvar1 = ((oracle.xml.parser.v2.XMLElement)
getVariableData(
"inputVariable"
, "payload"
, "/client:BPELProcess1ProcessRequest/client:input1")
).getFirstChild().getNodeValue();
String title = "Title "+ inputvar1;
setTitle(title);

Friday, January 05, 2007

Tuning BPEL in a nutshell

Ok, after doing some projects, I run into issues regarding performance and stability. The to tune the BPEL process manager take this into account:

Make sure you have to latest patches applied of BPEL. The latest patches can be found a metalink.

If you are using BPEL processes that are intensively using the DB-Adapter or AQ-Adapter. Verify that the max number of connections is high. Change the connection pooling in the data-source.xml file. For 10.1.3 this file can be found in $ORACLE_HOME/j2ee/oc4j_soa/config/data-sources.xml. Make sure your oc4j-ra.xml file (DbAdapter/AqAdapter) is using data sources in the JNDI lookup. In 10.1.0.2 verify that the max-read max-write connections are high.

If you are using many async processes that are using the hydration store for persistence, verify that the max number of connections is high. Change the connection pooling in the data-source.xml file. This file for 10.1.0.2 and 10.1.3 can be found in $ORACLE_HOME/j2ee/oc4j_soa/config/data-sources.xml.

While we see locks on the ydration store when we run a high load of process, increase the initrans of the tables "CUBE_INSTANCE" "CUBE_SCOPE".
  • alter table CUBE_INSTANCE initrans 16;
  • alter table CUBE_SCOPE initrans 16;
You can also apply this for the indexes; alter index initrans

Make sure that the following formula applies:
  • SUM(WorkBean + InvokerBean) >= SUM(dspMaxThread for each domain)
  • SUM(dspMaxThreads for each domain) <= BPEL Datasource
Do not increase the Java Heapsize to large. This could lead into swapping or too much overhead in JVM. In general I suggest to set the -Xms and -Xmx equal and make these 1 GB or 2GB (the half of psychical memory). Leave at least 30% memory for de rest; O/S, Apache...

Garbage collection is happening when the BPEL PM is overloaded with tasks. Full garbage collection will take place. A parameter that influence this behavior,a bit, is to reduce the Java stack size. By default the stacksize is 512KB. This is for each thread. If you have short running processes, they do not occupy a large stack. You can reduce the stack size. Use the value -Xss128k or even -Xss96k.

The determine the correct setting for WorkerBean and the InvokerBean is hard to tell. My experience is to set the WorkBean to a value around 100 and the InvokerBean 50. Run some performance test to determine your ideal values on which the system is performing well. If you have CPU left, increase these values and also the dspMaxThreads for the particular domain.

Another nice performance advantage is to increase the value of the "com.oracle.bpel.expirationAgent.threadCount". By default this value is 10. Run tests to determine your value. I experienced good results with 30 and 50. The value van be set in the file:

  • 10.1.0.2: "$ORACLE_HOME/integration/orabpel/domains/default/config/quartz-config.properties"
  • 10.1.3: "$ORACLE_HOME/bpel/domains/default/config/resources-quartz.properties"
When you have a lot of BPEL processes instances running, the BPEL PM must get the unique instance number to create this instance, and even to store it in the dehydration store, the key is retrieved from a internal hash table. If it runs out of this table, it will be refilled. The initial size of this table is 100. Increasing this value to large number reduces contention. The property can be found in the domain.xml file for the particular BPEL domain. The name of the property is "instanceKeyBlockSize". Set this value high, for example 100000.

Another bottleneck I saw, was in the Apache threads, the Apache client process. Tune the number of spare servers well. Set the value MaxRequestsPerChild to a non zero value. Otherwise the child process will run forever. If the process has handle 1024 requests, it will die and apache can stat a new process if needed

httpd.conf: MaxRequestsPerChild 1024

In the $OC4J_HOME/j2ee/home/config/transaction-manager.xml file you set the global transaction timeout with the transaction-timeout attribute of the <transaction-manager> element. For example, if you wanted to set the global transaction timeout to 1800 seconds, you would do as follows: <transaction-manager ... transaction-timeout="1800"
...
</transaction-manager>


Useful links: