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/