Using an EJB from BPEL with WSIF
A lot of people have told me that they found my entry on creating a Java WSIF file for consumption by BPEL very useful. Many of these people have asked for an EJB version of the same entry, so here it is.
Preparing the EJB
Generally EJBs have already been created with remoting in mind. The only issues that are likely to come up are the use of Java specific classes such as Locales. So in most cases you probably don't have to create a "special BPEL" version of your EJB before wrapping it in WSIF.
Creating the WSIF File
There are several steps involved in creating the WSIF file. Start with a simple WSDL file such as might describe a BPEL process and then do the following.
Definitions Tag
Add the highlighted schema to the normal WSDL defintions
<definitions targetNamespace="http://xmlns.oracle.com/RemoteEJB"
xmlns:tns="http://xmlns.oracle.com/RemoteEJB"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:format="http://schemas.xmlsoap.org/wsdl/formatbinding/"
xmlns:ejb="http://schemas.xmlsoap.org/wsdl/ejb/"
xmlns:plnk="http://schemas.xmlsoap.org/ws/2003/05/partner-link/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
The format namespace adds support for mapping Java types to XML Schema definitions. The ejb namespace allows the binding of WSDL operations to methods on a stateless EJB. The next sections will show how these schema extend WSDL to support EJB binding.
Type Definitions
It is necessary to map the Java types used in your API onto the XML Schema definitions in your WSIF document. This is done using the binding tag.
<binding name="EJBBinding" type="tns:EJBService">
<ejb:binding/>
The ejb:binding tag identifies that this is bound to an EJB rather than a SOAP service.
<format:typeMapping encoding="Java" style="Java">
The format:typeMapping tag tells us that we will be mapping XML Schema types onto Java types.
<format:typeMap typeName="xsd:string" formatType="java.lang.String" />
The format:typeMap tag explains what Java type is to be used for each XML schema type in the interface. In this case we are mapping an XML string onto a Java String object. In addition to Java object types it is also possible to map Java primitives.
<format:typeMap typeName="xsd:boolean" formatType="boolean" />
Most Java methods of any consequence throw some sort of exception. Rather than mapping the whole exception class it is often easier to treat the exception as a black box, the exception type being sufficient to figure out what went wrong. In that case we can define an XML holder for the exception that accepts any type. For example to map an exception wisdl.test.SimpleException we may have an XML type as shown.
<complexType name="SimpleExceptionType">
<sequence>
<any/>
</sequence>
</complexType>
This is then mapped onto the Java exception type as shown.
<format:typeMap typeName="tns:SimpleExceptionType" formatType="wisdl.SimpleException" />
Method Mapping
The final step is now to map the EJB method calls onto the WSDL operations. This is done using the ejb:operation tag to identify which EJB method should be used to support a given operation.
<operation name="hello">
<ejb:operation
methodName="hello"
parameterOrder="name"
interface="remote"
returnPart="response" />
<output name="response"/>
</operation>
This identifies the operation on the ejb "String hello(String name);", the parameters associated with the operation and their order, the type of interface (local or remote) and the return type as well as the associated message names. Lets look at how we specify multiple parameters.
<operation name="hello2">
<ejb:operation
methodName="hello2"
parameterOrder="name1 name2"
interface="remote"
returnPart="response" />
<output name="response">
</operation>
This method has two parameters such as "String hello(String name1, name2);" and so we need to identify the order that parameters are passed to the operation. This is done with the parameterOrder parameter. Note that the names used here are the part names in the interface definition, not the parameter names in the EJB. Positional ordering is used to identify which part maps to which parameter.
Locating the EJB
When dealing with simple Java classes we worry about classpaths and the like. When dealing with EJBs we worry about how to locate the EJB in the first place. The following portion of the WSIF describes the EJB location.
<service name="EJBService">
<port name="EJBPort" binding="tns:EJBBinding">
<!-- Put vendor-specific deployment information here -->
<!-- oc4j deployment configuration -->
<ejb:address className="blog.SimpleSessionEJBHome"
jndiName="SimpleSessionEJB"
initialContextFactory="com.evermind.server.rmi.RMIInitialContextFactory"
jndiProviderURL="ormi://axreynol-pc/SimpleEJB"/>
</port>
</service>
Here we describe the location in the JNDI namespace using the attribute to the ejb:address tag. We also identify the initial context factory with the "initialContextFactory" attribute. The JNDI provider (usually the EJB container) is identified with the jndiProviderURL attribute and we have set this to be the EJB server, in this case running on the default port.
The JNDI access may require additional system properties such as security principals and credentials. These can be placed in the bpel.xml file and associated with the partner link as shown below.
<partnerLinkBinding name="EJB_PartnerLink">
<property name="wsdlLocation">RemoteEJBWSIF.wsdl</property>
<property name="java.naming.security.principal">admin</property>
<property name="java.naming.security.credentials">welcome</property>
</partnerLinkBinding>
Sample Code
The sample code for this example is available in two files. The EJB used is
here. It comprises the following files
- SimpleEJB.jpr
<BR/>JDeveloper Project File for EJB.
- SimpleEJB.deploy
<BR/>Deployment Profile for EJB.
- src/blog/SimpleSessionEJB.java
<BR/>The EJB Remote Interface.
- src/blog/SimpleSessionEJBHome.java
<BR/>The EJB Home Interface.
- src/blog/SimpleSessionEJBBean.java
<BR/>The EJB itself.
- src/blog/SimpleSessionEJBClient.java
<BR/>Simple test client.
- src/META-INF/ejb-jar.xml
<BR/>EJB Deployment Descriptor.
- src/META-INF/orion-ejb-jar.xml
<BR/>OC4J Specific Deployment Descriptor.
The actual BPEL code itself wogether with the WSIF is available
here. It comprises the following files
- RemoteEJBWSIF.wsdl
<BR/>The WSIF File for Invoking a Remote EJB.
- bpel.xml
<BR/>BPEL deployment descriptor with security settings for invoking OC4J container.
- build.xml
<BR/>Ant script to build and deploy BPEL suitcase.
- InvokeRemoteEJB.jpr
<BR/>JDeveloper Project file for BPEL Process.
- InvokeRemoteEJB.wsdl
<BR/>WSDL file for BPEL Process.
- InvokeRemoteEJB.bpel
<BR/>BPEL Process.
To try it out unzip the files and then open the projects in JDeveloper. Fix the EJB location settings to point to your server and container type. Then deploy the EJB to the container and the BPEL process to the BPEL PM. You should now be able to invoke the BPEL process from the console and in turn have it invoke EJBs.
Other Example
Tutorial 702 in the BPEL Process Manager installation (look in samples/tutorials/702.Binding directory) has another example of the EJB binding that I used to help me build this blog entry.
Hope that some of you find this useful.