Friday, June 13, 2008

CXF vs OC4J ... Round 1

My deployment environment was recently switched to Oracle Application Server with Oracle Http Server (OC4J + OHS). Currently, our primary focus is integration with some external SOAP Web Services and we've been using the Apache CXF Project to generate a mock implementation of the service as well as a client from the WSDL.

I'm well aware of common pains of switching between JEE Application Servers, having worked with WebLogic, GlassFish v2, JBoss, and now OC4J. There's the initial learning curve for things like auto/hot-deployment directory, automated deployment w/in your build, getting to know the admin console, and log locations. Unfortunately it's never just that easy. You always end up running into issues around configuration differences and sometimes terrible class path and version nightmares.

The worst part of porting our applications to OC4J was most definitely deploying our Mock Service Implementation and CXF Clients. It's funny, after hitting the first CXF deployment issue I found myself at the CXF App Server Guide. A quick glance down the page indicates I'm in for quite the ride.

I found that in the end, a little more than half of the information on this page was correct... but not everything. Here are the differences I ran into. (Note: I hope I'm capturing everything, I meant to write this a month ago, during the time I was running into these issues, but never got around to it)

1. Shared Libraries and Deployment
I completely skipped the sections Replace the Oracle XML parser with Xerces and Deploying Applications Section.
I ended up having to make a number of modifications to the -Xbootclasspath/p: Java Option inside opmn.xml and by the time it was over and done with, managing shared libraries was unnecessary.

2. Setting System Properties
No matter what I did, OC4J gave me an implementation of javax.xml.parsers.DocumentBuilderFactory that would break CXF. So, I did end up setting a System Property (I know, I know ...). When using CXF to stand up a service, your web.xml will need to identify a listener as such:


<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

So, I wrote my own ContextLoadListener that extends this one (and modified the web.xml to point to mine). It's just a pass-through, simply making a call to the same method on the listener I'm extending. However, in the contextInitialized method, I set the system property just before calling the super class.

public void contextInitialized(ServletContextEvent event) {
System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
"org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
super.contextInitialized(event);
}


In the end...
  1. I Followed these Sections from the CXF App Server Guide:

    • Preparing stax-api

    • Get rid of OC4J JAX-WS libraries

    • swapping Oracle wsdl.jar with wsdl4j.jar and jaxb.jar API with jaxb-api-2.0.jar



  2. I Didn't Follow these Sections from the CXF App Server Guide:

    • Replace the Oracle XML parser with Xerces

    • Deploying Applications Section



  3. Ended up with the following -XbootClasspath/p: values:

    -Xbootclasspath^/p:C:\stax-api-1.0.1.jar;C:\xercesImpl-2.8.1.jar;C:\xalan-2.7.0.jar;C:\xml-apis-1.3.02.jar;C:\webservices\wsdl4j-1_6_2\lib\wsdl4j.jar;C:\jaxb-api-2.0.jar


  4. Set one system property in a custom ContextLoaderListener (as shown above)



Other Notes:

  • These steps worked for me with CXF Versions 2.0.2-incubator & 2.0.6

  • If you're on CXF version 2.1, you'll need jaxb-api-2.1 instead of 2.0

  • Download CXF here

  • Download Xerces 2.8.1 here

  • Download WSDL4J here

  • Make a directory to keep custom artifacts as you move through the process

4 comments:

Daniel said...

I added a link to here on that page in CXF's docs. Hopefully that will help someone in the future. :-)

Mustafa Daşgın said...

Hi,

Good article and i tryed it step by step but when oc4j is starting it gives an error. Can you help me?:

OC4J startup failed
javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found
at javax.xml.parsers.SAXParserFactory.newInstance(Unknown Source)
at oracle.classloader.util.XMLConfiguration. &ltinit&gt (XMLConfiguration.java:380)
at oracle.oc4j.loader.boot.BootConfigurationFactory.getConfiguration(BootConfigurationFactory.java:107)
at oracle.oc4j.loader.boot.BootConfigurationFactory.create(BootConfigurationFactory.java:59)
at oracle.oc4j.loader.boot.BootStrap.main(BootStrap.java:22)

Nicholas said...

oc4j throws that error when it can't find the xerces jar, but you've forced to use the xerces jar by specifying org.apache.xerces.jaxp.SAXParserFactoryImpl.
Make sure your bootclasspath is pointing correctly at xerces and xml-apis jars.

sulochan said...

where did you configure "XbootClasspath/p:values:" and can you explain how did you do that?