Hi all,

Long time listener, first time caller...

Currently I have a similar issue on a project I am working on. Taking some 
hints from this discussion I am wondering if it is possible, and makes sense, 
to extend a Camel Context to provide the IN, OUT and ERROR Endpoints. 

Then you could nest this context inside a top level context and use nested 
context ID as it's namespace reference. 

{bean definition}
blackboxContext
     in
     out
     error

routerContext
     from:seda
     to:blackboxContext

     from:blackboxContext
     to:mock

This isolates the namespaces and would allow abstraction of the desired 
capabilities. 

Thoughts?


Thanks,
Scott

On Oct 27, 2010, at 4:28 AM, James Strachan <[email protected]> wrote:

> Great discussion Kristof! More inline...
> 
> On 26 October 2010 22:12, kristofsajdak <[email protected]> wrote:
>> jstrachan wrote:
>>> 
>>> Or to say that a slightly different way; if you just want a
>>> parameterised RouteBuilder, well thats just a bean; no need for
>>> anything new, Camel can do that nicely today
>>> 
>> 
>> I considered using a parameterized RouteBuilder, however it failed to
>> address some specific
>> needs.
>> 
>> When using a solution based on parameterized RouteBuilders it requires you
>> to reference all
>> RouteBuilder used in the CamelContext.
>> 
>> This becomes complex when nesting route abstractions within route
>> abstractions several levels
>> deep. When using a top level RouteBuilder like
>> generateAndSignPdfRouteBuilder you are required
>> to also declare the signPdfRouteBuilder reference which exposes the
>> direct:signPdf endpoint.
>> 
>> E.g.
>> 
>>  <camelContext ...
>>    <routeBuilder ref="generateAndSignPdfRouteBuilder"/>
>>    <routeBuilder ref="signPdfRouteBuilder"/>
>>    ....
>> 
>> public class GenerateAndSignPdfRouteBuilder extends RouteBuilder {
>> 
>>    @Override
>>    public void configure() throws Exception {
>>                from("direct:generateAndSignPdf")
>>                   ...
>>                   to("direct:signPdf");
>>    }
>> 
>> }
>> 
>> public class SignPdfRouteBuilder extends RouteBuilder {
>> 
>>    @Override
>>    public void configure() throws Exception {
>>        from("direct:signPdf")
>>                        ...
>>    }
>> 
>> }
>> 
>> In other words, you would have to know how GenerateAndSignPdfRouteBuilder is
>> implemented
>> in order to use it.
> 
> Agreed. If you kinda squint a bit and think of the route builders as
> 'objects' and you want to compose 2 different routes together with
> shared dependencies its a bit like 'constructors' and 'data hiding'.
> 
> We have protocol A and B and we need to route the output of A to the
> input of B; so rather than B needing to know the implementation detail
> of A; we add a constructor parameter for B's input...
> 
> class A extends ProtocolBuilder {...}
> 
> class B extends ProtocolBuilder {
>  public B(String inputUri) { ... }
> }
> 
> // lets use Java code to simulate DI...
> ProtocolBuilder a = new A();
> ProtocolBuilder b = new B(b.getOutputUri());
> 
> 
> we've now wired A and B together without B knowing anything about the
> implementation detail of A.
> 
> Its quite common for lots of protocols to be 'unix pipe-ish' with an
> input and output; so we could have helper classes where there's
> standard input/output endpoints like this to create a pipeline...
> 
> CompositeProtocol composite = Protocols.pipeline(A.class, B.class, C.class);
> 
> where A:out -> B:in and B:out -> C:in. Indeed that could return a new
> protocol; where composite:in maps to A:in and composite:out maps to
> C:out
> 
> But then this is sounding like just treating A, B and C as endpoints :)
> 
> 
>> The Route Component solution (II) doesn't require the RouteBuilders used to
>> be referenced
>> in the camelContext. It instantiates an endpoint which adds the Route
>> information to the
>> camelcontext at runtime whenever a producer or consumer is started.
>> 
>> Would this concept be available in the ProtocolBuilder construct as well ?
>> I do see the added value of using a ProtocolBuilder and declaring it as a
>> bean in spring
>> but wouldn't you need to use some kind of generic component in the middle to
>> instantiate
>> and add those builders on demand ?
>> 
>> E.g.
>> 
>>        <route>
>>            <from uri="route:standardActions://out"/>
>>            <to uri="route:generateAndSignPdf://in"/>
>>            <to uri="mock:result"/>
>>        </route>
>> 
>> Another reason why I didn't consider the Parameterized RouteBuilder is the
>> risk of name clashes
>> . When nesting components several levels deep and/or reusing the same
>> RouteBuilder beans multiple times
>>  yet with different properties, this could lead to impredictable behaviour
>> when direct endpoints and routeIds are not unique within the CamelContext.
> 
> Thats a great point! Just like with OO, we probably need some kind of
> data hiding; or in this case its 'endpoint hiding'. So maybe using
> nested CamelContexts is a good thing.
> 
> Another random idea; imagine if we had a ProtocolBuilder which created
> a child CamelContext - so all "direct:foo" and "seda:bar" endpoints
> were totally private. Then imagine, as a simple implementation option
> - we map all URIs within the ProtocolBuilder's URI space to the
> direct: endpoint within the nested CamelContext.
> 
> So rather than having to add the "alias()" method I mentioned in the
> other thread - we could just use URIs inside the route for the
> 'input/output/error' URIs...
> http://camel.465427.n5.nabble.com/implementing-Protocols-or-a-way-to-make-it-easier-to-black-box-routes-and-compose-them-with-other-ros-td3218777.html#a3218777
> 
> e.g. imagine...
> 
> class A extends ProtocolBuilder {
>  public void configure() {
>    from("direct:in").
>     beanRef("foo").
>     to("direct:out");
>  }
> }
> 
> class B extends ProtocolBuilder {
>  public void configure() {
>    from("direct:in").
>     unmarshal().jaxb().
>     to("direct:out");
>  }
> }
> 
> // now lets wire A and B
> // kinda like "Foo | A | B | Bar" on a unix command line
> 
> class Foo extends RouteBuilder {
>  public void configure() {
>    from("activemq:Foo").to("a:in");
>    from("a:out").to("b:in");
>    from("b:out").to("activemq:Bar");
>  }
> }
> 
> 
> i.e. so A and B have no knowledge of each other (kinda like unix
> pipes), you can compose them together in any way you like (Foo) - and
> bind them to any middleware.
> 
> In this example the 'local endpoints' (using direct:) are totally
> private to each ProtocolBuilder so there's no name clashes as we're
> using nested CamelContext's.
> 
> Not totally sure if we should make "direct" into some magical
> component here; or if we should just introduce some kind of "local:"
> endpoint to use inside a ProtocolBuilder to emphasise a local,
> internal endpoint which is private to the ProtocolBuilder? e.g.
> replace "direct:in" to "local:in".
> 
> The question of local v global endpoint URIs is interesting; I wonder
> how many kinds of endpoints can even support the concept of local.
> Using nested CamelContexts we'd have local seda/vm/direct I think;
> though given their similarity, maybe a new 'local' endpoint is simpler
> as it clearly describes what really is local versus what really is an
> external/global endpoint?
> 
> Note that there's nothing to stop these protocols using
> external/global endpoints too; am sure they will. Its more where we
> parameterise things together we might want to use local endpoints
> which we can then route into / out of.
> 
> 
> 
>> jstrachan wrote:
>>> 
>>> ii) a parameterized RouteBuilder which is dependency injected using a
>>> URI (which is kinda like Kristof's example code
>>> 
>> 
>> Yeah, maybe the implementation of the RouteEndpoint class is somewhat
>> clumsy, but what I am trying to
>> do here is to pass header values to the nested route.
>> 
>> Normally you would go about this using the setHeader statement, however this
>> is quite verbose when
>> using xml dsl.
>> 
>>           <setHeader headerName="signatureReason">
>>                <constant>JustForFun</constant>
>>            </setHeader>
>>            <setHeader headerName="signatureVisible">
>>                <constant>true</constant>
>>            </setHeader>
>>            <setHeader headerName="xslUri">
>> 
>> <constant>com/xti/poc/camel/route/sample1/krusty.xsl</constant>
>>            </setHeader>
>> 
>> That's why I figured i'd use the uri parameters to have some kind of
>> shorthand notation for assigning
>> header values.
>> 
>> ?signatureReason=JustForFun&signatureVisible=true&xslUri=com/xti/poc/camel/route/sample1/krusty.xsl
> 
> Ah sorry - I misunderstood. (Bad James, should have read your code
> more closely).
> 
> Thats a pretty neat idea. Given that the 'local' endpoints I mention
> above would be pretty simple things; we could maybe do something
> similar in the ProtocolBuilder idea?
> 
> 
> 
>> Maybe the implementation would be cleaner if properties are used only for
>> dependency injection.
>> The shorthand notation could define an interceptor on the from of the target
>> RouteBuilder. The interceptor could then populate the headers
>> when the exchange comes in.
> 
> Or the setting of headers could be done inside the ProtocolBuilder's
> configure() method? So its hidden inside the implementation detail of
> the ProtocolBuilder, then folks wiring A and B together don't need to
> worry about that kinda thing?
> 
> -- 
> James
> -------
> FuseSource
> Email: [email protected]
> Web: http://fusesource.com
> Twitter: jstrachan
> Blog: http://macstrac.blogspot.com/
> 
> Open Source Integration

Reply via email to