Tuesday, January 21, 2014

JBoss 4.2.2 to Wildfly8/Jboss7 CXF migration

Prelude

Recently I was facing a migration project, migrating from from JBoss 4.2.2 to Wildfly 8. The old project was using Spring 2.5.5, Hibernate 3.6.7 and CXF 2.2.7.
Everything except CXF was fairly easy to migrate. Wildfly 8 comes with CXF 2.7.7 bundled and I wanted to use the managed dependencies. 
I have made this post to hopefully help other people facing a migration from an older JBoss to a more resent version.

Before starting any migration I would strongly recommend making sure you have at least some smoke tests of all services.
For old legacy systems no test might exist, but making a few smoke tests that exercise as much as possible of the service could work.   
An excellent tool for testing SOAP web service is SoapUI.

I have added short description of the project configuration in the bottom of the post.

Happy reading! 


Here we go!

First I made sure all CXF dependencies was removed from the war file, but WSDL and XSD files were causing a problem.


First try deploying, resulted in some problems loading the CXF beans from cxf-beans.xml.


ERROR [org.springframework.web.context.ContextLoader] (MSC service thread 1-5) Context initialization failed: org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Failed to import bean definitions from URL location [classpath:/cxf-beans.xml]
Offending resource: ServletContext resource [/WEB-INF/classes/applicationContext.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://cxf.apache.org/jaxws]
Offending resource: class path resource [cxf-beans.xml]
        at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68) [spring-2.5.5.jar:2.5.5]
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85) [spring-2.5.5.jar:2.5.5]
        at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:76) [spring-2.5.5.jar:2.5.5]
I solved this by completely removing cxf-beans.xml and let Wildfly manage the services.
Unfortunately this didn't solve all my problems. Now I was facing problems with the XSD's.
We used to create web services by, first creating a WSDL and XSD files and then running wsdl2jave, generating model and interface. 

Caused by: org.apache.ws.commons.schema.XmlSchemaException: Unable to locate imported document at '/ServiceObject.xsd', relative to 'vfs:/C:/Development/wildfly-8.0.0.CR1/bin/content/project.war/WEB-INF/classes/ServiceV1.wsdl#types1'.

After hours of googling about the problem, I decided to get rid of all WSDL and XSD's and let Wildfly handle everything. I removed the wsdlLocation = "classpath:ServiceV1.wsdl", from @WebService annotation and deleted alle WSDL and XSD's from the project. 

First success! The project was now able to deploy. However Wildfly was not showing any registered services in the console :(. 
The problem here was, that I was using standalone-full.xml, which did not have web services enabled by default.
Easy solved by adding:

<extension module="org.jboss.as.webservices">   
and
<subsystem xmlns="urn:jboss:domain:webservices:1.2">
 <modify-wsdl-address>true</modify-wsdl-address>
 <wsdl-host>${jboss.bind.address:127.0.0.1}</wsdl-host>
 <endpoint-config name="Standard-Endpoint-Config"/>
 <endpoint-config name="Recording-Endpoint-Config">
  <pre-handler-chain name="recording-handlers" protocol-bindings="##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM">
   <handler name="RecordingHandler" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
  </pre-handler-chain>
 </endpoint-config>
 <client-config name="Standard-Client-Config"/>
</subsystem>   

to standalone-full.xml.

The Wildfly console was now showing all my services. Wohoo!
However my newly gained success only lasted until i clicked the WSDL link :(.
I was now presented to a nice stack trace...
Exception handling request to /project/ServiceV1: java.lang.AbstractMethodError: org.apache.xerces.dom.DeferredDocumentImpl.setXmlStandalone(Z)V
If you have any dependencies to xerces either remove it if possible or use the version provided by Wildfly.

A quick check list to run through: 
  • Remove all WSDL and XSD files
  • Remove wsdlLocation in @WebService element
  • If Services was previously mapped using a name in the WSDL, change "serviceName" to reflect the right name of the service
  • Service endpoints can be found in the web console: http://localhost:9990/console/App.html#webservice-runtime
  • Make sure model classes is properly decorated with XML annotations according to XSD's. If originally generated from XSD's, it should not be a problem
  • Make sure xerces dependency is managed by Wildfly

Sample project configuration

The project structure was looking something like this:

war \
---- WEB-INF \
-------- web.xml
-------- lib \
------------ cxf-2.2.7.jar
-------- classes \
------------ applicationContext.xml
------------ cxf-beans.xml
------------ ServiceV1.wsdl
------------ ServiceObjectV1.xsd
------------ com.blogspot.jpdevelopment.v1.ServiceV1.class
------------ com.blogspot.jpdevelopment.v1.ServiceV1Impl.class
------------ com.blogspot.jpdevelopment.v1.ServiceObjectV1.class   

Web service implementation was looking like this:
@WebService(name = "ServiceV1",
   serviceName = "ServiceV1",
   portName = ServiceV1LOCAL",
   targetNamespace = "http://schema.jpdevelopment.blogspot.com/v1",
   wsdlLocation = "classpath:ServiceV1.wsdl",
   endpointInterface = "com.blogspot.jpdevelopment.v1.ServiceV1")

public class ServiceV1Impl implements ServiceV1 {            

And the interface:
@WebService(targetNamespace = "http://schema.jpdevelopment.blogspot.com/v1", name = "ServiceV1")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface ServiceV1 {

CXF was started in web.xml
<web-app>
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>WEB-INF/classes/applicationContext.xml</param-value>
 </context-param>
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <listener>
  <listener-class>com.blogspot.jpdevelopment.ContextLoadListener</listener-class>
 </listener>
 <servlet>
  <servlet-name>CXFServlet</servlet-name>
  <display-name>CXF Servlet</display-name>
  <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
  <servlet-name>CXFServlet</servlet-name>
  <url-pattern>/ws/*</url-pattern>
 </servlet-mapping>
</web-app> 

Web service end points was configured in cxf-beans.xml
<bean name="serviceV1Impl" class="com.blogspot.jpdevelopment.v1.ServiceV1Impl">
 <property name="someService" ref="someService" />
</bean>

<jaxws:endpoint id="serviceV1"
 implementor="#serviceV1Impl" address="/serviceV1"
 wsdlLocation="classpath:ServiceV1.wsdl">
</jaxws:endpoint>  

XSD's was referenced inside the WSDL with relative paths, because the project should be deployable to both test and production with any modifications to the generated was file.

1 comment:

  1. Thanks for guidance...It helped me in resolving issue when migrating from JBoss7 to WildFly10 by changing Xerces jar file from old version to latest 2.11SP4 version. Because of the AbstractMethodError, I was not able to access my WSDL file.

    ReplyDelete