You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@camel.apache.org by Roman Kalukiewicz <ro...@gmail.com> on 2007/12/05 12:35:47 UTC

in/out/fault messages discussion

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.

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

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)

all those examples show that the notation becomes VERY unnatural if
you use out messages. 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?

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)

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

The mail is pretty long so if you reached this point - thank you! ;)
If I'm mistaken in some points - let me know. 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! ;)

Roman

Re: in/out/fault messages discussion

Posted by Guillaume Nodet <gn...@gmail.com>.
On Mon, Feb 4, 2008 at 4:02 PM, James Strachan <ja...@gmail.com> wrote:
> BTW thanks to everyone's thoughts on this thread; keep 'em coming. (I
>  guess it should have been on camel-dev but never mind :)...
>
>
>  On 01/02/2008, Hiram Chirino <hi...@hiramchirino.com> wrote:
>  > I personally would like to get rid of the Fault message.  It should be
>  > possible ti interpret the output message as a Fault or interpret  an
>  > Exception as Fault.  Having an exception, a fault, and an output
>  > message be all valid outputs of a processor makes creating a DSL to
>  > handle all those cases MUCH more complex.
>
>  Agreed. Maybe the OUT v Fault is kinda meaningless and is more a kinda
>  helper method on a message. Something like exchange.isFault() or
>  exchange.getOut().isFault() etc.

Fwiw, wsdl2 defines a MEP (In-Optional-Out) where at some point, the
exchange can
contains a In, a Out and a Fault message.  Imho, this is not something
we need to support.

>
>  Certainly from the DSL its kinda meaningless currently to be able to
>  set the IN versus the OUT messages etc (thats a bit of legacy DSL from
>  the early days of Camel when a route was kinda an interceptor - we
>  should remove that I think...).
>
>  I'm still digesting this thread; I'm not yet sure what I think so far
>  but I thought I'd throw some other random thoughts into the mix.
>
>
>  I hit an issue today with a transformation that I'd written as a
>  Processor that wanted to spit out multiple OUT messages.
>
>  Now you could argue, well the transformation should have some kinda
>  ProducerTemplate or whatever so it could send multiple messages out of
>  itself. Though one thing I kinda like about a Processor is it doesn't
>  need to care about where the output goes; it just makes an OUT message
>  and the route it is invoked from takes care of the routing.
>
>  So I've been wondering if an Exchange should have one IN and zero to
>  many OUT messages so that the contract of a Processor (or Transformer)
>  is to make 0..N OUT messages that the router its inside then routes to
>  some place. If a more complex Transformer wants to start sending
>  messages to specific destinations itself, thats cool too - but most
>  transformations or processors don't really care where the output goes
>  - thats up to the caller to decide.

I'm not sure about that.  if the exchange does not formalize the a set
of messages being somehow an "invocation", I'm not sure what the
purpose of the Exchange is.  See below.

>
>
>  In my mind the Exchange was generally the object that owns the context
>  in which a message is being processed and some output (if any) is
>  being generated. So a Processor in generally should be able to access
>  the input message which caused it to be invoked - get access to the
>  Endpoint its being invoked from even - plus the CamelContext its
>  living inside.
>
>  So I guess another thing we could consider is, should I be able to see
>  previous Exchange instances which caused this Exchange to be invoked?
>  e.g. in some pipeline spanning patterns and transports, could I look
>  back at the history of exchanges which caused me to be invoked?

I think this would be very usefull to analyze what happens.

>
>  BTW yet another detail is, we used generics in the definition of an
>  Exchange, Endpoint, Component, Producer, Consumer. In hindsight this
>  is a bit of a mistake I think; I'd like to see the generics removed
>  from that. As it means we have to internally copy exchanges whenever
>  we send them (as the Producer usually casts it to a T rather than an
>  Exchange).
>
>
>  So I think its definitely worth revisiting what is an Exchange and
>  what should its contract be... I'm starting to wonder if its just a
>  context for the exchange (so you can access the IN) and a place in
>  which to register one or more OUT messages?

We could also use a property pointing to a context (instead of an
exchange, the context containing some generic information, usually
static), plus a property to a related message (it could be the IN
message, or maybe simply the message that is the cause for this
message).
I think we could drop the notion of exchange, and go for context +
properties, which may simplify the api.

>
>  I still need to ponder Roman's various mails and patch though... Keep
>  the thoughts coming though! :)
>
>
>
>  --
>  James
>  -------
>  http://macstrac.blogspot.com/
>
>  Open Source Integration
>  http://open.iona.com
>



-- 
Cheers,
Guillaume Nodet
------------------------
Blog: http://gnodet.blogspot.com/

Re: in/out/fault messages discussion

Posted by Hadrian Zbarcea <hz...@gmail.com>.
Hi, Gary,

I don't think that's what James has in mind :).

Based on James' post I would also like to amend one of my previous  
posts in this thread :).  I was saying that I like it the way it is,  
with a differentiation made between in/out/exception.  I think we  
agree at this point, from Hiram's comment that a distinction between  
out and fault doesnt make much sense (it may in some for some  
components, but then they'd be responsible to attach a flag to the out  
to qualify its semantics).

So I believe James suggested somthing like a stack (or list) in which  
first in is the IN, and instead of creating new exchanges we would  
just push a new out on the stack.  A producer would just send the last  
message on the stack as an IN and if there's any out it pushes it on  
the stack.  That way we'll have the whole message history.  I am not  
sure how this scales for large messages, so we might want to make this  
optional.  Maybe keep all the messages and drop just the   large  
bodies, preserve the headers, that may contain useful metadata, such  
as timestamps for measuring SLAs, etc.  The IN at the bottom of the  
stack should stay, I guess.

How does that sound?
Hadrian


On Feb 13, 2008, at 10:33 AM, gtully wrote:

>
>> So I think its definitely worth revisiting what is an Exchange and
>> what should its contract be... I'm starting to wonder if its just a
>> context for the exchange (so you can access the IN) and a place in
>> which to register one or more OUT messages?
>>
> Would N out messages result in N exchanges for the next hop?
>
> For WS-Addressing, where the original 'in' message is important,  
> would it
> makes sense to stash the (important) in message in the exchange as a
> property. The pipeline will propagate exchange properties so the  
> important
> in message will be visible from the pipeline to those who care.
> This may alleviate the need to traverse the set of chained exchanges  
> to get
> a handle on the original in message.
>
> -- 
> View this message in context: http://www.nabble.com/in-out-fault-messages-discussion-tp14170013s22882p15459603.html
> Sent from the Camel - Users mailing list archive at Nabble.com.
>


Re: in/out/fault messages discussion

Posted by gtully <ga...@gmail.com>.
>So I think its definitely worth revisiting what is an Exchange and
>what should its contract be... I'm starting to wonder if its just a
>context for the exchange (so you can access the IN) and a place in
>which to register one or more OUT messages?
>
Would N out messages result in N exchanges for the next hop?

For WS-Addressing, where the original 'in' message is important, would it
makes sense to stash the (important) in message in the exchange as a
property. The pipeline will propagate exchange properties so the important
in message will be visible from the pipeline to those who care.
This may alleviate the need to traverse the set of chained exchanges to get
a handle on the original in message.

-- 
View this message in context: http://www.nabble.com/in-out-fault-messages-discussion-tp14170013s22882p15459603.html
Sent from the Camel - Users mailing list archive at Nabble.com.


Re: in/out/fault messages discussion

Posted by James Strachan <ja...@gmail.com>.
BTW thanks to everyone's thoughts on this thread; keep 'em coming. (I
guess it should have been on camel-dev but never mind :)...

On 01/02/2008, Hiram Chirino <hi...@hiramchirino.com> wrote:
> I personally would like to get rid of the Fault message.  It should be
> possible ti interpret the output message as a Fault or interpret  an
> Exception as Fault.  Having an exception, a fault, and an output
> message be all valid outputs of a processor makes creating a DSL to
> handle all those cases MUCH more complex.

Agreed. Maybe the OUT v Fault is kinda meaningless and is more a kinda
helper method on a message. Something like exchange.isFault() or
exchange.getOut().isFault() etc.

Certainly from the DSL its kinda meaningless currently to be able to
set the IN versus the OUT messages etc (thats a bit of legacy DSL from
the early days of Camel when a route was kinda an interceptor - we
should remove that I think...).

I'm still digesting this thread; I'm not yet sure what I think so far
but I thought I'd throw some other random thoughts into the mix.


I hit an issue today with a transformation that I'd written as a
Processor that wanted to spit out multiple OUT messages.

Now you could argue, well the transformation should have some kinda
ProducerTemplate or whatever so it could send multiple messages out of
itself. Though one thing I kinda like about a Processor is it doesn't
need to care about where the output goes; it just makes an OUT message
and the route it is invoked from takes care of the routing.

So I've been wondering if an Exchange should have one IN and zero to
many OUT messages so that the contract of a Processor (or Transformer)
is to make 0..N OUT messages that the router its inside then routes to
some place. If a more complex Transformer wants to start sending
messages to specific destinations itself, thats cool too - but most
transformations or processors don't really care where the output goes
- thats up to the caller to decide.


In my mind the Exchange was generally the object that owns the context
in which a message is being processed and some output (if any) is
being generated. So a Processor in generally should be able to access
the input message which caused it to be invoked - get access to the
Endpoint its being invoked from even - plus the CamelContext its
living inside.

So I guess another thing we could consider is, should I be able to see
previous Exchange instances which caused this Exchange to be invoked?
e.g. in some pipeline spanning patterns and transports, could I look
back at the history of exchanges which caused me to be invoked?

BTW yet another detail is, we used generics in the definition of an
Exchange, Endpoint, Component, Producer, Consumer. In hindsight this
is a bit of a mistake I think; I'd like to see the generics removed
from that. As it means we have to internally copy exchanges whenever
we send them (as the Producer usually casts it to a T rather than an
Exchange).


So I think its definitely worth revisiting what is an Exchange and
what should its contract be... I'm starting to wonder if its just a
context for the exchange (so you can access the IN) and a place in
which to register one or more OUT messages?

I still need to ponder Roman's various mails and patch though... Keep
the thoughts coming though! :)

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

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

Re: in/out/fault messages discussion

Posted by Hadrian Zbarcea <hz...@gmail.com>.
This totally makes sense, especially given the fact that many  
components don't make that distinction.

I created camel-316 https://issues.apache.org/activemq/browse/CAMEL-316

Cheers
hadrian

On Feb 1, 2008, at 1:15 PM, Hiram Chirino wrote:

> I personally would like to get rid of the Fault message.  It should be
> possible ti interpret the output message as a Fault or interpret  an
> Exception as Fault.  Having an exception, a fault, and an output
> message be all valid outputs of a processor makes creating a DSL to
> handle all those cases MUCH more complex.
>
> Just my 2 cents.
>
> Regards,
> Hiram
>
> On Jan 31, 2008 1:18 PM, Roman Kalukiewicz <roman.kalukiewicz@gmail.com 
> > wrote:
>> 2008/1/31, Hadrian Zbarcea <hz...@gmail.com>:
>>> Actually to Guillaume's point, I am strongly in favor of keeping the
>>> input.  And to be honest, I like the model the way it is, for many
>>> reasons.  One is that the model is very intuitive for people  
>>> familiar
>>> with certain standards, myself included, and the emtpy chairs don't
>>> bother me.  If I understand correctly you are not claiming that  
>>> there
>>> are features that the current model (vs yours) cannot support, just
>>> that your proposal will make it clearer.
>>
>> That is right. I believe that current model could be harder to
>> implement all different scenarios, that we don't have to think about
>> in mine, but everything could be done in the current one (with 3
>> messages available you can for sure implement everything that can be
>> done with 1, right? ;) ). I even believe that I was able to show,  
>> that
>> my solution also can handle all features we need.
>>
>>> Well, de gustibus non est disputandum.  If you really feel strongly
>>> about that, a vote is the way to settle it :).
>>
>> This is what I say from the very beginning. I was simply curious if  
>> my
>> impressions are common. But the fact is, that if I want camel to
>> change in this direction, I need creators of camel to be convinced to
>> this direction and I cannot do it alone (or I have to think about my
>> own one-message-branch ;) ). It looks that you are not really
>> convinced  ;)
>>
>> Anyway thank you for all your feedback
>> Roman
>>
>
>
>
> -- 
> Regards,
> Hiram
>
> Blog: http://hiramchirino.com
>
> Open Source SOA
> http://open.iona.com


Re: in/out/fault messages discussion

Posted by Hiram Chirino <hi...@hiramchirino.com>.
I personally would like to get rid of the Fault message.  It should be
possible ti interpret the output message as a Fault or interpret  an
Exception as Fault.  Having an exception, a fault, and an output
message be all valid outputs of a processor makes creating a DSL to
handle all those cases MUCH more complex.

Just my 2 cents.

Regards,
Hiram

On Jan 31, 2008 1:18 PM, Roman Kalukiewicz <ro...@gmail.com> wrote:
> 2008/1/31, Hadrian Zbarcea <hz...@gmail.com>:
> > Actually to Guillaume's point, I am strongly in favor of keeping the
> > input.  And to be honest, I like the model the way it is, for many
> > reasons.  One is that the model is very intuitive for people familiar
> > with certain standards, myself included, and the emtpy chairs don't
> > bother me.  If I understand correctly you are not claiming that there
> > are features that the current model (vs yours) cannot support, just
> > that your proposal will make it clearer.
>
> That is right. I believe that current model could be harder to
> implement all different scenarios, that we don't have to think about
> in mine, but everything could be done in the current one (with 3
> messages available you can for sure implement everything that can be
> done with 1, right? ;) ). I even believe that I was able to show, that
> my solution also can handle all features we need.
>
> > Well, de gustibus non est disputandum.  If you really feel strongly
> > about that, a vote is the way to settle it :).
>
> This is what I say from the very beginning. I was simply curious if my
> impressions are common. But the fact is, that if I want camel to
> change in this direction, I need creators of camel to be convinced to
> this direction and I cannot do it alone (or I have to think about my
> own one-message-branch ;) ). It looks that you are not really
> convinced  ;)
>
> Anyway thank you for all your feedback
> Roman
>



-- 
Regards,
Hiram

Blog: http://hiramchirino.com

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

Re: in/out/fault messages discussion

Posted by Roman Kalukiewicz <ro...@gmail.com>.
2008/1/31, Hadrian Zbarcea <hz...@gmail.com>:
> Actually to Guillaume's point, I am strongly in favor of keeping the
> input.  And to be honest, I like the model the way it is, for many
> reasons.  One is that the model is very intuitive for people familiar
> with certain standards, myself included, and the emtpy chairs don't
> bother me.  If I understand correctly you are not claiming that there
> are features that the current model (vs yours) cannot support, just
> that your proposal will make it clearer.

That is right. I believe that current model could be harder to
implement all different scenarios, that we don't have to think about
in mine, but everything could be done in the current one (with 3
messages available you can for sure implement everything that can be
done with 1, right? ;) ). I even believe that I was able to show, that
my solution also can handle all features we need.

> Well, de gustibus non est disputandum.  If you really feel strongly
> about that, a vote is the way to settle it :).

This is what I say from the very beginning. I was simply curious if my
impressions are common. But the fact is, that if I want camel to
change in this direction, I need creators of camel to be convinced to
this direction and I cannot do it alone (or I have to think about my
own one-message-branch ;) ). It looks that you are not really
convinced  ;)

Anyway thank you for all your feedback
Roman

Re: in/out/fault messages discussion

Posted by Hadrian Zbarcea <hz...@gmail.com>.
Actually to Guillaume's point, I am strongly in favor of keeping the  
input.  And to be honest, I like the model the way it is, for many  
reasons.  One is that the model is very intuitive for people familiar  
with certain standards, myself included, and the emtpy chairs don't  
bother me.  If I understand correctly you are not claiming that there  
are features that the current model (vs yours) cannot support, just  
that your proposal will make it clearer.

Well, de gustibus non est disputandum.  If you really feel strongly  
about that, a vote is the way to settle it :).

Cheers,
Hadrian


On Jan 31, 2008, at 5:48 AM, Roman Kalukiewicz wrote:

> 2008/1/31, Guillaume Nodet <gn...@gmail.com>:
>> How would you handle SOAP processing like WS-Addressing, WS-RM where
>> the creation of the ouput message needs some information about the
>> input message ?
>> We can't really rely on our users to set all those informations on  
>> the
>> output message ...
>
> To be clear - I don't know those standards, so don't beat me if I say
> something stupid ;)
>
> But to answer your question - I believe that good old institution of
> local variable in your processor/endpoint is enough. You can remember
> your current message in local variable and create a new one you will
> respond with.
>
> I imagine this model to be composed of:
> * something similar to Exchange (I'll stick with this name for now) -
> it contains one message, and a set of properties - those properties
> contain business specific data, that we want to be available through
> the flow like transaction ID
> * Message - that contains body in the way it is now, and headers that
> contain some metadata, that are used in endpoints as protocol specific
> data (headers in HTTP, properties in JMS, METHOD_NAME to invoke in
> bean, ...)
>
> When you process the 'Exchange' (in endpoint/processor) you are free
> to change the message itself (like operation on 'in' message) or
> simply put a new one as a response (like operation on 'out' message).
> If you need both during your processing - simply keep the old one as
> your variable.
>
> It is like requiring a java function to return its own parameters. If
> you need them, just keep them. You just send the message (parameters
> and function name) to the object, and receive a message (the response)
> that doesn't have original parameters by default (but you can return
> them like when you return your original 'in' message)
>
> So (I believe) you are able to do it if you need, but this is
> processor specific need, and don't have to be exposed to general API.
>
> Roman


Re: in/out/fault messages discussion

Posted by Roman Kalukiewicz <ro...@gmail.com>.
2008/1/31, Guillaume Nodet <gn...@gmail.com>:
> How would you handle SOAP processing like WS-Addressing, WS-RM where
> the creation of the ouput message needs some information about the
> input message ?
> We can't really rely on our users to set all those informations on the
> output message ...

To be clear - I don't know those standards, so don't beat me if I say
something stupid ;)

But to answer your question - I believe that good old institution of
local variable in your processor/endpoint is enough. You can remember
your current message in local variable and create a new one you will
respond with.

I imagine this model to be composed of:
* something similar to Exchange (I'll stick with this name for now) -
it contains one message, and a set of properties - those properties
contain business specific data, that we want to be available through
the flow like transaction ID
* Message - that contains body in the way it is now, and headers that
contain some metadata, that are used in endpoints as protocol specific
data (headers in HTTP, properties in JMS, METHOD_NAME to invoke in
bean, ...)

When you process the 'Exchange' (in endpoint/processor) you are free
to change the message itself (like operation on 'in' message) or
simply put a new one as a response (like operation on 'out' message).
If you need both during your processing - simply keep the old one as
your variable.

It is like requiring a java function to return its own parameters. If
you need them, just keep them. You just send the message (parameters
and function name) to the object, and receive a message (the response)
that doesn't have original parameters by default (but you can return
them like when you return your original 'in' message)

So (I believe) you are able to do it if you need, but this is
processor specific need, and don't have to be exposed to general API.

Roman

Re: in/out/fault messages discussion

Posted by Guillaume Nodet <gn...@gmail.com>.
How would you handle SOAP processing like WS-Addressing, WS-RM where
the creation of the ouput message needs some information about the
input message ?
We can't really rely on our users to set all those informations on the
output message ...

I do agree that most of the time only a single message will be used,
but there are cases
where you need both the request and the response / fault.

On Jan 31, 2008 11:05 AM, Roman Kalukiewicz <ro...@gmail.com> wrote:
> 2008/1/30, Hadrian Zbarcea <hz...@gmail.com>:
> > Hi Roman,
> >
> > But it already is like that, sort of.  If you like, imagine that your
> > message has a tag (out/fault) that tells us how that message got
> > there, that we also keep the previous message around (in).
>
> This is exactly what I'm trying to propose.
> The difference is like between one chair and possible labels on it, or
> three chairs labeled in constant way. When I have one chair, I know
> where to sit. When I have three, I don't. Moreover consequences of
> this choice are significant, and not always clear. (OK - I know that
> software is not a furniture ;) )
>
> Whole discussion here is maybe simply about some taste - I prefer my
> the model I shown, while you prefer current one. I can perfectly work
> (and works) with the current one, and Camel is a great framework
> anyway - no question about it.
>
> I simply believe that my model is simpler and easier to understand for
> our users AND it could be simpler to code (once again - maybe a matter
> of taste).
>
> What is definitely against my idea is the fact that we have already
> working different model, and someone could argue "don't fix it if it
> is not broken". That is true, and we have to think about backward
> compatibility and other important stuff. My propose looks like a
> revolution in the whole framework. I believe, that it is not a
> revolution, because even now almost no component uses faults, while
> in/out distinction is simply lost when you use pipeline. Moreover my
> patch shows, that it is not revolution. I was able to have 1 message
> in the exchange, and every test passes. It means, that we can
> deprecate some methods (like getOut() and getFault()) temporarily and
> we ARE backward compatible, and no more guessing if I should use in or
> out message.
>
> Just to clarify - I had to create quite complicated flow using camel
> that included jms, xslts, JBI, http, splitters, error handling and
> many other stuff. My proposal comes from many problems I had with
> those in/out/fault messages. Many times it was a matter of guess (or
> looking into the code) why something doesn't work when I set in or out
> (don't mention about faults that couldn't be handled in DSL at all),
> why my headers are lost, ...
>
> All those problems could be fixed somehow - true. I'm trying to say -
> don't build bridges over those rivers. Just take another route, that
> doesn't have rivers at all, if it leads to the same destination...
> maybe even faster ;)
>
> Roman
>



-- 
Cheers,
Guillaume Nodet
------------------------
Blog: http://gnodet.blogspot.com/

Re: in/out/fault messages discussion

Posted by Roman Kalukiewicz <ro...@gmail.com>.
2008/1/30, Hadrian Zbarcea <hz...@gmail.com>:
> Hi Roman,
>
> But it already is like that, sort of.  If you like, imagine that your
> message has a tag (out/fault) that tells us how that message got
> there, that we also keep the previous message around (in).

This is exactly what I'm trying to propose.
The difference is like between one chair and possible labels on it, or
three chairs labeled in constant way. When I have one chair, I know
where to sit. When I have three, I don't. Moreover consequences of
this choice are significant, and not always clear. (OK - I know that
software is not a furniture ;) )

Whole discussion here is maybe simply about some taste - I prefer my
the model I shown, while you prefer current one. I can perfectly work
(and works) with the current one, and Camel is a great framework
anyway - no question about it.

I simply believe that my model is simpler and easier to understand for
our users AND it could be simpler to code (once again - maybe a matter
of taste).

What is definitely against my idea is the fact that we have already
working different model, and someone could argue "don't fix it if it
is not broken". That is true, and we have to think about backward
compatibility and other important stuff. My propose looks like a
revolution in the whole framework. I believe, that it is not a
revolution, because even now almost no component uses faults, while
in/out distinction is simply lost when you use pipeline. Moreover my
patch shows, that it is not revolution. I was able to have 1 message
in the exchange, and every test passes. It means, that we can
deprecate some methods (like getOut() and getFault()) temporarily and
we ARE backward compatible, and no more guessing if I should use in or
out message.

Just to clarify - I had to create quite complicated flow using camel
that included jms, xslts, JBI, http, splitters, error handling and
many other stuff. My proposal comes from many problems I had with
those in/out/fault messages. Many times it was a matter of guess (or
looking into the code) why something doesn't work when I set in or out
(don't mention about faults that couldn't be handled in DSL at all),
why my headers are lost, ...

All those problems could be fixed somehow - true. I'm trying to say -
don't build bridges over those rivers. Just take another route, that
doesn't have rivers at all, if it leads to the same destination...
maybe even faster ;)

Roman

Re: in/out/fault messages discussion

Posted by Hadrian Zbarcea <hz...@gmail.com>.
Hi Roman,

But it already is like that, sort of.  If you like, imagine that your  
message has a tag (out/fault) that tells us how that message got  
there, that we also keep the previous message around (in).

Hadrian


On Jan 30, 2008, at 1:52 PM, Roman Kalukiewicz wrote:

>>> As I understand it the whole reason Exchange exists is to model the
>>> correlation between the in/out/fault messages, not their format.
>>> Maybe the abstraction is too leaky to hide, but I thought that's
>>> what Camel was trying to do.  If you remove the distinction from
>>> Camel's API, it then becomes the responsibility of the players
>>> involved in the to keep track of the correlation.  That, to me
>>> anyway, sounds like it makes life more difficult for users of Camel,
>>> or at the least, anyone implementing a Camel component.
>>>
>>> As Hadrian said, I think a number of your concerns can be address by
>>> revisiting Pipeline and a few of the core routing mechanisms.  The
>>> in/out/fault distinction may not be clear or consistent throughout
>>> Camel, and rmaking it so is not a simple task,
>> I don't think it's a major effort either.  For the most part Camel
>> *does* things right.
>
> Maybe I should state it clearly -- I really believe that Cames *does*
> things right, and it is not a huge effort to correct things that are
> not working right in current model.
> On the other hand the whole discussion starts with my feeling that in
> Camel we have some flow, and the message that flows through the flow.
> _One message that simply flows through some number of steps_. This is
> the simplest possible model of the flow in Camel.
>
> The basic question is if this simple model is strong enough to
> describe everything we need. I believe, that it is, and I was trying
> to prove it with the patch I shown.
>
>>> For example, as you point out, the in/out distinction is clunky to
>>> processors that only want to modify a message or pass it along.  The
>>> convention or shortcut that's come about for these cases is merely
>>> modifying/using the In message, and having Pipeline forward it
>>> along.  Perhaps some benefit could come from further utilizing
>>> ExchangePattern, or generating better default wrappers from the DSL.
>
> Current model (even if it requires some fixes) with in/out/fault works
> and maybe it is even easier for someone using SOAP or JBI, but (I
> think) Camel shouldn't try to model SOAP, JBI, Java or something else.
> It is about patterns, and messages. If I think about messages flowing
> through my flow, what is the difference between body(), outBody() and
> faultBody()? It is the body of the message, period.
>
> Maybe it is my problem that I see those flows, as flow of a message?
> My perception is like "read the message from here, then process it
> this and this and that way and send it somewhere else". I think about
> it as a one message. Maybe majority of people see it as a set of
> exchanges between different processors or in some other way?
>
> If this is my perception of those flows, then I would like to see it
> in DSL and in APIs, because Camel tries very hard to match my
> perception of the flow. This is the biggest strength of Camel.
>
> Just by the way I think, that it could solve some of our problems, but
> it is not the core of my concerns.
>
> BTW Thanks for all your $0.02 ;)
>
> Roman


Re: in/out/fault messages discussion

Posted by Roman Kalukiewicz <ro...@gmail.com>.
> > As I understand it the whole reason Exchange exists is to model the
> > correlation between the in/out/fault messages, not their format.
> > Maybe the abstraction is too leaky to hide, but I thought that's
> > what Camel was trying to do.  If you remove the distinction from
> > Camel's API, it then becomes the responsibility of the players
> > involved in the to keep track of the correlation.  That, to me
> > anyway, sounds like it makes life more difficult for users of Camel,
> > or at the least, anyone implementing a Camel component.
> >
> > As Hadrian said, I think a number of your concerns can be address by
> > revisiting Pipeline and a few of the core routing mechanisms.  The
> > in/out/fault distinction may not be clear or consistent throughout
> > Camel, and rmaking it so is not a simple task,
> I don't think it's a major effort either.  For the most part Camel
> *does* things right.

Maybe I should state it clearly -- I really believe that Cames *does*
things right, and it is not a huge effort to correct things that are
not working right in current model.
On the other hand the whole discussion starts with my feeling that in
Camel we have some flow, and the message that flows through the flow.
_One message that simply flows through some number of steps_. This is
the simplest possible model of the flow in Camel.

The basic question is if this simple model is strong enough to
describe everything we need. I believe, that it is, and I was trying
to prove it with the patch I shown.

> > For example, as you point out, the in/out distinction is clunky to
> > processors that only want to modify a message or pass it along.  The
> > convention or shortcut that's come about for these cases is merely
> > modifying/using the In message, and having Pipeline forward it
> > along.  Perhaps some benefit could come from further utilizing
> > ExchangePattern, or generating better default wrappers from the DSL.

Current model (even if it requires some fixes) with in/out/fault works
and maybe it is even easier for someone using SOAP or JBI, but (I
think) Camel shouldn't try to model SOAP, JBI, Java or something else.
It is about patterns, and messages. If I think about messages flowing
through my flow, what is the difference between body(), outBody() and
faultBody()? It is the body of the message, period.

Maybe it is my problem that I see those flows, as flow of a message?
My perception is like "read the message from here, then process it
this and this and that way and send it somewhere else". I think about
it as a one message. Maybe majority of people see it as a set of
exchanges between different processors or in some other way?

If this is my perception of those flows, then I would like to see it
in DSL and in APIs, because Camel tries very hard to match my
perception of the flow. This is the biggest strength of Camel.

Just by the way I think, that it could solve some of our problems, but
it is not the core of my concerns.

BTW Thanks for all your $0.02 ;)

Roman

Re: in/out/fault messages discussion

Posted by Hadrian Zbarcea <hz...@gmail.com>.
Aaron, thanks for your input!  Comments inline.

Cheers,
Hadrian

On Jan 30, 2008, at 10:55 AM, Aaron Crickenberger wrote:

> On Jan 30, 2008, at 5:21 AM, Roman Kalukiewicz wrote:
>
>> WSDL describes formats of in/out/fault messages, because they are
>> different (formats).
>
>>> Inputs are sort of read-only from the point of view of the next
>>> processor in the pipeline.
>>
>> That is not definitely true, as in majority of cases we agree to
>> modify in message, and propagate it. BTW it is very handy as if you
>> want your headers to be propagated you simply cannot fill out message
>> in DSL.
>
>> This way it is YOU who define when you want your flow to be
>> interrupted. I can imagine that we can treat like a fault the fact
>> that your mail endpoint received a mail with 'no such address'  
>> string.
>
>> By belief is that such approach is simpler and more universal than
>> what we currently have. It is also how I can imagine some fault
>> handling in camel (that simply doesn't exist so far).
>
> Allow me to comment as a bit of an outsider here, as I haven't been  
> too involved with the parts of Camel that actually use the out/fault  
> messages, nor the exception handling capabilities.
>
> As I understand it the whole reason Exchange exists is to model the  
> correlation between the in/out/fault messages, not their format.   
> Maybe the abstraction is too leaky to hide, but I thought that's  
> what Camel was trying to do.  If you remove the distinction from  
> Camel's API, it then becomes the responsibility of the players  
> involved in the to keep track of the correlation.  That, to me  
> anyway, sounds like it makes life more difficult for users of Camel,  
> or at the least, anyone implementing a Camel component.
>
> As Hadrian said, I think a number of your concerns can be address by  
> revisiting Pipeline and a few of the core routing mechanisms.  The  
> in/out/fault distinction may not be clear or consistent throughout  
> Camel, and rmaking it so is not a simple task,
I don't think it's a major effort either.  For the most part Camel  
*does* things right.

> but I think to get rid of it entirely is throwing out the baby with  
> the bathwater, so to speak.
:)

>
>
> For example, as you point out, the in/out distinction is clunky to  
> processors that only want to modify a message or pass it along.  The  
> convention or shortcut that's come about for these cases is merely  
> modifying/using the In message, and having Pipeline forward it  
> along.  Perhaps some benefit could come from further utilizing  
> ExchangePattern, or generating better default wrappers from the DSL.
>
> - aaron




Re: in/out/fault messages discussion

Posted by Aaron Crickenberger <aa...@intalgent.com>.
On Jan 30, 2008, at 5:21 AM, Roman Kalukiewicz wrote:

> WSDL describes formats of in/out/fault messages, because they are
> different (formats).

>> Inputs are sort of read-only from the point of view of the next
>> processor in the pipeline.
>
> That is not definitely true, as in majority of cases we agree to
> modify in message, and propagate it. BTW it is very handy as if you
> want your headers to be propagated you simply cannot fill out message
> in DSL.

> This way it is YOU who define when you want your flow to be
> interrupted. I can imagine that we can treat like a fault the fact
> that your mail endpoint received a mail with 'no such address' string.

> By belief is that such approach is simpler and more universal than
> what we currently have. It is also how I can imagine some fault
> handling in camel (that simply doesn't exist so far).

Allow me to comment as a bit of an outsider here, as I haven't been  
too involved with the parts of Camel that actually use the out/fault  
messages, nor the exception handling capabilities.

As I understand it the whole reason Exchange exists is to model the  
correlation between the in/out/fault messages, not their format.   
Maybe the abstraction is too leaky to hide, but I thought that's what  
Camel was trying to do.  If you remove the distinction from Camel's  
API, it then becomes the responsibility of the players involved in the  
to keep track of the correlation.  That, to me anyway, sounds like it  
makes life more difficult for users of Camel, or at the least, anyone  
implementing a Camel component.

As Hadrian said, I think a number of your concerns can be address by  
revisiting Pipeline and a few of the core routing mechanisms.  The in/ 
out/fault distinction may not be clear or consistent throughout Camel,  
and rmaking it so is not a simple task, but I think to get rid of it  
entirely is throwing out the baby with the bathwater, so to speak.

For example, as you point out, the in/out distinction is clunky to  
processors that only want to modify a message or pass it along.  The  
convention or shortcut that's come about for these cases is merely  
modifying/using the In message, and having Pipeline forward it along.   
Perhaps some benefit could come from further utilizing  
ExchangePattern, or generating better default wrappers from the DSL.

- aaron

Re: in/out/fault messages discussion

Posted by Roman Kalukiewicz <ro...@gmail.com>.
2008/1/30, Hadrian Zbarcea <hz...@gmail.com>:
> Hi Roman,
>
> Interesting points.  From what I gather there are two questions you
> raise:
> 1. Is the distinction between in/out/fault/exception necessary
> 2. Is the DSL clear or at least intuitive enough
>
> On the second point, I think there are a few places that require a bit
> of a revisit.

That is definitely true now and I believe further discussion here is
not really necessary ;)
What I'm trying to point out is, that lot of those problem disappear
if we remove this distinction between in/out/fault.

> On the first point, my personal take is that the distinction is
> important and should be there.  There are influences from the WSDL
> spec(s) and I think there is a reason for that.

This is exactly my impression - that we have this distinction because
it is present in specs like WSDL or JBI. Let me try to stick with WSDL
as I believe JBI suffers from the same issue that Camel does (I
think).
WSDL describes formats of in/out/fault messages, because they are
different (formats). In Camel, our payload is Object. Moreover when
you send lets say SOAP, you have 1 message at a time. This out/fault
distinction works like a flag (what I propose) that specifies which
format should be consulted. We cannot receive out AND fault AND have
an access to in message at the same time (we can store in message in a
variable, but it is not the protocol).

> Inputs are sort of read-only from the point of view of the next
> processor in the pipeline.

That is not definitely true, as in majority of cases we agree to
modify in message, and propagate it. BTW it is very handy as if you
want your headers to be propagated you simply cannot fill out message
in DSL.

> Outputs provide a response after
> successful processing.  Faults are responses that indicate to the
> client that the expected goal was not achieved, and they usually
> provide a reason.  Faults are messages that tell a client that the
> server did receive the request and successfully processed it, but not
> in the way intended and the client may need to take further action.
> Exceptions on the other hand indicate that the message was not
> processed successfully, and the client should not make any
> assumptions.  The way the semantics of the result (output/fault/
> exception) is sent back to the client is dependent on the component.

This is what WebServices world does. But what bothers me here is that
we don't have the server always. This distinction you describe is not
really clear and could be confusing.
Lets look at http component. When we receive status code == 500 it
should be fault according to your description. It is not - it is out
message and we have http.responseCode set (I already found it very
handy BTW).
In validation component when validation fails we should have fault -
validation performed and the outcome is that the payload was bad. Now
it is exception.

Another problem is that we don't have any way in camel to handle
faults. My proposal is to have some sensible way of marking faults
(via header maybe), and maybe some way of defining what is fault for
you. This way you can interrupt your flow.

I can imagine something like this:

//this could be the default fault/exception definition
faultIs(or(isInstanceOf(Exception.class), header("isFault").isNotNull()));

//construct similar to exception(), but handles all different faults
fault(isInstanceOf(Exception.class)).to("jms:exceptionOccured");
fault().xpath("/myBody/error").to("jms:someErrorOccured");

This way it is YOU who define when you want your flow to be
interrupted. I can imagine that we can treat like a fault the fact
that your mail endpoint received a mail with 'no such address' string.

This goes even further - to merge faults and exceptions together. But
what is wrong with sending an exception as a body? In RPC SOAP fault
IS java exception anyway.

By belief is that such approach is simpler and more universal than
what we currently have. It is also how I can imagine some fault
handling in camel (that simply doesn't exist so far).

Roman

Re: in/out/fault messages discussion

Posted by Hadrian Zbarcea <hz...@gmail.com>.
Hi Roman,

Interesting points.  From what I gather there are two questions you  
raise:
1. Is the distinction between in/out/fault/exception necessary
2. Is the DSL clear or at least intuitive enough

On the second point, I think there are a few places that require a bit  
of a revisit.

On the first point, my personal take is that the distinction is  
important and should be there.  There are influences from the WSDL  
spec(s) and I think there is a reason for that.

Inputs are sort of read-only from the point of view of the next  
processor in the pipeline.  Outputs provide a response after  
successful processing.  Faults are responses that indicate to the  
client that the expected goal was not achieved, and they usually  
provide a reason.  Faults are messages that tell a client that the  
server did receive the request and successfully processed it, but not  
in the way intended and the client may need to take further action.   
Exceptions on the other hand indicate that the message was not  
processed successfully, and the client should not make any  
assumptions.  The way the semantics of the result (output/fault/ 
exception) is sent back to the client is dependent on the component.

So my take would be to look at the dsl and see if/when the constructs  
fail to model properly the eip pattern they represent and address that.

My $0.02,
Hadrian


On Jan 29, 2008, at 5:45 PM, Roman Kalukiewicz wrote:

> Hello!
>
> I would like to resurrect the discussion that I started on this list
> over a month ago, and if you want to see the roots, you can go here (I
> don't want to repeat myself ;) ):
>
> http://www.nabble.com/in-out-fault-messages-discussion-to14170013s22882.html#a14170013
>
> Summarizing my point of view: I think, that distinction between
> in/out/fault messages is not needed and that it makes more problems,
> than it solves.
>
> To actually check it I have prepared very small PoC that simply
> removes this distinction without changing general interface we have.
> The patch is attached at the very end of this message if someone is
> interested.
>
> To make it work I had to change only two tests in camel-core (also in
> the patch) and everything passes. Moreover such patch automatically
> eliminates some problems that we faced with to early initialization of
> out messages (getOut() invocation) that caused to loose your body,
> some strange behaviours of some endpoints that depend on out message
> being set like
>
> from("jetty:http://localhost:1234/test").setBody("response"); <--  
> doesn't work
> from("jetty:http://localhost:1234/ 
> test").setBody("response").setBody("response");
> <-- works
>
> (in the second case pipeline creates out message, while the first one
> doesn't have a pipeline so there is no out message set)
>
> Basically it proves (I think) that this distinction (in/out/fault) is
> not needed at all, and it would simplify the solution if we get rid of
> it. Moreover our solution gets more powerful, as we can think of
> defining predicates that stop the pipeline, so it doesn't stop simply
> on fault (but by default we could stop on 'fault' header set).
>
> Of course there are components will require some changes if we go this
> way - The first one I can think about is servicemix JBI component that
> sets in, out, and fault messages at the very beginning of the flow.
> Moreover I found another problem with JMS message that simply ignores
> setBody() invocations when there is JMSMessage associated with the
> message. (JIRA issue should be created I think)
> There was another problem with one of jetty tests that was reading the
> request stream in the mock endpoint once, and was trying to read it
> another time when was creating the response (as now body was not
> changed).
> Anyway all those problems are pretty small and we can solve them
> quickly if we would like to.
>
> Once again - I know that the change I would like to propose is a huge
> modification of basic interfaces, and I have really no idea if it
> could be introduced.
>
> Roman
>
> Index: src/main/java/org/apache/camel/impl/DefaultExchange.java
> ===================================================================
> --- src/main/java/org/apache/camel/impl/DefaultExchange.java	(wersja  
> 616530)
> +++ src/main/java/org/apache/camel/impl/DefaultExchange.java	(kopia  
> robocza)
> @@ -16,6 +16,9 @@
>  */
> package org.apache.camel.impl;
>
> +import java.util.HashMap;
> +import java.util.Map;
> +
> import org.apache.camel.CamelContext;
> import org.apache.camel.Exchange;
> import org.apache.camel.ExchangePattern;
> @@ -24,9 +27,6 @@
> import org.apache.camel.spi.UnitOfWork;
> import org.apache.camel.util.UuidGenerator;
>
> -import java.util.HashMap;
> -import java.util.Map;
> -
> /**
>  * A default implementation of {@link Exchange}
>  *
> @@ -37,8 +37,8 @@
>     protected final CamelContext context;
>     private Map<String, Object> properties;
>     private Message in;
> -    private Message out;
> -    private Message fault;
> +//    private Message out;
> +//    private Message fault;
>     private Throwable exception;
>     private String exchangeId =
> DefaultExchange.DEFAULT_ID_GENERATOR.generateId();
>     private UnitOfWork unitOfWork;
> @@ -174,15 +174,15 @@
>     }
>
>     public Message getOut(boolean lazyCreate) {
> -        if (out == null && lazyCreate) {
> -            out = createOutMessage();
> -            configureMessage(out);
> -        }
> -        return out;
> +    	if (lazyCreate) {
> +    		in.removeHeader("fault");
> +    		return in;
> +    	}
> +        return (in != null && in.getHeader("fault") == null) ? in :  
> null;
>     }
>
>     public void setOut(Message out) {
> -        this.out = out;
> +        this.in = out;
>         configureMessage(out);
>     }
>
> @@ -220,15 +220,16 @@
>     }
>
>     public Message getFault(boolean lazyCreate) {
> -        if (fault == null && lazyCreate) {
> -            fault = createFaultMessage();
> -            configureMessage(fault);
> +        if (lazyCreate) {
> +            in.setHeader("fault", true);
> +            return in;
>         }
> -        return fault;
> +        return ((in == null) || in.getHeader("fault") == null) ?  
> null : in;
>     }
>
>     public void setFault(Message fault) {
> -        this.fault = fault;
> +        this.in = fault;
> +        in.setHeader("fault", true);
>         configureMessage(fault);
>     }
> Index: src/test/java/org/apache/camel/processor/SplitterTest.java
> ===================================================================
> --- src/test/java/org/apache/camel/processor/SplitterTest.java	 
> (wersja 616530)
> +++ src/test/java/org/apache/camel/processor/SplitterTest.java	 
> (kopia robocza)
> @@ -80,7 +80,7 @@
>             }
>         });
>
> -        assertNull(result.getOut(false));
> +        assertNull(result.getOut().getBody());
>     }
>
>     protected RouteBuilder createRouteBuilder() {
> Index: src/test/java/org/apache/camel/processor/PipelineTest.java
> ===================================================================
> --- src/test/java/org/apache/camel/processor/PipelineTest.java	 
> (wersja 616530)
> +++ src/test/java/org/apache/camel/processor/PipelineTest.java	 
> (kopia robocza)
> @@ -107,7 +107,9 @@
>
>         // Check the out Message.. It should have only been  
> processed once.
>         // since the fault should stop it from going to the next  
> process.
> -        assertEquals(1, exchange.getOut().getHeader("copy-counter"));
> +//        We have here out AND fault message at the same time - what
> is the meaning
> +//        of such response??
> +//        assertEquals(1,
> exchange.getOut().getHeader("copy-counter"));
>     }
>
>     public void testOnlyProperties() {


Re: in/out/fault messages discussion

Posted by Roman Kalukiewicz <ro...@gmail.com>.
Hello!

I would like to resurrect the discussion that I started on this list
over a month ago, and if you want to see the roots, you can go here (I
don't want to repeat myself ;) ):

http://www.nabble.com/in-out-fault-messages-discussion-to14170013s22882.html#a14170013

Summarizing my point of view: I think, that distinction between
in/out/fault messages is not needed and that it makes more problems,
than it solves.

To actually check it I have prepared very small PoC that simply
removes this distinction without changing general interface we have.
The patch is attached at the very end of this message if someone is
interested.

To make it work I had to change only two tests in camel-core (also in
the patch) and everything passes. Moreover such patch automatically
eliminates some problems that we faced with to early initialization of
out messages (getOut() invocation) that caused to loose your body,
some strange behaviours of some endpoints that depend on out message
being set like

from("jetty:http://localhost:1234/test").setBody("response"); <-- doesn't work
from("jetty:http://localhost:1234/test").setBody("response").setBody("response");
<-- works

(in the second case pipeline creates out message, while the first one
doesn't have a pipeline so there is no out message set)

Basically it proves (I think) that this distinction (in/out/fault) is
not needed at all, and it would simplify the solution if we get rid of
it. Moreover our solution gets more powerful, as we can think of
defining predicates that stop the pipeline, so it doesn't stop simply
on fault (but by default we could stop on 'fault' header set).

Of course there are components will require some changes if we go this
way - The first one I can think about is servicemix JBI component that
sets in, out, and fault messages at the very beginning of the flow.
Moreover I found another problem with JMS message that simply ignores
setBody() invocations when there is JMSMessage associated with the
message. (JIRA issue should be created I think)
There was another problem with one of jetty tests that was reading the
request stream in the mock endpoint once, and was trying to read it
another time when was creating the response (as now body was not
changed).
Anyway all those problems are pretty small and we can solve them
quickly if we would like to.

Once again - I know that the change I would like to propose is a huge
modification of basic interfaces, and I have really no idea if it
could be introduced.

Roman

Index: src/main/java/org/apache/camel/impl/DefaultExchange.java
===================================================================
--- src/main/java/org/apache/camel/impl/DefaultExchange.java	(wersja 616530)
+++ src/main/java/org/apache/camel/impl/DefaultExchange.java	(kopia robocza)
@@ -16,6 +16,9 @@
  */
 package org.apache.camel.impl;

+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
@@ -24,9 +27,6 @@
 import org.apache.camel.spi.UnitOfWork;
 import org.apache.camel.util.UuidGenerator;

-import java.util.HashMap;
-import java.util.Map;
-
 /**
  * A default implementation of {@link Exchange}
  *
@@ -37,8 +37,8 @@
     protected final CamelContext context;
     private Map<String, Object> properties;
     private Message in;
-    private Message out;
-    private Message fault;
+//    private Message out;
+//    private Message fault;
     private Throwable exception;
     private String exchangeId =
DefaultExchange.DEFAULT_ID_GENERATOR.generateId();
     private UnitOfWork unitOfWork;
@@ -174,15 +174,15 @@
     }

     public Message getOut(boolean lazyCreate) {
-        if (out == null && lazyCreate) {
-            out = createOutMessage();
-            configureMessage(out);
-        }
-        return out;
+    	if (lazyCreate) {
+    		in.removeHeader("fault");
+    		return in;
+    	}
+        return (in != null && in.getHeader("fault") == null) ? in : null;
     }

     public void setOut(Message out) {
-        this.out = out;
+        this.in = out;
         configureMessage(out);
     }

@@ -220,15 +220,16 @@
     }

     public Message getFault(boolean lazyCreate) {
-        if (fault == null && lazyCreate) {
-            fault = createFaultMessage();
-            configureMessage(fault);
+        if (lazyCreate) {
+            in.setHeader("fault", true);
+            return in;
         }
-        return fault;
+        return ((in == null) || in.getHeader("fault") == null) ? null : in;
     }

     public void setFault(Message fault) {
-        this.fault = fault;
+        this.in = fault;
+        in.setHeader("fault", true);
         configureMessage(fault);
     }
Index: src/test/java/org/apache/camel/processor/SplitterTest.java
===================================================================
--- src/test/java/org/apache/camel/processor/SplitterTest.java	(wersja 616530)
+++ src/test/java/org/apache/camel/processor/SplitterTest.java	(kopia robocza)
@@ -80,7 +80,7 @@
             }
         });

-        assertNull(result.getOut(false));
+        assertNull(result.getOut().getBody());
     }

     protected RouteBuilder createRouteBuilder() {
Index: src/test/java/org/apache/camel/processor/PipelineTest.java
===================================================================
--- src/test/java/org/apache/camel/processor/PipelineTest.java	(wersja 616530)
+++ src/test/java/org/apache/camel/processor/PipelineTest.java	(kopia robocza)
@@ -107,7 +107,9 @@

         // Check the out Message.. It should have only been processed once.
         // since the fault should stop it from going to the next process.
-        assertEquals(1, exchange.getOut().getHeader("copy-counter"));
+//        We have here out AND fault message at the same time - what
is the meaning
+//        of such response??
+//        assertEquals(1,
exchange.getOut().getHeader("copy-counter"));
     }

     public void testOnlyProperties() {

Re: in/out/fault messages discussion

Posted by Roman Kalukiewicz <ro...@gmail.com>.
basically my idea was something like this:

from("direct:something")
.to("jbi:service:http://some.host/service/name")
.choice()
.when(header("isFault").isNotNull())
.to("xslt:faultTransformation.xsl")
.otherwise()
.to("xslt:successTransformation.xsl")
.end()
.to("mock:result");

In my situation I have to consult some property because I have to know
exact HTTP response code (HTTP endpoint is exposed via JBI), but I
believe there could be some header that marks faults (like this
"isFault").

Then if you want to have current behavior we could have plugable
predicate (at pipeline level) that is evaluated at every step and
breaks pipeline if true. By default it could even check this 'isFault'
header so we are backward compatible.

Anyway my example is currently impossible as pipeline is broken at the
jbi invocation and there is no way (I believe) to transform the
response.

Roman

2007/12/18, Guillaume Nodet <gn...@gmail.com>:
> Could you give more details on what you'd like to be able to do with the
> DSL, or how you would write it if there was no difference between an Out
> message and a Fault ?
>
> On Dec 18, 2007 2:23 PM, Roman Kalukiewicz <ro...@gmail.com>
> wrote:
>
> > <cut/>
> >
> > > 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.
> >
> > I've just faced the problem described above and I'm looking for some
> > solution. So far I failed..
> >
> > I have jbi endpoint that is HTTP and this endpoint returns soap fault
> > message I have to transform using XSLT and then merge back with other
> > responses I could receive. I'm looking for a way to handle this fault
> > response, but the only thing that (I believe) should work is writing
> > my own bean that will send the message and handle fault itself - I
> > cannot find any way to handle it using DSL.
> >
> > BTW this is another point in my in/out/fault discussion as if there
> > are no fault messages that behave in a different way the problem
> > wouldn't exist.
> >
> > Do we have any construct we could use to handle it or is it a thing
> > that just should be created?
> >
> > Thanks,
> > Roman
> >
>
>
>
> --
> Cheers,
> Guillaume Nodet
> ------------------------
> Blog: http://gnodet.blogspot.com/
>

Re: in/out/fault messages discussion

Posted by Guillaume Nodet <gn...@gmail.com>.
Could you give more details on what you'd like to be able to do with the
DSL, or how you would write it if there was no difference between an Out
message and a Fault ?

On Dec 18, 2007 2:23 PM, Roman Kalukiewicz <ro...@gmail.com>
wrote:

> <cut/>
>
> > 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.
>
> I've just faced the problem described above and I'm looking for some
> solution. So far I failed..
>
> I have jbi endpoint that is HTTP and this endpoint returns soap fault
> message I have to transform using XSLT and then merge back with other
> responses I could receive. I'm looking for a way to handle this fault
> response, but the only thing that (I believe) should work is writing
> my own bean that will send the message and handle fault itself - I
> cannot find any way to handle it using DSL.
>
> BTW this is another point in my in/out/fault discussion as if there
> are no fault messages that behave in a different way the problem
> wouldn't exist.
>
> Do we have any construct we could use to handle it or is it a thing
> that just should be created?
>
> Thanks,
> Roman
>



-- 
Cheers,
Guillaume Nodet
------------------------
Blog: http://gnodet.blogspot.com/

Re: in/out/fault messages discussion

Posted by Roman Kalukiewicz <ro...@gmail.com>.
<cut/>

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

I've just faced the problem described above and I'm looking for some
solution. So far I failed..

I have jbi endpoint that is HTTP and this endpoint returns soap fault
message I have to transform using XSLT and then merge back with other
responses I could receive. I'm looking for a way to handle this fault
response, but the only thing that (I believe) should work is writing
my own bean that will send the message and handle fault itself - I
cannot find any way to handle it using DSL.

BTW this is another point in my in/out/fault discussion as if there
are no fault messages that behave in a different way the problem
wouldn't exist.

Do we have any construct we could use to handle it or is it a thing
that just should be created?

Thanks,
Roman

Re: in/out/fault messages discussion

Posted by Roman Kalukiewicz <ro...@gmail.com>.
2007/12/6, James Strachan <ja...@gmail.com>:
> Hi Roman!
>
> On 05/12/2007, Roman Kalukiewicz <ro...@gmail.com> 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

Re: in/out/fault messages discussion

Posted by James Strachan <ja...@gmail.com>.
Hi Roman!

On 05/12/2007, Roman Kalukiewicz <ro...@gmail.com> 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