2007/12/6, James Strachan <[EMAIL PROTECTED]>:
> Hi Roman!
>
> On 05/12/2007, Roman Kalukiewicz <[EMAIL PROTECTED]> wrote:
> > I have few fundamental questions about in/out/fault messages inside Camel.
> > My impression is that they were introduced because of the model that
> > exist in JBI where this distinction is in JBI spec.
>
> JBI, WSDL and WS stacks like CXF / JAX-WS support the idea of IN, OUT,
> FAULT messages. So its mostly there to support patterns like InOut
> rather than just InOnly.
>
> If you want you can just ignore the InOnly world and focus on one-way
> messaging I guess?

There is no question about the fact that those technologies support
support this distinction, but on the other hand look at WSDL, CXF,
whatever - all those technologies could be implemented using JMS. In
JMS you send one message and you receive one message. The fact that it
is in/out/fault is just a matter of interpretation or difference in
the payload. It is needed then to specify correct behavior like
returning the value from the method or throwing the business
exception.

Anyway you send a message (execute method, open http connection) and
receive the response (have return value or business exception is
thrown, receive http body). In camel world this FAULT could be just a
flag, because we agree that it is not real exception.

> > Everything is based on behavior of pipeline element that:
> > * if there is some step of pipeline that returns out message, then it
> > takes it and copies it into in message of the next exchange
> > * if there is no out message then it copies this in message into in
> > message of next exchange.
> >
> > It is natural behavior. But what happens with fault messages? I could
> > check it in the code easily but what is the natural behavior?
>
> Faults and exceptions should be returned to the caller. If thats not
> working properly its a bug. (The code did get kinda complex when
> moving from the Processor based API to the async stuff - one day we
> should maybe rewrite the Pipeline and more of the internals using the
> async APIs maybe?)

At the moment we have easy way of handling exceptions and we have a
lot of constructs to express it. In case of faults there is no easy
way to express this.

We cannot implement fault handling using some choice() because flow is
interrupted at any fault and we don't reach this choice(). We cannot
use tryBlock() as it is not an exception. We cannot interrupt() as in
majority of (my) cases it is a flow that uses pipeline so it is
interrupted.

if fault would be just a message with a header we don't have any problem.

But this is important point you touched. If faults should be 'thrown'
like exceptions then maybe it is a good reason to distinguish them
(like results and exceptions are separated in java). On the other hand
if they are thrown then maybe they should be wrapped by exceptions -
this is standard behavior of faults in the SOAP world. Or we should
throw fault exception while the (OUT) body is set to the fault
message.

> This whole set*Body() / set*Header() stuff really needs cleaning up;
> as things have grown we've got some inconsistencies as you've found.
>
> In many ways we should probably merge the setBody / setOutBody and
> setHeader / setOutHeader now that we've added support for InOnly and
> InOut.
>
> The default behaviour also should be for processors like setBody /
> setHeader to automatically copy the IN message to the OUT message
> before it starts mutating - so that in those cases you describe things
> don't disappear.

If you say it you agree that we don't need this distinction in fact...
at least it has not to be exposed to the flow.

> The DSL could also get clever enough to merge together multiple
> setBody()/convertBody()/setHeader*() type operations together into a
> single Processor too which would further simplify things.

You're right - but basically it is not really connected with in/out/fault

> i.e. its kinda crappy code for the implementations of those methods.
> They should be easy to fix.
>
> Basically for all the processors which set or convert a body or change
> headers, we should employ the logic that if OUT == null then set the
> OUT to be a copy of the IN.
>
> Something like this
>
> Message out = exchange.getOut(false);
> if (out == null) {
>    out = exchange.getOut();
>    out.copyFrom(exchange.getIn());
> }
> ...
> which we could wrap up as a little helper method

Once again - if you always copy the message or modify it (and in fact
in pipeline you will lost the original one) you can have one message
that gets modified or remains the same. The result for the flow cannot
be distinguished.

> > What when some processor sets faults? How to
> > handle this scenario in your flows? Faults are business faults and
> > they should flow through the flow - they are not exceptions.
> >
> > if someone will argue that in and out messages are important, because
> > we want to have an access to in message while we create out message
> > then the answer is simple. The only place you could use it is in your
> > processor (because in message is lost at pipeline). Then the answer is
> > local variable that could hold the original value.
> > If you want to distinguish fault messages somehow - do it with headers
> > like 'http.responseCode' header - BTW if response code is not 200
> > should the response be in out or fault message?
>
> Thats an interesting point :). Off the top of my head I'm thinking for
> raw HTTP we just use OUT; then only use FAULT for WSDL/WS/SOAP stuff?
>
>
> > I'm wondering why Camel doesn't have this structure:
> > * exchange with properties that are used for application specific data
> > - those things should be propagated via all endpoints as it happens
> > now
> > * only one message where body represents the payload we actually use -
> > this is used as in message as it reaches an endpoint/processor and is
> > used as out message when it leaves the endpoint
> > * message contains headers that are protocol specific - are used to
> > store JMS properties, HTTP headers, whatever else. they are sometimes
> > propagated through a processor (like setBody() or setHeader()) or
> > replaced in other cases (like jms endpoint invocation when headers are
> > replaced with properties on incoming JMS message)
>
> Think HTTP; you have servletRequest and servletResponse (i.e. an IN
> and OUT). Ditto in JAX-WS, JBI and JMS (when doing InOut).
>
> So we need to support an IN message (the request) and an OUT message
> (the response we're creating). Though you could argue that FAULT can
> be ignored for raw HTTP when not doing WS/WSDL/SOAP stuff.

Right - try this HTTP. In HTTP we have separated request and response,
because they have different responsibilities - they are different
classes. Servlets doesn't try to chain invocations and doesn't try to
unify the message (via headers that could be used as in or out). You
cannot turn a response into a request while it is camel's everyday
job.
In camel in/out/fault messages are the same classes - moreover IN
message is lost anyway in pipeline while OUT/FAULT are mutually
exclusive.

> > This way we don't have any problem with strange behavior of pipelines,
> > we don't care about exchange.getOut() (when you accidentally
> > lazy-create out message that gets propagated), and we don't have
> > faults that are not really used in many points (I haven't seen them so
> > far).
>
> WSDL, JAX-WS and JBI support are the main use cases for FAULT so far -
> but we should definitely review how useful FAULT is.

returning back to HTTP - in camel I have "http.responseCode" header
that works great for me. But in ServiceMix world whenever you have
response code == 500 you have a fault message. In camel it is
extremely easy to handle such response code - in ServiceMix it flows
back and you don't really have a way to catch it somewhere and handle
it properly.

> (e.g. maybe IN should generally always be immutable, and folks should
> generally only use OUT and ignore FAULT unless doing SOAP?) - then the
> DSL should just have one concept of mutation (which always occurs on
> the OUT which is a copy of the IN).

in this case why do you need this IN/OUT distinction? The only reason
IN exists is you could be locally interested in some incoming value
while you create OUT message. My answer is local variable...

> > If you like
> > in/out/faults or know the reason we need them/they help us - let me
> > know.
> >
> > Thanks for great framework anyway! ;)
>
> Thanks for your awesome feedback (and all those other patches too!:)

You're welcome ;)

> Did my response help at all? Or does it still seem way too confusing? :)

I'm not convinced really, but we discuss, right? ;)

Roman

Reply via email to