Grokbase Groups Camel users June 2008
FAQ
I'm embedding camel in ActiveMQ. I start activemq, which reads
$ACTIVEMQ_HOME/conf/activemq.xml . I want to use the java DSL for my routes,
using the <package> tag in activemq.xml to allow them to be discovered from
the classpath. The RouteBuilders defined there use a Registry based on the
ApplicationContext defined by the activemq.xml file, whereas I want them to
see a registry built out of an ApplicationContext that already exists,
defined by my code and spring xml files in my jars.

It looks like the activemq.xml parsing of the camelContext element is
handled by org.apache.camel.spring.handler.CamelNamespaceHandler which uses
a org.apache.camel.spring.CamelContextFactoryBean. This is
ApplicationContextAware and uses the injected context as the basis for a
SpringCamelContext. This is used in installRoutes(), which calls addRoutes()
on the discovered RouteBuilders, whereupon each RouteBuilder's context is
set to the SpringCamelContext from CamelContextFactoryBean.

So it seems what I need to do is to tell the CamelContextFactoryBean to use
the ApplicationContext I want. An equivalent way is to start activemq and
have the application context it constructs from the activemq.xml use mine as
a parent. It looks like I could do that by overriding
createApplicationContext() in XBeanBrokerFactory to call
ResourceXmlApplicationContext(resource, parent) and having my subclass
override the handling of xbean: uri's. Is this overkill?



--
View this message in context: http://www.nabble.com/Controlling-the-ApplicationContext-used-by-a-RouteBuilder-tp17594236s22882p17594236.html
Sent from the Camel - Users mailing list archive at Nabble.com.

Search Discussions

  • James Strachan at Jun 2, 2008 at 6:51 am
    2008/6/2 bwtaylor <bryan_w_taylor@yahoo.com>:
    I'm embedding camel in ActiveMQ. I start activemq, which reads
    $ACTIVEMQ_HOME/conf/activemq.xml . I want to use the java DSL for my routes,
    using the <package> tag in activemq.xml to allow them to be discovered from
    the classpath. The RouteBuilders defined there use a Registry based on the
    ApplicationContext defined by the activemq.xml file, whereas I want them to
    see a registry built out of an ApplicationContext that already exists,
    defined by my code and spring xml files in my jars.
    Why not put the <camelContext ...> <package> elements into your other
    spring XML file? (i.e. remove the package element from the
    activemq.xml)

    --
    James
    -------
    http://macstrac.blogspot.com/

    Open Source Integration
    http://open.iona.com
  • Bwtaylor at Jun 3, 2008 at 12:28 am
    I'd still need the activemq.xml to start my ApplicationContext, as I want
    it's lifecycle coupled to that of ActiveMQ and effectively embedded within
    ActiveMQ. I suppose I could do by simply putting a factory bean for it in
    activemq.xml. I liked the idea of my AC being the parent of the one created
    by ActiveMQ, so that you still could put xml routes in activemq.xml with the
    combined registry. I already tried it by subclassing
    XBeanBrokerFactory.createApplicationContext(String uri) to call my parent
    locator class followed by new ResourceXmlApplicationContext(resource,
    parent). This solves my problem but isn't generalizable because I have to
    import my specific locator. It's not particularly elegant, but it works.

    Interestingly, ResourceXmlApplicationContext does implement
    ConfigurableApplicationContext which gives the setParent() method, so there
    might be a way to combine our ideas. CamelContextFactoryBean could support
    setParentApplicationContext() injected from the activmq.xml Context and then
    it could use the combined (adopted?) AC if the child can be cast to
    ConfigurableApplicationContext and a parent exists.

    Actually, ConfigurableApplicationContext might be better a better interface
    to use generally, since your implementation already conforms to it, and it
    also allows you to add application listeners, to add both flavors of post
    processors, to refresh, and to add shutdown hooks. Application listeners
    and refresh both seem very valueable. If this interests you, let me know, as
    I'd be willing to send in patches.


    James.Strachan wrote:
    Why not put the <camelContext ...> <package> elements into your other
    spring XML file? (i.e. remove the package element from the activemq.xml)
    --
    View this message in context: http://www.nabble.com/Controlling-the-ApplicationContext-used-by-a-RouteBuilder-tp17594236s22882p17613713.html
    Sent from the Camel - Users mailing list archive at Nabble.com.
  • James Strachan at Jun 3, 2008 at 6:08 am
    2008/6/3 bwtaylor <bryan_w_taylor@yahoo.com>:
    I'd still need the activemq.xml to start my ApplicationContext, as I want
    it's lifecycle coupled to that of ActiveMQ and effectively embedded within
    ActiveMQ. I suppose I could do by simply putting a factory bean for it in
    activemq.xml.
    You can also add <include/> tags to include other spring.xml files
    inside the activemq.xml if you want. Plus if you need it you can split
    routes between different spring XML files. (e.g. have a camelContext
    in each spring.xml defining some routes).
    I liked the idea of my AC being the parent of the one created
    by ActiveMQ, so that you still could put xml routes in activemq.xml with the
    combined registry.
    Note that the activemq.xml is just a spring AC; you can create them
    however you wish without the need to create new factory beans or hack
    XBean or Spring or whatever.

    e.g. just run the <broker> inside any spring.xml / AC you like.

    For the dependency stuff, just make sure you use the depends attribute
    on the beans that define the JMS ConnectionFactory etc.


    I already tried it by subclassing
    XBeanBrokerFactory.createApplicationContext(String uri) to call my parent
    locator class followed by new ResourceXmlApplicationContext(resource,
    parent). This solves my problem but isn't generalizable because I have to
    import my specific locator. It's not particularly elegant, but it works.

    Interestingly, ResourceXmlApplicationContext does implement
    ConfigurableApplicationContext which gives the setParent() method, so there
    might be a way to combine our ideas. CamelContextFactoryBean could support
    setParentApplicationContext() injected from the activmq.xml Context and then
    it could use the combined (adopted?) AC if the child can be cast to
    ConfigurableApplicationContext and a parent exists.

    Actually, ConfigurableApplicationContext might be better a better interface
    to use generally, since your implementation already conforms to it, and it
    also allows you to add application listeners, to add both flavors of post
    processors, to refresh, and to add shutdown hooks. Application listeners
    and refresh both seem very valueable. If this interests you, let me know, as
    I'd be willing to send in patches.
    FWIW we're generally trying to move away from hacking XBean and
    relying more on the standard Spring stuff now (and the Spring 2
    namespace handler stuff) so I'd rather a solution that works with
    normal Spring

    --
    James
    -------
    http://macstrac.blogspot.com/

    Open Source Integration
    http://open.iona.com
  • Bwtaylor at Jun 4, 2008 at 9:18 pm

    James.Strachan wrote:

    You can also add <include/> tags to include other spring.xml files
    inside the activemq.xml if you want. Plus if you need it you can split
    routes between different spring XML files. (e.g. have a camelContext
    in each spring.xml defining some routes).
    <include/> tags are the first approach I tried. This is just a mechanism to
    split up activemq.xml for manageability. The problem is that not every
    ApplicationContext is formed by loading from XML files. We use a mix of java
    and xml to create the AC we want to use. See below for more on non-XML AC
    configuration.


    James.Strachan wrote:
    Note that the activemq.xml is just a spring AC; you can create them
    however you wish without the need to create new factory beans or hack
    XBean or Spring or whatever.

    e.g. just run the <broker> inside any spring.xml / AC you like.
    Sure. But then you don't get the nice activemq admin scripts and startup
    model. We could always start everything ourselves and effectively embed
    activemq in our app rather than the other way around.


    James.Strachan wrote:
    FWIW we're generally trying to move away from hacking XBean and
    relying more on the standard Spring stuff now (and the Spring 2
    namespace handler stuff) so I'd rather a solution that works with
    normal Spring
    I guess it depends on what you mean by "normal" spring. Parent/child
    relationships between ACs are pretty powerful and I'd call them normal. Lots
    of people are using mechanisms besides XML to configure their ACs now.
    I think you'll see non XML mechanisms for AC configuration becoming much
    more common.
    The grails/groovy spring builder comes to mind, as does the spring java
    config project. Parent/child
    contexts are a natural way to mix AC's together that are defined in
    different ways. In
    some sense, by only allowing XML AC's you are fighting against the full
    power of Spring.

    I'm surprised you didn't like adding
    CamelContextFactoryBean.setParentApplicationContext()
    This would let you inject your parent using nothing more than simple XML.
    You
    could just add
    <property name="parentApplicationContext" ref="myCustomApplicationContext"
    />
    or leave it blank to match current behavior. No xbean hacking is involved.


    --
    View this message in context: http://www.nabble.com/Controlling-the-ApplicationContext-used-by-a-RouteBuilder-tp17594236s22882p17656860.html
    Sent from the Camel - Users mailing list archive at Nabble.com.
  • James Strachan at Jun 6, 2008 at 2:07 pm
    2008/6/4 bwtaylor <bryan_w_taylor@yahoo.com>:

    James.Strachan wrote:
    You can also add <include/> tags to include other spring.xml files
    inside the activemq.xml if you want. Plus if you need it you can split
    routes between different spring XML files. (e.g. have a camelContext
    in each spring.xml defining some routes).
    <include/> tags are the first approach I tried. This is just a mechanism to
    split up activemq.xml for manageability. The problem is that not every
    ApplicationContext is formed by loading from XML files. We use a mix of java
    and xml to create the AC we want to use. See below for more on non-XML AC
    configuration.


    James.Strachan wrote:
    Note that the activemq.xml is just a spring AC; you can create them
    however you wish without the need to create new factory beans or hack
    XBean or Spring or whatever.

    e.g. just run the <broker> inside any spring.xml / AC you like.
    Sure. But then you don't get the nice activemq admin scripts and startup
    model. We could always start everything ourselves and effectively embed
    activemq in our app rather than the other way around.


    James.Strachan wrote:
    FWIW we're generally trying to move away from hacking XBean and
    relying more on the standard Spring stuff now (and the Spring 2
    namespace handler stuff) so I'd rather a solution that works with
    normal Spring
    I guess it depends on what you mean by "normal" spring. Parent/child
    relationships between ACs are pretty powerful and I'd call them normal. Lots
    of people are using mechanisms besides XML to configure their ACs now.
    I think you'll see non XML mechanisms for AC configuration becoming much
    more common.
    The grails/groovy spring builder comes to mind, as does the spring java
    config project. Parent/child
    contexts are a natural way to mix AC's together that are defined in
    different ways. In
    some sense, by only allowing XML AC's you are fighting against the full
    power of Spring.

    I'm surprised you didn't like adding
    CamelContextFactoryBean.setParentApplicationContext()
    This would let you inject your parent using nothing more than simple XML.
    You
    could just add
    <property name="parentApplicationContext" ref="myCustomApplicationContext"
    />
    or leave it blank to match current behavior. No xbean hacking is involved.
    Sorry I misunderstood; I thought you meant hacking XBean :)

    Oh sure, specifying the parent applicationContext on the camel context
    factory bean is fine. I just wanted to check what you wanted the
    CamelContextFactoryBean to do with the parent applicationContext its
    given?

    BTW I'm still not quite sure why you couldn't just have this inside activemq.xml

    <include uri="myroutes.xml"/>

    then in myroutes.xml have a <camelContext> and whatever other routes you want?

    --
    James
    -------
    http://macstrac.blogspot.com/

    Open Source Integration
    http://open.iona.com
  • Bwtaylor at Jun 7, 2008 at 5:36 am
    I feel silly. I just came up with a way to do what I want in pure spring. The
    solution I was proposing with CamelContextFactoryBean, doesn't actually use
    any aspect of the Camel code. You can attach an AC to a new parent in
    standalone code, like so:

    -------------------------------------
    package utility.spring;

    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.context.ConfigurableApplicationContext;

    public class ParentInjector implements ApplicationContextAware {

    ConfigurableApplicationContext applicationContext;
    ApplicationContext parentApplicationContext;

    public void setApplicationContext(ApplicationContext applicationContext)
    throws BeansException {
    if ( (ConfigurableApplicationContext.class).isAssignableFrom(
    applicationContext.getClass() ) ) {
    this.applicationContext =
    (ConfigurableApplicationContext)applicationContext;
    attachParent();
    } else {
    throw new BeanNotOfRequiredTypeException("<ApplicationContext>",
    ConfigurableApplicationContext.class, applicationContext.getClass());
    }
    }

    public void setParentApplicationContext(ApplicationContext
    parentApplicationContext) throws BeansException {
    this.parentApplicationContext = parentApplicationContext;
    attachParent();
    }

    private void attachParent() {
    if (applicationContext != null && parentApplicationContext !=null)
    applicationContext.setParent(parentApplicationContext);
    }

    }
    -------------------------------------

    Then in ANY xml based config file, you can add a bean like so

    -------------------------------------
    <bean class="utility.spring.ParentInjector">
    <property name="parentApplicationContext">
    <bean class="utility.spring.MyFavSpringLocatorOrFactory"
    factory-method="getApplicationContext">
    <constructor-arg value="theNameOfMyContext"/>
    </bean>
    </property>
    </bean>
    -------------------------------------

    Where utility.spring.MyFavSpringLocatorOrFactory is a class that locates,
    builds, borrows, or steals an ApplicationContext object in any fashion it
    pleases, xml based or not.


    James.Strachan wrote:
    BTW I'm still not quite sure why you couldn't just have this inside
    activemq.xml
    <include uri="myroutes.xml"/>
    then in myroutes.xml have a <camelContext> and whatever other routes you
    want?
    For example, suppose I want to make a message enricher, and my route will be
    something like:
    from(activemq:inbox).to("enricher").to(activemq:outbox);

    Suppose the "enricher" bean is a camel Processor that will delegate to a
    bunch of preexisting beans, like my data access layer, defined in some
    ApplicationContext that is not 100% XML based. Maybe we used the grails
    spring builder or spring's java config for all or part of it. Maybe I have
    mostly XML, except that I do a little bit with java code that uses Spring
    APIs to manipulate the AC before it's offered up for consumption. Maybe I'm
    constructing my AC dynamically from a registry using mule's
    GalaxyApplicationContext.

    I could port the "enricher" bean to an XML config, but I'd have to do so for
    it and all it's bean dependencies, which might be hard to accomplish. If I
    succeed, then I'm double maintaining them, violating DRY. It might not even
    be possible to know what the dependencies are: if I use something like a
    strategy pattern with <property name="strategy"
    value="${strategy.impl.bean.name}" , a plugin system, or a registry
    indirection like GalaxyApplicationContext, they could be changing without my
    control.
    --
    View this message in context: http://www.nabble.com/Controlling-the-ApplicationContext-used-by-a-RouteBuilder-tp17594236s22882p17705503.html
    Sent from the Camel - Users mailing list archive at Nabble.com.
  • Bwtaylor at Jun 9, 2008 at 6:58 am
    I had to fix one little issue, by calling setParentBeanFactory also, as
    shown... and logged a message.

    private void attachParent() {
    if (applicationContext != null && parentApplicationContext !=null) {
    applicationContext.setParent(parentApplicationContext);

    applicationContext.getBeanFactory().setParentBeanFactory(parentApplicationContext);
    log.info("attached parentApplicationContext
    "+parentApplicationContext.getDisplayName()+" to
    "+applicationContext.getDisplayName());
    }
    }

    --
    View this message in context: http://www.nabble.com/Controlling-the-ApplicationContext-used-by-a-RouteBuilder-tp17594236s22882p17727409.html
    Sent from the Camel - Users mailing list archive at Nabble.com.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupusers @
categoriescamel
postedJun 2, '08 at 5:30a
activeJun 9, '08 at 6:58a
posts8
users2
websitecamel.apache.org

2 users in discussion

Bwtaylor: 5 posts James Strachan: 3 posts

People

Translate

site design / logo © 2022 Grokbase