cxf jax-ws websphere weblogic annotation DisableIBMJAXWSEngine Ignore-Scanning-Packages Ignore-Scanning-Archives prefer-web-inf-classes prefer-application-packages prefer-application-resources
Problem:
So CXF is your chosen JAX-WS framework for your application - perhaps because you want your appplication to work the same way in every servlet container - tomcat included - or because you can't avoid the need to reference the implementation rather than just the pure JAX-WS spec (access to the http-session for example). While these reasons seem valid they seem to have been considered as an afterthought in containers with built in JAX-WS handling - such as WebSphere and WebLogic.
So you follow the CXF notes and perhaps blog/mail-list posts and either are in the state where: (a) the application is not working or (b) is working but you're not sure how or why. What steps can you perform to guarantee successful deployment, and (if possible) can you understand the context for them - so you can decide if they're needed for example.
Solution:
The following are useful references:
- CXF Notes - Application Server Specific Configuration Guide
- WebSphere - Using a third-party JAX-WS Web services engine
- WebSphere - Reducing annotation searches during application deployment
- WebLogic - Deployment Descriptor Reference
Normally for these container/class-loader issues you can get the desired behaviour by simply getting the container to load the application's libraries first (parent last). The complication in this case is the annotation processing, which seems (in my testing at least) can happen independently of the annotation processing implementation - particularly for the association of
@Resource
references. To get past this, there's essentially three areas to cover:
- Supply JAX-WS annotation processing libraries (geronimo) that will override the container defaults - this includes all libraries that the CXF framework and annotation processing require - because nothing can be used from the container (parent)
- Tell the container you're handling annotations - explicitly
- Setup Parent-Last Class-loading - get the container to use your applications libraries before its own
Step 1: Supply JAX-WS annotation processing libraries and dependencies
There's a longer list of libraries in the CXF Notes but many of these are not specifically essential to the JAX-WS issue (the latest JAXB libraries for example will be required by CXF in a tomcat deployment). These are the libraries that appear to be need in addition to those that would have otherwise been included with the application:geronimo-annotation_1.0_spec-1.1.1.jar
- Annotation Processinggeronimo-jaxws_2.2_spec-1.1.jar
- Runtime Overridegeronimo-stax-api_1.0_spec-1.0.1.jar
- Runtime Overridegeronimo-ws-metadata_2.0_spec-1.1.3.jar
- Annotation Processingstax2-api-3.1.1.jar
- Runtime Overridewoodstox-core-asl-4.1.1.jar
- Library Requirement
[19/10/12 8:34:46:641 EST] 00000044 AbstractInjec W CWNEN0070W: The javax.annotation.Resource annotation class will not be recognized because it was loaded from the file:/E:/IBM/WebSphere/AppServer/profiles/AppSrv01/installedApps/SERVERNode01Cell/example-app.ear/lib/geronimo-annotation_1.0_spec-1.1.1.jar location rather than from a product class loader. [19/10/12 8:34:46:645 EST] 00000044 AbstractInjec W CWNEN0070W: The javax.xml.ws.WebServiceRef annotation class will not be recognized because it was loaded from the file:/E:/IBM/WebSphere/AppServer/profiles/AppSrv01/installedApps/SERVERNode01Cell/example-app.ear/lib/geronimo-jaxws_2.2_spec-1.1.jar location rather than from a product class loader.The "Runtime Override" libraries listed above are essential as the overridden annotation processing code can not load certain classes from the parent - this may include classes from
javax.xml.*
. These 'parent prevention' issues are most likely going to be reported as java.lang.VerifyError
. In WebSphere for example you'll encounter 'parent prevention' issues as:Caused by: java.lang.VerifyError: JVMVRFY013 class loading constraint violated; class=org/apache/cxf/jaxws/context/WebServiceContextImpl, method=getEndpointReference([Lorg/w3c/dom/Element;)Ljavax/xml/ws/EndpointReference;, pc=0 at java.lang.J9VMInternals.verifyImpl(Native Method) at java.lang.J9VMInternals.verify(J9VMInternals.java:85) at java.lang.J9VMInternals.initialize(J9VMInternals.java:162) at org.apache.cxf.jaxws.context.WebServiceContextResourceResolver.resolve(WebServiceContextResourceResolver.java:61)
Step 2: Tell the container you're handling annotations
This seems the strangest part but both WebSphere and WebLogic will continue to report errors - in particular about the@Resource
annotation. For example, on WebSphere:[19/10/12 17:11:03:261 EST] 00000053 webapp E com.ibm.ws.webcontainer.webapp.WebAppImpl populateJavaNameSpace SRVE8084E: An unexpected internal server error occurred while populating the namespace. com.ibm.wsspi.injectionengine.InjectionException: CWNEN0044E: A resource reference binding could not be found for the following resource references [org.example.hello.HelloSoapService/context], defined for the example-app component. at com.ibm.wsspi.injectionengine.InjectionProcessor.resolveInjectionBindings(InjectionProcessor.java:1208)For example, on WebLogic:
<24/10/2012 2:17:27 PM EST> <Error> <J2EE> <BEA-160223> <The resource-env-ref 'org.example.hello.HelloSoapService/context' declared in the standard descriptor or annotation has no JNDI name mapped to it. The resource-env-ref must be mapped to a JNDI name using the resource-env-description element of the weblogic proprietary descriptor or corresponding annotation.>
For WebSphere - Disable and Ignore Annotation Scanning
There are ways to configure this globally - in the application server settings and configuration. I'll only note here the application-specific approach. This involves setting attributes in theMETA-INF/MANIFEST.MF
of the war file.DisableIBMJAXWSEngine
: trueIgnore-Scanning-Packages
: comma-separated list of packages where there are service implementations - and use of the@Resource
and@WebService
annotationsIgnore-Scanning-Archives
: comma-separated list of jar-file libraries where there are service implementations - and use of the@Resource
and@WebService
annotations
(war-app)/WEB-INF/classes
for example. It does seem setting the Ignore-Scanning-Archives setting can significantly speed application deployment - and is harmless if there is no annotation processing required. Hand-coding MANIFEST files is risky - I'd recommend using an ant task (and define all three attributes):<target name="dist" description="make the war and ear"> <!-- list of packages with WS implementations - which should be ignored by container annotation processing --> <property name="service.packages"> org.example.hello, org.example.goodbye </property> <loadresource property="service.packages.delim"> <propertyresource name="service.packages"/> <filterchain> <tabstospaces/> <deletecharacters chars=" "/> <striplinebreaks/> </filterchain> </loadresource> <path id="webapp.archives"> <fileset dir="./example-app/WEB-INF/lib"> <include name="**/*.jar"/> </fileset> </path> <pathconvert property="webapp.archives.delim" refid="webapp.archives" pathsep="," dirsep="/"> <map from="${basedir}/example-app/WEB-INF/lib/" to=''/> </pathconvert> <!-- Define META-INF attributes --> <manifest file="./example-app/META-INF/MANIFEST.MF" mode="update" flattenAttributes="true"> <attribute name="DisableIBMJAXWSEngine" value="true"/> <attribute name="Ignore-Scanning-Packages" value="${service.packages.delim}"/> <attribute name="Ignore-Scanning-Archives" value="${webapp.archives.delim}"/> </manifest> <copy todir="./example-app/WEB-INF/lib"> <fileset dir="./runtime"> <include name="**/*.*"/> </fileset> </copy> <jar destfile="example-app.war" basedir="./example-app/" manifest="./example-app/META-INF/MANIFEST.MF"/> <ear destfile="example-app.ear" appxml="metadata/application.xml"> <fileset dir="." includes="example-app.war"/> <metainf dir="metadata" includes="*.*" excludes="application.xml"/> </ear> </target>
For WebLogic - Prefer Packages and Resources
In the(ear-app)/META-INF/weblogic-application.xml
you must explicitly preference the packages supplied as part of the CXF solution and the service resources these libraries include:<?xml version="1.0" encoding="UTF-8"?> <weblogic-application xmlns="http://www.bea.com/ns/weblogic/90"> <xml> <parser-factory> <saxparser-factory>org.apache.xerces.jaxp.SAXParserFactoryImpl</saxparser-factory> <document-builder-factory>org.apache.xerces.jaxp.DocumentBuilderFactoryImpl</document-builder-factory> <transformer-factory>org.apache.xalan.processor.TransformerFactoryImpl</transformer-factory> </parser-factory> </xml> <application-param> <param-name>webapp.encoding.default</param-name> <param-value>UTF-8</param-value> </application-param> <prefer-application-packages> <!-- // for logging --> <package-name>org.apache.log4j.*</package-name> <!-- // for jaxb --> <package-name>com.sun.xml.*</package-name> <!-- // for apache commons lang/io --> <package-name>org.apache.commons.*</package-name> <!-- // for spring/hibernate --> <package-name>antlr.*</package-name> <package-name>org.springframework.*</package-name> <!-- // for jstl --> <package-name>javax.servlet.jsp.jstl.*</package-name> <!-- // for jax-ws --> <package-name>javax.jws.*</package-name> <package-name>javax.ws.*</package-name> <!-- // xml processing --> <package-name>javax.xml.*</package-name> <package-name>javax.xml.stream.*</package-name> <package-name>org.xml.sax.*</package-name> <package-name>org.w3c.*</package-name> <package-name>org.apache.xmlcommons.*</package-name> <package-name>org.apache.xml.serializer.*</package-name> <package-name>org.apache.xerces.*</package-name> <package-name>org.apache.xalan.*</package-name> <package-name>com.ctc.wstx.*</package-name> <package-name>org.codehaus.*</package-name> </prefer-application-packages> <prefer-application-resources> <resource-name>META-INF/services/javax.ws.rs.ext.RuntimeDelegate</resource-name> <resource-name>META-INF/services/javax.xml.bind.JAXBContext</resource-name> <resource-name>META-INF/services/javax.xml.datatype.DatatypeFactory</resource-name> <resource-name>META-INF/services/javax.xml.parsers.DocumentBuilderFactory</resource-name> <resource-name>META-INF/services/javax.xml.parsers.SAXParserFactory</resource-name> <resource-name>META-INF/services/javax.xml.stream.XMLEventFactory</resource-name> <resource-name>META-INF/services/javax.xml.stream.XMLInputFactory</resource-name> <resource-name>META-INF/services/javax.xml.stream.XMLOutputFactory</resource-name> <resource-name>META-INF/services/javax.xml.transform.TransformerFactory</resource-name> <resource-name>META-INF/services/javax.xml.validation.SchemaFactory</resource-name> <resource-name>META-INF/services/javax.xml.ws.spi.Provider</resource-name> <resource-name>META-INF/services/javax.xml.xpath.XPathFactory</resource-name> <resource-name>META-INF/services/org.apache.cxf.bus.factory</resource-name> <resource-name>META-INF/services/org.apache.xalan.extensions.bsf.BSFManager</resource-name> <resource-name>META-INF/services/org.apache.xml.dtm.DTMManager</resource-name> <resource-name>META-INF/services/org.codehaus.stax2.validation.XMLValidationSchemaFactory.dtd</resource-name> <resource-name>META-INF/services/org.codehaus.stax2.validation.XMLValidationSchemaFactory.relaxng</resource-name> <resource-name>META-INF/services/org.codehaus.stax2.validation.XMLValidationSchemaFactory.w3c</resource-name> <resource-name>META-INF/services/org.osgi.framework.launch.FrameworkFactory</resource-name> <resource-name>META-INF/services/org.relaxng.datatype.DatatypeLibraryFactory</resource-name> <resource-name>META-INF/services/org.w3c.dom.DOMImplementationSourceList</resource-name> <resource-name>META-INF/services/org.xml.sax.driver</resource-name> <!-- // geronimo (at present) has no service such declaration (glassfish and others do) - include for future reference --> <resource-name>META-INF/services/com.sun.xml.ws.spi.db.BindingContextFactory</resource-name> </prefer-application-resources> </weblogic-application>
Step 3: Setup Parent-Last Class-loading
This is probably the easiest step.For WebSphere - set flags during deployment
Note that this should be set at the ear and war (web module) level.For WebLogic - set prefer-web-inf-classes
This doesn't seem to be a comprehensive setting based on what is required in theweblogic-application.xml
file, but in the (war-app)/WEB-INF/weblogic.xml
file, ensure prefer-web-inf-classes
is set to true:<?xml version="1.0" encoding="UTF-8"?> <weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/90" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bea.com/ns/weblogic/90 http://www.bea.com/ns/weblogic/90/weblogic-web-app.xsd"> <jsp-descriptor> <keepgenerated>false</keepgenerated> <page-check-seconds>-1</page-check-seconds> <precompile>true</precompile> <precompile-continue>true</precompile-continue> <verbose>false</verbose> </jsp-descriptor> <container-descriptor> <servlet-reload-check-secs>-1</servlet-reload-check-secs> <prefer-web-inf-classes>true</prefer-web-inf-classes> </container-descriptor> </weblogic-web-app>
Happy CXF servicing.