3

I use Apache Camel module deployed inside ActiveMQ service.

Given I use Spring DSL and I have route definition ( implemented as routeContext) in the FilteringRouteContext.xml file (simplified):

<routeContext id="filteringRouteContext" xmlns="http://camel.apache.org/schema/spring">
    <route id="myFilteringRoute">
        <from uri="direct:filteringRoute"/>
        <idempotentConsumer messageIdRepositoryRef="idempotentRepository" skipDuplicate="false">
            <simple>${header.JMSType}</simple>
            <filter>
                <property>CamelDuplicateMessage</property>
                <stop/>
            </filter>
        </idempotentConsumer>
    </route>
</routeContext>

Next, I have configured Camel Context in other XML file (simplified):

<import resource="classpath:FilteringRouteContext.xml"/>

    <camelContext xmlns="http://camel.apache.org/schema/spring">

        <routeContextRef ref="filteringRouteContext"/>

        <route id="myRoute1">
            <from uri="activemq:topic:source1" />
            <to uri="direct:filteringRoute" />
            <to uri="activemq:topic:target1" />
        </route>

        <route id="myRoute2">
            <from uri="activemq:topic:source2" />
            <to uri="direct:filteringRoute" />
            <to uri="activemq:topic:target2" />
        </route>

        <route id="myRoute3">
            <from uri="activemq:topic:source3" />
            <to uri="direct:filteringRoute" />
            <to uri="activemq:topic:target3" />
        </route>

    </camelContext>

    <bean id="idempotentRepository"
          class="org.apache.camel.processor.idempotent.MemoryIdempotentRepository">
        <property name="cacheSize" value="10"/>
    </bean>

I would like to have shared route (with id=myFilteringRoute) from filteringRouteContext declared as, using IoC terminology, instance per dependency, so each route from single Camel Context (with id=myRoute1, myRoute2, myRoute3) should use it's own instance of that shared route (with id=myFilteringRoute), with separate internal state, bean instances, etc.

In other words, each route from Camel Context (with id=myRoute1, myRoute2, myRoute3) should not use the same instance of shared route (with id=myFilteringRoute), but should has its own completely separate instances (with completely separated internal states and bean instances )

Please consider that my shared route (with id=myFilteringRoute) may use more beans, which may have various scopes (singleton, prototype, request etc.).

My questions are: Can I achieve this goal using single Camel Context, or do I need to place my routes (with id=myRoute1, myRoute2, myRoute3) in separate Camel Contexts? What is the best solution of my problem?

Is there important performance impact If I use more than one Camel Contexts, and each context uses beans to communicate with ActiveMQ (org.apache.activemq.camel.component.ActiveMQComponent), or other beans that consume internal or system resources?

Or maybe it's better to resolve my problem by using Java DSL instead of Spring DSL?

Thank You.

sgnsajgon
  • 664
  • 2
  • 13
  • 56
  • I'm not sure that from the Camel point of view, a separate instance of a shared route makes much sense. What exactly are you trying to achieve by doing this? I can understand that having separate beans might be useful but I can't see the point of separate instances of the shared route. – matt helliwell Jul 04 '14 at 13:28
  • @matthelliwell I have Camel deployed inside ActiveMQ Service. My shared route contains `Idempotent Consumer EIP`, which in turn uses `Idempotent Repository` Java bean. My ActiveMQ Service hosts a lot of queues and topics, some of them are interconnected with the aid of my shared route (thus they are interconnected with employing Idempotent Consumer mechanism). I need that each idempotent topic-to-topic connection utilize it's own, dedicated Idempotent Repository. These repositories of unique message IDs cannot be shared between Idempotent channel-to-channel connections. – sgnsajgon Jul 04 '14 at 13:55
  • @matthelliwell I do not want to use a single `Idempotent Repository` for all idempotent connections, because in this case the size of internal collection ( I use `com.google.common.cache.Cache` ) would rapidly grow, thus slow down collection searching time. Besides each idempotent connections should work independently, regardless of other idempotent connections, so sharing states, message IDs in the same collection is fairly unsafe. – sgnsajgon Jul 04 '14 at 14:10
  • I see, thanks. I don't know the answer in that case! I would start by declaring my idempotent repository as a prototype bean and see if that at least gives me a separate instance in each of the routes. From your description is sounds like the idempotent repository and other beans need to be independent for each route but the route definition itself could still be shared. – matt helliwell Jul 04 '14 at 14:59
  • 1
    Thought about it a bit more and that's not going to work - you don't know how often Camel will look up the bean so you might end up with a new instance of the idempotent repo when you don't expect it. I think you are stuck with managing the repo yourself based on which route it is being called from. eg each route could set a property on the exchange with the route id. Your shared route could then use that property to use select the correct repo to use. – matt helliwell Jul 04 '14 at 15:08

2 Answers2

1

Current Camel Spring DSL definitions are created by JAXB when it unmarshals the xml. This definitions help camel runtime to to build up processors and assemble them to route the message. In this way routeContextRef has nothing do with the scopes you mentioned.

But for the beans which you created by Spring with bean element, you can define the scopes if you like, and camel just grab it from Spring Application Context if there is bean reference in the Camel Spring DSL.

To answer you question, routeContextRef just give a way to share the route definition instance across the camel context, if you don't want share their instance you need to create the camel context in different spring application context which could hold the different instance of routeContext.

Willem Jiang
  • 3,291
  • 1
  • 14
  • 14
1

The answer is that Camel doesn't not provide an automatic mechanism for doing what you want to do. All routes in your example will share the same instance of idempotentRepository. The only solution is to provide a level of indirection.

For example, extend AbstractJdbcMessageIdRepository to provide your own implementation. This could then include the routeid in the look up to determine whether a message had already been processed.

Or you could have a set of repositories and look up which one to use from within the main idempotentRepository based on the route id.

Whatever you do, you'll need write code that uses the the route id of the outermost route to distinguish the messages.

matt helliwell
  • 2,574
  • 16
  • 24