[jboss-user] [JBoss Web Services CXF] - Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9

Andrew Dinn do-not-reply at jboss.com
Mon Jun 21 10:10:03 EDT 2010


Andrew Dinn [http://community.jboss.org/people/adinn] replied to the discussion

"Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9"

To view the discussion, visit: http://community.jboss.org/message/548969#548969

--------------------------------------------------------------
> 'll follow up with progress on the results of making the changes I described above.

Hmm, more regress than progress I am afraid.

The latest CXF stack wil dispatch from the client end the soap fault I am sending via the SoapFaultService . However, it will not deliver the fault to the target endpoint. This is not because the endpoint is masquerading as a SoapFaultService. Even if I were to install a pucker endpoint defined by my SoapFault service WSDL the current CXF would not deliver the message. Th eproblme is that the incoming message is actually a SoapFault and the incoming message chain assumes, invalidly, that it must relate to an outgoing request and ends up tripping over its own knickers with a null pointer exception.

The message gets received and routed to the relevant endpoint handler. Here is the stack trace for the exception which is causing mesage deliver to blow up:


> java.lang.NullPointerException
>     at org.apache.cxf.interceptor.InFaultChainInitiatorObserver.addToChain(InFaultChainInitiatorObserver.java:62)
>     at org.apache.cxf.interceptor.InFaultChainInitiatorObserver.initializeInterceptors(InFaultChainInitiatorObserver.java:59)
>     at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:95)
>     at org.apache.cxf.jaxws.handler.soap.SOAPHandlerInterceptor.handleMessage(SOAPHandlerInterceptor.java:142)
>     at org.apache.cxf.jaxws.handler.soap.SOAPHandlerInterceptor.handleMessage(SOAPHandlerInterceptor.java:71)
>     at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:243)
>     at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:110)
>     at org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:98)
>     at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:423)
>     at org.jboss.wsf.stack.cxf.ServletControllerExt.invoke(ServletControllerExt.java:172)
>     at org.jboss.wsf.stack.cxf.RequestHandlerImpl.handleHttpRequest(RequestHandlerImpl.java:57)
>     at org.jboss.wsf.stack.cxf.CXFServletExt.invoke(CXFServletExt.java:130)
>     at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:179)
>     at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:103)
>     at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
>     at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:159)
>     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:324)
>     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242)
>     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
>     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
>     at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181)
>     at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285)
>     at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261)
>     at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88)
>     at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:93)
>     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
>     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
>     at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
>     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
>     at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53)
>     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362)
>     at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877)
>     at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653)
>     at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951)
>     at java.lang.Thread.run(Thread.java:619)

So, things go all right up to the point where the SOAPHandlerInterceptor.handleMessage gets invoked. It calls handleMessageInternal which calls createProtocolMessageContext. The latter looks for incoming reference parameters and then checks to see if the message body contains a soap fault.

> protected MessageContext createProtocolMessageContext(SoapMessage message) {
>         SOAPMessageContextImpl sm = new SOAPMessageContextImpl(message);
>         
>         Exchange exch = message.getExchange();
>         setupBindingOperationInfo(exch, sm);
>         SOAPMessage msg = sm.getMessage();
>         try {            
>             List<SOAPElement> params = new ArrayList<SOAPElement>();
>             message.put(MessageContext.REFERENCE_PARAMETERS, params);
>             SOAPHeader head = msg.getSOAPHeader();
>             if (head != null) {
>                 Iterator<Node> it = CastUtils.cast(head.getChildElements());
>                 while (it != null && it.hasNext()) {
>                     Node nd = it.next();
>                     if (nd instanceof SOAPElement) {
>                         SOAPElement el = (SOAPElement)nd;
>                         if (el.hasAttributeNS(Names.WSA_NAMESPACE_NAME, "IsReferenceParameter")
>                             && ("1".equals(el.getAttributeNS(Names.WSA_NAMESPACE_NAME,
>                                                              "IsReferenceParameter"))
>                                 || Boolean.parseBoolean(el.getAttributeNS(Names.WSA_NAMESPACE_NAME,
>                                                                           "IsReferenceParameter")))) {
>                             params.add(el);
>                         }
>                     }
>                 }
>             }
>             if (msg.getSOAPPart().getEnvelope().getBody() != null 
>                 && msg.getSOAPPart().getEnvelope().getBody().hasFault()) {
>                 return null;
>             }            
>         } catch (SOAPException e) {
>             throw new Fault(e);
>         }
>         
>         
>         return sm;
>     } 
> 

Since the incoming message is indeed a soap fault it returns null rather than a soap message context. Now this would be appropriate if the message was a fault being delivered as part of a RPC MEP or on the outbound side of a OneWay MEP exchange indicating a delivery problem. However, this is not the case. This fault is the payload of an incoming OneWay MEP message.

Because createProtocolMessageContext returns null handleMessageInternal returns true without processing the message any further.
> private boolean handleMessageInternal(SoapMessage message) {
>         
>     MessageContext context = createProtocolMessageContext(message);
>     if (context == null) {
>         return true;
>     }
>     . . .
> 

handleMessage goes on to set up an XMLStreamReader on the SOAPMessage and runs SAAJInterceptor.replaceHeaders as per any incoming message and then, because it assumes this is a fault rather than a normal payload, aborts the current interceptor chain and runs the endpoint's incoming fault observer onMessage routine which is where we enter the exception stack trace shown above.


>     public void handleMessage(SoapMessage message) {
>         if (binding.getHandlerChain().isEmpty()) {
>             return;
>         }
>         if (getInvoker(message).getProtocolHandlers().isEmpty()) {
>             return;
>         }
> 
>         checkUnderstoodHeaders(message);
> 
>         if (getInvoker(message).isOutbound()) {
>             if (!chainAlreadyContainsSAAJ(message)) {
>                 SAAJ_OUT.handleMessage(message);
>             }
>             message.getInterceptorChain().add(ending);
>         } else {
>             boolean isFault = handleMessageInternal(message);
>             SOAPMessage msg = message.getContent(SOAPMessage.class);
>             if (msg != null) {
>                 XMLStreamReader xmlReader = createXMLStreamReaderFromSOAPMessage(msg);
>                 message.setContent(XMLStreamReader.class, xmlReader);
>                 // replace headers
>                 try {
>                     SAAJInInterceptor.replaceHeaders(msg, message);
>                 } catch (SOAPException e) {
>                     e.printStackTrace();
>                 }
>             }
>             if (isFault) {
>                 Endpoint ep = message.getExchange().get(Endpoint.class);
>                 message.getInterceptorChain().abort();
>                 if (ep.getInFaultObserver() != null) {
>                     ep.getInFaultObserver().onMessage(message);
>                     
>                 }
>             }
>         }
>     }
> 

The observer is an InFaultChainInitiatorObserver whose onMessage method is inherited from super AbstractFaultChainInitiatorObserver. This runs to the point where it calls initializeInterceptors which eventually calls addToChain. The null pointer exception happens here

> private void addToChain(PhaseInterceptorChain chain, Message m) {
>         Collection<InterceptorProvider> providers 
>             = CastUtils.cast((Collection<?>)m.get(Message.INTERCEPTOR_PROVIDERS)); // <= blow up!
>         if (providers != null) {
>             for (InterceptorProvider p : providers) {
>                 chain.add(p.getInFaultInterceptors());
>             }
>         }
>         Collection<Interceptor> is = CastUtils.cast((Collection<?>)m.get(Message.FAULT_IN_INTERCEPTORS));
>         if (is != null) {
>             chain.add(is);
>         }
>     }

It appears that m.get(Message.INTERCEPTOR_PROVIDERS) returns null. I cannot actually find any place in the CXF source where this value is ever put so I don't really know if this is the only thing which is wrong. Anyway, I think the fact that we have now switched to fautl processing rather than delivering an incoming fault message is the root cause of the problem here. I think createProtocolMessageContext needs to be changed as follows:

>     protected MessageContext createProtocolMessageContext(SoapMessage message) {
>         SOAPMessageContextImpl sm = new SOAPMessageContextImpl(message);
>         . . .
>             if (msg.getSOAPPart().getEnvelope().getBody() != null 
>                 && msg.getSOAPPart().getEnvelope().getBody().hasFault()
>                 && !(isRequestor(msg) && isInbound())) { // <== allow incoming fault request
>                 return null;
>             }            
>         } catch (SOAPException e) {
>             throw new Fault(e);
>         }
>         
>         
>         return sm;
>     } 

Sorry but I'm going to have to raise a Blocker JIRA for this on Jonathan's instructions. It is not possible for the update to CXF to go out in the product if it breaks XTS -- at least not without a decision from on high.

--------------------------------------------------------------

Reply to this message by going to Community
[http://community.jboss.org/message/548969#548969]

Start a new discussion in JBoss Web Services CXF at Community
[http://community.jboss.org/choose-container!input.jspa?contentType=1&containerType=14&container=2046]

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.jboss.org/pipermail/jboss-user/attachments/20100621/0860b3ac/attachment-0001.html 


More information about the jboss-user mailing list