I'm trying to find all routes associated with a camel context?
I can't find the camel exchange getContext() data sheets so I know what methods can be called?
I have a dynamic route builder, drop a config file and the route gets created.
I need to create the routes in registry, as not started, and use a JGroups/Controlbus route that controls who is the active route. But I can't figure out how to get all routes associated with a camel context? if you can shed some light on this, I'd really be in your dept. thanks in advance.
This is what I have but I can't get to work, found on stacktrace.
#Override
public void process(Exchange exchange) throws Exception {
List<ProcessorDefinition<?>> outputProcessorDefs = exchange.getContext().getRouteDefinition("[routeId]").getOutputs();
for ( ProcessorDefinition rte : outputProcessorDefs ) {
log.info("ROUTES: " + rte);
}
}
thanks to a question answered by Claus How to find all Endpoints of route (Apache Camel, Java)
I was able to locate some info and found another simpler way to do this.
public void process(Exchange exchange) throws Exception {
List<Route> routeList = exchange.getContext().getRoutes();
for ( Route rte : routeList ) {
log.info("ROUTES: " + rte.getId());
}
This is my test for JGroups ControlBus management made possible by getRoutes() for dynamic route creation.
public class EndpointControlBusFileRouteBuilder extends RouteBuilder {
private static final Logger log = LoggerFactory.getLogger(EndpointControlBusFileRouteBuilder.class);
private String routeId;
private String ClusterId;
public EndpointControlBusFileRouteBuilder(String routeId) {
this.routeId = routeId;
}
#Override
public void configure() throws Exception {
log.info("*** JGroups routeCluster - RouteId : " + routeId + " ***");
ClusterId = routeId + ".JGroups";
from("jgroups:" + ClusterId + "?enableViewMessages=true&channelProperties=etc/jgroups.xml")
.autoStartup(true)
.routeId(ClusterId)
.filter(dropNonCoordinatorViews())
.threads().delay(delayIfContextNotStarted(SECONDS.toMillis(5))) // run in separated and delayed thread. Delay only if the context hasn't been started already.
.log("Starting JGroups JChannel Routes Consumer!!!!!!!!!!!!!!!!!!!!!")
.to("controlbus:route?routeId=" + routeId + "&action=start&async=true");
}
}
public class EndpointControlBusProcessor implements Processor {
private String routeId = "";
private static final Logger log = LoggerFactory.getLogger(EndpointControlBusProcessor.class);
#Override
public void process(Exchange exchange) throws Exception {
List<Route> routeList = exchange.getContext().getRoutes();
ProducerTemplate template = exchange.getContext().createProducerTemplate();
for ( Route rte : routeList ) {
routeId = rte.getId();
// log.info("ROUTES: " + routeId);
// ServiceStatus routeStatus = exchange.getContext().getRouteStatus(routeId);
// log.info("Route " + routeId + " Status: " + routeStatus);
String status = template.requestBody("controlbus:route?routeId=" + routeId + "&action=status", null, String.class);
log.info("Controlbus Route Status: " + status + " for route: " + routeId);
if ( (null == status) || status.equalsIgnoreCase("Stopped") ) {
exchange.getContext().addRoutes(new EndpointControlBusFileRouteBuilder(routeId));
// status = template.requestBody("controlbus:route?routeId=" + routeId + "&action=status", null, String.class);
// log.info("Controlbus Route Status: " + status + " for route: " + routeId);
} else {
log.info("Route " + routeId + " already started");
}
}
template.stop();
}
}
Related
I have a spring batch process which does data reading from the database and writing to file. Basically, the scenario is, that the user can send a request and the job will start and execute the process. But the issue is if the user sends the request 5 times there will be 5 different spring jobs started and running. But those are duplicates. So is there a way that we can avoid or block creating duplicate spring jobs?
You can create a JobExecutionListener that stops the current job execution if another one is already running and configure your job with that listener...
public class SingleExecutionJobListener implements JobExecutionListener {
private static String MATCH_ALL_PATTERN = ".*";
#Autowired
private JobExplorer jobExplorer;
#Autowired
private JobRegistry jobRegistry;
private String jobNamePattern = MATCH_ALL_PATTERN;
#Override
public void beforeJob(JobExecution jobExecution) {
Collection<String> jobNames = jobRegistry.getJobNames();
for (String jobName : jobNames) {
if (jobName.matches(StringUtils.defaultIfBlank(jobNamePattern, MATCH_ALL_PATTERN))) {
Set<JobExecution> jobExecutions = jobExplorer.findRunningJobExecutions(jobName);
if (CollectionUtils.isNotEmpty(jobExecutions)) {
for (JobExecution execution : jobExecutions) {
if (execution.getJobInstance().getId().compareTo(jobExecution.getJobInstance().getId()) != 0) {
jobExecution.stop();
throw new IllegalStateException(jobName + " instance " + execution.getJobInstance().getId()
+ " is currently running. Please restart this job when " + jobName + " has finished.");
}
}
}
}
}
}
#Override
public void afterJob(JobExecution jobExecution) {}
public String getJobNamePattern() {
return jobNamePattern;
}
public void setJobNamePattern(String jobNamePattern) {
this.jobNamePattern = jobNamePattern;
}
}
So im trying to implement basic listener for when some value is set on redis, but when i set some value nothing happens and only expiry event gets called.
Subscriber
public class Subscriber {
private static JedisPool pool;
public static void main(String[] args) {
JedisPool pool = new JedisPool("localhost");
Jedis jedis = pool.getResource();
jedis.psubscribe(new SubListener(), "*");
}
}
SubListener
public class SubListener extends JedisPubSub {
#Override
public void onPSubscribe(String pattern, int subscribedChannels) {
System.out.println("onPSubscribe "
+ pattern + " " + subscribedChannels);
}
#Override
public void onPMessage(String pattern, String channel, String message) {
System.out
.println("onPMessage pattern "
+ pattern + " " + channel + " " + message);
}
}
Edit: i found out that i had the notify-keyspace-events in config set to Ex. Now i set it to KEA to call on every event but what should i use to only call the event on set
To only call the event on set, set the config to Ks
I want to measure the time from the start of an incoming HTTP request and the application getting to a certain point. Both those points in time are located in different classes. How would I start and stop a timer from these different classes. I don't see a way to use 'named' timers from the MeterRegistry.
How would I go about this?
You can use AOP as below :
#Aspect
#Component
public class ControllerMonitor {
protected static final Logger LOGGER = LoggerFactory.getLogger(ControllerMonitor.class);
#Before("execution(public * com.demo.controller.*Controller.*(..))")
public void logBeforeAccess(JoinPoint joinPoint) {
if(joinPoint!=null){
String packageName = joinPoint.getSignature()!=null?joinPoint.getSignature().getDeclaringTypeName():"LOG-404";
LOGGER.info(". . .A request initiated from controller [" + packageName + "."+ getMethodSignature(joinPoint) + "]. . .");
}
}
#After("execution(public * com.demo.controller.*Controller.*(..))")
public void logAfterAccess(JoinPoint joinPoint) {
if(joinPoint!=null){
String packageName = joinPoint.getSignature()!=null?joinPoint.getSignature().getDeclaringTypeName():"LOG-404";
LOGGER.info(". . .Request from controller [" + packageName + "."+ getMethodSignature(joinPoint) + "] completed. . .");
}
}
#AfterThrowing(pointcut = "execution(public * com.demo.controller.*Controller.*(..))",throwing="exception")
public void logAfterThrowing(Exception exception){
LOGGER.error("Exception caught:"+ exception.getMessage());
}
private String getMethodSignature(JoinPoint joinPoint){
if(joinPoint!=null){
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
StringBuilder sb=new StringBuilder();
if(arguments!=null){
for (Object param: arguments) {
sb.append(param).append(",");
}
sb =(sb.length()>1)?sb.deleteCharAt(sb.length()-1):sb;
}
methodName = methodName+"("+new String(sb)+")";
return methodName;
}else{
return "LOG-405";
}
}
}
Use AOP …...No need to do changes on each class level. It will be one place config..
I try to check Kafka topics on startup spring-boot application. I want to throw an exception and interrupt startup. It is my config:
#Slf4j
#Configuration
public class KafkaTopicConfig implements ApplicationRunner {
private final KafkaAdmin kafkaAdmin;
private final TopicProperties topicProperties;
public KafkaTopicConfig(KafkaAdmin kafkaAdmin, TopicProperties topicProperties) {
this.kafkaAdmin = kafkaAdmin;
this.topicProperties = topicProperties;
}
#Override
public void run(ApplicationArguments args) throws Exception {
AdminClient admin = AdminClient.create(kafkaAdmin.getConfig());
ListTopicsResult listTopicsResult = admin.listTopics();
listTopicsResult.names().whenComplete((existTopics, throwable) -> {
log.info("TOPICS LOAD: {}", existTopics.size());
topicProperties.getTopics().forEach((s, topic) -> {
if (!existTopics.contains(topic))
throw new IllegalStateException("Topic with name: " + topic + " not found in kafka.");
});
});
}
}
But after throws throw new IllegalStateException("Topic with name: " + topic + " not found in kafka."); this exception ignored and application continue works.
Instead of ApplicationRunner, implement SmartLifecycle with autoStartup=true and put your logic in start().
I'm currently trying to import some data from Oracle to ElasticSearch (in JSON format) using Apache Camel. I'm totally new on this framework, so I was thinking that you might help with it !
The problem is that my routeBuilder take the data from my table Entreprise .setBody(constant("select * from entreprise")).to("jdbc:myDataSource") and I get something like that : {id=1231, test=hello}, so I put it in a custom processor which add the quotes. I think this is quite ugly to modify a String because of the integers, booleans, arrays that shouldn't be between quotes, so I'd rather use an Object like a HashMap.
I've tried the apache-sql example which use Spring to create his route :
<route id="processOrder-route">
<from uri="sql:{{sql.selectOrder}}?consumer.onConsume={{sql.markOrder}}"/>
<to uri="bean:orderBean?method=processOrder"/>
<log message="${body}"/>
</route>
and finally get the informations into a HashMap :
public String processOrder(Map<String, Object> data) {
return "Processed order id " + data.get("id") + " item " + data.get("item") + " of " + data.get("amount") + " copies of " + data.get("description");
}
So my main question his : what is the equivalent to this route in Java DSL which could return a HashMap or something like that ?
Here is my code :
public class MainApp {
public static void main(String[] args) throws Exception {
String url = "jdbc:oracle:thin:alexis/alexis#localhost:1521:xe";
System.out.println("Setting up data source.");
DataSource dataSource = setupDataSource(url);
System.out.println("Done.");
SimpleRegistry reg = new SimpleRegistry() ;
reg.put("myDataSource", dataSource);
CamelContext context = new DefaultCamelContext(reg);
ProducerTemplate template = context.createProducerTemplate();
context.addRoutes(new MainApp().new MyRouteBuilder());
context.start();
Thread.sleep(3000);
context.stop();
}
class MyRouteBuilder extends RouteBuilder {
public void configure() {
Processor proc = new ConvertToJSON();
String dst = "C:/Users/**/Desktop/Workspace_sts/democamelJava/data";
from("timer://foo?period=2s")
.setBody(constant("select * from entreprise"))
.to("jdbc:myDataSource").split(body()).process(proc)
.convertBodyTo(String.class)
.to("file://" + dst);
//.to("elasticsearch://localhost:9200?operation=INDEX&indexName=twitter&indexType=tweet");
}
}
Thank you for every answer !