Is it possible to kick off a camel route using a java interface or bean?
I'd like to setup a spring bean (either via interface or bean class). that I can call to "start" a Route.
In this simple example when I call sayHello("world") from code I'd 开发者_如何学运维like it to route the return value of the sayHello method the endpoint that will write it out to a file.
Does anyone know if this is possible, or how to go about this? I know I can expose that same interface via CXF and make this work, but I really just want to call a method, not go through the trouble of sending a jms message or calling a webservice.
public interface Hello{
public String sayHello(String value);
}
from("bean:helloBean").to("file:/data/outbox?fileName=hello.txt");
You can use ProducerTemplate:
import org.apache.camel.Produce;
import org.apache.camel.ProducerTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Component
public class HelloImpl implements Hello {
@Produce(uri = "direct:start")
private ProducerTemplate template;
@Override
public Object sayHello(String value) throws ExecutionException, InterruptedException {
Future future = template.asyncSendBody(template.getDefaultEndpoint(), value);
return future.get();
}
}
and your camel route should looks like:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.mycompany.camel"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="direct:start"/>
<to uri="log:com.mycompany.camel?level=DEBUG"/>
</route>
</camelContext>
</beans>
Yes you can use proxy/remoting in Camel to do this.
Then when you invoke sayHello(value) the value is being routed to the chosen route. And the reply from the route is returned from the sayHello method.
See these links
- http://camel.apache.org/spring-remoting.html
- http://camel.apache.org/hiding-middleware.html
- http://camel.apache.org/using-camelproxy.html
Chapter 14 of the Camel in Action book covers this in much more detail: http://www.manning.com/ibsen
I need to look into Claus' answers, but for a quick and dirty UI I went with a different approach.
I was using Spring MVC 3.1.X and have an admin console for various items in my application. I wrote a Controller to display the routes and their statuses, as well as provided links to start and stop the routes as needed. Here's some of the code:
@Controller
public class CamelController {
private static final Log LOG = LogFactory.getLog(CamelController.class);
@Autowired
@Qualifier("myCamelContextID")
private CamelContext camelContext;
@RequestMapping(value = "/dashboard", method = RequestMethod.GET)
public String dashboard(Model model) {
if (LOG.isDebugEnabled()) {
LOG.debug("camel context is suspended : " + camelContext.isSuspended());
}
List<Route> routes = camelContext.getRoutes();
List<RouteStatus> routeStatuses = new ArrayList<RouteStatus>();
for (Route r : routes) {
RouteStatus rs = new RouteStatus();
rs.setId(r.getId());
rs.setServiceStatus(camelContext.getRouteStatus(r.getId()));
routeStatuses.add(rs);
}
model.addAttribute("routeStatuses", routeStatuses);
return "dashboard";
}
@RequestMapping(value = "/dashboard/{routeId}/start", method = RequestMethod.GET)
public String startRoute(@PathVariable String routeId) {
try {
camelContext.startRoute(routeId);
if (LOG.isDebugEnabled()) {
LOG.debug("camel context is starting route [" + routeId + "]");
}
} catch (Exception e) {
LOG.error("failed to start camel context [" + camelContext + "]");
}
return "redirect:/dashboard";
}
@RequestMapping(value = "/dashboard/{routeId}/stop", method = RequestMethod.GET)
public String stopRoute(@PathVariable String routeId) {
try {
camelContext.stopRoute(routeId);
if (LOG.isDebugEnabled()) {
LOG.debug("camel context is stopping route [" + routeId + "]");
}
} catch (Exception e) {
LOG.error("failed to stop camel context [" + camelContext + "]");
}
return "redirect:/dashboard";
}
}
}
There's a little POJO I made to go with it:
public class RouteStatus {
private String id;
private ServiceStatus serviceStatus;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public ServiceStatus getServiceStatus() {
return serviceStatus;
}
public void setServiceStatus(ServiceStatus serviceStatus) {
this.serviceStatus = serviceStatus;
}
}
None of the other answered worked for me, they all built and were valid, but the routes did not trigger.
This is the solution that I ended up using:
import org.apache.camel.Handler;
public class Hello{
@Produce(uri = "direct:start")
private ProducerTemplate producer;
@Handler
public void sayHello() {
producer.sendBody("hello")
}
}
from("timer:hubspotContacts?repeatCount=1").bean(Hello.class);
from("direct:start").to("log:hello");
- The timer component from the first route was the key missing part for me. With
repeatCount=1
it triggers exactly once, on startup and causes the bean method to be called. It also support a call rate or delay if you need the method to be called multiple times. - the
@Handler
annotations serves as a marker so the method name doesn't have to be made explicit in the route configuration - the direct component connects the producer with it's consumers
Since my routes were spring components using CamelConfiguration. I did following to use my interface in camel routes.
@Component
public class SomeRoute extends RouteBuilder {
@Autowired
private ApplicationContext applicationContext;
@Override
public void configure() throws Exception {
from("direct:someroute")
.bean(applicationContext.getBean(SomeInterface.class).getClass(), "someAbstractMethod")
.to("direct:otherroute");
}
}
This was very straight case, if you have multiple beans using same interface or abstract class you probably have to do some logic before using .getClass()
on bean.
精彩评论