Pages

Friday, May 30, 2008

Using Siebel WS in your ADF application

For our Siebel Unit I was making a demo which can search siebel accounts, displays a single account with the addresses and an insert page. The goal was to do this with the Siebel web service. This example gives an good example how to deal with complex web services, because the ADF Web Service Datacontrol only works with simple web services. You have a example on otn which use the ws datacontrol, but this only works on a simple web service method. When you want to search or create a new account you have to do more.
This is how it looks. The search page show all accounts ( calls SiebelAccountQueryByExample ). In this example you can search on Id and Name. You can also click on the Id then the account detail page is loaded.
When the detail page is loaded it calls SiebelAccountQueryById with the Id of the search page.

And the last page is the insert page

I did this by making a web service proxy on the local saved wsdl. To test this web service you have to do a lot.

nl.ordina.siebel.model.proxy.DefaultClient myPort = new nl.ordina.siebel.model.proxy.DefaultClient();
System.out.println("calling " + myPort.getEndpoint());
// Add your own code here
ListOfAccountInterfaceTopElmt inter = new ListOfAccountInterfaceTopElmt();
Account[] result = new Account[1];
Account acc = new Account();
acc.setAccountId("1-7SL");;
result[0]= acc;
inter.setListOfAccountInterface(result);
ListOfAccountInterfaceTopElmtHolder holder = new ListOfAccountInterfaceTopElmtHolder(inter);
myPort.siebelAccountQueryByExample(holder);
Account[] accs = holder.value.getListOfAccountInterface();
acc = accs[0];

This is to complex so I made it a bit easier. I created a java class where I call these ws methods and on this class I am making a datacontrol.

package nl.ordina.siebel;

import nl.ordina.siebel.model.proxy.DefaultClient;
import nl.ordina.siebel.model.proxy.holders.ListOfAccountInterfaceTopElmtHolder;
import nl.ordina.siebel.model.proxy.types.com.siebel.xml.account_interface.Account;
import nl.ordina.siebel.model.proxy.types.com.siebel.xml.account_interface.ListOfAccountInterfaceTopElmt;

public class SiebelActions {
public SiebelActions() {
}

public Account[] SearchAccount( Account msg ){
try {
DefaultClient myPort = new DefaultClient();
System.out.println("calling " + myPort.getEndpoint());
ListOfAccountInterfaceTopElmt inter = new ListOfAccountInterfaceTopElmt();
Account[] result = new Account[1];
result[0]= msg;
inter.setListOfAccountInterface(result);
ListOfAccountInterfaceTopElmtHolder holder = new ListOfAccountInterfaceTopElmtHolder(inter);
myPort.siebelAccountQueryByExample(holder);
return holder.value.getListOfAccountInterface();
}
catch (Exception ex) {
ex.printStackTrace();
}
return null;
}

public Account[] GetAccount( String id ){
try {
DefaultClient myPort = new DefaultClient();
System.out.println("calling " + myPort.getEndpoint());
ListOfAccountInterfaceTopElmt result = myPort.siebelAccountQueryById(id);
return result.getListOfAccountInterface();
}
catch (Exception ex) {
ex.printStackTrace();
}
return null;
}

public static void main(String[] args) {

SiebelActions sa = new SiebelActions();
Account acc = new Account();
acc.setAccountId("1-7SL");
Account[] result = sa.SearchAccount(acc);
acc = result[0];
System.out.println("account info "+acc.getAlias()+" name "+acc.getName());

result = sa.GetAccount("1-7SL");
acc = result[0];
System.out.println("account info 2 "+acc.getAlias()+" name 2 "+acc.getName());
}
}

I created an ADF Datacontrol on this class and use this datacontrol in the ADF JSF Pages. Because the input parameters of the ws methods are complex types, I had to create a bean with a method which returns the input parameter. In this bean I also added the search parameters field.
getAccount is used in the pagedef as input parameter on SiebelAccountQueryByExample.

package nl.ordina.siebel;

import nl.ordina.siebel.model.proxy.types.com.siebel.xml.account_interface.Account;

public class SiebelBean {

protected java.lang.String accountId;
protected java.lang.String showAccountId;
protected java.lang.String alias;
protected java.lang.String name;

public SiebelBean() {
}

public Account getAccount(){
Account acc = new Account();
acc.setAccountId(accountId);
acc.setAlias(alias);
acc.setName(name);
return acc;
}

public void setAccountId(String accountId) {
this.accountId = accountId;
}

public String getAccountId() {
return accountId;
}

public void setShowAccountId(String showAccountId) {
this.showAccountId = showAccountId;
}

public String getShowAccountId() {
return showAccountId;
}

public void setAlias(String alias) {
this.alias = alias;
}

public String getAlias() {
return alias;
}

public void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}
}

Here is a guide with all the steps I did. And here is the jdeveloper 10.1.3.3 project. To let it work on your own siebel 8 you only have to change the url of the ENDPOINT_ADDRESS_PROPERTY in the stub file created by the web service proxy and put in the right username / password else you can't insert new accounts.
_setProperty(ENDPOINT_ADDRESS_PROPERTY, "http://10.100.17.1/eai_nld/start.swe?SWEExtSource=WebService&SWEExtCmd=Execute&UserName=normani&Password=normani");

Sunday, May 25, 2008

Using OpenLDAP for net8 and AQ connection factory

In this blog I will show you can use OpenLDAP to lookup your Oracle Net (tnsnames) connections or AQ connection factories. Now you don't need to have an Oracle Internet Directory (OID) installed. The first step is to download openldap. Install this and download my oracle.schema and put this in the schema folder of openldap. This file has to be included in the slapd.conf.
Edit slapd.conf and add
"include schema/java.schema"
"include schema/oracle.schema" .
Make sure anonymous can read the tnsnames entries.
access to dn="" by * read
access to *
by self write
by users read
by anonymous read
We have to configure the ldap for Oracle by making an OracleContext and oracledbconnections entry.

I do this with ldapbrowser. You can download it here. For this free java application I made some templates which you can use.



Do the same for oracledbconnections ( this is for the AQ entries) Now use the queue template in ldapbrowser.

To make a tnsnames entry I select the OracleContext ldap entry and I use the orclNetService template to create a new Oracle connection.

We are ready to use it, we only has to create ldap.ora in the network\admin folder. The ldap.ora looks like this.
DIRECTORY_SERVERS= (localhost:389:636)

DEFAULT_ADMIN_CONTEXT = "o=sgi,c=us"

DIRECTORY_SERVER_TYPE = OID

We start sqlplus and use the ldap name as tnsnames entry. I can also start net manager and go the Directory menuitem to see our ldap entry

The second part shows you can lookup an AQ connection factory with JNDI and ldap. first let's register a new connection in the ldap server. For this I only need the following jars files. jndi-1.2.1.jar,jta-1.0.1.jar, jms-1.1.jar,aqapi.jar and the jdbc jar of oracle



package jms2;

import java.util.Hashtable;
import java.util.Properties;
import javax.jms.JMSException;
import javax.naming.Context;
import oracle.jms.AQjmsFactory;

public class register_jms_to_oid {
public register_jms_to_oid() {
Hashtable env = new Hashtable(5, 0.75f);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389");
env.put("server_dn", "o=sgi,c=us");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "o=sgi,c=us");
env.put(Context.SECURITY_CREDENTIALS, "secret");
String url = "jdbc:oracle:thin:@XPCND7010XMP:1521:orcl";
Properties properties = new Properties();
properties.setProperty("user","scott");
properties.setProperty("password","tiger");
try {
AQjmsFactory.registerConnectionFactory(env, "scott3", url ,properties, "queue");
} catch ( JMSException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
register_jms_to_oid register_jms_to_oid = new register_jms_to_oid();
}
}

Now we can lookup this entry with standard jms calls.

package jms2;

import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.jms.QueueConnectionFactory;
import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.NamingException;

public class lookup_jndi_queue {

private QueueConnection connection = null;
private QueueSession session = null;
private QueueSender sender = null;

public lookup_jndi_queue() {

Hashtable env = new Hashtable(5, 0.75f);
DirContext ctx;
QueueConnectionFactory queueConnectionFact;
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "o=sgi,c=us");
env.put(Context.SECURITY_CREDENTIALS, "secret");

try {
ctx = new InitialDirContext(env);
ctx = (DirContext)ctx.lookup("cn=connections, o=sgi,c=us");
Object reference = ctx.lookup("cn=scott");
queueConnectionFact = (QueueConnectionFactory)reference;
try {
connection = queueConnectionFact.createQueueConnection();
session = connection.createQueueSession(true, QueueSession.CLIENT_ACKNOWLEDGE);
connection.start();
QueueSession session = connection.createQueueSession(true, QueueSession.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("JMS_IN");
sender = session.createSender(queue);
String xmlData = "1111";
TextMessage message = session.createTextMessage(xmlData);
sender.send(message);
session.commit();
} catch (JMSException e) {
// TODO
e.printStackTrace();
}
} catch (NamingException ee) {
// TODO
ee.printStackTrace();
}
}

public static void main(String[] args) {
lookup_jndi_queue lookup_jndi_queue = new lookup_jndi_queue();
}
}


You can also use the ldapbrowser template. The entry look this in ldap.

Thursday, May 22, 2008

Employee search jsf page on Coherence with JPA

This I had this week a great coherence training for Oracle partners, where I learned a lot of interesting things about Coherence . This product is from tangosol ( Now owned byOracle ) and is a memory distributed data grid solution for clustered applications and application servers.

You may think coherence is a very complex product but it is a very easy to handle. It does everything automatically like backing up the cache on different nodes, distribute the load and recover from lost cache servers or adding new coherence servers to the cluster.
In this blog I will show how you can make a jsf employee search page on the coherence cache which get its data from a JPA datasource. Coherence runs above JPA. In this blog I will also update the cache entries with a salary raise and coherence will take care to update the right records in the employee table.
If you want to do it yourself you have to download coherence from Oracle. Add coherence.jar and tangosol.jar to the project libraries. Then we can create a entity bean ( entities from tables ( JPA / EJB3.0) on the employee table ( HR schema). Jdeveloper create a persistence.xml which we have to change with the right class and database parameters. persistence-unit name must match with the property of JpaCacheStore in the coherence jpa xml.

<?xml version="1.0" encoding="windows-1252" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="JPA">
<provider>oracle.toplink.essentials.PersistenceProvider</provider>
<class>nl.ordina.coherence.model.Employees</class>
<properties>
<property name="toplink.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="toplink.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:ORCL"/>
<property name="toplink.jdbc.user" value="hr"/>
<property name="toplink.jdbc.password" value="hr"/>
</properties>
</persistence-unit>
</persistence>
Next I created jpa-cache-config-web.xml

<?xml version="1.0" encoding="windows-1252" ?>
<cache-config>
<caching-scheme-mapping>
<cache-mapping>
<!-- Set the name of the cache to be the entity name -->
<cache-name>Employees</cache-name>
<!-- Configure this cache to use the scheme defined below -->
<scheme-name>jpa-distributed</scheme-name>
</cache-mapping>
</caching-scheme-mapping>
<caching-schemes>
<distributed-scheme>
<scheme-name>jpa-distributed</scheme-name>
<service-name>JpaDistributedCache</service-name>
<backing-map-scheme>
<read-write-backing-map-scheme>
<internal-cache-scheme>
<local-scheme/>
</internal-cache-scheme>
<cachestore-scheme>
<class-scheme>
<class-name>com.tangosol.coherence.jpa.JpaCacheStore</class-name>
<init-params>
<init-param>
<param-type>java.lang.String</param-type>
<param-value>{cache-name}</param-value>
</init-param>
<init-param>
<param-type>java.lang.String</param-type>
<param-value>nl.ordina.coherence.model.{cache-name}</param-value>
</init-param>
<init-param>
<param-type>java.lang.String</param-type>
<param-value>JPA</param-value>
</init-param>
</init-params>
</class-scheme>
</cachestore-scheme>
</read-write-backing-map-scheme>
</backing-map-scheme>
<autostart>true</autostart>
</distributed-scheme>
</caching-schemes>
</cache-config>

Add this file to the run options of the cache-server.cmd and the jdeveloper web project runtime options. -Dtangosol.coherence.cacheconfig=D:\oracle\coherence\bin\jpa-cache-config-web.xml
Now we can load the Employees cache. Do this with the following code
private NamedCache employees = CacheFactory.getCache("Employees");
For searching through the cache for the right employees I use a filter.

public void search(ActionEvent actionEvent) {

Filter filter = null;
if ( firstName.getValue() != null && lastName.getValue() != null ) {
filter = new OrFilter( new LikeFilter("getFirstName", firstName.getValue().toString())
, new LikeFilter("getLastName" , lastName.getValue().toString()));
} else if ( firstName.getValue() != null && lastName.getValue() == null ) {
filter = new LikeFilter("getFirstName", firstName.getValue().toString());
} else if ( firstName.getValue() == null && lastName.getValue() != null ) {
filter = new LikeFilter("getLastName", lastName.getValue().toString());
} else {
seeAll(actionEvent);
return;
}

Set empSet = employees.entrySet(filter);

int size = empSet.size();
List list = new ArrayList();

for (Iterator it = empSet.iterator(); it.hasNext(); ) {
Map.Entry entry = (Map.Entry)it.next();
Employees empl = (Employees)entry.getValue();
list.add(empl);
}
model = new ArrayDataModel(list.toArray());
}

To update the employee records. I first need to have a class which I can invoke on the cache

package nl.ordina.coherence.backing;

import com.tangosol.util.processor.AbstractProcessor;
import com.tangosol.util.InvocableMap.Entry;
import nl.ordina.coherence.model.Employees;

public class RaiseSalary extends AbstractProcessor {
public RaiseSalary() {
}

public Object process(Entry entry ) {
Employees emp = (Employees)entry.getValue();
emp.setSalary(emp.getSalary() * 1.10);
entry.setValue(emp);
return null;
}
}


We invoke this by the following statement employees.invokeAll(AlwaysFilter.INSTANCE, new RaiseSalary());. Coherence updates the affected records.
Here you can download the example project. You have to start 1 cache server on your network and you can start the webapp on different clients. Coherence connects automatically to the cache server. You can search the cache immediately. Start for example more cache servers and look at the timing. And update the cache by doing a salary raise on 1 webapp and query the changed employees in the other webapp.

To run this example you have to change some files.
Change the path parameters with the right folders of jpa-cache-server-web2.cmd file (this included in the zip) and the classpath of the employee bean
:launch
set java_opts="-Xms%memory% -Xmx%memory% -Dtangosol.coherence.cacheconfig=D:\oracle\coherence\bin\jpa-cache-config-web.xml"
"%java_exec%" -server -showversion "%java_opts%" -cp "%coherence_home%\lib\coherence.jar;%coherence_home%\lib\coherence-jpa.jar;D:\oracle\jdevstudio10133\jdbc\lib\ojdbc14.jar;D:\oracle\jdevstudio10133\toplink\jlib\toplink-essentials.jar;D:\projecten\workspace\10.1.3.3\coherence\web\public_html\WEB-INF\classes" com.tangosol.net.DefaultCacheServer %1
Change the run options and the libraries of the project and off course the persistence.xml for the database parmaters.

Monday, May 19, 2008

ADF JDeveloper 11g TP4 need to knows

Oracle just released jdeveloper 11g TP4 in this release they changed some ADF things and there some bugs which you should need to know when you are a ADF developer.
The changes are there is no ADF Create Form in TP4 ( See Steve Muench quote), to solve this drag the right create operation of the viewobject from the datacontrol to the taskflow. A method call is created, make sure this method call runs before the page is loaded and the page is now in insert mode.
Steve Muench quotes "Notice that in TP4 there is no longer an "ADF Create Form" and that we're encouraging you to create a create form using a method activity that declaratively invokes the create operation, then forwards to a page with a regular ADF Form on it. This is due to the numerous confusions that have always surrounded the ADF "invokeAction" now that we have a visual, declarative mechanism to model this type of initialization activity, we will prefer users adopting that. Also, notice that the page definition for the method activity has the new "SkipValidation" property set to true."
Andrejus made a create sample how to use a lov when the form is in create mode. If you don't do this you get validation errors and the lov is empty.
A other issue is that the Commit operation fails with a table, you get a null pointer exception. This is bug in the JSF 1.2 reference implementation's validator tag (issue# 641): This issue is fixed in JSF 1.2_05. The TP4 release still uses JSF 1.2_04 that has this bug. The workaround to comment out the tag.
In the datacontrol there is a bug
In TP3 you could reference to a valuebinding of a other pagedef (Task Flow memory scope), this fails in TP4 but there there is a workaround you can update the DataBindings.cpx file with the right pagedef id. At the pageMap remove the package name part of the usageId attribute and at the pageDefinitionUsages element remove also the package name part of id attribute. Now everything works again.
If you know other TP4 issues let me know and please update the oracle wiki yourself
http://wiki.oracle.com/page/Known+issues+and+limitations

Friday, May 16, 2008

Using sdo web services with service based entities (ADF BC)

If you ever need to make a web application build on services ( because of SOA or it has to be demilitarized zone application) then you can use the new service based entity and view of ADF BC. With this it is easy to make a service based application and there are no differences with normal ADF database development.
ADF BC can also create the sdo web service for you. You can use this service not only for ADF BC but also for the new soa suite 11g. It can be an alternative for the the database adapter See my previous blog for more details. In this blog entry I will show you how to create a adf bc sdo web service and use this service in an other application.
With 11g you can easily create a SDO web service. You only have to create a bc4j model project and add an entity with a viewobject. The viewobject which you want to service has to be added to the applicationmodule. The only thing you have to do now is open the applicationmodule and add a new service interface.

Add the viewobject and select the wanted operations on this viewobject

When it finishes you see JDeveloper generates a few xml schema's and java classes.
To test the new service run the ServiceImpl of the application module. This class is located in the serviceinterface package.
We have to make a ADF BC service deployment profile.


We can deploy the service to the local j2ee server. First start the oc4j container with JDEV_HOME/binoc4j.cmd -start. create a application server connection in your project and deploy this to this container. We have know two things, first we need our deployment profile name, this is CustomerService plus we add __MiddleTier. In my case the jndi lookup name will be CustomerService_MiddleTier. The second thing is the wdsl url this is http://localhost:8888/oe_sdo_service-model-context-root/CustomerModuleService?WDSL .
We are almost ready with sdo web service we only have to copy the reference from the connection.xml


Create a new fusion application where we add the just copied reference entry to this application connection.xml plus we add a few extra jndi entries

<?xml version = '1.0' encoding = 'UTF-8'?>
<ns2:References xmlns:ns2="http://xmlns.oracle.com/adf/jndi">
<Reference className="oracle.jbo.client.svc.Service" name="{/nl/ordina/sdo/service/common/}CustomerModuleService">
<Factory className="oracle.jbo.client.svc.ServiceFactory"/>
<RefAddresses>
<StringRefAddr addrType="serviceInterfaceName">
<Contents>nl.ordina.sdo.service.common.serviceinterface.CustomerModuleService</Contents>
</StringRefAddr>
<StringRefAddr addrType="serviceEndpointProvider">
<Contents>ADFBC</Contents>
</StringRefAddr>
<StringRefAddr addrType="jndiName">
<Contents>nl.ordina.sdo.service.common.CustomerModuleServiceBean</Contents>
</StringRefAddr>
<StringRefAddr addrType="jndiFactoryInitial">
<Contents>oracle.j2ee.rmi.RMIInitialContextFactory</Contents>
</StringRefAddr>
<StringRefAddr addrType="jndiProviderURL">
<Contents>ormi://localhost:23791/CustomerService_MiddleTier</Contents>
</StringRefAddr>
<StringRefAddr addrType="jndiSecurityPrincipal">
<Contents>fmwadmin</Contents>
</StringRefAddr>
<StringRefAddr addrType="jndiSecurityCredentials">
<Contents>welcome</Contents>
</StringRefAddr>
<StringRefAddr addrType="serviceSchemaName">
<Contents>CustomerModuleService.xsd</Contents>
</StringRefAddr>
<StringRefAddr addrType="serviceSchemaLocation">
<Contents>nl/ordina/sdo/service/common/serviceinterface/</Contents>
</StringRefAddr>
</RefAddresses>
</Reference>
</ns2:References>

Add the CustomerService_Common.jar to the project library. This jar is located in the deploy folder.
Finally we can create a entity based on a service. Create a new entity and select the service option where we add the ws wdsl url

And we can create in the last step an application and a viewobject.
Now start the bc4j tester by running the applicationmodule and we see all the customers.

We can use this application module in our jsf application.

Wednesday, May 14, 2008

ESB performance and synchronous soap calls

For one of my project we were performance tuning our esb / bpel projects on the soa suite 10.1.3.3 and we noticed that the esb dequeues one jms message a time and it waits until the whole process was completed before it dequeues the next message. Our project looks like this, the main esb calls a bpel process which start 2 other esb processes. So the total performance was a bit disappointing with hundreds of big messages. With the help of Chintan we found the problem. It seems that we used a synchronous bpel process so the calling esb process was waiting until it finishes
even when the first action of bpel is return true to the calling esb. It still waits until the whole bpel is finished. I had to create an asynchronous bpel process with a synchronous routing rule. Now the esb dequeues the next messages while the bpel is still running. Here is a example of the esb and bpel process.
First we add a jms adapter to the esb project. JDeveloper creates the adapter with a router.
The next step is to create a bpel project and make sure you use the asynchronous option.
In the bpel editor we first initiate the callback client and after that we do our business in my case we wait for a few seconds. We can deploy this bpel project to the soa suite server.
We return to the esb project where we add a soap adapter. This soap adapter is the wsdl url to bpel process. Next we add a routing rule to this bpel web service.
Now we can deploy this esb project to the soa suite server. If we add 10 messages to the queue we see that the esb does not wait now for the bpel process to finish.

Wednesday, May 7, 2008

Soa Suite 10.1.3 performance

For a customer I'm busy with a proof of concept where we try to build a new message handling system. This MHS can already handle many and big edifact smime messages in a few seconds. The MHS also transforms the edifact messages to a xml. The second part of the POC is to use Oracle soa suite 10.1.3 especially the ESB part to deliver edifact xml messages to the right backoffice database. The ESB /BPEL needs a little bit tuning because the MHS handles a 500kb DELFOR message in a few seconds and the ESB takes more then a minute. 500kb edifact message leads to a 3.5Mb xml message. The soa suite server is a new Sun server with two intel quad cores with a lot of memory.
First let me explain the esb processes. The esb /bpel process look like this. The esb reads the jms queue and gives the xml to a simple bpel process ( I did this to make sure that first the xml is inserted into the backoffice tables and after this process we can pass the incoming xml to the backoffice queue, so the backoffice database knows which messages are ready to process). This bpel process calls two other esb process. Maybe this can be solved in only one esb process ,let me know if you know a solution.
The first esb process reads the queue and pass the xml to the bpel process.

The bpel process calls the first esb process.( see my previous blog entry for details)

The last step of the bpel process is to call the last esb process which put the xml message in the backoffice queue.

The total process takes about 55 seconds and our goal is to do this in 10 seconds. The first performance step is to replace the jms oracle database queue with a oc4j file persistence memory queue. We have won 10 seconds with this new queue. AQ with big xml's are not so fast as a memory queue. You can also use openjms. This is about 20% faster then OC4J.
Let's look at the bpel process. This is a simple process so I only need to store the faulted instances. We add the following configuration part to the bpel.xml.

<?xml version = '1.0' encoding = 'UTF-8'?>
<BPELSuitcase>
<BPELProcess id="mhs_jms_esb_handling" src="mhs_jms_esb_handling.bpel">
<partnerLinkBindings>
.....
</partnerLinkBindings>
<configurations>
<property name="inMemoryOptimization">true</property>
<property name="completionPersistLevel">instanceHeader</property>
<property name="completionPersistPolicy">faulted</property>
<property name="deliveryPersistPolicy">off</property>
<property name="auditLevel">off</property>
</configurations>
</BPELProcess>
</BPELSuitcase>

We have won an another 8 seconds. So the total processing time is 38 seconds.
Because the db adapter takes about 7 seconds and passing the xml to the database queue takes also 7 seconds. We have a overhead of 24 seconds. This is propably due to by passing the 3.5Mb xml with web services from esb to bpel and back to the esb. The last step I did is to pass only the run identifier to the backoffice queue and not the whole xml messages. Now the total process takes 23 seconds and the AQ part is from 7 seconds reduced to 10ms. The overhead is still 15 seconds. So next week I will try to tweak the esb web services. If you know how to do this let me now.
This are the result with different delfor edifact message size.

If we look at the result table we see that small xml messages are handled very fast and that 3.5Mb or 7Mb xml messages have the same total processing time which is very strange. Maybe soa suite handles big messages differently.
The last problem I had is that the esb handles only one process and waits until this finish before starting the next process, because I have a server with 8 cores I want to have more parallel process else I only need to have two cores with a high clock frequency.
This problem is also solved by making a esb router (which dequeues) and calls with a synchronous routing rule the BPEL process. The BPEL is now a asynchronous process where the first step is to report back to the esb and after this I am calling the other ESB processes. Now I see parallel processing and a 700kb delfor xml is processed in a second, the 3.5 mb delfor in 16 seconds and the 7mb delfor in 12 seconds. I had to remove the deliveryPersistPolicy from the bpel.xml else It won't process the bpel instances.

Monday, May 5, 2008

Events in ADF BC and handled by the Soa Suite Mediator

You may already know that events plays an important role in Soa Suite 11g. In this blog entry I will show how you can raise events in your ADF JSF application with ADF BC ( BC4J). These events can be intercepted by a mediator of soa suite 11g and this mediator can start other processes. In my case I publish these events to a file. I hope with this blog you get an inside look how events works.
The first step is to configure the entity in BC4J for events. In this example I use the customer table of the oe schema. On this entity I add a CreditLimit event which fires for every customer insert or update. To this event I add two customers attributes, The customerId and the creditlimit( BC4J adds automatically the old and new value of these attribute ).
BC4J generates a edl and a schema file. Here are an example of the generated files

<?xml version = '1.0' encoding = 'UTF-8'?>
<definitions
targetNamespace="/nl/ordina/events/model/businessobjects/events/edl/Customers"
xmlns:ns0="/nl/ordina/events/model/businessobjects/events/schema/Customers"
xmlns="http://schemas.oracle.com/events/edl">
<schema-import
namespace="/nl/ordina/events/model/businessobjects/events/schema/Customers"
location="Customers.xsd"/>
<event-definition name="CreditLimit">
<content element="ns0:CreditLimitInfo"/>
</event-definition>
</definitions>

The customer schema

<?xml version = '1.0' encoding = 'UTF-8'?>
<xs:schema
targetNamespace="/nl/ordina/events/model/businessobjects/events/schema/Customers"
xmlns="/nl/ordina/events/model/businessobjects/events/schema/Customers"
elementFormDefault="qualified"
attributeFormDefault="unqualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="CreditLimitInfo">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerId" type="DecimalValuePair" minOccurs="1"/>
<xs:element name="CreditLimit" type="DecimalValuePair" minOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="ValuePair" abstract="true"/>
<xs:complexType name="DecimalValuePair">
<xs:complexContent>
<xs:extension base="ValuePair">
<xs:sequence>
<xs:element name="newValue" minOccurs="0">
<xs:complexType>
<xs:complexContent>
<xs:extension base="xs:anyType">
<xs:attribute name="value" type="xs:decimal"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="oldValue" minOccurs="0">
<xs:complexType>
<xs:complexContent>
<xs:extension base="xs:anyType">
<xs:attribute name="value" type="xs:decimal"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>

Let's make a JSF page on this entity and publish this application to the Soa suite server. If you don't do this I don't believe the events will be intercepted by the mediator.
Now we have to patch two procedures in the soasuite schema ( JDev TP4). The first procedure is edn_dequeue_bus_event, we have to change the schema name with your own soasuite schema do this before the queue name DBMS_AQ.dequeue(queue_name=>'xxxxx.edn_event_queue'. The same but now for procedure edn_enqueue_business_event DBMS_AQ.enqueue(queue_name=>'xxxxx.edn_event_queue'
The events are enqueued in the following queue edn_event_queue. This queue is located in your own soasuite schema. The published event looks like this.

<business-event
xmlns:ns="/nl/ordina/events/model/businessobjects/events/edl/Customers"
xmlns="http://oracle.com/fabric/businessEvent">
<name>ns:CreditLimit</name>
<id>30b14edf-f366-4091-97e8-3b6a2d514116</id>
<content>
<CreditLimitInfo xmlns="/nl/ordina/events/model/businessobjects/events/schema/Customers">
<CustomerId>
<oldValue value="148"/>
<newValue value="148"/>
</CustomerId>
<CreditLimit>
<oldValue value="1700"/>
<newValue value="1100"/>
</CreditLimit>
</CreditLimitInfo>
</content>
</business-event>

If I manually dequeue this queue the result looks like this.

We are ready with ADF and now we can go to the soa suite part. We create a new soa suite project where we add a mediator. Select now the Subscribe to events template. and browse to the customer.edl which is located in the bc4j model project.

In my case I add a file adapter and connect this file adapter to the mediator.

The last step is to make a stylesheet mapping between the mediator and the file adapter.

The events are now stored in a file. I hope you got a good impression how it works. In the next blogs I will continu this story by adding the CEP soa suite component and BAM j2ee edition to this example

Friday, May 2, 2008

What's new and interesting in JDeveloper 11g TP4

Oracle has just released the Technical Preview 4 of JDeveloper 11g, Webcenter, Soa Suite 11g and the J2EE edition of the BAM Server. See note 565899.1 on metalink how to enable Soa Suite and BAM Server on JDeveloper TP4. Download patch 7009059 for the Soa Suite TP4 Documentation and patch 7009057 for the BAM and B2B addon patch
This TP4 release is all about events.

In JDeveloper 11g TP4 there are some new features like
Active Data Service, this is very interesting push framework. ADS refreshes the ADF bindings when the data source is changed. This data source has to publish events. BAM can be a data source which can publish event.
MDS Metadata services, Customizing pages is more explained.

New features of Soa suite 11g
Event delivery network, A new Enterprise console and Business Rules is more explained and off course the J2EE edition of Oracle BAM.
There is a lot to blog about especially about events and how to use this in ADF, Soa suite and in BAM.

So check this blog and other Oracle bloggers for all the new details.