Distributed transactions using spring/tomcat
slybuford Apr 16, 2014 2:47 PMI have a requirement to support distributed transactions in a spring/tomcat application. As much as I would love to utilize JBOSS AS to accomplish this, for a variety of reasons it is not possible. As such, I've been working through numerous Quickstarts (very helpful btw) and this particular post: https://community.jboss.org/thread/154364. The test application that I have created has the following components:
ws-at client to initiate end-to-end transaction
webservice A
webservice B
I am deploying webservice A within my IDE and webservice B to my local tomcat instance on different ports (to simulate txn propagation/coordination over the wire). the process is invoked by a JUnit test which pulls a client from the spring context and makes a call to webservice A. webservice A first makes a call to webservice B, which always successfully saves data to a mysql db. webservice A then inserts/updates data locally to the same mysql instance. i have the ability to simulate success or failure for this last step. success means 2 tables have records inserted/updated. if the second set of db operations (at webservice A) fails, no records should be present in the db, i.e. the db work performed by webservice B is rolled back.
I have managed to make all this work utilizing the standard CompletionCoordinator service, however the implementation is wonky. Ideally, I would like to utilize the "non-standard", JBOSS specific RPC coordinator to avoid the necessity of exposing an endpoint at the client (CompletionCoordinatorRPCPortTypeImpl). In this configuration however, I am encountering the following error. It appears the webservice response is not including the appropriate addressing headers, but I am thoroughly confused as to why or even why it would matter. I've tried to include as much pertinent information without going overboard (may have failed there). I am also working to clean my environment and get the entire test application up on a public repo, since it seems there are a few brave souls who have attempted this in the past and maybe a few more who could benefit in the future from my days of cursing... Any help would be greatly appreciated.
Apr 16, 2014 10:58:31 AM org.apache.cxf.ws.addressing.soap.MAPCodec restoreExchange
WARNING: Response message does not contain WS-Addressing properties. Not correlating response.
Apr 16, 2014 10:58:31 AM org.apache.cxf.ws.addressing.ContextUtils retrieveMAPs
WARNING: WS-Addressing - failed to retrieve Message Addressing Properties from context
Apr 16, 2014 10:58:31 AM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
WARNING: Interceptor for {http://docs.oasis-open.org/ws-tx/wsat/2006/06}CompletionCoordinatorRPCService#{http://docs.oasis-open.org/ws-tx/wsat/2006/06}CommitOperation has thrown exception, unwinding now
org.apache.cxf.binding.soap.SoapFault: A required header representing a Message Addressing Property is not present
at org.apache.cxf.ws.addressing.impl.MAPAggregatorImpl.mediate(MAPAggregatorImpl.java:561)
at org.apache.cxf.ws.addressing.impl.MAPAggregatorImpl.handleMessage(MAPAggregatorImpl.java:143)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:835)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1614)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1504)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1310)
at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:50)
at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:223)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:628)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:565)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:474)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:377)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:330)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:135)
at com.sun.proxy.$Proxy51.commitOperation(Unknown Source)
at com.arjuna.webservices11.wsat.client.CompletionCoordinatorRPCClient.sendCommit(CompletionCoordinatorRPCClient.java:73)
at com.arjuna.wst11.stub.CompletionRPCStub.commit(CompletionRPCStub.java:44)
at com.arjuna.mwlabs.wst11.at.remote.UserTransactionStandaloneImple.commitWithoutAck(UserTransactionStandaloneImple.java:322)
at com.arjuna.mwlabs.wst11.at.remote.UserTransactionStandaloneImple.commit(UserTransactionStandaloneImple.java:120)
pom particulars:
<dependency>
<groupId>org.jboss.narayana</groupId>
<artifactId>jbosstxbridge</artifactId>
<version>5.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.ws.cxf</groupId>
<artifactId>jbossws-cxf-client</artifactId>
<version>4.3.0.Final</version>
<exclusions>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
relevant spring config:
<bean id="txnService" class="org.jboss.jbossts.XTSService" init-method="start"/>
<!-- my service which invokes remote ws-at txn and local JTA txn -->
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<jaxws:endpoint id="txnSoapService" implementor="com.hlc.soap.TestTxnSoapServiceImpl" address="/txnSoapService">
<jaxws:handlers>
<bean class="org.jboss.jbossts.txbridge.inbound.JaxWSTxInboundBridgeHandler" />
<bean class="com.arjuna.mw.wst11.service.JaxWSHeaderContextProcessor" />
</jaxws:handlers>
</jaxws:endpoint>
<!-- ws-at participant service (for our web services) -->
<jaxws:endpoint id="wsatParticipantService" implementor="com.arjuna.webservices11.wsat.sei.ParticipantPortTypeImpl" address="/ParticipantService"/>
<!-- ws-at coordination services -->
<jaxws:endpoint id="wsatCompCoordService" implementor="com.arjuna.webservices11.wsat.sei.CompletionCoordinatorPortTypeImpl" address="/CompletionCoordinatorService"/>
<jaxws:endpoint id="wsatCompletionCoordRPCService" implementor="com.arjuna.webservices11.wsat.sei.CompletionCoordinatorRPCPortTypeImpl" address="/CompletionCoordinatorRPCService"/>
<jaxws:endpoint id="wsatCoordService" implementor="com.arjuna.webservices11.wsat.sei.CoordinatorPortTypeImpl" address="/CoordinatorService"/>
<jaxws:endpoint id="wsatActivationService" implementor="com.arjuna.webservices11.wscoor.sei.ActivationPortTypeImpl" address="/ActivationService"/>
<jaxws:endpoint id="wsatRegistrationService" implementor="com.arjuna.webservices11.wscoor.sei.RegistrationPortTypeImpl" address="/RegistrationService"/>
<!-- ws-at client services -->
<jaxws:endpoint id="wsatCompletionInitService" implementor="com.arjuna.webservices11.wsat.sei.CompletionInitiatorPortTypeImpl" address="/CompletionInitiatorService"/>
<!-- client to initiate end-to-end transaction -->
<jaxws:client id="testClientLocal"
address="http://localhost:8181/ws/txnSoapService"
serviceClass="com.hlc.soap.TestTxnSoapService" >
<jaxws:handlers>
<bean class="com.arjuna.mw.wst11.client.JaxWSHeaderContextProcessor" />
</jaxws:handlers>
</jaxws:client>
<!-- client utilized within existing JTA txn to invoke ws-at web service on a distributed node -->
<jaxws:client id="testClientRemote"
address="http://localhost:8080/ws/txnSoapService"
serviceClass="com.hlc.soap.TestTxnSoapService" >
<jaxws:handlers>
<bean class="org.jboss.jbossts.txbridge.outbound.JaxWSTxOutboundBridgeHandler" />
<bean class="com.arjuna.mw.wst11.client.JaxWSHeaderContextProcessor" />
</jaxws:handlers>
</jaxws:client>
properties used to drive XTS configuration for webservice participants (adapted from original xts-properties.xml)
<entry key="org.jboss.jbossts.xts11.bind.address">localhost</entry>
<entry key="org.jboss.jbossts.xts11.bind.port">8181</entry>
<entry key="org.jboss.jbossts.xts11.wsat.UserTransaction">com.arjuna.mwlabs.wst11.at.remote.UserTransactionStandaloneImple</entry>
<entry key="org.jboss.jbossts.xts11.wsba.UserBusinessActivity">com.arjuna.mwlabs.wst11.ba.remote.UserBusinessActivityImple</entry>
<entry key="org.jboss.jbossts.xts11.wsat.TransactionManager">com.arjuna.mwlabs.wst11.at.remote.TransactionManagerImple</entry>
<entry key="org.jboss.jbossts.xts11.wsba.BusinessActivityManager">com.arjuna.mwlabs.wst11.ba.remote.BusinessActivityManagerImple</entry>
<entry key="org.jboss.jbossts.xts.initialisation.xtsInitialisation_1">org.jboss.jbossts.xts.initialisation.CoordinatorSideInitialisation</entry>
<entry key="org.jboss.jbossts.xts.initialisation.xtsInitialisation_2">org.jboss.jbossts.xts.initialisation.ParticipantSideInitialisation</entry>
<entry key="org.jboss.jbossts.xts.initialisation.xtsInitialisation_3">org.jboss.jbossts.xts.initialisation.ClientSideInitialisation</entry>
<entry key="org.jboss.jbossts.xts.wsc11.serviceURLPath">/xts</entry>
<entry key="org.jboss.jbossts.xts11.wsc.serviceURLPath">/xts</entry>
<entry key="org.jboss.jbossts.xts11.wst.coordinatorServiceURLPath">/xts</entry>
<entry key="org.jboss.jbossts.xts11.wst.clientServiceURLPath">/xts</entry>
<entry key="org.jboss.jbossts.xts11.wst.participantServiceURLPath">/xts</entry>
<entry key="org.jboss.jbossts.xts11.coordinatorURL">http://localhost:8181/xts/ActivationService</entry>
properties used to drive XTS configuration for standalone client (adapted from original xts-properties.xml)
<entry key="org.jboss.jbossts.xts11.bind.address">localhost</entry>
<entry key="org.jboss.jbossts.xts11.bind.port">8181</entry>
<entry key="org.jboss.jbossts.xts11.wsat.UserTransaction">com.arjuna.mwlabs.wst11.at.remote.UserTransactionStandaloneImple</entry>
<entry key="org.jboss.jbossts.xts11.wsat.TransactionManager">com.arjuna.mwlabs.wst11.at.remote.TransactionManagerImple</entry>
<entry key="org.jboss.jbossts.xts.initialisation.xtsInitialisation_3">org.jboss.jbossts.xts.initialisation.ClientSideStandaloneInitialisation</entry>
<entry key="org.jboss.jbossts.xts11.coordinatorURL">http://localhost:8181/xts/ActivationService</entry>
line 534 of MAPAggregatorImpl is where this is failing:
if (null == theMaps
&& !ContextUtils.isOutbound(message)
&& ContextUtils.isRequestor(message)
&& getWSAddressingFeature(message) != null
&& getWSAddressingFeature(message).isAddressingRequired()) {
boolean missingWsaHeader = false;
AssertionInfoMap aim = message.get(AssertionInfoMap.class);
if (aim == null || aim.size() == 0) {
missingWsaHeader = true;
}
this is the SOAP request:
INFO: Outbound Message
---------------------------
ID: 4
Address: http://localhost:8181/xts/CompletionCoordinatorRPCService
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=["http://docs.oasis-open.org/ws-tx/wsat/2006/06/Commit"]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Action xmlns="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/ws-tx/wsat/2006/06/Commit</Action><MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:83bea858b44500f2:671aae97:14566eff089:-7ffe</MessageID><To xmlns="http://www.w3.org/2005/08/addressing">http://localhost:8181/xts/CompletionCoordinatorRPCService</To><ReplyTo xmlns="http://www.w3.org/2005/08/addressing"><Address>http://www.w3.org/2005/08/addressing/none</Address></ReplyTo><wsarj:InstanceIdentifier xmlns="http://docs.oasis-open.org/ws-tx/wscoor/2006/06" xmlns:ns2="http://www.w3.org/2005/08/addressing" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsarj="http://schemas.arjuna.com/ws/2005/10/wsarj" ns2:IsReferenceParameter="1">0:ffffc0a80102:fa4d:534d8d13:3a</wsarj:InstanceIdentifier></soap:Header><soap:Body><Commit xmlns="http://docs.oasis-open.org/ws-tx/wsat/2006/06"/></soap:Body></soap:Envelope>
this is the SOAP response:
Apr 15, 2014 12:49:37 PM org.apache.cxf.services.CompletionCoordinatorRPCService.CompletionCoordinatorRPCPortType.CompletionCoordinatorRPCPortType
INFO: Inbound Message
----------------------------
ID: 4
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Date=[Tue, 15 Apr 2014 19:49:36 GMT], Server=[Apache-Coyote/1.1], transfer-encoding=[chunked]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/><soap:Body><Result xmlns="http://docs.oasis-open.org/ws-tx/wsat/2006/06">true</Result></soap:Body></soap:Envelope>