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...- 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
- I Didn't Follow these Sections from the CXF App Server Guide:
- Replace the Oracle XML parser with Xerces
- Deploying Applications Section
- 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
- 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