You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@camel.apache.org by Hadrian Zbarcea <hz...@gmail.com> on 2009/07/13 17:44:10 UTC

Re: [DISCUSS][IMPORTANT] Semantics of IN and OUT (was: Faults and Exceptions in Camel)

Hi,

Are you in fact proposing to rename get/setOut() to get/setMessage()?   
And hasOut() to be renamed as messageChanged(), kinda?  This is pretty  
much how it sounds to me.

I like the semantic cleanup.  Not sure about passing the message  
instead of the exchange.  That would have a significant impact on  
projects using camel and I don't think the benefit would justify it.

I would love for others to pitch in and express their thoughts.
Hadrian



On Jul 12, 2009, at 5:23 AM, Claus Ibsen wrote:

> Hi
>
> Starting the kettle to brew me a grok of hot coffee, as its sunday
> morning and I guess I got the energy to toss in my 2$ in the bucket of
> ideas
> Now that we are into the open talks and that it seems we can open the
> box with the IN, OUT, FAULT again.
>
> I advocate for only one message on the implementation side. On the API
> side we could still have some notion of IN / OUT to keep the API
> migration / impact simpler. But at the end having one message API
> makes it simpler. There could be a boolean to test whether an output
> has been set or not. Just as if we have a test for fault.
>
>
> Proposed Exchange API
> ==================
>
>  Message getMessage()
>  void setMessage(Message msg);
>
>  boolean messageChanged();
>   -- false = message have newer been mutated, eg its still the same  
> input
>   -- true = the message or message body have been mutated in some way
> (setMessage or setBody called)
>   -- need to find a good name for this method, eg testing whether the
> message have been changed/updated or not
>
> That leaves us with a simple API.
>
> Then we do not need to worry about all the message management
> internally in Camel, where we need to figure out whether to set data
> on IN or OUT and what else we kinda do, and it gets a bit complex over
> time how to do this correctly.
>
>
> MEP: InOnly
> =========
> Now we can do as Hadrian want. Newer return something in OUT. And
> leave the original input on the Exchange.
> Here we need to use James CopyOnWrite technique so we can preserve the
> original message in case its mutated during routing.
>
>
> MEP: InOut
> =========
> If an OUT message have been set (eg there is a reply), can be
> determined if the messageChanged() == true. (then its not the original
> message anymore). And yes the current code does this. It will just
> copy whatever there is in IN and use it as OUT if no OUT was set.
> With this proposal this will be improved as its easier to determine if
> there is an OUT message or not.
>
>
> Original message
> =============
> Currently there is an API to get the original message from the
> UnitOfWork as its needed when doing redeliveries and a message was
> doomed
> and had to be moved to the dead letter channel. Then it makes much
> more sense to move the original message than the current mutated
> message.
> ( i wonder if it should be default behavior )
>
>
> AggregationStrategy
> ===============
> Another benefit with a single getMessage() is that end users using
> AggregationStrategy will not be confused how to use it.
> Should I look in IN or OUT. And the current code can actually be a
> "lucky draw" as whether the data is in IN or OUT depending on facts
> such as how the route path is.
> We can even change it to pass in Message object instead of bare bone
> Exchange. You can always go from Message to exchange using
> getExchange().
>
>
> All the processors / components / data formats
> ===================================
> Logic will be easier as well as they do not need to cater for IN / OUT
> and where and how to set a result. Just work on the Message.
>
>
> Use @deprecated for steady migration
> ============================
> Hadrian suggested that for the API migration to a single getMessage
> you could let the getIn/setIn getOut/setOut delegate to
> getMessage/setMessage.
> And then mark them as @deprecated and then gradually change the camel
> code as we goes. So I do not think the hold up / change would take a
> lot of time and energy to get done.
>
>
> Final words
> ========
> So if it was possible to simplify the API and reduce the IN OUT FAULT
> to a simpler API, even go as far as I would like with a single
> Message.
> Then that would be really great and worth a hold up for a imminent  
> 2.0 release.
>
>
> Other frameworks
> =============
> I guess it wasn't final words after all :) Just wanted to say that
> Mule, Spring Integration also just have a single message for the
> message.
> And yes I think their projects are also successful so it is not a loss
> that they do not have IN OUT. In fact I think their API is easier to
> work with than Camel.
>
> We are fortunate that most people with Camel do not work directly with
> Exchange but work more with Camel returning the message as an expected
> body type using its type converters. That helps a lot.
>
> But we have stories form Camel 1.x where people get confused whey
> Camel return their original input in some situations where it was not
> expected in the OUT message. Or the fact producer template sendBody is
> not void in 1.x. Then people think it can be used for InOut.
>
> Okay end of mail.
>
>
> On Fri, Jul 10, 2009 at 5:16 PM, James Strachan<james.strachan@gmail.com 
> > wrote:
>> 2009/7/10 Hadrian Zbarcea <hz...@gmail.com>:
>>> Moved this slightly different topic to a separate thread.
>>>
>>> ++1 from me.
>>>
>>> Do we need a vote on this one or it's a consensus?  Claus, it  
>>> looks like you
>>> agree, but pointed out that there is some work involved, correct?
>>>
>>> Hadrian
>>>
>>>
>>>
>>> On Jul 10, 2009, at 8:40 AM, James Strachan wrote:
>>>
>>>> 2009/7/10 Claus Ibsen <cl...@gmail.com>:
>>>>>
>>>>> On Fri, Jul 10, 2009 at 1:20 PM, James Strachan<james.strachan@gmail.com 
>>>>> >
>>>>> wrote:
>>>>>>
>>>>>> 2009/7/10 Claus Ibsen <cl...@gmail.com>:
>>>>>>>
>>>>>>> Hi
>>>>>>>
>>>>>>> Another update on the IN vs OUT when you send in an Exchange.
>>>>>>>
>>>>>>> The ProducerCache that is doing the actual sending when using  
>>>>>>> template
>>>>>>> or sendTo etc, its basically doing all send X to endpoint.
>>>>>>>
>>>>>>> Well I am playing with to let it adhere to the principle Hadrian
>>>>>>> pointed out. He wanted the IN to be more static.
>>>>>>> And we cannot get there yet when you do routing as all the  
>>>>>>> processors
>>>>>>> rely on IN being able to mutate during routing.
>>>>>>>
>>>>>>> Anyway my grief is that when you send in an Exchange the  
>>>>>>> result would
>>>>>>> sometimes be stored on IN and not OUT.
>>>>>>> What I want it to do always is to store the result in OUT and  
>>>>>>> keep IN
>>>>>>> as the original input.
>>>>>>>
>>>>>>> The code to do this is now a bit more complex than just before
>>>>>>>
>>>>>>>               // copy the original input
>>>>>>>               Message original = exchange.getIn().copy();
>>>>>>>
>>>>>>>               producer.process(exchange);
>>>>>>>
>>>>>>>               // if no OUT then set current IN as result  
>>>>>>> (except for
>>>>>>> optional out)
>>>>>>>               if (!exchange.hasOut() && exchange.getPattern() !=
>>>>>>> ExchangePattern.InOptionalOut) {
>>>>>>>                   // but only if its not the same as original  
>>>>>>> IN to
>>>>>>> avoid duplicating it
>>>>>>>                   // and to adhere to the fact that there was  
>>>>>>> no OUT
>>>>>>> result at all
>>>>>>>                   if (original.getBody() != null &&
>>>>>>> !original.getBody().equals(exchange.getIn().getBody())) {
>>>>>>>                       exchange.setOut(exchange.getIn());
>>>>>>>                   }
>>>>>>>               }
>>>>>>>               // and restore original in
>>>>>>>               exchange.setIn(original);
>>>>>>>
>>>>>>>               return exchange;
>>>>>>>
>>>>>>>
>>>>>>> What I need to do is to copy the original IN message as it can  
>>>>>>> be
>>>>>>> mutated during routing.
>>>>>>
>>>>>> How about we prevent mutation of the IN message? Create a Message
>>>>>> facade which throws UnsupportedOperationException if you try to  
>>>>>> mutate
>>>>>> it in any way. Then we can pass the same read-only Message  
>>>>>> around as
>>>>>> the IN within retry loops or from step to step if no new output  
>>>>>> is
>>>>>> created (e.g. in a content based router where you just move a  
>>>>>> Message
>>>>>> to the right endpoint without changing it)
>>>>>>
>>>>>
>>>>> A good idea but will break a lot of logic in Camel.
>>>>
>>>> Agreed. But with the benefit that we'd be able to get rid of all  
>>>> the
>>>> defensive copies in our code; plus we'd be able to pass the same
>>>> Message from step to step. The API would be a bit more clean; to
>>>> change the output, you create an OUT message (maybe by copying the
>>>> IN).
>>>>
>>>>
>>>>> Most of the Camel
>>>>> processors work on the IN message and set the result on either  
>>>>> IN or
>>>>> OUT. At best they set it on OUT. But then the IN is always the
>>>>> original input? Or am I mistaking?
>>>>
>>>> Yeah, we'd have to patch code to no longer mutate IN
>>>>
>>>>
>>>>> How will this work with the Pipes And Filters EIP if the IN is
>>>>> immutable and always the original input?
>>>>
>>>> If no OUT, then no output was created, so pass the IN along...
>>>>
>>>>
>>>> OK how about this; a CopyOnWriteMessageFacade which does not mutate
>>>> the original message at all ever; if a message is used in a purely
>>>> read only way, it does nothing but delegate to the original  
>>>> message -
>>>> but then as soon as someone mutates it, it creates a copy and uses
>>>> that from that point on?
>>>>
>>>> i.e. make the copy of the message lazy - and only make a copy  
>>>> when a
>>>> Processor really does try to mutate the Message?
>>>>
>>>> Then we'd get the best of both worlds; avoid breaking old code but
>>>> avoid tons of unnecessary copies?
>>
>> BTW then using the current API you could have a Message and then call
>>
>> Message origin = ...;
>> Message newMsg = origin.copy().copy().copy().copy();
>>
>> and the message would not actually be copied at all; new would just  
>> be
>> a CopyOnWriteMessageFacade which would hold a reference to 'origin'  
>> as
>> the readOnlyMessage (which it never mutates).
>>
>> The copy would only take place if you did
>>
>> newMsg.setBody("foo")
>>
>> --
>> James
>> -------
>> http://macstrac.blogspot.com/
>>
>> Open Source Integration
>> http://fusesource.com/
>>
>
>
>
> -- 
> Claus Ibsen
> Apache Camel Committer
>
> Open Source Integration: http://fusesource.com
> Blog: http://davsclaus.blogspot.com/
> Twitter: http://twitter.com/davsclaus


Re: [DISCUSS][IMPORTANT] Semantics of IN and OUT (was: Faults and Exceptions in Camel)

Posted by Claus Ibsen <cl...@gmail.com>.
On Mon, Jul 13, 2009 at 5:44 PM, Hadrian Zbarcea<hz...@gmail.com> wrote:
> Hi,
>
> Are you in fact proposing to rename get/setOut() to get/setMessage()?  And
> hasOut() to be renamed as messageChanged(), kinda?  This is pretty much how
> it sounds to me.
>

Yes,

However I would rename getIn/setIn instead as a lot of Camel
processors etc rely on getIn() instead of getOut when they get access
to the payload/message.



> I like the semantic cleanup.  Not sure about passing the message instead of
> the exchange.  That would have a significant impact on projects using camel
> and I don't think the benefit would justify it.
>
> I would love for others to pitch in and express their thoughts.
> Hadrian
>
>
>
> On Jul 12, 2009, at 5:23 AM, Claus Ibsen wrote:
>
>> Hi
>>
>> Starting the kettle to brew me a grok of hot coffee, as its sunday
>> morning and I guess I got the energy to toss in my 2$ in the bucket of
>> ideas
>> Now that we are into the open talks and that it seems we can open the
>> box with the IN, OUT, FAULT again.
>>
>> I advocate for only one message on the implementation side. On the API
>> side we could still have some notion of IN / OUT to keep the API
>> migration / impact simpler. But at the end having one message API
>> makes it simpler. There could be a boolean to test whether an output
>> has been set or not. Just as if we have a test for fault.
>>
>>
>> Proposed Exchange API
>> ==================
>>
>>  Message getMessage()
>>  void setMessage(Message msg);
>>
>>  boolean messageChanged();
>>  -- false = message have newer been mutated, eg its still the same input
>>  -- true = the message or message body have been mutated in some way
>> (setMessage or setBody called)
>>  -- need to find a good name for this method, eg testing whether the
>> message have been changed/updated or not
>>
>> That leaves us with a simple API.
>>
>> Then we do not need to worry about all the message management
>> internally in Camel, where we need to figure out whether to set data
>> on IN or OUT and what else we kinda do, and it gets a bit complex over
>> time how to do this correctly.
>>
>>
>> MEP: InOnly
>> =========
>> Now we can do as Hadrian want. Newer return something in OUT. And
>> leave the original input on the Exchange.
>> Here we need to use James CopyOnWrite technique so we can preserve the
>> original message in case its mutated during routing.
>>
>>
>> MEP: InOut
>> =========
>> If an OUT message have been set (eg there is a reply), can be
>> determined if the messageChanged() == true. (then its not the original
>> message anymore). And yes the current code does this. It will just
>> copy whatever there is in IN and use it as OUT if no OUT was set.
>> With this proposal this will be improved as its easier to determine if
>> there is an OUT message or not.
>>
>>
>> Original message
>> =============
>> Currently there is an API to get the original message from the
>> UnitOfWork as its needed when doing redeliveries and a message was
>> doomed
>> and had to be moved to the dead letter channel. Then it makes much
>> more sense to move the original message than the current mutated
>> message.
>> ( i wonder if it should be default behavior )
>>
>>
>> AggregationStrategy
>> ===============
>> Another benefit with a single getMessage() is that end users using
>> AggregationStrategy will not be confused how to use it.
>> Should I look in IN or OUT. And the current code can actually be a
>> "lucky draw" as whether the data is in IN or OUT depending on facts
>> such as how the route path is.
>> We can even change it to pass in Message object instead of bare bone
>> Exchange. You can always go from Message to exchange using
>> getExchange().
>>
>>
>> All the processors / components / data formats
>> ===================================
>> Logic will be easier as well as they do not need to cater for IN / OUT
>> and where and how to set a result. Just work on the Message.
>>
>>
>> Use @deprecated for steady migration
>> ============================
>> Hadrian suggested that for the API migration to a single getMessage
>> you could let the getIn/setIn getOut/setOut delegate to
>> getMessage/setMessage.
>> And then mark them as @deprecated and then gradually change the camel
>> code as we goes. So I do not think the hold up / change would take a
>> lot of time and energy to get done.
>>
>>
>> Final words
>> ========
>> So if it was possible to simplify the API and reduce the IN OUT FAULT
>> to a simpler API, even go as far as I would like with a single
>> Message.
>> Then that would be really great and worth a hold up for a imminent 2.0
>> release.
>>
>>
>> Other frameworks
>> =============
>> I guess it wasn't final words after all :) Just wanted to say that
>> Mule, Spring Integration also just have a single message for the
>> message.
>> And yes I think their projects are also successful so it is not a loss
>> that they do not have IN OUT. In fact I think their API is easier to
>> work with than Camel.
>>
>> We are fortunate that most people with Camel do not work directly with
>> Exchange but work more with Camel returning the message as an expected
>> body type using its type converters. That helps a lot.
>>
>> But we have stories form Camel 1.x where people get confused whey
>> Camel return their original input in some situations where it was not
>> expected in the OUT message. Or the fact producer template sendBody is
>> not void in 1.x. Then people think it can be used for InOut.
>>
>> Okay end of mail.
>>
>>
>> On Fri, Jul 10, 2009 at 5:16 PM, James Strachan<ja...@gmail.com>
>> wrote:
>>>
>>> 2009/7/10 Hadrian Zbarcea <hz...@gmail.com>:
>>>>
>>>> Moved this slightly different topic to a separate thread.
>>>>
>>>> ++1 from me.
>>>>
>>>> Do we need a vote on this one or it's a consensus?  Claus, it looks like
>>>> you
>>>> agree, but pointed out that there is some work involved, correct?
>>>>
>>>> Hadrian
>>>>
>>>>
>>>>
>>>> On Jul 10, 2009, at 8:40 AM, James Strachan wrote:
>>>>
>>>>> 2009/7/10 Claus Ibsen <cl...@gmail.com>:
>>>>>>
>>>>>> On Fri, Jul 10, 2009 at 1:20 PM, James
>>>>>> Strachan<ja...@gmail.com>
>>>>>> wrote:
>>>>>>>
>>>>>>> 2009/7/10 Claus Ibsen <cl...@gmail.com>:
>>>>>>>>
>>>>>>>> Hi
>>>>>>>>
>>>>>>>> Another update on the IN vs OUT when you send in an Exchange.
>>>>>>>>
>>>>>>>> The ProducerCache that is doing the actual sending when using
>>>>>>>> template
>>>>>>>> or sendTo etc, its basically doing all send X to endpoint.
>>>>>>>>
>>>>>>>> Well I am playing with to let it adhere to the principle Hadrian
>>>>>>>> pointed out. He wanted the IN to be more static.
>>>>>>>> And we cannot get there yet when you do routing as all the
>>>>>>>> processors
>>>>>>>> rely on IN being able to mutate during routing.
>>>>>>>>
>>>>>>>> Anyway my grief is that when you send in an Exchange the result
>>>>>>>> would
>>>>>>>> sometimes be stored on IN and not OUT.
>>>>>>>> What I want it to do always is to store the result in OUT and keep
>>>>>>>> IN
>>>>>>>> as the original input.
>>>>>>>>
>>>>>>>> The code to do this is now a bit more complex than just before
>>>>>>>>
>>>>>>>>              // copy the original input
>>>>>>>>              Message original = exchange.getIn().copy();
>>>>>>>>
>>>>>>>>              producer.process(exchange);
>>>>>>>>
>>>>>>>>              // if no OUT then set current IN as result (except for
>>>>>>>> optional out)
>>>>>>>>              if (!exchange.hasOut() && exchange.getPattern() !=
>>>>>>>> ExchangePattern.InOptionalOut) {
>>>>>>>>                  // but only if its not the same as original IN to
>>>>>>>> avoid duplicating it
>>>>>>>>                  // and to adhere to the fact that there was no OUT
>>>>>>>> result at all
>>>>>>>>                  if (original.getBody() != null &&
>>>>>>>> !original.getBody().equals(exchange.getIn().getBody())) {
>>>>>>>>                      exchange.setOut(exchange.getIn());
>>>>>>>>                  }
>>>>>>>>              }
>>>>>>>>              // and restore original in
>>>>>>>>              exchange.setIn(original);
>>>>>>>>
>>>>>>>>              return exchange;
>>>>>>>>
>>>>>>>>
>>>>>>>> What I need to do is to copy the original IN message as it can be
>>>>>>>> mutated during routing.
>>>>>>>
>>>>>>> How about we prevent mutation of the IN message? Create a Message
>>>>>>> facade which throws UnsupportedOperationException if you try to
>>>>>>> mutate
>>>>>>> it in any way. Then we can pass the same read-only Message around as
>>>>>>> the IN within retry loops or from step to step if no new output is
>>>>>>> created (e.g. in a content based router where you just move a Message
>>>>>>> to the right endpoint without changing it)
>>>>>>>
>>>>>>
>>>>>> A good idea but will break a lot of logic in Camel.
>>>>>
>>>>> Agreed. But with the benefit that we'd be able to get rid of all the
>>>>> defensive copies in our code; plus we'd be able to pass the same
>>>>> Message from step to step. The API would be a bit more clean; to
>>>>> change the output, you create an OUT message (maybe by copying the
>>>>> IN).
>>>>>
>>>>>
>>>>>> Most of the Camel
>>>>>> processors work on the IN message and set the result on either IN or
>>>>>> OUT. At best they set it on OUT. But then the IN is always the
>>>>>> original input? Or am I mistaking?
>>>>>
>>>>> Yeah, we'd have to patch code to no longer mutate IN
>>>>>
>>>>>
>>>>>> How will this work with the Pipes And Filters EIP if the IN is
>>>>>> immutable and always the original input?
>>>>>
>>>>> If no OUT, then no output was created, so pass the IN along...
>>>>>
>>>>>
>>>>> OK how about this; a CopyOnWriteMessageFacade which does not mutate
>>>>> the original message at all ever; if a message is used in a purely
>>>>> read only way, it does nothing but delegate to the original message -
>>>>> but then as soon as someone mutates it, it creates a copy and uses
>>>>> that from that point on?
>>>>>
>>>>> i.e. make the copy of the message lazy - and only make a copy when a
>>>>> Processor really does try to mutate the Message?
>>>>>
>>>>> Then we'd get the best of both worlds; avoid breaking old code but
>>>>> avoid tons of unnecessary copies?
>>>
>>> BTW then using the current API you could have a Message and then call
>>>
>>> Message origin = ...;
>>> Message newMsg = origin.copy().copy().copy().copy();
>>>
>>> and the message would not actually be copied at all; new would just be
>>> a CopyOnWriteMessageFacade which would hold a reference to 'origin' as
>>> the readOnlyMessage (which it never mutates).
>>>
>>> The copy would only take place if you did
>>>
>>> newMsg.setBody("foo")
>>>
>>> --
>>> James
>>> -------
>>> http://macstrac.blogspot.com/
>>>
>>> Open Source Integration
>>> http://fusesource.com/
>>>
>>
>>
>>
>> --
>> Claus Ibsen
>> Apache Camel Committer
>>
>> Open Source Integration: http://fusesource.com
>> Blog: http://davsclaus.blogspot.com/
>> Twitter: http://twitter.com/davsclaus
>
>



-- 
Claus Ibsen
Apache Camel Committer

Open Source Integration: http://fusesource.com
Blog: http://davsclaus.blogspot.com/
Twitter: http://twitter.com/davsclaus

Re: [DISCUSS][IMPORTANT] Semantics of IN and OUT (was: Faults and Exceptions in Camel)

Posted by Claus Ibsen <cl...@gmail.com>.
On Mon, Jul 13, 2009 at 5:44 PM, Hadrian Zbarcea<hz...@gmail.com> wrote:
> Hi,
>
> Are you in fact proposing to rename get/setOut() to get/setMessage()?  And
> hasOut() to be renamed as messageChanged(), kinda?  This is pretty much how
> it sounds to me.
>
> I like the semantic cleanup.  Not sure about passing the message instead of
> the exchange.  That would have a significant impact on projects using camel
> and I don't think the benefit would justify it.
Its hardly a significant impact. Removing the generics is a bigger
impact that changing a single interface

And what they used to do in the AggregationStrategy (with much
confusion, may I stress out - see the user mailinglist)

public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
  // hmmm is my payload in IN or OUT today?
 String oldBody = oldExchange.getIn().getBody(String.class);
String newBody = newExchange.getIn().getBody(String.class);
 ... do more stuff
 ... jesus should I store the aggregated body on IN or OUT
 .. if I store it in the wrong one I lose all my headers ... . help
Camel riders!!!
... for instance as:
   oldExchange.getOut().setBody(aggregatedBody);
   return oldExchange;
}

And this simpler API

public Message aggregate(Message oldMessage, Exchange newMessage) {
  // yeah I have the message directly no more IN or OUT confusion
 String oldBody = oldMessage.getBody(String.class);
String newBody = newMessage.getBody(String.class);
 ... do more stuff
... great no more lost headers
}


The API migration is super simple. Before they had to go from exchange
-> IN or OUT (???) -> Message
Now they have it directly.


>
> I would love for others to pitch in and express their thoughts.
> Hadrian
>
>
>
> On Jul 12, 2009, at 5:23 AM, Claus Ibsen wrote:
>
>> Hi
>>
>> Starting the kettle to brew me a grok of hot coffee, as its sunday
>> morning and I guess I got the energy to toss in my 2$ in the bucket of
>> ideas
>> Now that we are into the open talks and that it seems we can open the
>> box with the IN, OUT, FAULT again.
>>
>> I advocate for only one message on the implementation side. On the API
>> side we could still have some notion of IN / OUT to keep the API
>> migration / impact simpler. But at the end having one message API
>> makes it simpler. There could be a boolean to test whether an output
>> has been set or not. Just as if we have a test for fault.
>>
>>
>> Proposed Exchange API
>> ==================
>>
>>  Message getMessage()
>>  void setMessage(Message msg);
>>
>>  boolean messageChanged();
>>  -- false = message have newer been mutated, eg its still the same input
>>  -- true = the message or message body have been mutated in some way
>> (setMessage or setBody called)
>>  -- need to find a good name for this method, eg testing whether the
>> message have been changed/updated or not
>>
>> That leaves us with a simple API.
>>
>> Then we do not need to worry about all the message management
>> internally in Camel, where we need to figure out whether to set data
>> on IN or OUT and what else we kinda do, and it gets a bit complex over
>> time how to do this correctly.
>>
>>
>> MEP: InOnly
>> =========
>> Now we can do as Hadrian want. Newer return something in OUT. And
>> leave the original input on the Exchange.
>> Here we need to use James CopyOnWrite technique so we can preserve the
>> original message in case its mutated during routing.
>>
>>
>> MEP: InOut
>> =========
>> If an OUT message have been set (eg there is a reply), can be
>> determined if the messageChanged() == true. (then its not the original
>> message anymore). And yes the current code does this. It will just
>> copy whatever there is in IN and use it as OUT if no OUT was set.
>> With this proposal this will be improved as its easier to determine if
>> there is an OUT message or not.
>>
>>
>> Original message
>> =============
>> Currently there is an API to get the original message from the
>> UnitOfWork as its needed when doing redeliveries and a message was
>> doomed
>> and had to be moved to the dead letter channel. Then it makes much
>> more sense to move the original message than the current mutated
>> message.
>> ( i wonder if it should be default behavior )
>>
>>
>> AggregationStrategy
>> ===============
>> Another benefit with a single getMessage() is that end users using
>> AggregationStrategy will not be confused how to use it.
>> Should I look in IN or OUT. And the current code can actually be a
>> "lucky draw" as whether the data is in IN or OUT depending on facts
>> such as how the route path is.
>> We can even change it to pass in Message object instead of bare bone
>> Exchange. You can always go from Message to exchange using
>> getExchange().
>>
>>
>> All the processors / components / data formats
>> ===================================
>> Logic will be easier as well as they do not need to cater for IN / OUT
>> and where and how to set a result. Just work on the Message.
>>
>>
>> Use @deprecated for steady migration
>> ============================
>> Hadrian suggested that for the API migration to a single getMessage
>> you could let the getIn/setIn getOut/setOut delegate to
>> getMessage/setMessage.
>> And then mark them as @deprecated and then gradually change the camel
>> code as we goes. So I do not think the hold up / change would take a
>> lot of time and energy to get done.
>>
>>
>> Final words
>> ========
>> So if it was possible to simplify the API and reduce the IN OUT FAULT
>> to a simpler API, even go as far as I would like with a single
>> Message.
>> Then that would be really great and worth a hold up for a imminent 2.0
>> release.
>>
>>
>> Other frameworks
>> =============
>> I guess it wasn't final words after all :) Just wanted to say that
>> Mule, Spring Integration also just have a single message for the
>> message.
>> And yes I think their projects are also successful so it is not a loss
>> that they do not have IN OUT. In fact I think their API is easier to
>> work with than Camel.
>>
>> We are fortunate that most people with Camel do not work directly with
>> Exchange but work more with Camel returning the message as an expected
>> body type using its type converters. That helps a lot.
>>
>> But we have stories form Camel 1.x where people get confused whey
>> Camel return their original input in some situations where it was not
>> expected in the OUT message. Or the fact producer template sendBody is
>> not void in 1.x. Then people think it can be used for InOut.
>>
>> Okay end of mail.
>>
>>
>> On Fri, Jul 10, 2009 at 5:16 PM, James Strachan<ja...@gmail.com>
>> wrote:
>>>
>>> 2009/7/10 Hadrian Zbarcea <hz...@gmail.com>:
>>>>
>>>> Moved this slightly different topic to a separate thread.
>>>>
>>>> ++1 from me.
>>>>
>>>> Do we need a vote on this one or it's a consensus?  Claus, it looks like
>>>> you
>>>> agree, but pointed out that there is some work involved, correct?
>>>>
>>>> Hadrian
>>>>
>>>>
>>>>
>>>> On Jul 10, 2009, at 8:40 AM, James Strachan wrote:
>>>>
>>>>> 2009/7/10 Claus Ibsen <cl...@gmail.com>:
>>>>>>
>>>>>> On Fri, Jul 10, 2009 at 1:20 PM, James
>>>>>> Strachan<ja...@gmail.com>
>>>>>> wrote:
>>>>>>>
>>>>>>> 2009/7/10 Claus Ibsen <cl...@gmail.com>:
>>>>>>>>
>>>>>>>> Hi
>>>>>>>>
>>>>>>>> Another update on the IN vs OUT when you send in an Exchange.
>>>>>>>>
>>>>>>>> The ProducerCache that is doing the actual sending when using
>>>>>>>> template
>>>>>>>> or sendTo etc, its basically doing all send X to endpoint.
>>>>>>>>
>>>>>>>> Well I am playing with to let it adhere to the principle Hadrian
>>>>>>>> pointed out. He wanted the IN to be more static.
>>>>>>>> And we cannot get there yet when you do routing as all the
>>>>>>>> processors
>>>>>>>> rely on IN being able to mutate during routing.
>>>>>>>>
>>>>>>>> Anyway my grief is that when you send in an Exchange the result
>>>>>>>> would
>>>>>>>> sometimes be stored on IN and not OUT.
>>>>>>>> What I want it to do always is to store the result in OUT and keep
>>>>>>>> IN
>>>>>>>> as the original input.
>>>>>>>>
>>>>>>>> The code to do this is now a bit more complex than just before
>>>>>>>>
>>>>>>>>              // copy the original input
>>>>>>>>              Message original = exchange.getIn().copy();
>>>>>>>>
>>>>>>>>              producer.process(exchange);
>>>>>>>>
>>>>>>>>              // if no OUT then set current IN as result (except for
>>>>>>>> optional out)
>>>>>>>>              if (!exchange.hasOut() && exchange.getPattern() !=
>>>>>>>> ExchangePattern.InOptionalOut) {
>>>>>>>>                  // but only if its not the same as original IN to
>>>>>>>> avoid duplicating it
>>>>>>>>                  // and to adhere to the fact that there was no OUT
>>>>>>>> result at all
>>>>>>>>                  if (original.getBody() != null &&
>>>>>>>> !original.getBody().equals(exchange.getIn().getBody())) {
>>>>>>>>                      exchange.setOut(exchange.getIn());
>>>>>>>>                  }
>>>>>>>>              }
>>>>>>>>              // and restore original in
>>>>>>>>              exchange.setIn(original);
>>>>>>>>
>>>>>>>>              return exchange;
>>>>>>>>
>>>>>>>>
>>>>>>>> What I need to do is to copy the original IN message as it can be
>>>>>>>> mutated during routing.
>>>>>>>
>>>>>>> How about we prevent mutation of the IN message? Create a Message
>>>>>>> facade which throws UnsupportedOperationException if you try to
>>>>>>> mutate
>>>>>>> it in any way. Then we can pass the same read-only Message around as
>>>>>>> the IN within retry loops or from step to step if no new output is
>>>>>>> created (e.g. in a content based router where you just move a Message
>>>>>>> to the right endpoint without changing it)
>>>>>>>
>>>>>>
>>>>>> A good idea but will break a lot of logic in Camel.
>>>>>
>>>>> Agreed. But with the benefit that we'd be able to get rid of all the
>>>>> defensive copies in our code; plus we'd be able to pass the same
>>>>> Message from step to step. The API would be a bit more clean; to
>>>>> change the output, you create an OUT message (maybe by copying the
>>>>> IN).
>>>>>
>>>>>
>>>>>> Most of the Camel
>>>>>> processors work on the IN message and set the result on either IN or
>>>>>> OUT. At best they set it on OUT. But then the IN is always the
>>>>>> original input? Or am I mistaking?
>>>>>
>>>>> Yeah, we'd have to patch code to no longer mutate IN
>>>>>
>>>>>
>>>>>> How will this work with the Pipes And Filters EIP if the IN is
>>>>>> immutable and always the original input?
>>>>>
>>>>> If no OUT, then no output was created, so pass the IN along...
>>>>>
>>>>>
>>>>> OK how about this; a CopyOnWriteMessageFacade which does not mutate
>>>>> the original message at all ever; if a message is used in a purely
>>>>> read only way, it does nothing but delegate to the original message -
>>>>> but then as soon as someone mutates it, it creates a copy and uses
>>>>> that from that point on?
>>>>>
>>>>> i.e. make the copy of the message lazy - and only make a copy when a
>>>>> Processor really does try to mutate the Message?
>>>>>
>>>>> Then we'd get the best of both worlds; avoid breaking old code but
>>>>> avoid tons of unnecessary copies?
>>>
>>> BTW then using the current API you could have a Message and then call
>>>
>>> Message origin = ...;
>>> Message newMsg = origin.copy().copy().copy().copy();
>>>
>>> and the message would not actually be copied at all; new would just be
>>> a CopyOnWriteMessageFacade which would hold a reference to 'origin' as
>>> the readOnlyMessage (which it never mutates).
>>>
>>> The copy would only take place if you did
>>>
>>> newMsg.setBody("foo")
>>>
>>> --
>>> James
>>> -------
>>> http://macstrac.blogspot.com/
>>>
>>> Open Source Integration
>>> http://fusesource.com/
>>>
>>
>>
>>
>> --
>> Claus Ibsen
>> Apache Camel Committer
>>
>> Open Source Integration: http://fusesource.com
>> Blog: http://davsclaus.blogspot.com/
>> Twitter: http://twitter.com/davsclaus
>
>



-- 
Claus Ibsen
Apache Camel Committer

Open Source Integration: http://fusesource.com
Blog: http://davsclaus.blogspot.com/
Twitter: http://twitter.com/davsclaus