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?
--
>>>>>>>>>> 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.
--
>>>>>>>>>> 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.
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.
<beans xmlns="http://www.springframework.org/schema/beans"A consumer like this
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&queue=rewardAquire1&username=guest&password=guest&routingKey=S1111BBB&autoDelete=false&threadPoolSize=1" />
<to uri="direct:consumer1" />
</route>
</camelContext>
</beans>
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 );
}
}
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();
}
}
org.apache.camel.component.direct.DirectConsumerNotAvailableException: No consumers available on endpoint: Endpoint[direct://consumer1]. Exchange[Message: <?xml version="1.0" encoding="utf-16"?>
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/