Tuesday, November 17, 2009

Monkey-Patching Oracle SOA Suite 11g Ant Files to Build Without JDeveloper

I hate having to have more than the bare minimum installed on my build boxes. We’re using SOA Suite 11g and JDeveloper on our current project and much to my annoyance it seemed as if I’d have to install the Oracle IDE on all my build boxes in order to run the Ant scripts which it can generate. I didn’t like the idea of that, so I did some hacking and monkey patched them.

The Problem

I started at the beginning - with ant-sca-compile.xml and build.xml from JDeveloper.  Using these I could run Ant targets such as “scac” which meant my composite was compiled and verified.  The problem was, I needed to tell Ant where JDeveloper was installed. This in turn hid a mass of dependencies. 

I don’t like unmanaged dependencies. I like to know what goes into the various steps of my build.

The Solution

The first task was to move all the dependencies out of the JDeveloper install and into a project-local location. I created a “lib” directory in my Composite project for this purpose.  I then worked my way down through all the dependencies listed in “FileSet” elements in path “scac.tasks.class.path” in ant-sca-compile.xml  and copied them to ./lib.

Now I had to surgically extract all the references from ant-sca-compile.xml to the JDeveloper install.  I tackled all references to “oracle.home” first as I found this particularly galling. I created a new property called “applications.home” and set it to be the directory where ant-sca-compile.xml lived. I then worked down the definition of “scac.tasks.class.path” and changed all references from “${oracle.home}/…” to “${applications.home}/lib”, removing the additional directories as I went. (i.e. I ended up with “include name=”orabpel.jar””, etc.)

Every time I moved a large chunk of references I ran my built with Ant to check I’d not broken anything.  (Slowly, slowly, catchee monkee…)

Once I’d done this, I did the same for all the other elements in this path declaration. With this done, I then simplified things by removing all the checking of properties from the top of the file.

Now I was able to focus on the actual taskdef I was interested in: “scac”.  Firstly, I again simplified by removing the property checking. this left me with a single line; a call to the Oracle Ant task “scac”.

One by one, I took each of the parameters, and set them manually to extricate them from the mass of JDeveloper Ant complexity.  This involved:

  • creating my own version of scac.input – myscac.input which I set to point at the location of my composite.xml file
  • setting compositeName to the name of my SOA Suite Composite project (“GetEmployeeName” in my case)
  • setting compositeDir to the path to my SOA Suite Composite project
  • replacing scac.output with tmp.output.dir (pointing at “./”) combined with ${compositeName}.xml
  • replacing scac.error with tmp.output.dir combined with ${compositeName}.error
  • replacing scac.application.home with ${compositeDir}
  • setting displayLevel manually to be “3” (the maximum)

I was almost there. It all worked. All I needed to do was remove the now redundant properties.

The Real Problem

This is where the monkey patching came in. I realised as I removed the now redundant properties that something, somewhere still needed to be told what oracle.home was.  I guess this is buried deep in the Oracle Ant tasks themselves. I tried to take a look but a decompiler was no help. (I guess they’re obfuscated.)

The Real Solution

But I didn’t want to give up (and here comes the monkey patch.)  To find out what actually was in oracle.home (effectively the JDeveloper install which was needed for a successful build and validation I took a copy of all the files, pointed oracle.home at this copy, and then piece by piece removed bits until I had the barest minimum needed for the target to run. The end result?  All you needed was orabpel.jar. The thing was, it needed to be in a directory like this: ${oracle.home}/soa/modules/oracle.soa.bpel_11.1.1

Problem solved! All then had to do was create this directory structure in my project’s ./lib directory, copy orabpel.jar into it, and then set ${oracle.home} to point to ${applications.home}/lib and we were up and running.

Where Now?

Next step is to get all the other SOA Suite Ant scripts (ant-scac-package.xml, ant-scac-upgrade.xml, ant-scac-dploy.xml and ant-scac-test.xml) to work without being umbillically attached to a JDeveloper install.

After that I’m going to use some Ivy and put all these dependencies (with some meaningful jar names including version numbers) into a Maven repository.

Finally I hope to wrap up the Ant targets themselves as Maven 2.x plugins.  It’d be really nice if Oracle put all these dependencies in the Maven repositories already, but knowing how long it’s taken/taking Sun, and how non-open to the idea IBM are I’m not holding my breath.  I guess this means there will need to be a little setup script which you’ll need to run against JDeveloper to get all the bits you need in a Local Maven repo.

Expect more blog posts as I progress.  There will also (hopefully) be some Ant source once I tidy things up.


Henk Hommersom said...

Great article!

We've done something similar in the jdev/soa 10g timeframe to get our build running.

do you use the jvm option "-verbose:class"? for this monkey patching? Combined with some grepping, it might give a quick insight into the .jar files used by the deploy.

Andrew Law said...

Thanks Henk. Glad to hear I'm not alone.

I didn;t manage to do anything anywhere near so advanced. I'll give it a try though and see if I can find out the exact nature of the coupling.

Wilco Greven said...

Thanks for blogpost Andrew. I'm trying to build a maven plugin for building and deploying composites and your posts have helped a lot.

Regarding the monkey patching to get orabpel.jar on the bpelc classpath, there is another way to accomplish this. That is by (ab)using the scac.user.classpath property.

Andrew Law said...

Hi Wilco,

Thanks for the comment. I'd love to help out if you need it on the maven plugins. Do you have the URL of a public source code reopsitory where you have this hosted?

I'm also interested in how you (ab)used the scac.user.classpath property. My workaround (as you've seen) involved putting this jar in our source cnotrol which I disilke. Have you blogged this?