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]