Using Metro in JBoss AS 7.2.0 Final
tmfkell Sep 20, 2013 10:23 AMDear Community,
recently I've been doing some research on how to migrate an application from JBoss AS 5.1.0 to JBoss AS 7.2.0 Final.
The main features of the application are:
- it's a spring application (+struts+tiles)
- the services are implemented as ejbs
- it operates as client for different web services
- it doesn't provide own web services
- it uses Metro stack (2.2.1-1)
Of course, the goal is and was to keep all the functionality without massive changes - neither on application nor on application server level.
Suprisingly the number of critical, deployment-preventing issues was marginal:
- mapping existing configuration to new model
- integrating with security/ldap
- add external application configuration file to classpath via JBoss Module
- jndi-url-schema
- change some xml-files to be conform to spec (tld-files).
The main problem was to establish the ws-communication at runtime. Apache CXF didn't work out of the box. Some time ago, we integrated Metro in JBoss 5.1.0 due to the policy requirements of a ws provider which defined a bunch of non-optional policies such as WS-Policy 1.5, WS-SecurityPolicy 1.2, WS-RM Policy (RMP) 1.2:
<wsp:Policy wsu:Id="ServicePolicy">
<wsp:ExactlyOne>
<wsp:All>
<wsam:Addressing wsp:Optional="false" />
<wsrm:RMAssertion>
<wsp:Policy>
<wsrm:SequenceTransportSecurity />
</wsp:Policy>
</wsrm:RMAssertion>
<sp:TransportBinding>
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken RequireClientCertificate="false" />
</wsp:Policy>
</sp:TransportToken>
<sp:Layout>
<wsp:Policy>
<sp:Lax />
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp />
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic128 />
</wsp:Policy>
</sp:AlgorithmSuite>
</wsp:Policy>
</sp:TransportBinding>
<sp:Wss10 />
<sp:Trust13 /> <!-- causes Exception in Apache CXF -->
<sp:EndorsingSupportingTokens>
<wsp:Policy>
<sp:SecureConversationToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:BootstrapPolicy>
<wsp:Policy>
<sp:TransportBinding>
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken RequireClientCertificate="false" />
</wsp:Policy>
</sp:TransportToken>
<sp:Layout>
<wsp:Policy>
<sp:Strict />
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp />
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic128 />
</wsp:Policy>
</sp:AlgorithmSuite>
</wsp:Policy>
</sp:TransportBinding>
<sp:EncryptedParts>
<sp:Body />
</sp:EncryptedParts>
<sp:SignedParts>
<sp:Body />
<sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing" />
<sp:Header Name="From" Namespace="http://www.w3.org/2005/08/addressing" />
<sp:Header Name="FaultTo" Namespace="http://www.w3.org/2005/08/addressing" />
<sp:Header Name="ReplyTo" Namespace="http://www.w3.org/2005/08/addressing" />
<sp:Header Name="MessageID" Namespace="http://www.w3.org/2005/08/addressing" />
<sp:Header Name="RelatesTo" Namespace="http://www.w3.org/2005/08/addressing" />
<sp:Header Name="Action" Namespace="http://www.w3.org/2005/08/addressing" />
<sp:Header Name="AckRequested" Namespace="http://docs.oasis-open.org/ws-rx/wsrm/200702" />
<sp:Header Name="SequenceAcknowledgement" Namespace="http://docs.oasis-open.org/ws-rx/wsrm/200702" />
<sp:Header Name="Sequence" Namespace="http://docs.oasis-open.org/ws-rx/wsrm/200702" />
<sp:Header Name="CreateSequence" Namespace="http://docs.oasis-open.org/ws-rx/wsrm/200702" />
</sp:SignedParts>
<sp:SignedEncryptedSupportingTokens>
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssUsernameToken10 />
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SignedEncryptedSupportingTokens>
</wsp:Policy>
<sp:Wss11>
<wsp:Policy>
<sp:MustSupportRefIssuerSerial />
<sp:MustSupportRefThumbprint />
<sp:MustSupportRefEncryptedKey />
</wsp:Policy>
</sp:Wss11>
<sp:Trust13>
<wsp:Policy>
<sp:MustSupportIssuedTokens />
<sp:RequireClientEntropy />
<sp:RequireServerEntropy />
</wsp:Policy>
</sp:Trust13>
</sp:BootstrapPolicy>
</wsp:Policy>
</sp:SecureConversationToken>
</wsp:Policy>
</sp:EndorsingSupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
When integrating Metro, it seemed to be the only framework that supports all these policies. We finally got ws-access and -communication working by simply replacing the jboss ws-native jars by the Metro jars and setting up some properties for username, password (see http://www.oio.de/public/xml/usernametoken-tutorial-webservice-security-artikel.htm) and timeout. No need to handle with policy feature configuration, probably since the WS is also implemented with Metro.
Now, while still doing research on migration, we had the choice: either A) map the (currently minimal) configuration-code from Metro to Apache CXF or B) use Metro in JBoss AS 7.2.
I read some documentations about Apache CXF (2.6.6 ships with JBoss 7.2.0 Final) and its features and configurations. I also tried some Apache CXF examples with little success. If I get it right the support for WS-RMP1.2 is not yet implemented in 2.6.6.
In addition, the WSDL given by the ws provider (according to comments generated by Metro) was not parsable - it leads to the following exception:
java.lang.IllegalArgumentException: Trust13 assertion doesn't contain any Policy
at org.apache.cxf.ws.security.policy.builders.Trust13Builder.build(Trust13Builder.java:40)
at org.apache.cxf.ws.security.policy.builders.Trust13Builder.build(Trust13Builder.java:34)
at org.apache.neethi.AssertionBuilderFactoryImpl.invokeBuilder(AssertionBuilderFactoryImpl.java:138)
at org.apache.neethi.AssertionBuilderFactoryImpl.build(AssertionBuilderFactoryImpl.java:117)
...
Finally we decided to try B) Metro on JBoss AS 7.2.
There are only a few posts dealing with Metro on JBoss. In JBoss AS 7 Apache CXF is everybodys darling and so there's few support for Metro, the outcast adoptive child.
I got inspired by the posts, that there might be a way, to get it working.
- https://community.jboss.org/thread/173486
- https://community.jboss.org/thread/204752
- https://community.jboss.org/message/732708
Because these posts are quite old I'm trying to start a new one.
--------------------------------------------------
Finally, I got communication working with Metro in JBoss AS 7 without code changes by using the following configuration in JBoss AS 7.2.0 Final:
1. provided a Metro-module (Metro 2.2.1-1) with following structure:
-module.xml
-webservices-api.jar
-webservices-extra-api.jar
-webservices-extra.jar
-webservices-rt.jar
-webservices-tools.jar
-service-loader-resources
-services
-javax.xml.ws.spi.Provider
I my case I chose the module name 'com.sun.xml.ws'.
The file javax.xml.ws.spi.Provider contains the class-name of the Metro Provider Implementation which is 'com.sun.xml.ws.spi.ProviderImpl'.
The module.xml has the following content:declaring dependencies
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="com.sun.xml.ws">
<resources>
<resource-root path="webservices-rt.jar"/>
<resource-root path="webservices-api.jar"/>
<resource-root path="webservices-extra.jar"/>
<resource-root path="webservices-extra-api.jar"/>
<resource-root path="webservices-tools.jar"/>
<resource-root path="service-loader-resources"/>
</resources>
<dependencies>
<module name="javax.activation.api"/>
<module name="javax.annotation.api"/>
<module name="javax.ejb.api"/>
<module name="javax.jws.api"/>
<module name="javax.mail.api"/>
<module name="javax.resource.api"/>
<module name="javax.security.auth.message.api"/>
<module name="javax.servlet.api"/>
<module name="javax.transaction.api"/>
<module name="javax.xml.bind.api"/>
<module name="javax.xml.registry.api"/>
<module name="javax.xml.soap.api"/>
<module name="javax.xml.ws.api"/>
<module name="nu.xom"/>
<module name="org.apache.xerces"/>
<module name="org.apache.xml-resolver"/>
<module name="javax.xml.stream.api" />
<system>
<paths>
<path name="com/sun/org/apache/xerces/internal/dom"/>
<path name="com/sun/org/apache/xerces/internal/jaxp"/>
<path name="javax/xml/transform"/>
<path name="javax/xml/parsers"/>
<path name="javax/xml/transform/dom"/>
<path name="javax/xml/transform/sax"/>
<path name="javax/xml/transform/stax"/>
<path name="javax/xml/transform/stream"/>
<path name="javax/xml/namespace"/>
<path name="org/xml/sax"/>
<path name="org/xml/sax/helpers"/>
<path name="org/xml/sax/ext"/>
<path name="com/sun/xml/internal"/>
<path name="com/sun/xml/internal/ws"/>
<path name="com/sun/org/apache/xml/internal/resolver"/>
<path name="com/sun/org/apache/xml/internal/resolver/tools"/>
<path name="javax/xml/datatype"/>
<path name="javax/management"/>
<path name="javax/management/openmbean"/>
<path name="javax/management/modelmbean"/>
<path name="org/w3c/dom"/>
<path name="javax/xml/validation"/>
<path name="META-INF/services"/>
</paths>
<exports>
<include-set>
<path name="META-INF/services"/>
<!-- due to applications dependency to class Closable (close sequence for WS-RM1.1, see https://community.jboss.org/wiki/JBossWS-MetroWS-ReliableMessagingTutorial) -->
<path name="com/sun/xml/internal/ws"/>
</include-set>
</exports>
</system>
</dependencies>
</module>
2. changed the module.xml file of the modules 'javax.xml.soap.api' and 'javax.xml.ws.api' to disable "class loading hacks". Therefore we removed the dependency to the 'org.jboss.modules'-module.
-javax.xml.soap.api:
<module xmlns="urn:jboss:module:1.1" name="javax.xml.soap.api">
<dependencies>
<module name="javax.activation.api" export="true"/>
<module name="javax.api"/>
<!--<module name="org.jboss.modules"/>-->
</dependencies>
<resources>
<resource-root path="jboss-saaj-api_1.3_spec-1.0.2.Final.jar"/>
</resources>
</module>
-javax.xml.ws.api:
<module xmlns="urn:jboss:module:1.1" name="javax.xml.ws.api">
<dependencies>
<module name="javax.xml.bind.api" export="true"/>
<module name="javax.xml.soap.api" export="true"/>
<module name="javax.api"/>
<!--<module name="org.jboss.modules"/>-->
</dependencies>
<resources>
<resource-root path="jboss-jaxws-api_2.2_spec-2.0.1.Final.jar"/>
</resources>
</module>
3. added an depedency to the Metro-module, so the Metro Provider gets found at runtime. We did this by declaring it to a global module. Therefore we added following lines to the standalone.xml:
<subsystem xmlns="urn:jboss:domain:ee:1.1">
<global-modules>
<module name="com.sun.xml.ws" slot="main"/>
</global-modules>
</subsystem>
Alternatively setting the dependency on application level is also possible by providing a jboss-deployment-structure.xml in META-INF-directory of the ear:
<jboss-deployment-structure>
<ear-subdeployments-isolated>false</ear-subdeployments-isolated>
<deployment>
<dependencies>
<module name="com.sun.xml.ws" export="true" services="export"/>
</dependencies>
</deployment>
</jboss-deployment-structure>
--------------------------------------------------
As I said, this solution fits for our application and we're now ready to migrate. Let me again stress that our application only acts as ws client - with no own web services provided. I'm quite certain providing own web wervices in production would force us to do a bit more changes on class loading.
Nevertheless I was able to deploy a dummy implementation of the web service (jaxws 2.2, without any policies) for test purposes. It get's regularily (and successfully) deployed with Apache CXF. Switching to Metro is possible by removing the webservices extension/subsystem from standalone.xml or manually excluding the webservices-subsystem in the jboss-deployment-structure.xml of the war-file:
<exclude-subsystems>
<subsystem name="webservices"/>
</exclude-subsystems>
Since it's not the common way to solve the problem, would you like to give me some advice what I'm missing?
Will these changes cause some class loading issues that I'm not aware of?
Any pointers or suggestions? Is there maybe a way to fulfill our given policy requirements with Apache CXF (in JBoss 7.2.0)?
Thanks