axis-java-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Anne Thomas Manes" <atma...@gmail.com>
Subject Re: request always calls the first operation defined in server-config.wsdd
Date Wed, 16 Aug 2006 12:51:46 GMT
Richard,

Although adding a SOAPAction parameter will solve your problem with
Axis2, this solution may not work with other systems, and therefore is
not a good practice to adopt. In addition, the SOAPAction parameter is
being deprecated in SOAP 1.2. (It is being replaced by the Action
parameter in WS-Addressing.)

See Section 4.7.6 of the WS-I Basic Profile [1] for guidance on how to
define unique message signatures. The profile requires that you rely
only on the on-the-wire message signature, and that you not rely on
SOAPAction.

I think the reason it doesn't feel intuitive to you is that you're
thinking in terms of the Java method signature rather than on-the-wire
signature. And you're also thinking of Document style as something
that's basically the same as RPC style. When using RPC style, you are
sending a set of parameters (defined by their types). But when you are
using Document style, you are sending a document (an element). Axis2
can automatically bind the element to a Java object for you, but it
really helps if you switch your thinking to a message-oriented
perspective.

The reason why switching to RPC style works is that RPC style will
automatically generate a wrapper element around your input parameters.
That wrapper element has the same name as your operation, and
therefore provides a unique signature. When using RPC style, you can
specify multiple message parts, because each part represents a
parameter, and all the parameters get turned into child elements of
the wrapper element. (When using Document style, your message can
contain at most one message part.)

But note that you can't simply change the style attribute from
"document" to "rpc" and expect it to work. (If it does, then that's a
bug, so please file a JIRA.) In order to switch to RPC style, you must
change the message parts and have them reference types rather than
elements, and you must add a namespace attribute to the <soap:body>
definition to the binding.

Here's an example of the pertinent bits when using Document style:

          <xsd:element name="getFile" type="simpleGuidType"/>

          <wsdl:message name="getFileRequest">
               <w:part name="request" element="getFile"/>
          </wsdl:message>

          <wsdl:operation name="getFile">
               <soap:operation style="document"
soapAction="urn:example:getFile" />
               <wsdl:input>
                   <soap:body use="literal" />
               </wsdl:input>
               ...
           </wsdl:operation>

And here's the pertinent bits for an RPC style service:

          <xsd:complexType name="simpleGuidType">
                ....
          </xsd:complexType

          <wsdl:message name="getFileRequest">
               <w:part name="simpleGUID" type="simpleGuidType"/>
          </wsdl:message>

          <wsdl:operation name="getFile">
               <soap:operation style="getFile"
soapAction="urn:example:service:getFile" />
               <wsdl:input>
                   <soap:body use="literal" namespace="urn:example:service"/>
               </wsdl:input>
               ...
           </wsdl:operation>

If switching to RPC style solves your problem, then go with it. But I
strongly encourage you not to get in the habot of relying on
SOAPAction to route your message. You should follow the advice given
in the WS-I Basic Profile and define a unique on-the-wire signature.

There's a WSDL convention for document style known as "wrapped", and
this is what I always recommend. I've written up a description of the
wrapped convention in my blog. [2] The wrapped convention supports a
programming model for document style that's essentially identical to
RPC style. When using the wrapped style, you define wrapper elements
for your input parameters (essentially what RPC style does for you
automatically), and you reference these wrapper elements from your
message parts. Most SOAP toolkits can automatically wrap and unwrap
the parameters for you so that you can use an RPC-style method
invocation. The developers are building support for the wrapped
convention as we type.

[1] http://www.ws-i.org/Profiles/BasicProfile-1.1.html#Operation_Signatures
[2] http://atmanes.blogspot.com/2005/03/wrapped-documentliteral-convention.html

Anne

On 8/16/06, Richard Jones <richard.d.jones@imperial.ac.uk> wrote:
> Hi Anne,
>
> Sorry for my slow response - I wanted to spend some time playing with
> the settings and code to see if I could make some headway.
>
> I have, now, two solutions to this particular problem, which I'll detail
> here for the purposes of list archive:
>
> 1) Switching from doc/lit to rpc/lit and rebuilding client and server
> code with WSDL2Java immediately solves the problem.
>
> This is done by switching/inserting 'style="rpc"' into the binding
> declaration:
>
> <soap:binding transport="http://schemas.xmlsoap.org/soap/http"
> style="rpc" />
>
> and leaving 'use="literal"' in the soap:body declaration.
>
> I had not understood that "signature" in the frame of a web service is
> defined by the body, and that in doc/lit form that this "signature" is
> different to the way that signature is traditionally defined in OOP.  It
> appears that using rpc/lit recovers the more traditional definition of
> signature.
>
> 2) The operation that is called can be specified as a soapAction and
> passed in the HTTP header in doc/lit form.  My WSDL did not define a
> default soapAction, but the addition of the relevant attribute, along
> with a rebuild of all the client and server code does the job.  So here
> is a snippet from the WSDL which uses doc/lit, but which can distinguish
> between different operations at the end of the service while using the
> same soap body:
>
> <soap:binding transport="http://schemas.xmlsoap.org/soap/http"
> style="document" />
> <wsdl:operation name="RequestFileDetails">
>    <soap:operation soapAction="RequestFileDetails"/>
>      <wsdl:input>
>        <soap:body use="literal" />
>      </wsdl:input>
>      <wsdl:output>
>        <soap:body use="literal" />
>      </wsdl:output>
> </wsdl:operation>
>
> > According to your WSDL, you have five request messages that have
> > identical signatures:
> > - ArticleUpdateNotificationRequest
> > - UnsetLicenseRequest
> > - ViewLicenseRequest
> > - LicenseStatusRequest
> > - RequestFileDetailsRequest
> >
> > A SOAP message signature is determined by the child element of the
> > <soap:Body>. When using document style, that message signature element
> > is the element referenced in the <wsdl:part> definition.
>
> This is what scuppered me.  In doc/lit, the message names are basically
> irrelevant unless you specify a soapAction.  I would say this is very
> counter intuitive, since the traditional definition of the signature
> would include at least the operation name, as well as the parameters.
>
> > But you have four other request messages that look exactly the same.
> > There is absolutely no way for Axis to determine which operation you
> > want to invoke, therefore it always invokes the first operation.  So
> > as I said in my first response, you must define unique signatures for
> > each operation -- that means that each operation request message must
> > reference a unique element name in its message part.
>
> Although there actually is a way for Axis to determine which operation
> you want to invoke, which is to do exactly what it does do when you
> specify a soapAction, and look in the HTTP headers.
>
> > I recommend that you define a type called "singleGuidType" and then
> > define five separate elements, each with a name corresponding to the
> > method name, e.g.:
> >
> > <xsd:complexType name="singleGuidType">
> >   <xsd:sequence>
> >       <xsd:element maxOccurs="1" minOccurs="1" name="guid"
> > type="xsd:string"/>
> >   </xsd:sequence>
> > </xsd:complexType>
> >
> > <xsd:element name="ArticleUpdateNotification" type="singleGuidType"/>
> >
> > <wsdl:message name="ArticleUpdateNotificationRequest">
> >     <wsdl:part element="tns:ArticleUpdateNotification"
> >           name="body"/>
> > </wsdl:message>
>
> I think this is overly complicated, and misses the crux of the problem,
> since the addition of the relevant soapAction did the job.
>
> The problem that I encountered was due to a number of factors: first
> (and foremost), I was fairly clueless about how the deep internals of
> Axis worked with regard to mapping requests onto operations; second,
> that doc/lit when implemented using axis does not behave as you might
> expect (i.e. in this situation, it would probably make more sense for
> WSDL2Java to throw an error if no soapAction is defined, or at least
> generate a warning); and third that Eclipse web tools doesn't enforce,
> or recommend the addition of the relevant soapAction in the UI.
>
> Anyway, I don't want to be a bad workman blaming his tools, so really
> it's down to me not understanding doc/lit fully before using it.
> Hopefully this post will help other people who get confused about the
> same thing ;)
>
> Thanks for all your help,
>
> Richard
>
>
> >> >> I am starting to really get to grips with my web services now, with
> >> much
> >> >> thanks to Axis.  This morning, though, I have encountered a problem
> >> >> which I can't work out whether is my fault (likely) or a potential
> >> >> problem.
> >> >>
> >> >> I have two requests defined (in the scope of this problem):
> >> >>
> >> >> public void requestFileDetails(String guid)
> >> >>    throws ServiceException, RemoteException
> >> >> {
> >> >>    // make the request
> >> >>    SpiralTestSoapService service = getService();
> >> >>    SingleGUID sguid = new SingleGUID(guid);
> >> >>    RequestFileDetailsResponse response =
> >> >>      service.requestFileDetails(sguid);
> >> >> }
> >> >>
> >> >> public void articleUpdateNotification(String guid)
> >> >>    throws ServiceException, RemoteException
> >> >> {
> >> >>    // make the request
> >> >>    SpiralTestSoapService service = getService();
> >> >>    SingleGUID sguid = new SingleGUID(guid);
> >> >>    service.articleUpdateNotification(sguid);
> >> >> }
> >> >>
> >> >> these in turn call the relevant operations on the port type (The
> >> >> xxx_BindingImpl class).
> >> >>
> >> >> When either of the above methods are called in the client, the server
> >> >> /always/ processes the request to "requestFileDetails".  I discovered
> >> >> that I could fix this so that it always processed the request to
> >> >> "articleUpdateNotification" by reversing the order that these two
> >> >> operations are specified in the server-config.wsdd:
> >> >>
> >> >> <operation name="articleUpdateNotification"
> >> >>      qname="ArticleUpdateNotification" mep="oneway" >
> >> >>    <parameter qname="pns:SingleGUID"
> >> >>        xmlns:pns="http://[...]/SpiralWebService/"
> >> type="tns:>SingleGUID"
> >> >>        xmlns:tns="http://[...]/SpiralWebService/"/>
> >> >> </operation>
> >> >> <operation name="requestFileDetails" qname="RequestFileDetails"
> >> >>      returnQName="retNS:RequestFileDetailsResponse"
> >> >>      xmlns:retNS="http://[...]/SpiralWebService/"
> >> >>      returnType="rtns:>RequestFileDetailsResponse"
> >> >>      xmlns:rtns="http://[...]/SpiralWebService/" >
> >> >>    <parameter qname="pns:SingleGUID"
> >> >>        xmlns:pns="http://[...]/SpiralWebService/"
> >> >>        type="tns:>SingleGUID"
> >> >>        xmlns:tns="http://[...]/SpiralWebService/"/>
> >> >> </operation>
> >> >>
> >> >> I upped log4j to DEBUG, and observed that the body of the request
> >> seems
> >> >> only to contain the data type, not the operation name:
> >> >>
> >> >> 2006-08-11 12:39:00,795 DEBUG
> >> org.apache.axis.providers.java.RPCProvider
> >> >> @ body is <SingleGUID xmlns="http://[...]/SpiralWebService/"><guid
> >> >> xmlns="">1234567890</guid></SingleGUID>
> >> >>
> >> >> The two above methods both take the SingleGUID data type as an
> >> argument,
> >> >> so I defined this type in the WSDL and re-used it all over the place.
> >> >> My current guess (and it is only a guess) is that Axis is just looking
> >> >> for the first operation that takes this data type, and executing
> >> it, no
> >> >> matter which operation it was intended for.
> >> >>
> >> >> Can anyone see what I might have done wrong?  Am I misappropriating
> >> the
> >> >> data types and the way that axis uses them, or have I missed something
> >> >> in the way to call the web service, or is there something else?
> >> >>
> >> >> Any help much appreciated,
> >> >>
> >> >> Cheers
>
> --
> Richard
> -------
> Richard Jones
> Web and Database Technology Specialist
> Imperial College London
> t: +44 (0)20 759 41815
> e: richard.d.jones@imperial.ac.uk
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: axis-user-unsubscribe@ws.apache.org
> For additional commands, e-mail: axis-user-help@ws.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: axis-user-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-user-help@ws.apache.org


Mime
View raw message