Hi Roman!

On 05/12/2007, Roman Kalukiewicz <[EMAIL PROTECTED]> wrote:
> Hello!
>
> 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. On the other hand
> by belief is that this separation of in/out/fault messages makes more
> problems that it solves. Another question is if it solves anything -
> if I cannot see it then let me know.

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?


> 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?)


> If there
> is exception then we already know what happens - it is handled by
> exception() clause or is catched by catch() clause - anyway exceptions
> are thrown and behavior of the flow reflects it. But what with
> faults??
>
> My examples are based on DSL notation as I don't use XML at all.
>
> what this code does?
>
> from("jms:inQueue").setBody(constant("abc")).setHeader("bar",
> constant("foo")).to("jms:outQueue");
>
> it takes the message from inQueue, sets body to abc, sets bar header
> to foo and sends jms message with bar property set and 'abc' body -
> moreover it propagates every property of the original message to
> outgoing message.
>
> what this code does?
>
> from("jms:inQueue").setOutBody(constant("abc")).setOutHeader("bar",
> constant("foo")).to("jms:outQueue");
>
> basically it sends EMPTY JMS message with "bar" property set. It
> doesn't have any body as it is dropped by underlying pipeline when
> setOutHeader() sets a header on out message while in message contains
> "abc" (it is in message as it was copied by pipeline from previous
> out)
>
> if we change the order of setOutHeader() and setOutBody() we will have
> "abc" text message without any headers.

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.

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.

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


> how to remove all headers from your message now? it is easy:
> setOutBody(body()) - we don't have removeAllHeaders() processor (but
> it is easy to add anyway - it is not a problem)

Yeah.


> all those examples show that the notation becomes VERY unnatural if
> you use out messages.

Yeah - I'm thinking we might wana remove the difference and just have
setBody() / setHeader() maybe?


> 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.


> 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.


> The mail is pretty long so if you reached this point - thank you! ;)

:)


> If I'm mistaken in some points - let me know.

You've definitely identified some areas of confusion - and definitely
found some smelly areas of the code which we have to fix ASAP. Coming
up with a single, simple model of messaging that works for all use
cases is a bit hard - and am sure through more discussions we can
improve things more and more.

(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).


> If you like
> in/out/faults or know the reason we need them/they help us - let me
> know.
>
> I don't really know if those ideas could be implemented in camel - I
> know that it touches the very core architecture of the framework. I
> just wanted to share my thoughts.
>
> Thanks for great framework anyway! ;)

Thanks for your awesome feedback (and all those other patches too!:)

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

-- 
James
-------
http://macstrac.blogspot.com/

Open Source Integration
http://open.iona.com

Reply via email to