Ah, there's actually a third advantage to the second approach I gave of having the data binding code generate a method like:

 OMElement processFoo(OMElement elem)

This third advantage relates to the way most data binding frameworks handle unmarshalling. Typically you need some form of context set up to handle the unmarshalling, and the context can be relatively expensive to construct. Using a single method call like this allows the data binding code to just construct a single context and use it for all the parameters, while the separate methods approach would probably require a separate context to be created for each parameter.

 - Dennis

Dennis Sosnoski wrote:
I'm talking about the same idea. What made me think you were suggesting something else was your earlier comment:

Reduce the # of classes? Unwrapping *increases* the number of classes ..
each arg becomes a separate class. I must be missing something.

But unwrapping *does* reduce the number of classes involved - in your example below, the plain doc/lit case has the fooRequest and fooResponse classes, while these are not needed in the unwrapped case.

So it sounds like we're in basic agreement on how things are supposed to work. I think we still differ on the details, though. Take your sample service method:

   int foo(float a, Address b)

How do you actually generate the code to call this on the server? You start with an input OMElement, and need to get back an OMElement as the response. The input OMElement has child elements with the actual data for the parameters, and the data binding code needs to handle converting those child elements into the method parameter values. Likewise, the data binding code needs to handle converting the return value into the output OMElement. Are we in agreement so far?

I can think of two reasonable ways to implement this in the code. The first is to implement separate data binding methods per-parameter and per-return, so that you have methods like:

   float convertFooParamA(OMElement elem) { ... }
   Address convertFooParamB(OMElement elem) { ... }
   OMElement convertFooResult(int value) { ... }

To use these, the common operation code would need to extract the child elements from the input OMElement and then pass each one to the appropriate method. But child elements can be optional (minOccurs="0"), in which case they may have a default value - so the data binding conversion method still needs to be called in this case (presumably with a null instead of an element).

The second is to just turn the service method call generation over to the data binding code, so that you instead have a single generated method like:

   OMElement processFoo(OMElement elem) { ... }

The drawback as compared to the first approach is that this way the data binding code generation has more complexity, since it needs to process each child parameter element and actually call the service method - but I don't see this as much more difficult than just generating all the methods separately in the first approach.

I see two important advantages as compared to the first approach. First, the code generation task is divided more cleanly between the message receiver xslt and the databinding xslt, making them easier to debug. Second, data binding frameworks such as XMLBeans which could probably not work with the first approach (because it wants everything to always be an object) could work with this one by continuing to use a wrapper class internally but just taking the values out of the wrapper class in order to call the service method.

So my preference between the two I've outlined is the second approach. Is there another approach I'm missing?

 - Dennis

Sanjiva Weerawarana wrote:
Hmm. That's *exactly* what Anne, Ajith and I are saying too, I believe.

This is the idea: Suppose you have:
    int foo (float a, Address b)

Then the doc/lit (or WSDL 2.0) description of this would have two GEDs
(using a syntax hack):

<fooRequest>
  <a @type=xsd:float>
  <b @type=x:Address>
</fooRequest>

<fooResponse>
  <return @type=xsd:int>
</fooResponse>

Now switch sides to generating stubs and skeletons for an operation that
has these as their in's and out's respectively.
What we do now (*without unwrapping) is to generate exactly one class as
an argument:

fooReqest foo (fooResponse)

where they are beans with properties.
If we had unwrap turned on, what I'd expect to see as the signature of
the stub or the skeleton is:

int foo (float, Address)

The implementation of the stub must "wrap" these arguments into a single
OMElement and use ServiceClient underneath to send the message out. When
the response is received, it must "unwrap" the incoming element to pull
out the child of the <fooRequest> element and get the value of the child
element as an int and return that. The implementation of the message
receiver is the opposite.
To do this, all we have to do is to tell the data binding framework to
data bind all the elements one level below the top level GED
representing the "wrapped" message. Data binding *does not* have to
change. Each such child must be treated as a typed thing that must
become a certain name when serialized, not as an element itself. That's
the way to avoid XMLBeans like class proliferation.

Are you talking about the same idea or something different? If so where
do we differ in our understanding of the problem to be solved and/or the
approach?

Sanjiva.


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to