9 Replies Latest reply on May 10, 2010 4:03 PM by dward

    SOAPProxy unable to identify the right soapaction/binding

    udaypal.aarkoti

      Background:

         I am trying to integrate JBoss SOA-P with DSP. In my implementation SOA-P is consuming a web service exposed by DSP. The WSDL of the Web Service and a sample request are attached.

       

      Problem:

           SOAPProxy works as expected when the "SOAPAction" attribute is set either in the HTTP headers or the ESB properties but when the SOAPAction is not set, SOAPProxy is unable to determine the right binding for the attached WSDL.
      The attached WSDL has four operations. getCustomers, getaccount, getaccountholdings & getcustomer. Lets look at getCustomers for this example.

      {code:xml}  <portType name="Customers">     <operation name="getCustomers">       <input message="tns:Customers_getCustomers_CustomerID" />       <output message="tns:Customers_getCustomers_Customers" />     </operation>   </portType>{code}

       

      The operations input message is of type "tns:Customers_getCustomers_CustomerID" and the same is defined as

       

      {code:xml}<message name="Customers_getCustomers_CustomerID">     <documentation>Input message for operation Customers/getCustomers.</documentation>     <part name="Customers_getCustomers_CustomerID" element="schema1:CustomerID" />   </message>{code}

       

      As you can see the message part's element attribute points to "schema1:CustomerID". So the incoming message is of the format

       

      {code:xml}<soapenv:Envelope xmlns:inp="http://metamatrix.com/customerholdings/input" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">    <soapenv:Header>       <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">          <wsse:UsernameToken wsu:Id="UsernameToken-2" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">             <wsse:Username>MetaMatrixWSDLUser</wsse:Username>             <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">mm</wsse:Password>             <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">vhurTjtnyXosYrTCTdM7aQ==</wsse:Nonce>             <wsu:Created>2010-04-27T21:56:25.816Z</wsu:Created>          </wsse:UsernameToken>       </wsse:Security>    </soapenv:Header>    <soapenv:Body>       <inp:CustomerID>CST01008</inp:CustomerID>    </soapenv:Body> </soapenv:Envelope>{code}

       

       

      Now the actual issue

       

      SOAPProxy for the attached WSDL creates the following operation_to_binding map

       

       

      {code}{{http://com.metamatrix/MMFinancials_VDB}getaccount={http://com.metamatrix/MMFinancials_VDB}AllCustomerAccounts_account, {http://com.metamatrix/MMFinancials_VDB}getcustomer={http://com.metamatrix/MMFinancials_VDB}AllCustomerAccounts_customer, {http://com.metamatrix/MMFinancials_VDB}getCustomers={http://com.metamatrix/MMFinancials_VDB}Customers, {http://com.metamatrix/MMFinancials_VDB}getaccountholdings={http://com.metamatrix/MMFinancials_VDB}AllCustomerAccounts_accountholdings}{code}

       

      and the soapaction_to_binding map is (this is only for reference and is not relevant for this issue)

       

      {code}{"mm:&ServerURL=mm://localhost:31000&VDBName=MMFinancials_VDB&VDBVersion=1&procedure=AllCustomerAccounts_WS.AllCustomerAccounts_accountholdings.getaccountholdings"={http://com.metamatrix/MMFinancials_VDB}AllCustomerAccounts_accountholdings, "mm:&ServerURL=mm://localhost:31000&VDBName=MMFinancials_VDB&VDBVersion=1&procedure=Customers_WS.Customers.getCustomers"={http://com.metamatrix/MMFinancials_VDB}Customers, "mm:&ServerURL=mm://localhost:31000&VDBName=MMFinancials_VDB&VDBVersion=1&procedure=AllCustomerAccounts_WS.AllCustomerAccounts_customer.getcustomer"={http://com.metamatrix/MMFinancials_VDB}AllCustomerAccounts_customer, "mm:&ServerURL=mm://localhost:31000&VDBName=MMFinancials_VDB&VDBVersion=1&procedure=AllCustomerAccounts_WS.AllCustomerAccounts_account.getaccount"={http://com.metamatrix/MMFinancials_VDB}AllCustomerAccounts_account}{code}

       

      but when I send the request I posted above its actually looking for the operation

       

      {code}{http://metamatrix.com/customerholdings/input}CustomerID{code}

       

      which obviously is not there in the operation_to_binding map.

       

      I am not a WSDL expert so I am not really sure if the WSDL is incorrect or SOAPProxy did not cover the use case presented in this WSDL?

        • 1. Re: SOAPProxy unable to identify the right soapaction/binding
          dward

          Uday, it looks like your sample message is doc/literal.  If you are going to do this, you have to specify the SOAPAction.  The reason is that a doc/literal message is not going to contain the operation name, so it makes it impossible for SOAPProxy to determine which operation to invoke.  If you were using rpc/literal, the operation name is part of the message, and thus SOAPProxy can figure it out.

           

          Check out this web page.  I am giving you a link that jumps down to the statement which backs mine above:

          http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/#doclitweak

           

          RPC/literal

          Strengths: "The operation name still appears in the message."

           

          Document/literal

          Weaknesses: "The operation name in the SOAP message is lost.  Without the name, dispatching can be difficult, and sometimes impossible."

          • 2. Re: SOAPProxy unable to identify the right soapaction/binding
            udaypal.aarkoti

            David,

             

            I did think about what you said before and hence did some debugging to see how SOAP proxy is determining the soapaction. It seems that SOAPProxy does have logic to lookup SOAPAction when its not specified in the headers. For example, when I look at the examples, packaged with the jbossesb download, the webservice_proxy_basic sets the SOAPAction to an empty string (or to nothing) and SOAPProxy is able to lookup the right SOAPAction and execute.

             

            Here is the log from the example

             

             

                 [java] ****  REQUEST BODY: <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:hello="http://webservice_proxy_basic/helloworld"><soapenv:Header/><soapenv:Body><hello:sayHello><toWhom>uaarkoti</toWhom></hello:sayHello></soapenv:Body></soapenv:Envelope>
                 [java] 11:23:54,567 DEBUG [main][header] >> "POST /Quickstart_webservice_proxy_basic/http/Proxy_Basic/Proxy HTTP/1.1[\r][\n]"
                 [java] 11:23:54,619 DEBUG [main][header] >> "Content-Type: text/xml;charset=UTF-8[\r][\n]"
                 [java] 11:23:54,619 DEBUG [main][header] >> "SOAPAction: ""[\r][\n]"
                 [java] 11:23:54,620 DEBUG [main][header] >> "User-Agent: Jakarta Commons-HttpClient/3.0.1[\r][\n]"
                 [java] 11:23:54,621 DEBUG [main][header] >> "Host: localhost:8080[\r][\n]"
                 [java] 11:23:54,621 DEBUG [main][header] >> "Content-Length: 254[\r][\n]"
                 [java] 11:23:54,621 DEBUG [main][header] >> "[\r][\n]"
                 [java] 11:23:54,621 DEBUG [main][content] >> "<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:hello="http://webservice_proxy_basic/helloworld"><soapenv:Header/><soapenv:Body><hello:sayHello><toWhom>uaarkoti</toWhom></hello:sayHello></soapenv:Body></soapenv:Envelope>"
                 [java] 11:23:55,753 DEBUG [main][header] << "HTTP/1.1 200 OK[\r][\n]"
                 [java] 11:23:55,755 DEBUG [main][header] << "Server: Apache-Coyote/1.1[\r][\n]"
                 [java] 11:23:55,755 DEBUG [main][header] << "X-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1[\r][\n]"
                 [java] 11:23:55,755 DEBUG [main][header] << "asyncServiceInvoke: false[\r][\n]"
                 [java] 11:23:55,756 DEBUG [main][header] << "Date: Mon, 10 May 2010 18:23:55 GMT[\r][\n]"
                 [java] 11:23:55,756 DEBUG [main][header] << "Content-Type: text/xml;charset=UTF-8[\r][\n]"
                 [java] 11:23:55,756 DEBUG [main][header] << "Content-Length: 292[\r][\n]"
                 [java] **** RESPONSE CODE: 200
                 [java] 11:23:55,775 DEBUG [main][content] << "<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'><env:Header></env:Header><env:Body><ns2:sayHelloResponse xmlns:ns2="http://webservice_proxy_basic/helloworld"><return>Hello 'uaarkoti' on Mon May 10 11:23:55 PDT 2010</return></ns2:sayHell"
                 [java] 11:23:55,775 DEBUG [main][content] << "oResponse></env:Body></env:Envelope>"
                 [java] **** RESPONSE BODY: <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'><env:Header></env:Header><env:Body><ns2:sayHelloResponse xmlns:ns2="http://webservice_proxy_basic/helloworld"><return>Hello 'uaarkoti' on Mon May 10 11:23:55 PDT 2010</return></ns2:sayHelloResponse></env:Body></env:Envelope>
            XX

            {code}

             

            So I am not really sure if the SOAPAction has to be specified if the WSDL definitions are described properly. Just to make sure my theory is right I am also trying to consume the same WSDL from other WS/ESB implementations to see how they are handling it. I will post the results as soon as I have the setup running.

            • 3. Re: SOAPProxy unable to identify the right soapaction/binding
              dward

              Nope.  SOAPProxy first looks for the SOAPAction header and, if found, cross-references that with the soapaction_to_binding Map.  If the header is not defined, it then starts parsing the SOAP Body for the first element, and if that matches a name in the operation_to_binding Map, then it uses that binding.  (Whether it matches or not, parsing is short-circuited ASAP for obvious performance reasons.)

               

              In the quickstart examples, the reason SOAPProxy can still figure out which binding to use without a SOAPAction header is because the messages sent are RPC/literal (the message contains the operation name).  For example in :

                   <hello:sayHello><toWhom>uaarkoti</toWhom></hello:sayHello>

              , the operation name is "sayHello".

               

              If the messages were DOC/literal like this:

                   <hello:toWhom>uaarkoti</hello:toWhom>

              , then the SOAPAction header would need to have been set.  Does that make sense?

              • 4. Re: SOAPProxy unable to identify the right soapaction/binding
                udaypal.aarkoti

                I think I should have attached the WSDL. According to the WSDL, its not RPC/literal.

                 

                 

                {code:xml}

                <definitions name='HelloWorldWSService' targetNamespace='http://webservice_proxy_basic/helloworld' xmlns='http://schemas.xmlsoap.org/wsdl/' xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' xmlns:tns='http://webservice_proxy_basic/helloworld' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>                                                                                                                  
                <types>                                                                                                                                                                                                 
                  <xs:schema targetNamespace='http://webservice_proxy_basic/helloworld' version='1.0' xmlns:tns='http://webservice_proxy_basic/helloworld' xmlns:xs='http://www.w3.org/2001/XMLSchema'>                  
                   <xs:element name='sayHello' type='tns:sayHello'/>                                                                                                                                                     
                   <xs:element name='sayHelloResponse' type='tns:sayHelloResponse'/>                                                                                                                                     
                   <xs:complexType name='sayHello'>                                                                                                                                                                      
                    <xs:sequence>                                                                                                                                                                                        
                     <xs:element minOccurs='0' name='toWhom' type='xs:string'/>                                                                                                                                          
                    </xs:sequence>                                                                                                                                                                                       
                   </xs:complexType>                                                                                                                                                                                     
                   <xs:complexType name='sayHelloResponse'>                                                                                                                                                              
                    <xs:sequence>                                                                                                                                                                                        
                     <xs:element minOccurs='0' name='return' type='xs:string'/>                                                                                                                                          
                    </xs:sequence>                                                                                                                                                                                       
                   </xs:complexType>                                                                                                                                                                                     
                  </xs:schema>                                                                                                                                                                                           
                </types>                                                                                                                                                                                                
                <message name='HelloWorld_sayHelloResponse'>                                                                                                                                                            
                  <part element='tns:sayHelloResponse' name='sayHelloResponse'></part>                                                                                                                                   
                </message>                                                                                                                                                                                              
                <message name='HelloWorld_sayHello'>                                                                                                                                                                    
                  <part element='tns:sayHello' name='sayHello'></part>                                                                                                                                                   
                </message>                                                                                                                                                                                                <portType name='HelloWorld'>                                                                                                                                                                            
                  <operation name='sayHello' parameterOrder='sayHello'>                                                                                                                                                  
                   <input message='tns:HelloWorld_sayHello'></input>                                                                                                                                                     
                   <output message='tns:HelloWorld_sayHelloResponse'></output>                                                                                                                                           
                  </operation>                                                                                                                                                                                           
                </portType>                                                                                                                                                                                             
                <binding name='HelloWorldBinding' type='tns:HelloWorld'>                                                                                                                                                
                  <soap:binding style='document' transport='http://schemas.xmlsoap.org/soap/http'/>                                                                                                                      
                  <operation name='sayHello'>                                                                                                                                                                                <soap:operation soapAction=''/>                                                                                                                                                                       
                   <input>                                                                                                                                                                                               
                    <soap:body use='literal'/>                                                                                                                                                                           
                   </input>                                                                                                                                                                                              
                   <output>                                                                                                                                                                                              
                    <soap:body use='literal'/>                                                                                                                                                                           
                   </output>                                                                                                                                                                                             
                  </operation>                                                                                                                                                                                           
                </binding>                                                                                                                                                                                              
                <service name='HelloWorldWSService'>                                                                                                                                                                       <port binding='tns:HelloWorldBinding' name='HelloWorldPort'>                                                                                                                                           
                   <soap:address location='http://localhost:8080/Quickstart_webservice_proxy_basic_ws/HelloWorldWS'/>                                                                                                    
                  </port>                                                                                                                                                                                                  </service>                                                                                                                                                                                              
                </definitions>
                {code}

                 

                • 5. Re: SOAPProxy unable to identify the right soapaction/binding
                  dward

                  Okay, you got me there.  I never caught that before, but I see why it still works.  The operation name and the root element of the document in the SOAP body are the same name.    If they were different, than a SOAPAction header would've needed to be set.

                   

                  The behavior of SOAPProxy is still how I described it, and my explanation of why it didn't work in your DSP example still holds true.  Let's step back for a moment here...

                   

                  Please tell me, if you don't specify the operation name in the SOAPAction header, and you don't specify the operation name in the body, how in the world do you expect the SOAPProxy to figure it out?  If you find some other product that can magically guess this, than I would love to know how they implement it so I can do the same thing in SOAPProxy. 

                  • 6. Re: SOAPProxy unable to identify the right soapaction/binding
                    udaypal.aarkoti

                    This definitely is NOT my area of expertise BUT here is what I was thinking how WSDL's definitions work, especially with doc/literal

                     

                    <operation> defines input and output message types.

                    <message> describes the message where <part>'s element attribute describes how these incoming/outgoing messages look like.

                     

                    I know I am teaching to the choir here but my theory is looking @ the incoming messages we should be able to identify the message, that should in return identify the operation and then operation's SOAPAction eventually.

                     

                    The reason I say theory is because I don't know what will happen if for the same message its possible, based on WSDL definitions, to map to multiple operations. I don't know if that's even allowed/possible. Perhaps that's why there are namespaces?

                    • 7. Re: SOAPProxy unable to identify the right soapaction/binding
                      dward

                      Even if there is a one-to-one mapping between input message and operation, I still don't think we can use that.  The reason is because a message defines a part, and a part refers to a schema element, which could be re-used.  And considering the root element in the SOAP Body is that schema element... 

                       

                      Maybe some more close studying of WSDL is in order...  (by both of us) 

                      • 8. Re: SOAPProxy unable to identify the right soapaction/binding
                        udaypal.aarkoti

                        The message <part> in this context will have to be the root element in <soap:body>. Yes the same <part> can be emedded in other request @ some other level (not root).

                         

                        Even then I can see there might be some collisions. At this point I am thinking one should be using different namespaces.

                         

                        That's exactly why I wanted to see how others are implementing it. Trying something similar with a .NET app right now. Will keep you posted.

                        • 9. Re: SOAPProxy unable to identify the right soapaction/binding
                          dward

                          Yes, please do.  Thanks for digging into this, Uday.  Much appreciated.