Search code examples
web-servicessoapwsdljax-wsapache-axis

JAXWS - problems generating correct structure of SOAP message


We have an application which needs to consume an external web service. To do this we have generated the set of Java artifacts from the WSDL via Maven using the wsdl2java goal provided by the cxf-codegen-plugin plugin.

We have written an integration test as part of our test suite which calls the real web service and everything works fine.

The code to integrate with the actual web service is then packaged into a set of JARs and used inside the front end application which needs to use the web service.

We are having an issue when the FE application uses the integration code. Exactly the same code is being executed by the FE application as is being used in our working integration test but the SOAP message which is ultimately generated is different between the two and the message generated by the actual application is incorrect.

The working SOAP request produced by our integration tests is:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <S:Body>
    <ns12:ProcessUIRequest xmlns:ns10="http://zzz/yyyentityview/validation/"
    xmlns:ns11="http://zzz/yyyview/search/list/"
    xmlns:ns12="http://zzz/yyywebservice/v5/types/"
    xmlns:ns2="http://zzz/yyyentityview/app/"
    xmlns:ns3="http://zzz/yyyentityview/client/"
    xmlns:ns4="http://zzz/yyyview/search/postcode/"
    xmlns:ns5="http://zzz/yyyview/app/"
    xmlns:ns6="http://zzz/yyyview/search/app/"
    xmlns:ns7="http://zzz/yyyview/search/bank/"
    xmlns:ns8="http://zzz/yyyview/uw/"
    xmlns:ns9="http://zzz/yyybase/">
      <ns12:ProcessUIRequest CallType="Submit" DisplayError="false"
      IsAnonymous="false" IsCompactRequest="false" IsError="false">
        <ns9:ModelData>
          <ns9:TransactionData ApplicationReference="20000003CR3.00000003"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:type="ns5:QuoteLoadTxnDataVO" />
        </ns9:ModelData>
        <ns9:Activity ActionCode="QuoteLoad" ActionMode="Default"
        ActivityCode="QuoteApplicationFull" ActivityMode="Default"
        ActivityReference="" ActivityStatus="Inital"
        ActivityTransaction="StartNewActivityAndLogOffUser"
        CanProceedWithValidationsOutstanding="true">
          <ns9:BusinessKeys>
            <item>
              <key>
                <string>ADVREF</string>
              </key>
              <value>
                <BusinessKeyVO KeyName="ADVREF" KeyValue="AVAGT01">
                  <BusinessKey KeyName="ADVREF" KeyType="Unknown"
                  KeyValue="AVAGT01" />
                </BusinessKeyVO>
              </value>
            </item>
          </ns9:BusinessKeys>
        </ns9:Activity>
      </ns12:ProcessUIRequest>
    </ns12:ProcessUIRequest>
  </S:Body>
</S:Envelope>

The POJO which is marshalled into that SOAP request is:

<tcp.ssgbase.BaseVO>
  <modelData>
    <transactionData class="tcp.ssgview.app.QuoteLoadTxnDataVO">
      <applicationReference>20000003CR3.00000003</applicationReference>
    </transactionData>
  </modelData>
  <activity>
    <businessKeys>
      <item>
        <tcp.serializable__dictionary.BusinessKeyItem>
          <key>
            <string>ADVREF</string>
          </key>
          <value>
            <businessKeyVO>
              <businessKey>
                <keyName>ADVREF</keyName>
                <keyValue>AVAGT01</keyValue>
                <keyType>Unknown</keyType>
              </businessKey>
              <keyName>ADVREF</keyName>
              <keyValue>AVAGT01</keyValue>
            </businessKeyVO>
          </value>
        </tcp.serializable__dictionary.BusinessKeyItem>
      </item>
    </businessKeys>
    <actionMode>DEFAULT</actionMode>
    <activityMode>DEFAULT</activityMode>
    <activityTransaction>START_NEW_ACTIVITY_AND_LOG_OFF_USER</activityTransaction>
    <actionCode>QuoteLoad</actionCode>
    <activityReference></activityReference>
    <activityStatus>INITAL</activityStatus>
    <activityCode>QuoteApplicationFull</activityCode>
    <canProceedWithValidationsOutstanding>true</canProceedWithValidationsOutstanding>
  </activity>
  <displayError>false</displayError>
  <isAnonymous>false</isAnonymous>
  <isError>false</isError>
  <isCompactRequest>false</isCompactRequest>
  <callType>SUBMIT</callType>
</tcp.ssgbase.BaseVO>

The SOAP request generated by the actual FE application is:

<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
  <soapenv:Body>
    <ns2:ProcessUIRequest xmlns:ns2="http://zzz/yyywebservice/v5/types/">
      <processUIRequest>
        <activity>
          <actionCode>QuoteLoad</actionCode>
          <actionMode>DEFAULT</actionMode>
          <activityCode>QuoteApplicationFull</activityCode>
          <activityMode>DEFAULT</activityMode>
          <activityReference />
          <activityStatus>INITAL</activityStatus>
          <activityTransaction>
          START_NEW_ACTIVITY_AND_LOG_OFF_USER</activityTransaction>
          <businessKeys />
          <canProceedWithValidationsOutstanding>
          true</canProceedWithValidationsOutstanding>
        </activity>
        <callType>SUBMIT</callType>
        <displayError>false</displayError>
        <isAnonymous>false</isAnonymous>
        <isCompactRequest>false</isCompactRequest>
        <isError>false</isError>
        <modelData>
          <transactionData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:type="ns2:quoteLoadTxnDataVO">
            <applicationReference>
            20000003ESF.00000018</applicationReference>
          </transactionData>
        </modelData>
      </processUIRequest>
    </ns2:ProcessUIRequest>
  </soapenv:Body>
</soapenv:Envelope>

The POJO which is marshalled into that SOAP request is:

<tcp.ssgbase.BaseVO>
  <modelData>
    <transactionData class="tcp.ssgview.app.QuoteLoadTxnDataVO">
      <applicationReference>20000003ESF.00000018</applicationReference>
    </transactionData>
  </modelData>
  <activity>
    <businessKeys>
      <item>
        <tcp.serializable__dictionary.BusinessKeyItem>
          <key>
            <string>ADVREF</string>
          </key>
          <value>
            <businessKeyVO>
              <businessKey>
                <keyName>ADVREF</keyName>
                <keyValue>AVAGT01</keyValue>
                <keyType>Unknown</keyType>
              </businessKey>
              <keyName>ADVREF</keyName>
              <keyValue>AVAGT01</keyValue>
            </businessKeyVO>
          </value>
        </tcp.serializable__dictionary.BusinessKeyItem>
      </item>
    </businessKeys>
    <actionMode>DEFAULT</actionMode>
    <activityMode>DEFAULT</activityMode>
    <activityTransaction>START_NEW_ACTIVITY_AND_LOG_OFF_USER</activityTransaction>
    <actionCode>QuoteLoad</actionCode>
    <activityReference></activityReference>
    <activityStatus>INITAL</activityStatus>
    <activityCode>QuoteApplicationFull</activityCode>
    <canProceedWithValidationsOutstanding>true</canProceedWithValidationsOutstanding>
  </activity>
  <displayError>false</displayError>
  <isAnonymous>false</isAnonymous>
  <isError>false</isError>
  <isCompactRequest>false</isCompactRequest>
  <callType>SUBMIT</callType>
</tcp.ssgbase.BaseVO>

You can see that the structure of the two requests are different even though the code being executed in our integration JARs is exactly the same and the structure of the POJOs used to create the SOAP message is the same (barring one value). From the request, it looks to be like the request generated in the FE application is not picking up the correct WSDL and associated XSDs.

Our code to generate the correct service endpoint interface implementation is:

private <T> T createServiceObject(final Class<T> p_seiClass) throws ApplicationException {
        try {
            final Service serviceFactory = Service.create(new URL(wsdlLocation), new QName(targetNamespace, serviceName));

            final SoapHandlerResolver handlerResolver = new SoapHandlerResolver();
            handlerResolver.addHandler(new SoapMessageLoggingHandler());
            serviceFactory.setHandlerResolver(handlerResolver);

            final T service = serviceFactory.getPort(p_seiClass);
            ((BindingProvider) service).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
                "endpoint");

            return service;
        } catch (MalformedURLException e) {
            throw new ApplicationException(ApplicationErrorCode.COMM_ERR_UNEXPECTED_ERROR, e);
        }
    }

After doing some debugging, I have noticed that the instance of the serviceFactory is different in the integration test and when we are running within the FE application.

In the integration test, the instance of the class (taken from the Eclipse debugger where we run the integration test using jUnit) is: 'JAX-WS RI 2.1.6 in JDK 6: Stub for ' and it appears to be of type 'SEIStub'.

When running within the FE application, the instance of the class is org.apache.axis2.jaxws.client.proxy.JAXWSProxyHandler. The FE application is hosted and executed on WebSphere Application Server.

So, my question is what could be happening when running in the actual FE application to cause the incorrect WSDL and XSD definitions to be picked up when marshalling the POJO into the SOAP request? I have spent a long time trying to debug this but to no avail.


Solution

  • The two soap request are different because, as you already said, the two serviceFactory is different and using different specifications 1.1 and 1.2.

    My suggestion is that you configure your maven project to import the right jars on your test enviroment or update the jar on the container (the jar that create the serviceFactory). As I'm not familiarized with cxf-codegen-plugin I can't suggest more than that.

    This suggestion was originally posted as a comment. The OP ask to put it as an answer.