2009/7/10 Hadrian Zbarcea <[email protected]>:
> 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 <[email protected]>:
>>>
>>> On Fri, Jul 10, 2009 at 1:20 PM, James Strachan<[email protected]>
>>> wrote:
>>>>
>>>> 2009/7/10 Claus Ibsen <[email protected]>:
>>>>>
>>>>> 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/