Axis-C++
  1. Axis-C++
  2. AXISCPP-429

generated stubs use request message name, instead of operation name for setOperation

    Details

      Description

      The WSDL2Ws tool generates doc/literal stubs where the setOperation method uses the request message name, rather than the operation name.

      Regretably, all of our tests have these values set the same, hence this problem never having been seen before.

        Activity

        Hide
        nadir amra added a comment -

        Issue is now resolved. Will wait to close when a test case is created.

        Show
        nadir amra added a comment - Issue is now resolved. Will wait to close when a test case is created.
        Hide
        nadir amra added a comment -

        Further investigation and I have found the real problem. It seems that because we do not invoke setOperation() when an document/literal operation has no input parameters, the request that is generated is something like:

        <?xml version='1.0' encoding='utf-8' ?>
        <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <SOAP-ENV:Body>
        <SOAP-ENV:Fault>
        <faultcode>SOAP-ENV:Server</faultcode>
        <faultstring>Webservice failed</faultstring>
        <faultactor>server name:listen port</faultactor>
        <detail><appSpecific></appSpecific>
        </detail>
        </SOAP-ENV:Fault>
        </SOAP-ENV:Body>
        </SOAP-ENV:Envelope>

        This is the result of the following if-check in SoapBody::serialize() method:

        else if(NULL != m_pSoapMethod)

        { iStatus= m_pSoapMethod->serialize(pSZ); if(iStatus==AXIS_FAIL) break; }

        else
        {
        m_pSoapFault = SoapFault::getSoapFault(SERVER_ENGINE_WEBSERVICE_FAILED);
        if(m_pSoapFault!=NULL)

        { iStatus= m_pSoapFault->serialize(pSZ, eSoapVersion); if(iStatus==AXIS_FAIL) break; }

        }

        Obviously, this is incorrect. So what I have done is generate setOperation() call in stub with namespace set to null string. For example:

        m_pCall->setOperation("getVersion", "");

        and I have modifed the SoapBody::serialize() method if-check so that it looks like the following:

        else if(NULL != m_pSoapMethod)
        {
        // A null-string namespace means the operation does not have input parameters and
        // thus we skip this serialization step!
        AxisString prefix = m_pSoapMethod->getPrefix();
        if (prefix.length() != 0)

        { iStatus= m_pSoapMethod->serialize(pSZ); if(iStatus==AXIS_FAIL) break; }

        }

        So a null-string namespace is an indication that there are no parameters. The generated request now seems to be correct, it looks like the following:

        <?xml version='1.0' encoding='utf-8' ?>
        <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <SOAP-ENV:Body>
        </SOAP -ENV:Body>
        </SOAP-ENV:Envelope>

        which is consistent with what eclipse generates for the WSDL in the Web Services Explorer tool.

        Some more testing to be done....

        Show
        nadir amra added a comment - Further investigation and I have found the real problem. It seems that because we do not invoke setOperation() when an document/literal operation has no input parameters, the request that is generated is something like: <?xml version='1.0' encoding='utf-8' ?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <SOAP-ENV:Fault> <faultcode>SOAP-ENV:Server</faultcode> <faultstring>Webservice failed</faultstring> <faultactor>server name:listen port</faultactor> <detail><appSpecific></appSpecific> </detail> </SOAP-ENV:Fault> </SOAP-ENV:Body> </SOAP-ENV:Envelope> This is the result of the following if-check in SoapBody::serialize() method: else if(NULL != m_pSoapMethod) { iStatus= m_pSoapMethod->serialize(pSZ); if(iStatus==AXIS_FAIL) break; } else { m_pSoapFault = SoapFault::getSoapFault(SERVER_ENGINE_WEBSERVICE_FAILED); if(m_pSoapFault!=NULL) { iStatus= m_pSoapFault->serialize(pSZ, eSoapVersion); if(iStatus==AXIS_FAIL) break; } } Obviously, this is incorrect. So what I have done is generate setOperation() call in stub with namespace set to null string. For example: m_pCall->setOperation("getVersion", ""); and I have modifed the SoapBody::serialize() method if-check so that it looks like the following: else if(NULL != m_pSoapMethod) { // A null-string namespace means the operation does not have input parameters and // thus we skip this serialization step! AxisString prefix = m_pSoapMethod->getPrefix(); if (prefix.length() != 0) { iStatus= m_pSoapMethod->serialize(pSZ); if(iStatus==AXIS_FAIL) break; } } So a null-string namespace is an indication that there are no parameters. The generated request now seems to be correct, it looks like the following: <?xml version='1.0' encoding='utf-8' ?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> </SOAP -ENV:Body> </SOAP-ENV:Envelope> which is consistent with what eclipse generates for the WSDL in the Web Services Explorer tool. Some more testing to be done....
        Hide
        nadir amra added a comment -

        hmmm, running a test I get:

        AxisSoapException: Soap message is incomplete.
        The SOAP serializer has detected errors in the header or envelope. Transmission has been aborted.

        Seems the serializer expects a non-zero length namespace.

        So I am inclined to check the output messages and use that namespace if there are no input messages....

        But I sure would like some direction from the SOAP/WSDL guru's out there....what is the recommendation when for namespace for doc/literal when there are no input parameters?

        Show
        nadir amra added a comment - hmmm, running a test I get: AxisSoapException: Soap message is incomplete. The SOAP serializer has detected errors in the header or envelope. Transmission has been aborted. Seems the serializer expects a non-zero length namespace. So I am inclined to check the output messages and use that namespace if there are no input messages.... But I sure would like some direction from the SOAP/WSDL guru's out there....what is the recommendation when for namespace for doc/literal when there are no input parameters?
        Hide
        nadir amra added a comment -

        Will wait until a test case is created before closing.

        Show
        nadir amra added a comment - Will wait until a test case is created before closing.
        Hide
        nadir amra added a comment - - edited

        OK, I think from RPC side of things everything is OK, however, from doc/literal side of things I did a little research and from my observations on what Java side of things does when generating Java stubs, it seems to be that:

        If input parameters exist, namespace specified for param is used
        else if no input parameters exist, then the namespace for the <soap:body > is used if it exists
        else null string is used for namespace.

        That will be the logic I will be using.

        Thus, for org.apache.axis.wsdl.wsdl2ws.cpp.literal.ClientStubWriter.java (and C equivalent), I have changed the following:

        + // Issue setOperation logic...namespace for the operation is
        + // obtained from the namespace of the input message...if there
        + // is no input message then the namespace is obtained from
        + // the SOAP body extensability element for the input element; if
        + // there is no namespace, then we will use a null string.
        + // Techincally speaking, the SOAP body extensability element
        + // must not contain the namespace attribute. The SOAP body
        + // entry element for doc/literal style gets its namespace from the
        + // target namespace of the XML schema declaring this element.
        + String namespaceURI;
        if( minfo.getInputMessage() != null)

        • { - writer.write( "\t\tm_pCall->setOperation(\"" - + minfo.getInputMessage().getLocalPart() + "\", \"" - + minfo.getInputMessage().getNamespaceURI() + "\");\n"); - }

          + namespaceURI = minfo.getInputMessage().getNamespaceURI();
          + else
          + namespaceURI = minfo.getInputNamespaceURI();
          +
          + if (namespaceURI == null)
          + namespaceURI = "";

        + writer.write( "\t\tm_pCall->setOperation(\""
        + + minfo.getMethodname() + "\", \""
        + + namespaceURI + "\");\n");

        This also ensures the setOperation is issued even if there are no input parameters.

        Show
        nadir amra added a comment - - edited OK, I think from RPC side of things everything is OK, however, from doc/literal side of things I did a little research and from my observations on what Java side of things does when generating Java stubs, it seems to be that: If input parameters exist, namespace specified for param is used else if no input parameters exist, then the namespace for the <soap:body > is used if it exists else null string is used for namespace. That will be the logic I will be using. Thus, for org.apache.axis.wsdl.wsdl2ws.cpp.literal.ClientStubWriter.java (and C equivalent), I have changed the following: + // Issue setOperation logic...namespace for the operation is + // obtained from the namespace of the input message...if there + // is no input message then the namespace is obtained from + // the SOAP body extensability element for the input element; if + // there is no namespace, then we will use a null string. + // Techincally speaking, the SOAP body extensability element + // must not contain the namespace attribute. The SOAP body + // entry element for doc/literal style gets its namespace from the + // target namespace of the XML schema declaring this element. + String namespaceURI; if( minfo.getInputMessage() != null) { - writer.write( "\t\tm_pCall->setOperation(\"" - + minfo.getInputMessage().getLocalPart() + "\", \"" - + minfo.getInputMessage().getNamespaceURI() + "\");\n"); - } + namespaceURI = minfo.getInputMessage().getNamespaceURI(); + else + namespaceURI = minfo.getInputNamespaceURI(); + + if (namespaceURI == null) + namespaceURI = ""; + writer.write( "\t\tm_pCall->setOperation(\"" + + minfo.getMethodname() + "\", \"" + + namespaceURI + "\");\n"); This also ensures the setOperation is issued even if there are no input parameters.
        Hide
        nadir amra added a comment -

        I am reopening this issue. It seems that if no input parameters are passed in the setOperation call does not happen. Here is the code snippet (in org.apache.axis.wsdl.wsdl2ws.cpp.literal.ClientStubWriter.java):

        if( minfo.getInputMessage() != null)

        { writer.write( "\t\tm_pCall->setOperation(\"" + minfo.getInputMessage().getLocalPart() + "\", \"" + minfo.getInputMessage().getNamespaceURI() + "\");\n"); }

        So I do agree that the operation needs to be obtained from operation name. One thing I am not sure about is where to obtain the namespace from....I did notice that in org.apache.axis.wsdl.wsdl2ws.cpp.ClientStubWriter.java (RPC) the following two lines may provide me with a solution:

        // Use namespace specified in input/output binding if one exists
        String namespaceURI = minfo.getNamespaceURI();
        if (namespaceURI == null)
        namespaceURI = wscontext.getWrapInfo().getTargetNameSpaceOfWSDL();

        These two lines are not in the doc/literal version of the code, and I am not sure why.

        I have searched the literature and still am not sure what to do about namespace. Without some expert direction or until I know for certain, I plan to add the following code (the else leg):

        if( minfo.getInputMessage() != null)
        { writer.write( "ttm_pCall->setOperation("" + minfo.getInputMessage().getLocalPart() + "", "" + minfo.getInputMessage().getNamespaceURI() + "");n"); }

        else

        { // Use namespace specified in input/output binding if one exists String namespaceURI = minfo.getNamespaceURI(); if (namespaceURI == null) namespaceURI = wscontext.getWrapInfo().getTargetNameSpaceOfWSDL(); writer.write( "\t\tm_pCall->setOperation(\"" + minfo.getMethodname() + "\", \"" + namespaceURI + "\");\n"); }

        I think eventually, after doing more research, I will probably remove the code in the if-leg.

        Please let me know if I am in the right direction.

        Show
        nadir amra added a comment - I am reopening this issue. It seems that if no input parameters are passed in the setOperation call does not happen. Here is the code snippet (in org.apache.axis.wsdl.wsdl2ws.cpp.literal.ClientStubWriter.java): if( minfo.getInputMessage() != null) { writer.write( "\t\tm_pCall->setOperation(\"" + minfo.getInputMessage().getLocalPart() + "\", \"" + minfo.getInputMessage().getNamespaceURI() + "\");\n"); } So I do agree that the operation needs to be obtained from operation name. One thing I am not sure about is where to obtain the namespace from....I did notice that in org.apache.axis.wsdl.wsdl2ws.cpp.ClientStubWriter.java (RPC) the following two lines may provide me with a solution: // Use namespace specified in input/output binding if one exists String namespaceURI = minfo.getNamespaceURI(); if (namespaceURI == null) namespaceURI = wscontext.getWrapInfo().getTargetNameSpaceOfWSDL(); These two lines are not in the doc/literal version of the code, and I am not sure why. I have searched the literature and still am not sure what to do about namespace. Without some expert direction or until I know for certain, I plan to add the following code (the else leg): if( minfo.getInputMessage() != null) { writer.write( "ttm_pCall->setOperation("" + minfo.getInputMessage().getLocalPart() + "", "" + minfo.getInputMessage().getNamespaceURI() + "");n"); } else { // Use namespace specified in input/output binding if one exists String namespaceURI = minfo.getNamespaceURI(); if (namespaceURI == null) namespaceURI = wscontext.getWrapInfo().getTargetNameSpaceOfWSDL(); writer.write( "\t\tm_pCall->setOperation(\"" + minfo.getMethodname() + "\", \"" + namespaceURI + "\");\n"); } I think eventually, after doing more research, I will probably remove the code in the if-leg. Please let me know if I am in the right direction.
        Hide
        Adrian Dick added a comment -

        I've not received any comments to say this is still an issue, so am now closing.

        Show
        Adrian Dick added a comment - I've not received any comments to say this is still an issue, so am now closing.

          People

          • Assignee:
            nadir amra
            Reporter:
            Adrian Dick
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development