2009/7/10 Hadrian Zbarcea <hzbar...@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 <claus.ib...@gmail.com>:
>>>
>>> On Fri, Jul 10, 2009 at 1:20 PM, James Strachan<james.strac...@gmail.com>
>>> wrote:
>>>>
>>>> 2009/7/10 Claus Ibsen <claus.ib...@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/

Reply via email to