Thanks Glen for your feedback. 

Read my comments inline, any one interested in having higher level support
for soap header should do so too! ;-)

Sylvain.

-----Original Message-----
From: Glen Daniels [mailto:[EMAIL PROTECTED]]
Sent: Thursday, May 02, 2002 4:28 PM
To: '[EMAIL PROTECTED]'
Subject: RE: soap:header new implementation



Hi Sylvain!

First off, I'm psyched that you're moving in this direction, because we
clearly need to support headers in some way.    The following is my take on
things, both in terms of where I'd like to be able to go wrt extensions in
general and also how to deal with the particular "fine-grained" approach
you're taking.

Headers have completely arbitrary semantics, and what happens as a result of
a header being sent/received is really completely up to the specification
wherein that header was defined.  In fact, such a specification might well
define *multiple* headers and how they relate to each other, message
exchange patterns, challenge/response rules, etc.... This can get hairy and
you don't really want your clients having to deal with it directly.

What you really want (IMO) for the interesting cases is some well-defined
chunk of code that plugs in and implements the entire specification for the
module, including generating/reading all the appropriate headers.  We
already have Handlers for precisely this purpose, except that they're even a
little too fine-grained.  What's needed, I think, is a "Module" concept
which contains Handlers, rules/code for automatically deploying them (on
either the client or the server side), and some kind of optional API for
getting any interesting values into or out of them.  (This is post-1.0 Axis
we're talking about here, btw)  I can give you some examples later if you're
interested.

[sylvain] Definitely interrested in getting my hands on those examples. 

Now, that said, there are certainly more simple cases where you just want to
"send the 7 as the ID header" or something like that, this is why we have
the addHeader() API on Call, and this is the kind of thing you're trying to
support with your code.

[sylvain] True.   

In looking at the code you submitted, I'm not sure I see a real need for so
much mechanism (i.e. all the Headers/HeaderKey/etc... classes) if we're
going for the "simple" approach.  It feels to me like we either want to:

[sylvain] True that I can easily get rid of some stuff there.  

1) Put the headers in parameters on the generated method signatures (I think
this is what .NET does?  It's also one style recommended in JAX-RPC).  Add
parameters named for the header parts to the list, and Holders for any out
headers:

   public void doSomething(String realArg, String headerArg, IntHolder
outputHeaderArg)

[sylvain] I am not quite sure I see the value in poluting the interface with
the headers, this is not the most natural approach for me, but that is me.
About dotNet, from what I can see that is not what my colleague is doing
with dotNet.  From what I know (and I have double checked) he does
setHeader(object) and do multiple call, each call that has this header
registered in the wsdl through soap:header element send this object as a
soap header, and even, send the modified header as soon as call has returned
a modified version.  I do not know how they figure this behaviour from the
WSDL, there is nothing about that there but that is what happens.

or

2) Just let people add headers by QName via an _addHeader() call on the
Stub.  I'm OK with your "DISCARD"/"PERSIST" options, so perhaps those should
be allowed, but I don't think we need much more than an ArrayList of
HeaderDescriptor objects (where HeaderDescriptor == [SOAPHeaderElement,
DISCARD/PERSIST flag]) in the Stub to make this happen.

[sylvain] I think this is close to the implementation I have now.  

Thoughts?

A few more specific comments re: your message inline below.
[sylvain] same for me, read on!

Thanks,
--Glen

> -----Original Message-----
> From: St-Germain, Sylvain [mailto:[EMAIL PROTECTED]]
> Sent: Thursday, May 02, 2002 10:44 AM
> To: Axis Dev (E-mail)
> Subject: soap:header new implementation
> 
> 
> Read on - design issue at the end.
> 
> I have modified the original soap:header support 
> implementation to allow
> full flexibility around the header management.  The way I 
> have achieve this
> is by allowing the user to specify the header object 
> lifecycle.  The current
> three lifecycles are: 
> 
> HeaderLifeCycle.REPLACE: the response's header object will 
> overwrite the
> request's one

This seems like kind of a bad idea to me, since it implies semantic
knowledge of what the header is supposed to do, and I don't know of a lot of
cases where this style is used (do you?).  If you want to get at a header in
the response message, you should have an API for that, but I don't think
that we want to get into replacing headers like this (what happens if there
are multiple returned headers with the same QName, for instance?).  Leave
that up to the user, or up to the Module if/when we get there.

[sylvain] I could be wrong but IMO future serious webServices that require
authentication, session management and such, will document quite precisly
what the header requirements and life cycle are.  About REPLACE, in dotNet
REPLACE is THE behaviour I see happening.

> HeaderLifeCycle.DISCARD: the request's header object is 
> removed from the
> list after the call.
> HeaderLifeCycle.PERSIST: the request's header stays as is.

These seem like OK options.

> A user then do:
>       binding.setHeader("CAM", cam, HeaderLifeCycle.REPLACE );
>       binding.setHeader("hdrSession", hdrs, HeaderLifeCycle.DISCARD );
> 
> To allow the setHeader() and getHeader() method to work off 
> the binding
> (PortType) class I had to add a new extension to the PortType 
> interface
> (currently org.apache.axis.client.HeaderSupport) this is all 
> fine for client
> side since the HeaderSupport interface is implemented by the 
> abstract Stub,
> but doing so, I broke the Impl class since it also implements 
> the PortType.

Why not just stick these methods on Stub, like _getProperty/_setProperty?
In fact it looks like you already did that, so I don't get why this should
change the PortType interface at all....

[sylvain] You are right this is what I am doing.   I had to change the
PortType interface (unfortunately) to be able to write (on the client side) 

        binding.setHeader();
        instead than the uglier
        ((ConcreteStub)binding).setHeader();

if the later does not mind you I would be more than happy to get rid of this
PortType interface change artifact.

> This being said we will ultimately want access to those two 
> methods on the
> server-side but in the mean time (since I am not implementing 
> server support
> now) I need a spot to put those two methods.  Any idea?

I don't understand this - these are client-side methods, not server-side
ones....?  On the server, you can get access to the headers via the
SOAPEnvelope.

[sylvain] Wouldn't you prefer to access header by name and deal with an
Object, the same as you used on the client?

> Would bringing back the skeleton be the answer to my problem?

Skeletons never disappeared, they're just not the default anymore.
Regardless, I don't think they're the answer. :)

[sylvain]  You must be right here. ;-)  

[sylvain]  All that being said, I am a little confused about how we can move
on with this?   Do you see any value in integrating such an implementation
(maybe not as is  - agreed) may it only be for the sake of getting feedback
from user of Axis?  

I understand that the header are not that well understood, however, based on
the feedback I got from the previous submission I tried to implement their
support in a flexible way so the client of the webService can really decide
what to do with them.

About implementing the header support using Handler I though about that but
since nobody suggested that when I originaly asked for design choices I
droped it.   I may be wrong but isn't this an implementation detail (to a
certain point at least)?

I am still surprised by the little amount of code I had to write to get this
working: some code to generate more code in the Stub and some code to cache
the header objects.  This makes me think it would be rather easy to turn
this implementaion into another form.

Just to be clear again, here is a scenario that is possible with MY axis ;-)


Given the following simplified WSDL chunk (please follow me, don't give up
just yet ;-) )

<wsdl:operation name="getObject">
  <soap:operation soapAction="..."/>
  <wsdl:input >
    <soap:header required="true" message="tns:CAM" part="CAM" />
    <soap:header required="false" message="tns:hdrSession" part="hdrSession"
/>
    <soap:body/>
  </wsdl:input>
  <wsdl:output >
    <soap:header required="true" message="tns:CAM" part="CAM" />
    <soap:header required="false" message="tns:hdrSession" part="hdrSession"
/>
    <soap:body/>
  </wsdl:output>
</wsdl:operation>

<wsdl:operation name="setObject">
  <soap:operation soapAction="..."/>
  <wsdl:input >
    <soap:header required="true" message="tns:CAM" part="CAM" />
    <soap:header required="false" message="tns:hdrSession" part="hdrSession"
/>
    <soap:body/>
  </wsdl:input>
  <wsdl:output >
    <soap:header required="true" message="tns:CAM" part="CAM" />
    <soap:header required="false" message="tns:hdrSession" part="hdrSession"
/>
    <soap:body/>
  </wsdl:output>
</wsdl:operation>

I can write:

1  MyServiceLocator  service = new MyServiceLocator();          
2  MyServicePortType binding = service.getMyServicePort();

3  // Set the cam and hdrs objects
4  [...] 

5  // Set the CAM header which instruct the server to log me in, 
6  // set its lifecycle to 
7  // REPLACE since the returned header will contain my passport.
8  binding.setHeader("CAM", cam, HeaderLifeCycle.REPLACE );

9  // Provide login information so the authentication can go through
10 binding.setHeader("hdrSession", hdrs, HeaderLifeCycle.DISCARD );

11 ABob bob = binding.getObject("/content/bob");
12 binding.setObject( update(bob) );
 

Line 11: the getObject send the headers as described in the wsdl, the user
is authenticated and the requested object is returned, after Stub.invoke()
the response's CAM header REPLACEs the request's one and the hdrSession is
DISCARDed from the list of headers. 

Line 12: the setObject send the updated CAM object as a header as well as
the updated bob, the object is updated on the server.  Without the user
having to deal with the headers.

This is the kind of thing I would like Axis to be capable of.  Am I
dreaming?  Possible, but hard to say since this all make sense to me now!

I hope you can appreciate the flexibility brought to the Axis user by the
proposed implementation.  I leave you on this note: let's give it a try, we
will see what users will say and we will go from there.

Regards,
Sylvain.










This message may contain privileged and/or confidential information.  If you
have received this e-mail in error or are not the intended recipient, you
may not use, copy, disseminate or distribute it; do not open any
attachments, delete it immediately from your system and notify the sender
promptly by e-mail that you have done so.  Thank you.

Reply via email to