1 2 Previous Next 19 Replies Latest reply on Jul 29, 2010 11:47 AM by adinn

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

    adinn

      The XTS tests are still seeing some failures on the latest AS trunk with cxf stack 3.3.1.SP1. I think they all appear to stem from a single issue which relates to dispatch of soap faults. It's  not actually CXF's  fault handling which is the problem. The XTS code uses its own JaxWS based service to dispatch faults -- I know that sounds weird but I'll explain that in a minute. Anyway, the problem is not actually to do with the dispatch, routing or receipt of the soap faults, it's to do with creating the relevant JaxWS service. This is a WSDL first service defined as follows:

       

       

      <?xml version="1.0" encoding="utf-8"?>
      <!--
          a specification for a service which can be used to dispatch a SOAP 1.1 SoapFault
          to an arbitrary client
      -->
      <definitions
              xmlns:s="http://www.w3.org/2001/XMLSchema"
              xmlns:tns="http://jbossts.jboss.org/xts/soapfault"
              xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
              xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
              xmlns:wsaw="http://www.w3.org/2006/02/addressing/wsdl"
              targetNamespace="http://jbossts.jboss.org/xts/soapfault"
          xmlns="http://schemas.xmlsoap.org/wsdl/">
          <types>
              <s:schema>
                  <s:import namespace="http://schemas.xmlsoap.org/soap/envelope/"
                            schemaLocation="http://schemas.xmlsoap.org/soap/envelope"/>
              </s:schema>
          </types>
          <message name="SoapFault">
               <part name="fault" element="soapenv:Fault" />
          </message>

       


          <portType name="SoapFaultPortType">
              <operation name="SoapFault">
                  <input name="SoapFault" message="tns:SoapFault" />
              </operation>
          </portType>

       


          <binding name="SoapFault_SOAPBinding" type="tns:SoapFaultPortType">
            <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
            <operation name="SoapFault">
              <input message="tns:Soapfault">
                <soap:body use="literal"/>
              </input>
            </operation>
          </binding>

       


          <service name="SoapFaultService">
            <port binding="tns:SoapFault_SOAPBinding" name="SoapFaultPortType">
          <wsaw:UsingAddressing required="true"/>
          <soap:address location="http://localhost:9000/interopat/SoapFaultService"/>
            </port>
          </service>

       


      </definitions>

       

       

      I generated code from  this WSDL using wsconsume (well, actually, I think I generated it using Glassfish's wsimport but essentially it is the same thing) as follows:

       

      @WebServiceClient(name = "SoapFaultService", targetNamespace = "http://jbossts.jboss.org/xts/soapfault", wsdlLocation = "wsdl/soapfault.wsdl")
      public class SoapFaultService extends Service
      {
          private final static URL SOAPFAULTSERVICE_WSDL_LOCATION;
          private final static Logger logger = Logger.getLogger(org.jboss.jbossts.xts.soapfault.SoapFaultService.class.getName());

       


          static {
              URL url = null;
              try {
                  URL baseUrl;
                  baseUrl = org.jboss.jbossts.xts.soapfault.SoapFaultService.class.getResource(".");
                  url = new URL(baseUrl, "wsdl/soapfault.wsdl");
              } catch (MalformedURLException e) {
                  logger.warning("Failed to create URL for the wsdl Location: 'wsdl/soapfault.wsdl', retrying as a local file");
                  logger.warning(e.getMessage());
              }
              SOAPFAULTSERVICE_WSDL_LOCATION = url;
          }

       


          public SoapFaultService(URL wsdlLocation, QName serviceName) {
              super(wsdlLocation, serviceName);
          }

       


          public SoapFaultService() {
              super(SOAPFAULTSERVICE_WSDL_LOCATION, new QName("http://jbossts.jboss.org/xts/soapfault", "SoapFaultService"));
          }
          /**
           *
           * @return
           *     returns SoapFaultPortType
           */
          @WebEndpoint(name = "SoapFaultPortType")
          public SoapFaultPortType getSoapFaultPortType() {
              return super.getPort(new QName("http://jbossts.jboss.org/xts/soapfault", "SoapFaultPortType"), SoapFaultPortType.class);
          }
          /**
           *
           * @param features
           *     A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy.  Supported features not in the <code>features</code> parameter will have their default values.
           * @return
           *     returns SoapFaultPortType
           */
          @WebEndpoint(name = "SoapFaultPortType")
          public SoapFaultPortType getSoapFaultPortType(WebServiceFeature... features) {
              return super.getPort(new QName("http://jbossts.jboss.org/xts/soapfault", "SoapFaultPortType"), SoapFaultPortType.class, features);
          }
      }

      @WebService(name = "SoapFaultPortType", targetNamespace = "http://jbossts.jboss.org/xts/soapfault")
      @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
      @XmlSeeAlso({
          ObjectFactory.class
      })
      public interface SoapFaultPortType {
          /**
           *
           * @param fault
           */
          @WebMethod(operationName = "SoapFault")
          @Oneway
          public void soapFault(
              @WebParam(name = "Fault", targetNamespace = "http://schemas.xmlsoap.org/soap/envelope/", partName = "fault")
              Fault fault);
      }

       

      The problem is that when my tests try to create a SoapFaultPortType I get a parse error during processing of the WSDL. Unfortunately, the error is not reported as being in my WDSL. It ahppens wen processing the imported schema

       

              <s:schema>
                  <s:import namespace="http://schemas.xmlsoap.org/soap/envelope/"
                            schemaLocation="http://schemas.xmlsoap.org/soap/envelope"/>
              </s:schema>

       

      I stepped through the code and found that it successfully loads the schema located at http://schemas.xmlsoap.org/soap/envelope but then runs into problems processing the contents. Here is the error message:

      [Fatal Error] strict.dtd:81:5: The declaration for the entity "ContentType" must end with '>'.
      [Fatal Error] envelope:2:2: The markup in the document following the root element must be well-formed.
      javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException: Failed to create service.
          at org.apache.cxf.jaxws.ServiceImpl.<init>(ServiceImpl.java:152)
          at org.apache.cxf.jaxws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:63)
          at javax.xml.ws.Service.<init>(Service.java:57)
          at org.jboss.jbossts.xts.soapfault.SoapFaultService.<init>(SoapFaultService.java:46)
          at com.arjuna.webservices11.wsaddr.client.SoapFaultClient.getSoapFaultService(SoapFaultClient.java:98)
          at com.arjuna.webservices11.wsaddr.client.SoapFaultClient.getSoapFaultPort(SoapFaultClient.java:130)
          at com.arjuna.webservices11.wsaddr.client.SoapFaultClient.sendSoapFault(SoapFaultClient.java:86)
          at com.arjuna.webservices11.wsat.client.CompletionInitiatorClient.sendSoapFault(CompletionInitiatorClient.java:123)
          at com.arjuna.wst11.tests.junit.CompletionCoordinatorTestCase.testSendError(CompletionCoordinatorTestCase.java:180)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
          at java.lang.reflect.Method.invoke(Method.java:597)
          at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
          at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
          at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
          at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
          at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
          at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
          at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
          at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
          at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
          at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
          at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
          at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
          at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
          at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
          at org.junit.runners.Suite.runChild(Suite.java:128)
          at org.junit.runners.Suite.runChild(Suite.java:24)
          at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
          at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
          at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
          at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
          at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
          at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
          at org.junit.runners.Suite.runChild(Suite.java:128)
          at org.junit.runners.Suite.runChild(Suite.java:24)
          at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
          at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
          at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
          at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
          at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
          at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
          at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
          at org.junit.runner.JUnitCore.run(JUnitCore.java:136)
          at org.junit.runner.JUnitCore.run(JUnitCore.java:117)
          at com.arjuna.qa.junit.TestRunnerServlet$RunnerThread.run(TestRunnerServlet.java:523)
      Caused by: org.apache.cxf.service.factory.ServiceConstructionException: Failed to create service.
          at org.apache.cxf.wsdl11.WSDLServiceFactory.<init>(WSDLServiceFactory.java:93)
          at org.apache.cxf.jaxws.ServiceImpl.initializePorts(ServiceImpl.java:207)
          at org.apache.cxf.jaxws.ServiceImpl.<init>(ServiceImpl.java:150)
          ... 46 more
      Caused by: javax.wsdl.WSDLException: WSDLException (at /definitions/types/s:schema): faultCode=PARSER_ERROR: Problem parsing 'http://schemas.xmlsoap.org/soap/envelope'.: org.xml.sax.SAXParseException: The markup in the document following the root element must be well-formed.
          at com.ibm.wsdl.xml.WSDLReaderImpl.getDocument(Unknown Source)
          at com.ibm.wsdl.xml.WSDLReaderImpl.parseSchema(Unknown Source)
          at com.ibm.wsdl.xml.WSDLReaderImpl.parseSchema(Unknown Source)
          at com.ibm.wsdl.xml.WSDLReaderImpl.parseTypes(Unknown Source)
          at com.ibm.wsdl.xml.WSDLReaderImpl.parseDefinitions(Unknown Source)
          at com.ibm.wsdl.xml.WSDLReaderImpl.readWSDL(Unknown Source)
          at com.ibm.wsdl.xml.WSDLReaderImpl.readWSDL(Unknown Source)
          at org.apache.cxf.wsdl11.WSDLManagerImpl.loadDefinition(WSDLManagerImpl.java:230)
          at org.apache.cxf.wsdl11.WSDLManagerImpl.getDefinition(WSDLManagerImpl.java:179)
          at org.apache.cxf.wsdl11.WSDLServiceFactory.<init>(WSDLServiceFactory.java:91)
          ... 48 more
      Caused by: org.xml.sax.SAXParseException: The markup in the document following the root element must be well-formed.
          at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
          at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source)
          ... 58 more

       

      As you can see the problem occurs under ServiceImple.<init> below SoapFaultService.<init> when trying to create the SoapFaultService class  generated by wsconsume. This is somewhat bizarre given where the schema comes from.

       

      Ok, so you might want an explanation for what this servcie is and why it needs to import the soap envelope schema. It's a bit convoluted but here goes. XTS implements the WS-C and WS-T services defined by the WSTX standard. WS-C includes two generic services for creating and enlisting with transactions from various transaction-specific protocols. WS-T includes two families of transaction protocol specific services which allow transaction clients and transactional web services to progress towards transaction completion. The service APIs are specified by WSDL and our implementation uses JaxWS to implement that WSDL.

       

      The WS-T services (WS-AT atomic transaction and WS-BA business activity), are mandated only to employ a OneWay MEP. Tthe SOAP used to deliver these messages is required to be configured with various WSA headers, including MessageId, ReplyTo and FaultTo. The SOAP headers also need to include service specific transaction identifiers as header elements. This is achieved by by installing them as ReferenceParameters in the endpoints used by the transaction protocol services and transactional web services communicate ie. they are attached to

       

      • the transaction protocol specific Coordinator service endpoints handed out to transactional web services by the WS-C Registration service when they enlist in a transaction
      • the endpoint in the ReplyTo/FaultTo header included by web services when they negotiate with the WS-C Registration service or with their Coordinator service

       

      Yes, as you can see, the use of one way messaging means that the container for the transactional web service must also run a WS-AT or WS-BA Initiator service. The Coordinator talks back to this Initiator service in order to be able to constuct a long-running dialogue with the transactional web service composed  of a series of 1-way messages such as e.g. enlist, prepare, prepared, commit, commited. In the case of WS-BA this dialogue can be initiated asynchronously from either end --  that's why OneWay MEP was chosen over RPC.

       

      The service specification mandates that in cases where processing of a message runs into certain error conditions a SoapFault must be dispatched to the FaultTo address configured in the WSA headers. Obviously, if a fault  occurs in delivering the message the JaxWS layer will dispatch a fault to the sender. But that's not that the spec is talking about (or  at least not all it is talking about). The spec is concerned with faults which occur after delivery when the delivered message is being processed. By this stage JaxWS has done its stuff and told the sender 'message delivered'. If the service endpoint bean were to throw a fault at this point nothing would get dispatched back to  the sender. So, the threads which are handling a request to the Coordinator or Initiator services need to be able to dispatch a fault to the FaultTo address asynchronously -- from a standing start. This fault needs to

      • be sent to the FaultTo address
      • provide a WSA RelatesTo header which includes the originating MessageId
      • include the ReferenceParameter header obtained with the FaultTo address.

       

      Now the WS-AT/BA Coordinator and Initiator service endpoint beans all implement a WebMethod which accepts a SoapFault with a specific SOAPAction or WSA Action. This web method is declared by interface SoapFaultPortType generated from the SoapFaultService WSDL and all the Coordinator/Initiator services implement the interface i.e. they are capable of acting as an endpoint for the SoapFaultPortType of the SoapFaultService as well as an endpont for the transaction-specific protocol. So, in order to dispatch an asynchronous SoapFault to the sender the handler thread merely needs to create a fault and an instance of SoapFaultService, clone a proxy port from it and call method soapFault(). So this is what is happening when my current implementation blows up trying to read the soap envelope WSDL.

        • 1. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
          jim.ma
          As you can see the problem occurs under ServiceImple.<init> below  SoapFaultService.<init> when trying to create the SoapFaultService  class  generated by wsconsume. This is somewhat bizarre given where the  schema comes from.

          CXF's customized wsdlLocator(used to retrive the import xsd or wsdl) configured in wsdl4j can not redirect the schemaLocation "http://schemas.xmlsoap.org/soap/envelope" to "http://schemas.xmlsoap.org/soap/envelope/" . The server replys with html page :

           

          <head><title>Document Moved</title></head>
          <body><h1>Object Moved</h1>This document may be found <a HREF="http://schemas.xmlsoap.org/soap/envelope/">here</a></body>

          I looked at the CXF's code. The org.apache.cxf.transport.TransportURIResolver used to resolve the resource with http prefix does not set any http headers. This may cause the different behivior when access this file via web browser.  I've filled a jira issue in CXF for this : https://issues.apache.org/jira/browse/CXF-2858.

           

          I tested modify the schemaLocation to "http://schemas.xmlsoap.org/soap/envelope/" can fix this issue .  If you can not change this standard wsdl ,you can define a catalog configuration file to load a local xsd file. CXF runtime searchs the META-INFO/jax-ws-catalog.xml in the classpath and resolve and set this catalog file before the service is created. Here is the jax-ws-catalog.xml sample from CXF code base:

           

          <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
              <rewriteSystem systemIdStartString="http://www.w3.org/2005/08/addressing" rewritePrefix="classpath:/schemas/wsdl"/>
          </catalog> 
          • 2. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
            adinn

            Hi Jim,

            I tested modify the schemaLocation to "http://schemas.xmlsoap.org/soap/envelope/" can fix this issue .

            I tried that previously and it did not seem to fix things. However, I have just tried it again and it does resolve the parsing problem -- thanks very much for the diagnosis.

             

            Unfortunately, the tests are still failing because of another problem which is much more serious. I failed to notice it because it was masked by the parsing error. The fault is still not being delivered and the problem is still because of a failure to obtain a proxy under getPort. However, the reason I am getting the error is different.

             

            The thing which has changed between the old native/cxf and the latest cxf and which is causing this error is the FaultTo endpoint used as the address for the fault I am sending via the SoapFaultService. The previous implementations did not contain metadata, they only contained the address of the Initiator service and the reference parameter identifying the transaction (well, at least, if they did include metadata it was not used when creating the proxy and dispatching the fault). The current CXF includes metadata for my Initiator service i.e. it defines the service as InitiatorService and the port as InitiatorPortType. However, I am trying to obtain a port for the SoapFaultService with name SoapFaultPortType and use this port to route the fault back to my endpoint bean. The call to getPort is failing because the metadata does not mention a port with name SoapFaultPortType.

             

            Using this mechanism the way I have been doing is probably an abuse of JaxWS. However, it did work and, in fact, it was the only way of sending an asynchronous fault to the originating endpoint. This is not the only place I had to bend the rules. I was also relying upon Native and CXF to accept an incoming fault addressed to the Initiator endpoint bean and invoke the soapFault() web method associated with the SoapFault Action attached to the fault. They both used to do this even though the wsdl which defines the service and port under which the endpoint bean was published do not include this web method. I am not sure if they will still do this but I had to rely on this in order to be able to send asynchronous faults using only JaxWS. I invented the SoapFaultService to provide a uniform way of dispatching faults on the client side but it is not part of the OASIS spec. The spec does not address how asynchronous faults are dispatched or delivered. It merely assumes that this can and will happen.

             

            Ok, so having diagnosed the problem what can be done about it? Well, there are two things I can try in order to get XTS working again JBoss to JBoss (I am not yet sure what the implications are for interoperability). Firstly, when I create the FaultTo endpoint I can set the service and port in the endpoint to be SoapFaultService and SoapFaultPortType. So, if any of my services need to dispatch a fault then this will mean that they will be able to obtain a JaxWS proxy for the fault service and then use JaxWS to dispatch the fault.

             

            Once I have done this I will then be able to see whether CXF will deliver an incoming asynchronous fault to my endpoint beans according to the SoapFault Action even thoguht the endpoint wsdl does not define the web method. If it does then I can perhaps continue to use my endpoint beans to field the faults. If it doesn't (or if I decide not to rely on this continuing to work -- it is a maybe a little fragile) I will have to provide a SoapFaultService endpoint bean to field the incoming faults and route them back to the relevant XTS beans.

             

            These two changes ought to allow me to get JBoss to JBoss working again. My concern is that this may cause a problem for interoperability. Why? Well, lets recap the situation.

             

            My code has to use JaxWS to dispatch an asynchronous fault to the FaultTo endpoint -- the whole point of the XTS redesign between 1.0 and 1.1 was to remove our own SOAP stack from the XTS codebase and rely entirely on JBossWS. I cannot change the the OASIS spec wsdl which my service beans implement. Since the OASIS wsdl does not not define operations to dispatch/receive faults I have had to resort to inevnting an independent fault service for asynchronous fault delivery. This in turn means I have to include the service and port names in the FaultTo endpoint and use the invented fault service wsdl to deliver the fault.

             

            Now, if we are now handing out FaultTo endpoints which inlcude metadata referencing this invented service then it is not clear whether this will cause problems for other implementations which are not built over JaxWS. They might just ignore any metadata and only look at the endpoint address. However, they might also quite legitimately expect the metadata in the FaultTo endpoint to refer to the OASIS service and port which sent them the endpoint. After all that is the service which they expect to be communicating with. By contrast, any implementation which is based on JaxWS will not be able to dispatch faults without using my SoapFaultService wsdl. So, what was a protocol private to the JBoss implementation may now need to become a public protocol and require, at least, documentation and, at worst, agreement and standardization.

             

            There is one further option I might pursue. When I create the FaultTo endpoint woudl it be possible to create it without any medtadata by not specifying a service/port? Will the CXF endpoint builder build such an endpoint? If it does then will ServiceImpl.getPort allow me to create a JaxWS port for the SoapFault service? I am already half-convinced that a FaultTo endpoint really ought not to have any service/port metadata associated with it. After all it is only supposed to be used for delivering faults.

             

            I will experiment with making each of the two changes I described above, one after the other -- changing the endpoint metadata, adding an independent endpoint/bean for receipt of the fault messages. However, I would also be interested to hear what others think about what I am trying to do here. Here is a summary of my posiiton

             

            • services which employ multi-message dialogues based on OneWay MEPs will benefit from being able to dispatch asynchronous faults to a FaultTo endpoint supplied in the OneWay message Message Addressing Properties (MAP)
            • these services ought to be able to employ JaxWS to dispatch and deliver the fault
            • if there is a need for metadata to be included in the FaultTo endpoint in order to guarantee dispatch and/or delivery then the metadata ought to reference a JaxWS standard wsdl defining the relevant service and ports (i.e. somethign liek my SoapFaultService ought to be agreed on as a standard way to do this)
            • if there is no need for any metadata to be included in the FaultTo endpoint then it should be possible to create a FaultTo endpoint without specifying a sevrice/port name and pass this using the MAP

             

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

            • 3. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
              adinn

              '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 a reply to an RPC MEP (or  inbound with 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.

              • 4. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                jim.ma

                After looked at the testcase, I think fix this NPE can not resolve this problem completely. If I understand correctly , after server receive this "soapFault" request, it still needs to invoke the method "soapFault(Fault fault)" in service imlementation class.  So far , CXF is not capable to do this.  It is because the CXF Intercetors to process soapFault is only designed to work in the client side.  So fix this one , there will be couple of another issues pop up.

                 

                This could be a workaroud: modify the wsdl schema and wrap the soap fault element in another element:

                <xs:element name="XTSFault" type="tns:XTSFault"/>

                  <complexType name="XTSFault">
                   <sequence>
                       <element name="fault" type="soapEnv:Fault"/>
                   </sequence>
                  </complexType>

                 

                <message  name="SoapFault">
                      <part name="fault"  element="tns:XTSFault" />
                </message>

                This will make CXF treat this soap request not a soap fault response and handle it correctly.

                Does this change need a lot of work in JBossTS and work for dispatching the fault message ?

                • 5. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                  adinn

                  Jim Ma wrote:

                   

                  After looked at the testcase, I think fix this NPE can not resolve this problem completely. If I understand correctly , after server receive this "soapFault" request, it still needs to invoke the method "soapFault(Fault fault)" in service imlementation class.  So far , CXF is not capable to do this.  It is because the CXF Intercetors to process soapFault is only designed to work in the client side.  So fix this one , there will be couple of another issues pop up.

                  Yes, I assumed there woud lbe further problems. This may require a few chnages from me -- for example I may need to provide a real implemntation of SoapFaultService rather than just adding a doapFault(Fault) WebMethod to the WS-T service endpoint beans. If you can get past the problems with interceptors not expecting  soap faults let me know what else breaks.

                   

                  I am not sure how big an issue this is for CXF. It ought to be perfectly legitimate to define (as I have done) a  JaxWS service whose web methods accept a single soap fault as argument. In practice I am not clear what the implications are of requiring this to be supported. It is quite possible for the implementation to isolate the case where a fault is being delivered as an incoming payload from the case where it is being returned from a failed (OneWay or RPC) request. However,  this implies that the handler stack has to discriminate these cases by evaluating somthing like isRequest() && isFault() rather than just isFault().

                  Jim Ma wrote:


                  This could be a workaroud: modify the wsdl schema and wrap the soap fault element in another element:

                  <xs:element name="XTSFault" type="tns:XTSFault"/>

                    <complexType name="XTSFault">
                     <sequence>
                         <element name="fault" type="soapEnv:Fault"/>
                     </sequence>
                    </complexType>

                   

                  <message  name="SoapFault">
                        <part name="fault"  element="tns:XTSFault" />
                  </message>

                  This will make CXF treat this soap request not a soap fault response and handle it correctly.

                  Does this change need a lot of work in JBossTS and work for dispatching the fault message ?

                  This wioudl most likely work but it is not acceptable for this specific service. The spec requires that a soap fault be delivered to the endpoint at the FaulttTo address. This is critical for interoperability. Alternative implementations of WS-T such as the ones provided by Microsoft, IBM  and Sun will expect my services to send a soap fault to their endpoints and will be sendng soap faults to my endpoint.

                   

                  n.b. this problem can also arise with synchronous fault delivery on any JaxWS request when using WSA. This is because when using WSA it is possible to configure a FaultTo endpoint which is not the same as the From endpoint. So, if, for example, delivery of a OneWay message failed because of a problem with a mustUnderstand header the fault should be routed to the FaultTo endpoint rather than returned to the sender on the HTTP connection used to make the request. So, the fault will still be an incoming message for the FaultTo endpoint; it wiill not be paired with an outgoing message.

                  • 6. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                    jim.ma

                    Yes, I assumed there woud lbe further problems. This may require a  few chnages from me -- for example I may need to provide a real  implemntation of SoapFaultService rather than just adding a  doapFault(Fault) WebMethod to the WS-T service endpoint beans. If you  can get past the problems with interceptors not expecting  soap faults  let me know what else breaks.

                    OK. I will continue to look at this issue in CXF and give you update.

                    I am not sure how big an issue this is for CXF. It ought to be perfectly  legitimate to define (as I have done) a  JaxWS service whose web  methods accept a single soap fault as argument. In practice I am not  clear what the implications are of requiring this to be supported. It is  quite possible for the implementation to isolate the case where a fault  is being delivered as an incoming payload from the case where it is  being returned from a failed (OneWay or RPC) request. However,  this  implies that the handler stack has to discriminate these cases by  evaluating somthing like isRequest()  && isFault() rather than just isFault().

                    Agreed.  I need to change the current code to route the asynchronous fault to the server pipeline to process the normal soap request.  I'll figure out and shoot the blocks for this request in CXF.

                     

                    n.b. this problem can also arise with synchronous fault delivery on any  JaxWS request when using WSA. This is because when using WSA it is  possible to configure a FaultTo endpoint which is not the same as the  From endpoint. So, if, for example, delivery of a OneWay message failed  because of a problem with a mustUnderstand header the fault should be  routed to the FaultTo endpoint rather than returned to the sender on the  HTTP connection used to make the request. So, the fault will still be  an incoming message for the FaultTo endpoint; it wiill not be paired  with an outgoing message.

                    This could be a common user case for Fault message will be delievered to another Endpoint not the sender .  I remembered a similar case in CXF couple of months ago,   the ReplyTo is not the sender and another endpoint with http url address. CXF can not  send this response message to the ReplyTo endpoint correctly. And only with jms transport , it works well . Anyway , I will look at this problem and fix it in CXF.

                    The CXF jira for this issue : https://issues.apache.org/jira/browse/CXF-2860.

                    • 7. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                      jim.ma

                      Hi Andrew ,  I've fixed this issue in CXF.  I now got this error when I ran the XTS testsuite , this is expected, right ?

                      11:26:00,396 WARNING [org.apache.cxf.phase.PhaseInterceptorChain] Interceptor for {http://docs.oasis-open.org/ws-tx/wsat/2006/06}CompletionInitiatorService has thrown exception, unwinding now: org.apache.cxf.interceptor.Fault: Message part {http://schemas.xmlsoap.org/soap/envelope/}Fault was not recognized.  (Does it exist in service WSDL?)      at org.apache.cxf.interceptor.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:194) [:2.2.9]      at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:243) [:2.2.9]      at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:110) [:2.2.9]      at org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:98)

                      The received soap response for sendError :

                      Server: Apache-Coyote/1.1
                      Content-Type: text/xml;charset=UTF-8
                      Content-Length: 674
                      Date: Mon, 28 Jun 2010 03:26:00 GMT
                      Connection: close

                      <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Action xmlns="http://www.w3.org/2005/08/addressing" /><MessageID xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:42e8b03c-3644-41a7-ba79-7181f2784e6e</MessageID><To xmlns="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/none</To><RelatesTo xmlns="http://www.w3.org/2005/08/addressing">123456</RelatesTo></soap:Header><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>Message part {http://schemas.xmlsoap.org/soap/envelope/}Fault was not recognized.  (Does it exist in service WSDL?)</faultstring></soap:Fault></soap:Body></soap:Envelope>

                      I will send you the patched jar file for this NPE issue if you need. Then we can see if there are anything else in CXF needs to be fixed.

                      • 8. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                        adinn

                        Hi Jim,

                        Jim Ma wrote:

                         

                        Hi Andrew ,  I've fixed this issue in CXF.  I now got this error when I ran the XTS testsuite , this is expected, right ?

                        11:26:00,396 WARNING [org.apache.cxf.phase.PhaseInterceptorChain] Interceptor for {http://docs.oasis-open.org/ws-tx/wsat/2006/06}CompletionInitiatorService has thrown exception, unwinding now: org.apache.cxf.interceptor.Fault: Message part {http://schemas.xmlsoap.org/soap/envelope/}Fault was not recognized.  (Does it exist in service WSDL?)      at org.apache.cxf.interceptor.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:194) [:2.2.9]      at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:243) [:2.2.9]      at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:110) [:2.2.9]      at org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:98)

                        Yes, that looks like it's now my problem rather than CXF's. I will test your fix by adding the extra operation to the WSDL and see if it will now deliver the fault to the endpoint. That should be enough to prove that asynchronous fault dispatch and delivery works.

                         

                        I don't think I can legitimately rely on that as a full solution since my service WSDL ought to conform to the OASIS standard. Instead I will deploy an independent fault service endpoint and have it dispatch the fauits to the relevant WS-T endpoint bean.

                         

                        Thanks very much for responding so quickly.

                        • 9. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                          adinn

                          I will send you the patched jar file for this NPE issue if you need. Then we can see if there are anything else in CXF needs to be fixed.

                          Sorry, Jim, I forgot to respond to this. Yes, please, could you send me the patched jars. Patched source (or source diffs) would be helpful too. Thanks.

                          • 10. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                            jim.ma
                            Sorry, Jim, I forgot to respond to this. Yes, please, could you send me the patched jars. Patched source (or source diffs) would be helpful too. Thanks.

                            I attched the pached jars and source files to https://jira.jboss.org/browse/JBWS-3069. Please let me know if you have furthur CXF issues. Thanks.

                            • 11. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                              adinn

                              Hi Jim,

                               

                              Apologies for the delay in getting bak. It's been a long haul working through the rets of the changes needed after you fixed the soap fault delivery problem.

                              Jim Ma wrote:


                              I attched the pached jars and source files to https://jira.jboss.org/browse/JBWS-3069. Please let me know if you have furthur CXF issues. Thanks.

                              The patches work fine and soap fault delivery is happening as expected.

                               

                              Unfortunately, I then ran into a further problem which meant that I was not able to employ a separate SOAP service to dispatch/catch the faults. CXF includes metadata in its W3C endpoints so I can no longer take an endpoint derived from one of the WS-T services and pass it to the getPort method of my SoapFaultService. This means that I have had no choice but to explicitly include the soap fault delivery method in my WS-T service WSDL and generate corresponding methods on the SEI interfaces and implementation beans.

                               

                              So, I am now having to use a non-standard WSDL and non-standard endpoint for these services. We can live with this because the service is a conservative extension of the expected implementation (i.e. it does everything expected and then some).

                               

                              So, it looks as if you can close JBWS-3069.

                               

                              I ran into one other problem which does not break anything immediately but will be an issue for interoperability, specifically with Microsoft. When my services get an incoming request they normally need to hand back an endpoint for a continuation message. If the incoming request arrives via an https scheme URL then the endpoint for the the continuation should be created using an https scheme. So, in the WebMethod implementation I use code as follows to identify the request scheme

                               

                              @WebMethod(...)

                              public void foo()

                              {

                                  MessageContext ctx = webServiceCtx.getMessageContext();
                                  HttpServletRequest request = (HttpServletRequest)ctx.get(MessageContext.SERVLET_REQUEST);
                                  boolean isSecure = "https".equals(request.getScheme());

                                  . . .

                              The problem is that when foo is a OneWay method request.getScheme always returns null. Now this does not break anything (it did when I did the equals test the other way round which is why I spotted it :-) but it does mean that I always think the client is contacting the services via a non-secure URL. Now, Microsoft's WSTX always uses https and it will throw up if handed an http endpont for the continuation message. So, I need a reliable way to obtain the request scheme when the message is OneWay. Any ideas? Or do I have to raise a JIRA feature request for this?

                              • 12. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                                jim.ma
                                Any ideas? Or do I have to raise a JIRA feature request for this?

                                I just have a quick test in cxf code base with jetty https connection, and I can always get the schema from HttpServletRequest.  So looks like it is an issue in our cxf integration code. I've created the jira issue https://jira.jboss.org/browse/JBWS-3081 for it.  Will look at it later.

                                • 13. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                                  adinn

                                  Jim Ma wrote:


                                  I just have a quick test in cxf code base with jetty https connection, and I can always get the schema from HttpServletRequest.  So looks like it is an issue in our cxf integration code. I've created the jira issue https://jira.jboss.org/browse/JBWS-3081 for it.  Will look at it later.

                                   

                                  Yes, I suspect that it is a result of the way the integration code hands off the request to a worker thread and closes the HTTP connection. I think the worker thread does not have access to the original request. When I looked at the request in the debugger all itsfields were null. It seemed to me that it was just an empty object created by the getRequest() method when it failed to detect a request associated with  the worker thread.

                                  • 14. Re: Continuing problem with XTS WS-T tests in AS trunk/CXF 2.2.9
                                    jim.ma

                                    Hi Andrew,

                                     

                                    I wrote a simple oneway service and configure the 8443 port connecotor for jboss server:

                                    @WebService(serviceName = "SOAPService",

                                     

                                                endpointInterface = "org.jboss.ssl.Greeter",

                                     

                                                targetNamespace = "http://jbossws.jboss.org/hello_world")

                                     

                                    public class GreeterImpl implements Greeter {

                                     

                                        WebServiceContext wscontext;

                                     

                                        public void pingMe() {

                                     

                                            MessageContext msgContext = wscontext.getMessageContext();

                                     

                                            HttpServletRequest httpServletRequest =

                                     

                                                (HttpServletRequest)msgContext.get(MessageContext.SERVLET_REQUEST);

                                     

                                            System.out.println(httpServletRequest.getScheme());

                                     

                                        } 

                                     

                                    }

                                    When I use a ssl client running in another jvm to send oneway request, the server can always get the "https" schema without error.  Can you see if there any difference between my test setup with XTS test code and configuration here?

                                    1 2 Previous Next