Uploaded image for project: 'Camel'
  1. Camel
  2. CAMEL-3285

Create a new blackbox component which can encapsulate routes using a specialized ProtocolBuilder endpoint (similar to RouteBuilder)

    Details

    • Type: New Feature
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 2.6.0
    • Component/s: None
    • Labels:
      None

      Description

      Given below is the discussion forum thread that spawned this thought.

      http://camel.465427.n5.nabble.com/Abstracting-Routes-using-Components-td3234703.html#a3234703

      Component requirements:

      Need a Camel component (called Backbox, maybe) that can nicely expose a ProtocolBuilder endpoint that does the following
      a> Instantiate route definitions/route(s) configured in Spring or DSL at startup
      b> Launch a Producer or Consumer with a well known protocol(s) so that a client can invoke it (could be direct or seda initially but could be any protocol... really) . Must support multiple consumer endpoints and routes using a URI scheme.
      c> redirect received payloads (with marshalling into an exchange if necessary) to the inner route(s) since they are launched and started. If there are multiple inner routes with many consumers, we could expect the user to provide a clue using the payload and/or an exchange property as to how the payload should be routed.
      d> Extend from a Default Consumer, Producer, Endpoint and Component.
      e> Internally manage inner route lifecycles and operations.

      1. camel-routebox-20101220.zip
        108 kB
        Ashwin Karpe
      2. routebox.diff
        118 kB
        Ashwin Karpe

        Activity

        Hide
        akarpe Ashwin Karpe added a comment -

        Hi All,

        I have started the buildout of this component based on the requirements expressed in Nabble. I will bring out a version in the coming few weeks.

        Cheers,

        Ashwin...

        Show
        akarpe Ashwin Karpe added a comment - Hi All, I have started the buildout of this component based on the requirements expressed in Nabble. I will bring out a version in the coming few weeks. Cheers, Ashwin...
        Hide
        akarpe Ashwin Karpe added a comment -

        Hi All,

        I have created the routebox component that facilitates encapsulation of routes in a context and exposes the context as a single URI based endpoint called routebox.

        The Routebox component supports both consumer and producer endpoints. Producer endpoints are capable of sending requests to a consumer endpoint or to directly invoke routes in a Producer embedded context thereby not requiring a consumer.

        For example a consumer endpoint could be created as
        from("routebox:multipleRoutes?innerRegistry=#registry&routeBuilders=#routes&dispatchMap=#map")
        .to("log:Routes operation performed?showAll=true");

        A producer endpoint could be created as
        from("direct:start")
        .to("routebox:multipleRoutes?sendToConsumer=false&innerContext=#ctx&dispatchStrategy=#strategy")
        .to("log:Routes operation performed?showAll=true");

        The sendToConsumer Query parameter specifies whether producer dispatches to an inner context or an external Routebox consumer.

        Internally the component supports SEDA and Direct protocol based communication.

        When a request is sent to the routebox component a user provided RouteboxDispatchStrategy or a HashMap containing Dispatch URI information is used to direct the data to inner routes in a separate inner context.

        The inner context is fully under the control of the routebox component and is JVM bound.

        The inner routes may have consumers which can be any of the available camel supported consumer endpoints (ActiveMQ, CXF... etc).

        I welcome your comments, thoughts & suggestions.

        Cheers,

        Ashwin...

        P.S: I have added requisite unit tests, performed checkstyle sourcecheck(s) and verified everything to be in good working order. I will be committing this version shortly and look forward to your thoughts, suggestions, updates and recommendations. I will apply any recommendations to the trunk as enhancement requests.

        Show
        akarpe Ashwin Karpe added a comment - Hi All, I have created the routebox component that facilitates encapsulation of routes in a context and exposes the context as a single URI based endpoint called routebox. The Routebox component supports both consumer and producer endpoints. Producer endpoints are capable of sending requests to a consumer endpoint or to directly invoke routes in a Producer embedded context thereby not requiring a consumer. For example a consumer endpoint could be created as from("routebox:multipleRoutes?innerRegistry=#registry&routeBuilders=#routes&dispatchMap=#map") .to("log:Routes operation performed?showAll=true"); A producer endpoint could be created as from("direct:start") .to("routebox:multipleRoutes?sendToConsumer=false&innerContext=#ctx&dispatchStrategy=#strategy") .to("log:Routes operation performed?showAll=true"); The sendToConsumer Query parameter specifies whether producer dispatches to an inner context or an external Routebox consumer. Internally the component supports SEDA and Direct protocol based communication. When a request is sent to the routebox component a user provided RouteboxDispatchStrategy or a HashMap containing Dispatch URI information is used to direct the data to inner routes in a separate inner context. The inner context is fully under the control of the routebox component and is JVM bound. The inner routes may have consumers which can be any of the available camel supported consumer endpoints (ActiveMQ, CXF... etc). I welcome your comments, thoughts & suggestions. Cheers, Ashwin... P.S: I have added requisite unit tests, performed checkstyle sourcecheck(s) and verified everything to be in good working order. I will be committing this version shortly and look forward to your thoughts, suggestions, updates and recommendations. I will apply any recommendations to the trunk as enhancement requests.
        Hide
        akarpe Ashwin Karpe added a comment -

        Hi All,

        Some enhancements I am considering at the moment include

        • Support for XSL based route dispatch support
        • Support for Drools based route dispatch support

        I will add these in due course.

        Cheers,

        Ashwin...

        Show
        akarpe Ashwin Karpe added a comment - Hi All, Some enhancements I am considering at the moment include Support for XSL based route dispatch support Support for Drools based route dispatch support I will add these in due course. Cheers, Ashwin...
        Hide
        akarpe Ashwin Karpe added a comment -

        Committed to the Camel trunk as revision r1051321

        Show
        akarpe Ashwin Karpe added a comment - Committed to the Camel trunk as revision r1051321
        Hide
        davsclaus Claus Ibsen added a comment -

        Great work Ashwin. I will take a closer look when I get some time.

        Show
        davsclaus Claus Ibsen added a comment - Great work Ashwin. I will take a closer look when I get some time.
        Hide
        davsclaus Claus Ibsen added a comment -

        I have some comments on reviewing the source code
        =========================================

        1) RouteboxConfiguration
        I dont think its advised to tie the configuration to a runtime instance of Camel. eg you have instances of producer template, camel context in there.

        All the logic you do to set parameters from the Map to the setters in RouteboxConfiguration is not really needed, as Camel can do this for you.

        2)
        You start a producer template in RouteboxConfiguration but you never stop it. eg you dont handle its lifecycle properly.
        If you create a template using the API from CamelContext you can let CamelContext handle its lifecycle and thus dont need to worry about it

        3)
        Use final modifier for internal fields, for shared resources such as queues (if possible). This is better for the JVM. Otherwise you will have to use volatile to ensure thread safety.

        4)
        Looks like the start logic in RouteboxServiceSupport may add the same routes multiple times, because the stop logic doesn't remove the routes.

        5)
        PendingExchanges is not a setter/getter property end users can set!. Its an internal information for graceful shutdown, to let it know that there are XXX number of exchanges in flight that this route is currently processing. So remove the getter/setter for it.

        6)
        Wonder if it would be better to extend SedaConsumer, DirectConsumer instead of not doing that. I will have to re-check this as there is a lot of logic in SedaConsumer which you may have to duplicate to make it work well.

        7)
        Looks like the asynchronous routing engine isn't supported as its supposed to. I will have to revisit this as well.

        9)
        Having interfaces for RouteConsumer and RouteProducer is maybe overkill as there doesn't seem to be anything out of the ordinary that a regular Consumer / Producer. We may think about this if we want to enforce such a restriction.

        Show
        davsclaus Claus Ibsen added a comment - I have some comments on reviewing the source code ========================================= 1) RouteboxConfiguration I dont think its advised to tie the configuration to a runtime instance of Camel. eg you have instances of producer template, camel context in there. All the logic you do to set parameters from the Map to the setters in RouteboxConfiguration is not really needed, as Camel can do this for you. 2) You start a producer template in RouteboxConfiguration but you never stop it. eg you dont handle its lifecycle properly. If you create a template using the API from CamelContext you can let CamelContext handle its lifecycle and thus dont need to worry about it 3) Use final modifier for internal fields, for shared resources such as queues (if possible). This is better for the JVM. Otherwise you will have to use volatile to ensure thread safety. 4) Looks like the start logic in RouteboxServiceSupport may add the same routes multiple times, because the stop logic doesn't remove the routes. 5) PendingExchanges is not a setter/getter property end users can set!. Its an internal information for graceful shutdown, to let it know that there are XXX number of exchanges in flight that this route is currently processing. So remove the getter/setter for it. 6) Wonder if it would be better to extend SedaConsumer, DirectConsumer instead of not doing that. I will have to re-check this as there is a lot of logic in SedaConsumer which you may have to duplicate to make it work well. 7) Looks like the asynchronous routing engine isn't supported as its supposed to. I will have to revisit this as well. 9) Having interfaces for RouteConsumer and RouteProducer is maybe overkill as there doesn't seem to be anything out of the ordinary that a regular Consumer / Producer. We may think about this if we want to enforce such a restriction.
        Hide
        davsclaus Claus Ibsen added a comment -

        Polished code a bit in rev: 1053342.

        Show
        davsclaus Claus Ibsen added a comment - Polished code a bit in rev: 1053342.
        Hide
        akarpe Ashwin Karpe added a comment -

        Hi Claus,

        Sure thing. Thanks for the code review & your recommendations.

        I will make the requisite changes and submit a patch.

        Cheers,

        Ashwin...

        Show
        akarpe Ashwin Karpe added a comment - Hi Claus, Sure thing. Thanks for the code review & your recommendations. I will make the requisite changes and submit a patch. Cheers, Ashwin...
        Hide
        akarpe Ashwin Karpe added a comment -

        Hi Claus,

        Looks like you have already implemented the changes and checked in the code.

        BTW, on (6), the reason I did not directly extend SEDAConsumer and DirectConsumer was because, it would create a dependency between two components. I did not want to cause any updates to the SEDA code to have to consider the Routebox component and vice-versa. I therefore went one level higher and worked from there.
        I wanted to clearly delineate between the SEDA and Direct in their respective components from the implementation in the routebox so that it could be revved independently.

        On (9), I created the RouteConsumer and RouteProducer so that if there was a need to add other protocols (HTTP, JMS, TCP etc) so that the routebox implementation was not JVM bound as it is right now, it could be done in a consistent way.

        Thanks for the code updates.

        Cheers,

        Ashwin...

        Show
        akarpe Ashwin Karpe added a comment - Hi Claus, Looks like you have already implemented the changes and checked in the code. BTW, on (6), the reason I did not directly extend SEDAConsumer and DirectConsumer was because, it would create a dependency between two components. I did not want to cause any updates to the SEDA code to have to consider the Routebox component and vice-versa. I therefore went one level higher and worked from there. I wanted to clearly delineate between the SEDA and Direct in their respective components from the implementation in the routebox so that it could be revved independently. On (9), I created the RouteConsumer and RouteProducer so that if there was a need to add other protocols (HTTP, JMS, TCP etc) so that the routebox implementation was not JVM bound as it is right now, it could be done in a consistent way. Thanks for the code updates. Cheers, Ashwin...
        Hide
        kristofsajdak Kristof Sajdak added a comment -

        Hi Ashwin,

        Browsed through the codebase just now.
        It looks quite flexible, however I feel it might not be a good fit for the use case which I described a while back in the camel users thread (http://camel.465427.n5.nabble.com/Abstracting-Routes-using-Components-td3234703.html).

        To illustrate my point I would like to use the routebuilder which you have defined as part of your unit tests in the camel-routebox sources.

        // Routes
        from("seda:addToCatalog")
        .to("log:Received request for seda:addToCatalog")
        .to("bean:library?method=addToCatalog");

        from("seda:findBook")
        .to("log:Received request for seda:findBook")
        .to("bean:library?method=findBook");

        from("seda:findAuthor")
        .to("log:Received request for seda:findAuthor")
        .to("bean:library?method=findAuthor");

        using the routebox component to address these routes it could look like the following :

        <route>
        <from uri="direct://start"/>

        <setHeader headerName="ROUTE_DISPATCH_KEY">
        <constant>addToCatalog</constant>
        </setHeader>
        <to uri="routebox:multipleRoutes?routeBuilders=#bookRoutes&dispatchStrategy=#strategy"/>
        </route>

        This is a little bit complex when you would have to explain this to non technical person.
        In such a case the syntax described in the camel users thread would be more intuitive in my opinion :

        <route>
        <from uri="direct://start"/>
        <to uri="book://addtoCatalog"/>
        </route>

        Best regards,

        Kristof

        Show
        kristofsajdak Kristof Sajdak added a comment - Hi Ashwin, Browsed through the codebase just now. It looks quite flexible, however I feel it might not be a good fit for the use case which I described a while back in the camel users thread ( http://camel.465427.n5.nabble.com/Abstracting-Routes-using-Components-td3234703.html ). To illustrate my point I would like to use the routebuilder which you have defined as part of your unit tests in the camel-routebox sources. // Routes from("seda:addToCatalog") .to("log:Received request for seda:addToCatalog") .to("bean:library?method=addToCatalog"); from("seda:findBook") .to("log:Received request for seda:findBook") .to("bean:library?method=findBook"); from("seda:findAuthor") .to("log:Received request for seda:findAuthor") .to("bean:library?method=findAuthor"); using the routebox component to address these routes it could look like the following : <route> <from uri="direct://start"/> <setHeader headerName="ROUTE_DISPATCH_KEY"> <constant>addToCatalog</constant> </setHeader> <to uri="routebox:multipleRoutes?routeBuilders=#bookRoutes&dispatchStrategy=#strategy"/> </route> This is a little bit complex when you would have to explain this to non technical person. In such a case the syntax described in the camel users thread would be more intuitive in my opinion : <route> <from uri="direct://start"/> <to uri="book://addtoCatalog"/> </route> Best regards, Kristof
        Hide
        akarpe Ashwin Karpe added a comment - - edited

        Hi Kristof,

        If I understand your requirement correctly, there are major issues with doing it the way you have described, the key ones among them I have described below.

        a> Something like the URI (book://addToCatalog) described already exists in Camel in the bean component.
        bean:book?method=addToCatalog
        b> The use of "routebox:" is primarily used to indicate a URI scheme that clearly indicates that the URI indirects to a collection of underlying routes which are encapsulated/housed in a inner camel context. The book://addToCatalog is not reflective of that since it becomes single indirection based endpoint and therefore book://findBook becomes another single indirection endpoint to a single inner route/method housed in its own inner context.
        At this point the mapping of camel context <--> route becomes 1:1 which is way too expensive and narrow/limited in terms of utilizing camel capabilities.
        c> The URI for book:addToCatalog has the potential to cause a lot of confusion since book is an application entity and not a camel offered protocol or URI scheme. Camel provides generic component(s) that facilitate via URIs an ability for the integration architect to wire any application entities of his choice.
        d>The routebox URI accurately follows standard conventions for URI design. If there is something I am missing in terms of intuitiveness, but addressing the points listed above, I would be happy to address them.

        Hope this clarifies my design choices.

        There is however a valid question as to how a client would know of what payload to send and what header to set, which I am planning to address in the next update using a Query extensor (routebox:myroutes:query?...) and/or a set of routebox processors that can provide these details with a bunch of helper interfaces and abstract classes, which can again be implemented by users to achieve what they want.

        Hope this helps.

        Cheers,

        Ashwin...

        Show
        akarpe Ashwin Karpe added a comment - - edited Hi Kristof, If I understand your requirement correctly, there are major issues with doing it the way you have described, the key ones among them I have described below. a> Something like the URI (book://addToCatalog) described already exists in Camel in the bean component. bean:book?method=addToCatalog b> The use of "routebox:" is primarily used to indicate a URI scheme that clearly indicates that the URI indirects to a collection of underlying routes which are encapsulated/housed in a inner camel context. The book://addToCatalog is not reflective of that since it becomes single indirection based endpoint and therefore book://findBook becomes another single indirection endpoint to a single inner route/method housed in its own inner context. At this point the mapping of camel context <--> route becomes 1:1 which is way too expensive and narrow/limited in terms of utilizing camel capabilities. c> The URI for book:addToCatalog has the potential to cause a lot of confusion since book is an application entity and not a camel offered protocol or URI scheme. Camel provides generic component(s) that facilitate via URIs an ability for the integration architect to wire any application entities of his choice. d>The routebox URI accurately follows standard conventions for URI design. If there is something I am missing in terms of intuitiveness, but addressing the points listed above, I would be happy to address them. Hope this clarifies my design choices. There is however a valid question as to how a client would know of what payload to send and what header to set, which I am planning to address in the next update using a Query extensor (routebox:myroutes:query?...) and/or a set of routebox processors that can provide these details with a bunch of helper interfaces and abstract classes, which can again be implemented by users to achieve what they want. Hope this helps. Cheers, Ashwin...
        Hide
        kristofsajdak Kristof Sajdak added a comment -

        a) A bean component is not a good fit for this use case in my opinion.

        If I would use a bean component then how would you implement the abstracted routes ? :

        from("seda:addToCatalog")
        .to("log:Received request for seda:addToCatalog")
        .to("bean:library?method=addToCatalog");

        In the bean component, which is a pojo, there is no dsl which i can use.

        Another option which was mentioned in the camel users thread was to define a RouteBuilder per abstraction
        and use direct or seda endpoints to send/receive messages to/from this routebuilder.

        This however has several drawbacks as well :

        1. Not intuitive -> Declare the routebuilder refs in the CamelContext for each routebuilder used
        OR Too much overhead -> initialize all routebuilders using scanning features

        2. Possible direct/seda endpoint name collisions when using lots of routebuilders with internal direct endpoints
        in the same CamelContext. The end user would have to know about the internals of all the routebuilders he/she is using.

        b) Maybe I wasn't clear on this.
        I would definitely use at most one inner context for all the routes within a single routebuilder.

        so addToCatalog, findBook and findAuthor would all be endpoints located on the same CamelContext.

        This improves encapsulation in my book, you don't have to worry about any conflicts of direct endpoints acrross
        different routebuilders. All the end user needs to know is the logical endpoint names he/she can address.

        c) Maybe book sounds too much like an entity, something like bookstore might be a better protocol name
        bookstore://addToCatalog, bookstore://findBook, bookstore://findAuthor

        Correct me if I am wrong but wasn't it the orginial idea that camel users could easily create
        route abstractions and serve them using custom protocols ?

        See below an extract of the camel users thread where James suggests :

        <route>
        <from uri="activemq:SomeInputQueue"/>
        <to uri="generateAndSignPdf://in"/>
        </route>
        <route>
        <from uri="file://someDir/foo"/>
        <to uri="generateAndSignPdf://in"/>
        </route>

        This is something you can hand off to an end user without any problems.
        Provide a bunch of well documented components and let the end user pick and choose whatever he needs.
        Intuitive and concise.

        Combined with something as the Camel Rider tool this would be quite a powerful concept for these kind of use cases.

        Best regards,

        K.

        Show
        kristofsajdak Kristof Sajdak added a comment - a) A bean component is not a good fit for this use case in my opinion. If I would use a bean component then how would you implement the abstracted routes ? : from("seda:addToCatalog") .to("log:Received request for seda:addToCatalog") .to("bean:library?method=addToCatalog"); In the bean component, which is a pojo, there is no dsl which i can use. Another option which was mentioned in the camel users thread was to define a RouteBuilder per abstraction and use direct or seda endpoints to send/receive messages to/from this routebuilder. This however has several drawbacks as well : 1. Not intuitive -> Declare the routebuilder refs in the CamelContext for each routebuilder used OR Too much overhead -> initialize all routebuilders using scanning features 2. Possible direct/seda endpoint name collisions when using lots of routebuilders with internal direct endpoints in the same CamelContext. The end user would have to know about the internals of all the routebuilders he/she is using. b) Maybe I wasn't clear on this. I would definitely use at most one inner context for all the routes within a single routebuilder. so addToCatalog, findBook and findAuthor would all be endpoints located on the same CamelContext. This improves encapsulation in my book, you don't have to worry about any conflicts of direct endpoints acrross different routebuilders. All the end user needs to know is the logical endpoint names he/she can address. c) Maybe book sounds too much like an entity, something like bookstore might be a better protocol name bookstore://addToCatalog, bookstore://findBook, bookstore://findAuthor Correct me if I am wrong but wasn't it the orginial idea that camel users could easily create route abstractions and serve them using custom protocols ? See below an extract of the camel users thread where James suggests : <route> <from uri="activemq:SomeInputQueue"/> <to uri="generateAndSignPdf://in"/> </route> <route> <from uri="file://someDir/foo"/> <to uri="generateAndSignPdf://in"/> </route> This is something you can hand off to an end user without any problems. Provide a bunch of well documented components and let the end user pick and choose whatever he needs. Intuitive and concise. Combined with something as the Camel Rider tool this would be quite a powerful concept for these kind of use cases. Best regards, K.
        Hide
        akarpe Ashwin Karpe added a comment - - edited

        Hi Kristof,

        We agree on a) and b) and the current implementation clearly follows this.

        In the current implementation of the routebox component, there is only one inner context created for a unique endpoint name. The endpoint name is then tied uniquely to its innerContext and host multiple inner routes. This should meet your requirement relating to encapsulation, hosting and strategy/map based payload indirection to inner routes.

        As for point c) in your comment, the URI definition is where the divergence with your requirement is indeed present and I am aware of this.

        My design/implementation choices were guided by the following reasoning given below
        --------------------------
        Currently in Camel, Protocols/URI schemes enable binding & registration of a specific component known to the Camel Context which is then used as a factory to create specialized endpoints of a given type (e.g http, jms etc). The protocol/URI scheme mapping to a component registration is done at context creation automatically using an API called addComponent(String componentName, final Component component) .The only exception is when a routebuilder is used to add a component.

        Therefore, you will find that when you add a camel component maven dependency in your pom file the component is automatically registered under its fixed name. This happens via a file which is scanned during context creation and is present for every component in .../trunk/components/camel-routebox/src/main/resources/META-INF/services/org/apache/camel/component/routebox which contains a single entry for its associated component. The name of the file (routebox) is wired to the URI scheme and the component associated is added to the component list. Following this, camel now has the ability to create the requisite endpoints.

        Now coming to the answer you are looking for... The reason James talked about a ProtocolBuilder akin to a RouteBuilder was so that this magic of mapping "bookstore" to the Routebox component could be performed by the API which the user could write code for (or maybe not, based on the design)... This addComponent() would need to be done every protocol (bookstore, bookstore1, mybookstore etc) you were planning to use.

        Also, since the URI scheme suddenly became cheap, you could add all manner of names for components and potentially override the values of well known protocols. You could run into name clashes in different ProtocolBuilders trying to do the same thing.

        RouteBuilders currently can do the same for you. You can add a line to your configure method to do an addComponent("bookstore", RouteComponent")
        -----------------------------

        I decided not to pursue this road since RouteBuilders currently can do the same for you and the ProtocolBuilder was in my view over-engineering for little gain. You can add a line to your configure method to do an addComponent("bookstore", RouteComponent") even now and then do a
        bookstore:bookstore_routes?...
        instead of
        routebox:bookstore_routes?...
        with an exchange header ROUTE_DISPATCH_KEY=addToCatalog so the payload can be indirected to URI seda:addToCatalog.

        BTW, I spoke to James and Claus a few weeks ago in early December about my design and implementation strategy. I also rotated this many times in my own mind, ran these ideas by an existing customer with similar needs regarding pros/cons and arrived at this point. James did think that my design was proper (though not how he had envisioned it in the beginning) and asked me to go ahead and contribute the code as seen in my current implementation. I also spoke to Claus briefly and he was quite happy with the implementation plan.

        I am not saying this is the final form for this component. I am happy to take on any thoughts, ideas and/or patches you may have and re-factor the component appropriately.

        Sorry about the rather long winded answer. I hope this given you a sense of where I am coming from.

        Cheers,

        Ashwin...

        Show
        akarpe Ashwin Karpe added a comment - - edited Hi Kristof, We agree on a) and b) and the current implementation clearly follows this. In the current implementation of the routebox component, there is only one inner context created for a unique endpoint name. The endpoint name is then tied uniquely to its innerContext and host multiple inner routes. This should meet your requirement relating to encapsulation, hosting and strategy/map based payload indirection to inner routes. As for point c) in your comment, the URI definition is where the divergence with your requirement is indeed present and I am aware of this. My design/implementation choices were guided by the following reasoning given below -------------------------- Currently in Camel, Protocols/URI schemes enable binding & registration of a specific component known to the Camel Context which is then used as a factory to create specialized endpoints of a given type (e.g http, jms etc). The protocol/URI scheme mapping to a component registration is done at context creation automatically using an API called addComponent(String componentName, final Component component) .The only exception is when a routebuilder is used to add a component. Therefore, you will find that when you add a camel component maven dependency in your pom file the component is automatically registered under its fixed name. This happens via a file which is scanned during context creation and is present for every component in .../trunk/components/camel-routebox/src/main/resources/META-INF/services/org/apache/camel/component/routebox which contains a single entry for its associated component. The name of the file (routebox) is wired to the URI scheme and the component associated is added to the component list. Following this, camel now has the ability to create the requisite endpoints. Now coming to the answer you are looking for... The reason James talked about a ProtocolBuilder akin to a RouteBuilder was so that this magic of mapping "bookstore" to the Routebox component could be performed by the API which the user could write code for (or maybe not, based on the design)... This addComponent() would need to be done every protocol (bookstore, bookstore1, mybookstore etc) you were planning to use. Also, since the URI scheme suddenly became cheap, you could add all manner of names for components and potentially override the values of well known protocols. You could run into name clashes in different ProtocolBuilders trying to do the same thing. RouteBuilders currently can do the same for you. You can add a line to your configure method to do an addComponent("bookstore", RouteComponent") ----------------------------- I decided not to pursue this road since RouteBuilders currently can do the same for you and the ProtocolBuilder was in my view over-engineering for little gain. You can add a line to your configure method to do an addComponent("bookstore", RouteComponent") even now and then do a bookstore:bookstore_routes?... instead of routebox:bookstore_routes?... with an exchange header ROUTE_DISPATCH_KEY=addToCatalog so the payload can be indirected to URI seda:addToCatalog. BTW, I spoke to James and Claus a few weeks ago in early December about my design and implementation strategy. I also rotated this many times in my own mind, ran these ideas by an existing customer with similar needs regarding pros/cons and arrived at this point. James did think that my design was proper (though not how he had envisioned it in the beginning) and asked me to go ahead and contribute the code as seen in my current implementation. I also spoke to Claus briefly and he was quite happy with the implementation plan. I am not saying this is the final form for this component. I am happy to take on any thoughts, ideas and/or patches you may have and re-factor the component appropriately. Sorry about the rather long winded answer. I hope this given you a sense of where I am coming from. Cheers, Ashwin...
        Hide
        kristofsajdak Kristof Sajdak added a comment - - edited

        yes, i am aware of various ways to create a new uri scheme in camel :
        A file in the meta-inf, adding it thourgh the API via a routebuilder as you described and
        also by defining a component as a spring bean if I am not mistaking.

        Whether creating your own uri schemes is good or bad depends on the use case I guess.
        In my case it wouldn't be that much of a problem.

        In any case, starting the endpoint url with a routebox: scheme or without to me isn't the biggest issue.

        Something I am concerned with is the verboseness of the url and setting the dispatch key.
        This is a very flexible approach however it might be nice to have some kind of alternative way of specifying the logical endpoint
        in the routebox, something which is more intuitive to non technical people.

        perhaps something like :

        routebox://bookstore_routes/addToCatalog

        where bookstore_routes would resolve to a routeBuilder or a camel context located in the bean registry.
        A default dispatchStrategy could then dispatch the logical endpoint name to a corresponding direct/seda endpoint in the routebox ?
        This reduces verboseness quite a lot and makes it more managable and productive for the non technical people in my opinion.

        To me this seems a nice compromise to satisfy the use case I am targetting as well, what do you think ?

        Best regards,

        Kristof

        Show
        kristofsajdak Kristof Sajdak added a comment - - edited yes, i am aware of various ways to create a new uri scheme in camel : A file in the meta-inf, adding it thourgh the API via a routebuilder as you described and also by defining a component as a spring bean if I am not mistaking. Whether creating your own uri schemes is good or bad depends on the use case I guess. In my case it wouldn't be that much of a problem. In any case, starting the endpoint url with a routebox: scheme or without to me isn't the biggest issue. Something I am concerned with is the verboseness of the url and setting the dispatch key. This is a very flexible approach however it might be nice to have some kind of alternative way of specifying the logical endpoint in the routebox, something which is more intuitive to non technical people. perhaps something like : routebox://bookstore_routes/addToCatalog where bookstore_routes would resolve to a routeBuilder or a camel context located in the bean registry. A default dispatchStrategy could then dispatch the logical endpoint name to a corresponding direct/seda endpoint in the routebox ? This reduces verboseness quite a lot and makes it more managable and productive for the non technical people in my opinion. To me this seems a nice compromise to satisfy the use case I am targetting as well, what do you think ? Best regards, Kristof
        Hide
        rkettelerij Richard Kettelerij added a comment -

        Since this new component is part of the 2.6 release I've added it to the release notes (http://camel.apache.org/camel-260-release.html).

        Show
        rkettelerij Richard Kettelerij added a comment - Since this new component is part of the 2.6 release I've added it to the release notes ( http://camel.apache.org/camel-260-release.html ).
        Hide
        kristofsajdak Kristof Sajdak added a comment -

        Any thoughts on my last comment ?

        Kristof

        Show
        kristofsajdak Kristof Sajdak added a comment - Any thoughts on my last comment ? Kristof
        Hide
        akarpe Ashwin Karpe added a comment - - edited

        Kristof,

        Your suggestion above has the implication of a 1:1 indirection i.e the addToCatalog endpoint will only indirect to the seda:addToCatalog route . It does not have the ability to perform content based routing to inner routes based on payload content.

        Secondly, it is perfectly legal to have multiple consumers in the routebox with
        from("direct:addtoCatalog")...
        from("seda:addtoCatalog")...
        and
        from("http://localhost:9000/addToCatalog) in the routebox at the same time.

        How would you then indirect to the right route...? I am sure your usecase can be satisfied in the current implementation with a dispatchMap in the Routebox URI referring to a Spring defined Hashmap if the developer is averse to writing code.

        I am afraid this particular simplification is a behavioral change that impacts capability and serves to confuse.

        Cheers,

        Ashwin...

        Show
        akarpe Ashwin Karpe added a comment - - edited Kristof, Your suggestion above has the implication of a 1:1 indirection i.e the addToCatalog endpoint will only indirect to the seda:addToCatalog route . It does not have the ability to perform content based routing to inner routes based on payload content. Secondly, it is perfectly legal to have multiple consumers in the routebox with from("direct:addtoCatalog")... from("seda:addtoCatalog")... and from("http://localhost:9000/addToCatalog) in the routebox at the same time. How would you then indirect to the right route...? I am sure your usecase can be satisfied in the current implementation with a dispatchMap in the Routebox URI referring to a Spring defined Hashmap if the developer is averse to writing code. I am afraid this particular simplification is a behavioral change that impacts capability and serves to confuse. Cheers, Ashwin...
        Hide
        davsclaus Claus Ibsen added a comment -

        Yes I think the goal should be to simplify from end user perspective. What we are aiming for is to let non-developers (or very inexperience developers) to orchestrates business flows.

        And that requires a DSL / endpoint syntax which is simple and intuitive. And convention over configuration.
        If that means a little flexibility must be sacrificed then so be it.
        The error messages returned should be more verbose trying to explain what may be wrong. And provide hints what to do to remedy that.

        Also given more thought I dont like the inner CamelContext. The CamelContext wasn't really designed to be embedded in a outer context.
        Also by default the context setup JMX, Cache, Type Converters and a lot of other resources which is not needed to be duplicated.

        That's why I suggested that the current routebox should be marked as subject to change (at the documentation page) as we just got started working on it.
        I think Ashwin have done a good start, but I am very open to improve and make it more flexible and easier to use in Camel 2.7 onwards.

        And from a tooling point of view, then the FuseSource Camel IDE may help as a vehicle to steer for simplicity, as it forces us to think of using the routebox without having to do any coding at all. Or to setup spring beans or any other weird stuff that a non-developer don't know how to do.

        Show
        davsclaus Claus Ibsen added a comment - Yes I think the goal should be to simplify from end user perspective. What we are aiming for is to let non-developers (or very inexperience developers) to orchestrates business flows. And that requires a DSL / endpoint syntax which is simple and intuitive. And convention over configuration. If that means a little flexibility must be sacrificed then so be it. The error messages returned should be more verbose trying to explain what may be wrong. And provide hints what to do to remedy that. Also given more thought I dont like the inner CamelContext. The CamelContext wasn't really designed to be embedded in a outer context. Also by default the context setup JMX, Cache, Type Converters and a lot of other resources which is not needed to be duplicated. That's why I suggested that the current routebox should be marked as subject to change (at the documentation page) as we just got started working on it. I think Ashwin have done a good start, but I am very open to improve and make it more flexible and easier to use in Camel 2.7 onwards. And from a tooling point of view, then the FuseSource Camel IDE may help as a vehicle to steer for simplicity, as it forces us to think of using the routebox without having to do any coding at all. Or to setup spring beans or any other weird stuff that a non-developer don't know how to do.
        Hide
        akarpe Ashwin Karpe added a comment -

        Hi Claus & Kristof,

        I do take onboard your recommendation to look at ways to avoid registries and spring beans/code. I will look into package scanning and using routeIds to select inner routes for payload routing. Using routeIds (not endpoint consumer names) could get rid of the dispatchMap as we have it now. Also package scanning could take care not needing to add routebuilders into the context.

        The inner Context creation or injection is optional. With a forkContext flag set to false, the current camel context will be reused. I agree that the CamelContext was not originally intended to be embeddable in another context. It is also possible to abuse this capability by nesting camel contexts within other nested camel contexts with the relationships not immediately clear from a JMX standpoint. Is this where you are coming from?

        I am happy to add the "subject to change" note on the routebox documentation page.

        Please let me know if you agree with my package scanning and routeId based routing recommendations. It will cut down URI options and be more intuitive.

        Cheers,

        Ashwin...

        Show
        akarpe Ashwin Karpe added a comment - Hi Claus & Kristof, I do take onboard your recommendation to look at ways to avoid registries and spring beans/code. I will look into package scanning and using routeIds to select inner routes for payload routing. Using routeIds (not endpoint consumer names) could get rid of the dispatchMap as we have it now. Also package scanning could take care not needing to add routebuilders into the context. The inner Context creation or injection is optional. With a forkContext flag set to false, the current camel context will be reused. I agree that the CamelContext was not originally intended to be embeddable in another context. It is also possible to abuse this capability by nesting camel contexts within other nested camel contexts with the relationships not immediately clear from a JMX standpoint. Is this where you are coming from? I am happy to add the "subject to change" note on the routebox documentation page. Please let me know if you agree with my package scanning and routeId based routing recommendations. It will cut down URI options and be more intuitive. Cheers, Ashwin...
        Hide
        akarpe Ashwin Karpe added a comment -

        Hi Claus & Kristof,

        I have added a warning to the documentation that the component and options are subject to change in future releases.

        Please let me know whether you like my recommendations in my previous comment to eliminate the dispatchMap and Strategy and instead use routeIds to indirect to routes.

        I am also planning to use package scanning to look up Routebuilders.

        Cheers,

        Ashwin...

        Show
        akarpe Ashwin Karpe added a comment - Hi Claus & Kristof, I have added a warning to the documentation that the component and options are subject to change in future releases. Please let me know whether you like my recommendations in my previous comment to eliminate the dispatchMap and Strategy and instead use routeIds to indirect to routes. I am also planning to use package scanning to look up Routebuilders. Cheers, Ashwin...

          People

          • Assignee:
            akarpe Ashwin Karpe
            Reporter:
            akarpe Ashwin Karpe
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development