TL;DR : I tried to create a test which performs 2 CXF calls on 2 different SOAP Operations (saveUser and then getUser) but the second one fail because the SOAPAction in the http Request is set as "saveUser" instead of "getUser". I found 2 solution to overcome this problem, BUT I'm not fully satisfied of them.
Configurations
Here is my Endpoint configuration :
final JaxWsProxyFactoryBean jaxWsProxyFactory = new JaxWsProxyFactoryBean();
jaxWsProxyFactory.setServiceClass(Internal.class);
jaxWsProxyFactory.setAddress(backendUrl + "INTERNAL");
jaxWsProxyFactory.setFeatures(getFeatures());
final Internal portType = (Internal) jaxWsProxyFactory.create();
((BindingProvider) portType).getRequestContext().put("thread.local.request.context", "true");
((BindingProvider) portType).getRequestContext().put("schema-validation-enabled", "false");
And here is my usage :
internalBackendG5.saveUser(getRequest);
internalBackendG5.getUser(saveRequest);
The Two operations are defined (thanks to wsdl2java) as :
(I override some packages to be more concise, code below may contains typo)
@WebMethod(action = "http://www.test.org/internal/saveUser")
@WebResult(name = "saveUserResponse", targetNamespace = "urn:test.com:xsd:internal:userpreferences", partName = "parameters")
public com.test.internal.type.SaveUserResponseType saveUser(
@WebParam(partName = "parameters", name = "saveUser", targetNamespace = "urn:test.com:xsd:internal:userpreferences")
com.test.internal.type.SaveUserRequestType parameters
);
and
@WebMethod(action = "http://www.test.org/internal/getUser")
@WebResult(name = "getUserResponse", targetNamespace = "urn:test.com:xsd:internal:userpreferences", partName = "parameters")
public com.test.internal.type.GetUserResponseType getUser(
@WebParam(partName = "parameters", name = "getUser", targetNamespace = "urn:test.com:xsd:internal:userpreferences")
com.test.internal.type.GetUserRequestType parameters
);
Runtime
When I run my test, I get an error on the second call which is thrown from the backend as Soap exception :
javax.xml.ws.soap.SOAPFaultException: Unexpected element {urn:test.com:xsd:internal:userpreferences}getUser found. Expected {urn:test.com:xsd:internal:userpreferences}saveUser.
And when I look at the Soap Request received by the server, i get :
For the first request (saveUser) :
Headers: {[...] SOAPAction=["http://www.test.org/internal/saveUser"], user-agent=[Apache CXF 2.7.12]}
Payload: <soap:Envelope><soap:Body><saveUser>[...]</ns5:saveUser></soap:Body></soap:Envelope>
For the second request (getUser) :
Headers: {[...] SOAPAction=["http://www.test.org/internal/saveUser"], user-agent=[Apache CXF 2.7.12]}
Payload: <soap:Envelope><soap:Body><getUser>[...]</getUser></soap:Body></soap:Envelope>
When I launch only one of the two request, they both work.
Solution I found
After some research, I found that the Apache Cxf Interceptor SoapPreProtocolOutInterceptor was the responsible.
When the SoapAction string is already present in the request, it doesn't override it. And my second call (for some reasons I can't explain) reuses the Cxf Request context computed while processing the first call !
What I did to overcome that : - Write an interceptor called before SoapPreProtocolOutInterceptor that force the SoapAction deletion in the header, in order to force this interceptor to re-compute the action. - Or alternatively I can reset the request context between the 2 requests :
((BindingProvider) portType).getRequestContext().put(Header.HEADER_LIST, emptyList);
Question
So my question is : is there a CXF bug ? (the requestContext shouldn't be shared between 2 requests) or I missed some Cxf configuration ?
PS : I Used this dependencies :
group:'org.apache.cxf', name:'cxf-rt-transports-http-jetty', version:'2.7.5'
group: 'org.apache.cxf', name: 'cxf-rt-features-clustering', version:'2.7.12'
group:'org.apache.cxf', name:'cxf-rt-frontend-jaxws', version:'2.7.12'
group: 'org.apache.cxf', name: 'cxf-api', version: '2.7.12'
group: 'org.apache.cxf', name: 'cxf-rt-bindings-soap', version: '2.7.12'
Thanks in advance !