I have multiple route builders within my project,
I want to define a single interceptSendToEndpoint that will affect all of the defined routes
For Example:
Public Route1 extends RouteBuilder {
public void configure() throws Exception {
from("direct:endpoint1").toD("http:\\someAddress1");
}
}
Public Route2 extends RouteBuilder {
public void configure() throws Exception {
from("direct:endpoint2").toD("http:\\someAddress2");
}
}
what I want to do here is to define a central interceptSendToEndpoint that will automatically capture all traffic sent to the camel HTTP component for all routes.
public class InterceptRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
interceptSendToEndpoint("http:*")
.process(exchange -> System.out.println("Hi from intercept"));
}
}
However due to how camel injects the intercept scope, I'm unable to do this easily,
Is there a way to tell the camel context that this intercept is for all defined routes within the context?
Note: I'm using camel 3.0.0
Camel team works for similar task in there (https://issues.apache.org/jira/projects/CAMEL/issues/CAMEL-16757?filter=allissues&orderby=cf%5B12310200%5D+ASC%2C+priority+DESC%2C+updated+DESC).
Create an abstract base class and define your in there and then extends it in main route
public abstract class BaseRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
interceptSendToEndpoint("http:*")
.process(exchange -> System.out.println("Hi from intercept"));
}
}
public class TaskRoute2 extends BaseRoute {
#Override
public void configure() throws Exception {
super.configure();
from("direct:endpoint2").toD("http:\\someAddress2");
}
}
public class TaskRoute2 extends BaseRoute {
#Override
public void configure() throws Exception {
super.configure();
from("direct:endpoint2").toD("http:\\someAddress2");
}
}
Related
I am looking for a way to add global exception handling on all routes generated by multiple RouteTemplates. I have tried the following way but the onException block is not getting added to the routes.
Can you help me understand what I am doing wrong?
Thanks
public abstract class BaseRouteBuilder extends RouteBuilder {
#Override
public void configure(){
this.onException(IllegalStateException.class)
.log("global onException")
.maximumRedeliveries(2)
.redeliveryDelay(100)
.logStackTrace(true)
.to("direct:retryChannel");
}
}
public static class SampleRouteTemplate extends BaseRouteBuilder {
#Override
public void configure() {
super.configure();
this.routeTemplate("myTemplate")
.templateParameter("parameter1")
.from("direct:start")
.setHeader("parameter1", constant("value1"))
.log("RouteCompleted");
}
}
Try to extract a separate method for route, e.g. configureRoute() and call it in parent class in configure() method. Also make a child class non-static.
public abstract class BaseRouteBuilder extends RouteBuilder {
#Override
public final void configure(){
onException(IllegalStateException.class)
.log("global onException")
.maximumRedeliveries(2)
.redeliveryDelay(100)
.logStackTrace(true)
.to("direct:retryChannel");
configureRoute();
}
public abstract void configureRoute();
}
public class SampleRouteTemplate extends BaseRouteBuilder {
#Override
public void configureRoute() {
this.routeTemplate("myTemplate")
.templateParameter("parameter1")
.from("direct:start")
.setHeader("parameter1", constant("value1"))
.log("RouteCompleted");
}
}
}
How to inject a dependency inside a Web Socket handler:
public class WebsocketHandler extends AbstractWebSocketHandler {
#Autowired
GreetingMap greetingMap;
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
// NullPointerException here
String greeting = greetingMap.getSampleGreetings().get("hello") + " " + message.getPayload();
session.sendMessage(new TextMessage(greeting));
}
}
The code above throws NullPointerException
What could be missing here?
Try using dependency injection with constructor instead #Autowired:
private GreetingMap greetingMap;
public WebsocketHandler(GreetingMap greetingMap){
this.greetingMap = greetingMap
}
I think the problem is that SocketHanler is not a spring bean, but is created by "new" operator:
#Configuration
#EnableWebSocket
public class WebSocketsConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketHandler(), "/socket")
.setAllowedOrigins("*");
}
}
What you need to do in this case, is to inject your dependency into WebSocketConfiguration and pass it manually to SocketHandler constructor:
#Configuration
#EnableWebSocket
public class WebSocketsConfiguration implements WebSocketConfigurer {
#Autowired
MyDependency myDependency;
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new SocketHandler(myDependency), "/socket")
.setAllowedOrigins("*");
}
}
And in the handler, you need to add constructor that receives the dependency
public class SocketHandler extends AbstractWebSocketHandler {
private MyDependency myDependency;
public SocketHandler(MyDependency myDependency) {
this.myDependency = myDependency;
}
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
System.out.println(String.format("Message from client: %s", message));
}
}
I've implemented a starter that configures Swagger the way I like. In addition, I'd like to redirect every call to the app's root URL (e.g. localhost:8080) to /swagger-ui.html.
Therefore, I added an own AbstractEndpoint which is instantiated in the #Configuration class as follows:
#Configuration
#Profile("swagger")
#EnableSwagger2
public class SwaggerConfig {
...
#Bean
public RootEndpoint rootEndpoint() {
return new RootEndpoint();
}
#Bean
#ConditionalOnBean(RootEndpoint.class)
#ConditionalOnEnabledEndpoint("root")
public RootMvcEndpoint rootMvcEndpoint(RootEndpoint rootEndpoint) {
return new RootMvcEndpoint(rootEndpoint);
}
}
The respective classes look like this:
public class RootEndpoint extends AbstractEndpoint<String> {
public RootEndpoint() {
super("root");
}
#Override
public String invoke() {
return ""; // real calls shall be handled by RootMvcEndpoint
}
}
and
public class RootMvcEndpoint extends EndpointMvcAdapter {
public RootMvcEndpoint(RootEndpoint delegate) {
super(delegate);
}
#RequestMapping(method = {RequestMethod.GET}, produces = { "*/*" })
public void redirect(HttpServletResponse httpServletResponse) throws IOException {
httpServletResponse.sendRedirect("/swagger-ui.html");
}
}
As stated in public RootEndpoint(), the custom Endpoint is bound to /root. Unfortunately, I can't specify super(""); or super("/"); as those values throw an exception (Id must only contains letters, numbers and '_').
How can I achieve having a custom Endpoint listening to the root URL in a starter using #Configuration files to instantiate beans?
I solved it with an easier approach by adding a WebMvcConfigurerAdapter bean in the #Configuration:
#Bean
public WebMvcConfigurerAdapter redirectToSwagger() {
return new WebMvcConfigurerAdapter() {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("").setViewName("redirect:/swagger-ui.html");
}
};
}
I'm trying to send a message to an async route but it's not working.
I have just created a projeto on github to simulate the problem
#SpringBootApplication
public class SedaQueueApplication implements CommandLineRunner {
#Autowired
#EndpointInject(uri = "direct://direct-queue")
ProducerTemplate producerTemplate;
public static void main(String[] args) {
SpringApplication.run(SedaQueueApplication.class, args);
}
#Override
public void run(String... strings) throws Exception {
producerTemplate.sendBody("Teste Direct - Async");
}
#Component
class Router extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct://direct-queue").routeId("toAsync").to("seda://async-queue?size=100");
from("seda://async-queue").routeId("toLog").log("${body}");
}
}
you have two routes. In one of the route you have specified seda://async-queue and in other seda://async-queue?size=100 make this consistent i.e. add size attribute to first route or remove from second. It will work like a peach.
The reason for this is (Not sure if it is a bug in camel code), In SedaComponent::getOrCreateQueue they are comparing for size attribute also. Hence you get an exception if the size attribute if present and doeśn't match.
Hope that helps.
public class ProcessSchedulerServlet implements javax.servlet.Servlet {
Timer timer=new Timer();
#Override
public void init(ServletConfig arg0) throws ServletException {
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
LogProcessorService logProcessorService=new LogProcessorServiceImpl();
logProcessorService.processPageRequestsLogs();
}
}, 60*1000, 120*1000);
}
This is ugly and it doesn't work, anyway. The LogProcessorServiceImpl has properties with #Autowired annotation. These properties are not autowired when this code runs. This may be expected.
The real question is: how to make this run() method work. It seems to me that Spring wants the logProcessorService to be autowired to have properties within LogProcessorServiceImpl autowired, as well.
=== SCENARIO 1 ==============================================================
public void run() {
final LogProcessorService logProcessorService=null;
WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getAutowireCapableBeanFactory().autowireBean(logProcessorService);
logProcessorService.processPageRequestsLogs();
}
Result: compile time error: Cannot refer to a non-final variable arg0 inside an inner class defined in a different method
=== SCENARIO 2 ==============================================================
#Autowired
LogProcessorService logProcessorService;
public void run() {
logProcessorService.processPageRequestsLogs();
}
Result: run time error: logProcessorService is null;
==== SOLUTION (from Boris) ======================================================
public class ProcessSchedulerServlet implements javax.servlet.Servlet {
Timer timer=new Timer();
#Autowired
LogProcessorService logProcessorService;
#Override
public void init(ServletConfig arg0) throws ServletException {
final AutowireCapableBeanFactory autowireCapableBeanFactory=WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getAutowireCapableBeanFactory();
autowireCapableBeanFactory.autowireBean(this);
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
logProcessorService.processPageRequestsLogs();
}
}, 60*1000, 120*1000);
}
Why bother with servlets and Timer class if Spring has a built in scheduling support:
#Service
public class LogProcessorService {
#Scheduled(fixedRate=120*1000, initialDelay=60*1000)
public void processPageRequestsLogs() {
//...
}
}
That's it! No timers, runnables and servlets. Note: initialDelay was introduced in Spring 3.2 M1 (see SPR-7022).