akka-camel and Spring XML (newbie)

848 views
Skip to first unread message

nw31304

unread,
Oct 14, 2013, 4:24:49 AM10/14/13
to akka...@googlegroups.com

I am using akka-camel 2.2.1 and need to configure routes to and away from Consumer and Producer actors, respectively. I am currently defining routes and adding them to the internal Camel context within the CamelExtension programmatically like so:

camel.context.addRoutes(new RouteBuilder { 
    def configure() = {
      from("file:/tmp?include=whatever.*.log&noop=true&sendEmptyMessageWhenIdle=true")
        .split(body(classOf[String]).tokenize("\n"))
        .streaming()
        .to("seda:input-route")

      from("seda:update-route")
        .to("bean:db-update-bean?method=process")
  }})

I have an Actor that extends Consumer which reads from "seda:input-route" via its endPointUri, and another Actor that extends Producer that writes to "seda:update-route". The "db-update-bean" in defined in a Spring applicationContext.xml like so:


<bean
id="db-update-bean" class="nz.co.whatever.DBUpdate"> <constructor-arg ref="jdbcTemplate"/> <constructor-arg value="some_other_constructor_arg"/> </bean>


The Spring context is loaded and started in a supervisor Actor started by akka.Main. However (and understandably), Camel is unaware of this Spring context, and thus went to great lengths to inform me that it had no clue what the "db-update-bean" was:

2013-10-11 08:55:09,614 [SedaConsumer ] WARN Error processing exchange. Exchange[Message: 1378642997698,27684,true,57.000000,0.750000,97]. Caused by: 

[org.apache.camel.NoSuchBeanException - No bean could be found in the registry for: db-update-bean]

 

Of course, I could programmatically add the components to the akka-provided CamelContext, or else do something like this:


from("seda:update-route") .bean(new DBUpdate(jdbcTemplate, "gps_temp_status"), "process")


but I would rather use Spring to define beans. Clearly, the CamelExtension needs to use the Spring-defined CamelContext rather than creating one of its own.

Furthermore, and more importantly, I would like to externalize the definition of the Camel routes into the same applicationContext.xml within a <CamelContext/> tag. Accoring to articles such as https://weblogs.java.net/blog/manningpubs/archive/2013/02/13/akka-and-camel, it seems the way to do so is to instantiate a "camel-service" bean and inject the Spring-defined CamelContext as so:

<camel:camelContext id="camelContext">   
</camel:camelContext>

<akka:camel-service id="camelService">                             
    <akka:camel-context ref="camelContext" />
</akka:camel-service>


Here is where the wheels come off. According to Roland Kuhn's reply in Why spring integration doc for akka exists only for 1.3.1 but not for next versions, the akka-spring library is not included in Akka 2.2.1, and thus there is no Spring namespace handler for akka, and I'm unable to instantiate this camel-service bean. Though not for lack of trying. Or cursing.

And so (finally), the question: How does one define Camel routes in Spring XML whose endpoints can be used by Consumer or Producer Actors using akka-camel 2.2.1 without akka-spring? Does one instantiate a Factory bean that produces a CamelService with a CamelContext injected or some other such witchcraft? Secondarily (but related) how can I use Spring to instantiate beans to be referenced in camel routes if I am forced to define them via a RouteBuilder?

Akka Team

unread,
Oct 14, 2013, 5:04:39 AM10/14/13
to Akka User List
Hi David,

The Camel extension provided by akka-camel currently creates its own DefaultCamelContext and does not allow injection of an external one. Unfortunately DefaultCamelContext does not have a method that allows passing an external context apart from its constructor, so without changing the CamelExtension API you will not be able to inject an external one. You should file a ticket if you are interested in this feature.

-Endre


--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://akka.io/faq/
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/groups/opt_out.



--
Akka Team
Typesafe - The software stack for applications that scale
Blog: letitcrash.com
Twitter: @akkateam

√iktor Ҡlang

unread,
Oct 14, 2013, 5:12:42 AM10/14/13
to Akka User List
Or even better: A Pull Request! :)

Cheers,
Viktor Klang
Director of Engineering

Twitter: @viktorklang

Raymond Roestenburg

unread,
Oct 14, 2013, 6:13:38 PM10/14/13
to akka...@googlegroups.com
Have you tried setting the Registry on the DefaultCamelContext?


there is a setRegistry on DefaultCamelContext.

You might get this to work with creating an org.apache.camel.spring.spi.ApplicationContextRegistry
and setting this on the DefaultCamelContext with setRegistry.

That should make it possible to find your beans.



On Mon, Oct 14, 2013 at 10:24 AM, nw31304 <david.ni...@gmail.com> wrote:

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://akka.io/faq/
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at http://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/groups/opt_out.



--
Raymond Roestenburg

nw31304

unread,
Oct 14, 2013, 11:50:13 PM10/14/13
to akka...@googlegroups.com
Thanks.  Yep, that solved that part of the equation rather neatly. I had my Actor extend ApplicationContextAware and this handler did the trick:

  def setApplicationContext(applicationContext: ApplicationContext) {
    this.applicationContext = applicationContext
    camel.context.setRegistry(new ApplicationContextRegistry(applicationContext))
    camel.context.addRoutes(routeBuilder)
  }

Now I'll have to concoct some way of getting route definitions out of Spring XML and into Akka's Camel context.  I shudder to think of having to recompile a RouteBuilder every time I wanted to make a simple route change.

But in any event, thanks to your tip I'm farther down the road.

That's the good news.  The bad news is that I now feel morally obligated to buy your book.

--Dave

Raymond Roestenburg

unread,
Oct 15, 2013, 3:55:31 AM10/15/13
to akka...@googlegroups.com
On Tue, Oct 15, 2013 at 5:50 AM, nw31304 <david.ni...@gmail.com> wrote:
Thanks.  Yep, that solved that part of the equation rather neatly. I had my Actor extend ApplicationContextAware and this handler did the trick:

  def setApplicationContext(applicationContext: ApplicationContext) {
    this.applicationContext = applicationContext
    camel.context.setRegistry(new ApplicationContextRegistry(applicationContext))
    camel.context.addRoutes(routeBuilder)
  }


Cool.
 
Now I'll have to concoct some way of getting route definitions out of Spring XML and into Akka's Camel context.  I shudder to think of having to recompile a RouteBuilder every time I wanted to make a simple route change.
I shudder at the thought of Spring XML, so to each his own! ;-) 
 
But in any event, thanks to your tip I'm farther down the road.
 
That's the good news.  The bad news is that I now feel morally obligated to buy your book.

LOL :-)

Matteo Cusmai

unread,
Dec 14, 2013, 3:45:01 AM12/14/13
to akka...@googlegroups.com
Hi all,
I have an issue similar to your.

I would like to define my camel route using a spring xml, but I have found out that akka camel extension uses DefaultCamelContext.

I am trying your solution, but without success, where i am wronging?

I have an xml file like this:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

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

        <route>
            <from uri="rabbitmq://localhost/SIM_DATA?exchangeType=topic&amp;queue=rewardAquire1&amp;username=guest&amp;password=guest&amp;routingKey=S1111BBB&amp;autoDelete=false&amp;threadPoolSize=1" />
            <to uri="direct:consumer1" />
        </route>

    </camelContext>

</beans>
A consumer like this

public class CamelConsumer extends UntypedConsumerActor {

    private String _uri;

    private LoggingAdapter log = Logging.getLogger(getContext().system(), this);

    @Override
    public void preStart() {
        log.debug( "preStart" );
        super.preStart();
    }

    public CamelConsumer() {
        _uri = "direct:consumer1";
    }

    @Override
    public String getEndpointUri() {
        return _uri;
    }

    @Override
    public void onReceive(Object o) throws Exception {
        if(o instanceof CamelMessage){
            CamelMessage camelMessage = (CamelMessage) o;
            String message = camelMessage.getBodyAs(String.class, getCamelContext() );
            transformer.tell(message, getSelf());
        }
        else unhandled( o );
    }


}

finally a main like this:

public class Main {

    public static void main(String[] args) throws Exception{

        ClassPathXmlApplicationContext appctx = new ClassPathXmlApplicationContext("META-INF/camel-context.xml");

        ActorSystem _system = ActorSystem.create("camel");
        Camel camel = CamelExtension.get(_system);
        camel.context().setRegistry( new ApplicationContextRegistry( appctx) );

        ActorRef ref = _system.actorOf( Props.create( SensorSupervisorActor.class ), "sensor" );

        Thread.sleep( 600000 );

        _system.shutdown();

    }


}


The consumer actor is create inside the supervisor, I omit it for sake of simplicity.

The error is the following:
org.apache.camel.component.direct.DirectConsumerNotAvailableException: No consumers available on endpoint: Endpoint[direct://consumer1]. Exchange[Message: <?xml version="1.0" encoding="utf-16"?>

Can you suggest me the right solution?
Thanks in advance,
Matteo.

nw31304

unread,
Mar 4, 2014, 6:33:23 PM3/4/14
to akka...@googlegroups.com
I recently stumbled across the external route definition facility introduced in Camel 2.6: https://camel.apache.org/loading-routes-from-xml-files.html.  This solved my problem perfectly well, as I simply load the route definitions and add them to the DefaultContext provided by akka.  This at least allows me to externalize the routes without the need for modifying the source of a RouteBuilder instance.

Björn Antonsson

unread,
Mar 6, 2014, 5:35:53 AM3/6/14
to akka...@googlegroups.com
Hi David,

On 5 March 2014 at 06:50:56, nw31304 (david.ni...@gmail.com) wrote:

I recently stumbled across the external route definition facility introduced in Camel 2.6: https://camel.apache.org/loading-routes-from-xml-files.html.  This solved my problem perfectly well, as I simply load the route definitions and add them to the DefaultContext provided by akka.  This at least allows me to externalize the routes without the need for modifying the source of a RouteBuilder instance.


That’s a great tip. Thanks for sharing.


B/


-- 
Björn Antonsson
Typesafe – Reactive Apps on the JVM
twitter: @bantonsson

Reply all
Reply to author
Forward
0 new messages