Tuesday, 15 September 2009

I can do WSIF me...

Today I struggled with WSIF using the WSIF-chapter in the BPEL Cookbook.
WSIF stands for Webservice Invocation Framework and is an Apache technology that enables a Java service call to be described in a WSDL (Webservice Definition Language). The WSDL describes how the request and response documents map to the input and output objects of the java-service-call and how the Soap operation binds to the java-method-call.
BPEL Process Manager supports several java-technologies to be called using WSIF. The advantage for using WSIF is that from BPEL perspective it works exactly the same as with Webservices. The functional definition part of the WSDL (the schema’s, message definitions and the ports) are the same. The differences are in the implementation parts. In stead of using SOAP over HTTP the BPEL PM will directly call the java-service. The performance is then about the same as with calling java from embedded java. The BPELP PM has to be able to call the java-libraries. They have to be in the class path.

Altough the chapter "Using WSIF for Integration" from the bpel-cookbook, quite clearly states how to work out the java callout from BPEL, I still ran into some strugglings.

Generating the XML Facades
The BPEL cookbook suggests to use the schemac utility to compile the schema's in the WSDL to the XML Facade classes. The target directory should be <bpelpm_oracle_home>\integration\orabpel\system\classes. I found this not so handy. First of all I don't like to have a bunch of classes in this folder. It tend to get messed up. So I want to get them in a jar file. But I also found that the schemac was not able to compile the classes as such. So I started off by adding two parameters:
C:\DATA\projects\EmailConverter\wsdl>schemac -sourceOut ..\src -noCompile WS_EmailConverter.wsdl
The -sourceOut parameter will take care of creating source files in the denoted folder. The -noCompile folder will cause the utility not to compile the classes.

You could also use the -jar option to jar the compiled classes into a jar-file, what essentially my goal is (but then you should omit the -noCompile option presumably).
Also you could add a -classpath <path> option to denote a classpath.

I found that my major problem was that I missed some jar-files. So although I used schemac from the OraBPEL Developer prompt, my classpath was not set properly. Something I did not find in the cookbook. The jar-files you need to succesfully compile the classes are:
  • orabpel.jar
  • orabpel-boot.jar
  • orabpel-thirdparty.jar
  • xmlparserv2.jar
So with this information you could expand the schemac command above to compile the classes into a jar-file.

But the XML Facade classes are to be used in a java implementation class that is to be called from BPEL PM using WSIF. And since it is one project where the facades are strictly for the implementing java class I want them shipped within the same jar file as my custom-code. That way I have to deliver only one jar file to the test and production servers. So I still do not want the schemac utility to compile and jar my XML Facade classes.

To automate this I created an ant file.

Generate the XML Facades using Ant
To be able to use ant within your project it is handy to use the ANT technology scope. That way you're able to let JDeveloper generate an Ant-build-file based on your project.
To do so go to the project properties and go to the Technology Scope entry where you can shuttle the Ant scope to the right:




Then it is handy to have a user-library created that contains the OraBPEL libraries needed to compile the XML Facades:

Having done that you can create a build file based on your project that contains amongst others a compile target with the appropriate classpath (including the just created user-libs) set:

Add genFacedes ant targe with the schemac task
To add the genFacades ant target for generating the facades, you have to define the schemac task in the top of your build.xml file:
<taskdef name="schemac" classname="com.collaxa.cube.ant.taskdefs.Schemac"
classpath="${bpel.home}\lib\orabpel-ant.jar"/>

For this to work you have to extend the build.properties with the bpel.home property:
#Tue Sep 15 11:28:59 CEST 2009
javac.debug=on
javac.deprecation=on
javac.nowarn=off
oracle.home=c:/oracle/jdeveloper101340
bpel.home=C:\\oracle\\bpelpm\\integration\\orabpel
app.server.lib=${bpel.home}\\system\\classes
build.home=${basedir}/build
output.dir=${build.home}/classes
build.classes.home=${build.home}/classes
build.jar.home=${build.home}/jar
build.jar.name=${ant.project.name}.jar
build.jar.mainclass=nl.rabobank.crmi.emailconverter.EmailConverter
(I also added some other properties I'll use later on).
Mark that the bpel home (for 10.1.2) is in the "integration\orabpel" sub-folder of the oracle-home.

Having done that, my genFacades target looks like:
<target name="genFacades" description="Generate XML Facade sources">
<echo>First delete the XML Facade sources generated earlier from ${basedir}/src/nl/darwin-it/www/INT </echo>
<mkdir dir="${basedir}/src/nl/darwin-it/www/INT"/>
<delete>
<fileset dir="${basedir}/src/nl/darwin-it/www/INT" includes="**/*"/>
</delete>
<echo>Generate XML Facade sources from ${basedir}\wsdl\INTI_WS_EmailConverter.wsdl to ${basedir}/src</echo>
<schemac input="${basedir}\wsdl\INTI_WS_EmailConverter.wsdl"
sourceout="${basedir}/src" nocompile="true"/>
</target>

This target first creates a directory where the classes are generated into (if it does not exist yet) and then delete files that are generated in that directory within an earlier iteration. This is to cleanup classes that became obsolete because of XSD changes.
Then it does the schemac task that is defined earlier in the project.

Compile and Jar the files
You can now implement your java code as suggested in the BPEL Cookbook. After that you want to compile and jar the project files.
Since we use BPEL 10.1.2 at my current customer (I know it's high time to upgrade, the team is busy with that), I found that the classes were not accepted by the BPEL PM. It lead to an unsupported class version error. BPEL 10.1.2 only supports Java SE 1.4 compiled classes. So I had to adapt my compile target:
<target name="compile" description="Compile Java source files" depends="init">
<echo>Compile Java source files</echo>
<javac destdir="${output.dir}" classpathref="classpath"
debug="${javac.debug}" nowarn="${javac.nowarn}"
deprecation="${javac.deprecation}" encoding="Cp1252" source="1.4"
target="1.4">
<src path="src"/>
</javac>
</target>
Because it is sometimes handy to compile/build within JDeveloper it is safe to also set the java-compile-version properties in the project-properties.

The create-jar and deploy-jar targets look like:
<!-- create Jar -->
<target name="create-jar" description="Create Jar file" depends="compile">
<echo message="Create Jar file"></echo>
<jar destfile="${build.jar.home}/${build.jar.name}" basedir="${output.dir}">
<manifest>
<attribute name="Main-Class" value="${build.jar.mainclass}"/>
</manifest>
</jar>
</target>
<!-- deploy Jar -->
<target name="deploy-jar" description="deploy jar file" depends="create-jar">
<echo message="Deploy Jar file to ${app.server.lib}"></echo>
<copy  todir="${app.server.lib}" file="${build.jar.home}/${build.jar.name}" overwrite="true" />
</target>
So this should work, together with the BPEL Cookbook it resulted in a working integration. And since it is a direct coupling it is pretty fast (although my implementation does not do much yet...

No comments :