I am trying to use an Apache Camel interface called a Processor and am running into some difficulties. I was expected the messages to 1) be sent to the ActiveMQ queues in the JBoss Fuse application server, 2) be processed by the Camel Processor, and then 3) be sent to a different Queue specified in the source-code. What happens now is that the SOP statements in main print and some error messages on Logging but nothing is sent to the queues from the program.
Here is my code:
/* create a Camel processor */
package foo;
import org.apache.camel.Processor;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
public class MyOwnProcessor implements Processor {
//main
public static void main(String[] args) {
System.out.println("Starting main method in MyOwnProcessor.java");
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("QueueA").processRef("MyOwnProcessor").to("QueueB");
}
};
System.out.println("main is done.");
} //end main
public void process(Exchange exchange) {
System.out.println("Hello the process was executed.");
String s = exchange.getIn().getBody(String.class);
exchange.getIn().setBody("The body of the message is: " + s);
} //end process method
} //end class
Here is the current output:
Starting main method in MyOwnProcessor.java
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
main is done.
Try this,
public static void main(String args[]) throws Exception {
// create CamelContext
CamelContext context = new DefaultCamelContext();
// connect to embedded ActiveMQ JMS broker
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
"tcp://localhost:61616");
context.addComponent("jms",
JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
// add our route to the CamelContext
context.addRoutes(new RouteBuilder() {
#Override
public void configure() {
from("jms:queue:QueueA")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
String s = exchange.getIn().getBody(String.class);
System.out.println("The body of the message is: " + s);
}
}).to("jms:queue:QueueB");
}
});
// start the route and let it do its work
context.start();
Thread.sleep(10000);
// stop the CamelContext
context.stop();
}
Creating a route isn't going to cause it to run -- you still need a running CamelContext, and it needs to be passed a message in order to get things started. Try getting this to work first, just using an anonymous inner class for your Processor:
public static void main(String[] args) throws Exception {
CamelContext context = new DefaultCamelContext();
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("direct:source").process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("Success!");
}
});
}
};
context.addRoutes(builder);
ProducerTemplate template = context.createProducerTemplate();
context.start();
template.sendBody("direct:source", "test");
}
Once that works, add a separate class that implements Processor and use that instead of the anonymous inner class.
Related
I'm trying to start an application with spring boot that have a JMSListener to connect to an external ActiveMQ, this application need to start even the ActiveMQ is down.
I'm using a failover transport protocol in the connection, but when I start the application the main thread is blocked while the JMS try to establish the connection and the application don't start until the first connection is made.
I was trying this solution, where I extend the DefaultMessageListenerContainer and override the start method to run in a new thread that will free the main thread.
Consumer.java
#SpringBootApplication
public class Consumer {
public static void main(String[] args) {
SpringApplication.run(Consumer.class, args);
System.out.println("Consumer Start");
}
}
Receiver
#Component
public class Receiver {
#Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new MyListenerContainerFactory();
configurer.configure(factory, connectionFactory);
return factory;
}
#JmsListener(destination = "mailbox", containerFactory = "myFactory")
public void receiveMessage(String email) {
System.out.println("Received <" + email + ">");
}
}
MyListenerContainer.java
public class MyListenerContainer extends DefaultMessageListenerContainer {
#Override
public void start() throws JmsException {
new Thread(() -> {
super.start();
}).start();
}
}
MyListenerContainerFactory.java
public class MyListenerContainerFactory extends DefaultJmsListenerContainerFactory {
#Override
protected DefaultMessageListenerContainer createContainerInstance() {
return new MyListenerContainer();
}
}
1º Question:
This solution work but I'm not sure if this does not break anything in the start of spring beans since I'm finishing the start method before the connection is created. Can this break the bean creation process in spring boot?
2º Question:
In additional to this if I have in the same application a JMSListener and a JMSProducer they will try to use the same connection or they use different ones?
If someone has a different solution that is better please share.
Thank you for the time and best regards
Bernardo Neves
It's probably cleaner to use factory.setAutoStartup(false); which will prevent Spring from attempting to start the container; use container.start() when you are ready (on whatever thread you want).
#Autowired
private JmsListenerEndpointRegistry registry;
...
registry.start(); // starts all containers
// or
registry.getListenerContainer(myContainerId).start();
They will use the same connection.
Code sample:
#SpringBootApplication
public class Launcher {
public static void main(String[] args) {
System.out.println("Server Started!");
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(Launcher.class)
.headless(false).run(args);
ctx.getBean(Launcher.class);
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Administration(ctx).setVisible(true);
}
});
}
}
When the Administration class runs , will it have a valid context ? I want to pass the context inside Administration so that I can call some of the services that is provided. If this doesn't work, how can I access the services from a thread that is not in it's context ?
I have configured my route as shown below. I am not getting exception, but at the same time there is no output.
public static void main(String[] args) {
CamelContext camelContext = new DefaultCamelContext();
try {
camelContext.addRoutes(new RouteBuilder() {
public void configure() {
from("direct:foo")
.to("ahc:http://services.odata.org/V2/Northwind/Northwind.svc/")
.to("file:c:/workpro/outbox?fileName=ahc.xml");
}
});
camelContext.start();
}catch (Exception e1) {
}
}
After the execution I should have a folder by name workpro created in c drive. Do you see any issue with the way I have defined the routes.
Many Thanks,
Rakesh
Use a timer in the from, and set it to repeatCount=1 if you only want to call it once.
And the start method in non blocking - I just added a sleep 30 second. But see this FAQ for better ways: http://camel.apache.org/running-camel-standalone-and-have-it-keep-running.html
public static void main(String[] args) {
CamelContext camelContext = new DefaultCamelContext();
try {
camelContext.addRoutes(new RouteBuilder() {
public void configure() {
from("timer:foo?repeatCount=1")
.to("ahc:http://services.odata.org/V2/Northwind/Northwind.svc/")
.to("file:c:/workpro/outbox?fileName=ahc.xml");
}
});
camelContext.start();
Thread.sleep(30000);
camelContext.stop();
}catch (Exception e1) {
}
}
Or instead of the timer you can use direct, but then you would need to send a message to the direct endpoint to trigger your route to run. This is all documented in the Apache Camel getting started, such as http://camel.apache.org/walk-through-an-example.html. And new users to Camel is recommended to read: http://java.dzone.com/articles/open-source-integration-apache
package com.camel;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
public class FirstRoute {
public static void main(String args []) throws Exception{
CamelContext context = new DefaultCamelContext();
context.addRoutes(new RouteBuilder() {
#Override
public void configure() throws Exception {
from("file:C:\\workspace\\input?noop=true").process(new strong textProcessor() {
#Override
public void process(Exchange arg0) throws Exception {
System.out.println("hello camel!");
}
}).to("file:C:\\workspace\\output").end();
}
});
context.start();
Thread.sleep(1000);
context.stop();
}
}
This is my first camel program. looks like every thing is correct. but the file transfer is not happening.
I added
camel conext 2.12.1 jar
camel core 2.12.1 jar
camel ftp 2.12.1 jar
slf4j api 1.7.6 jar
increase the sleep time to get the result correctly.
That 1000 ms is not enough to copy the files from input directory to output directory.
That sleep time specifies a time limit to copy files from input to output. if you increase sleep time context will copy more files from input to output directory
Usually when Camel is used as a standalone application, you should use Main provided by Camel. I have posted the code from their site :
public class MainExample {
private Main main;
public static void main(String[] args) throws Exception {
MainExample example = new MainExample();
example.boot();
}
public void boot() throws Exception {
// create a Main instance
main = new Main();
// enable hangup support so you can press ctrl + c to terminate the JVM
main.enableHangupSupport();
// bind MyBean into the registery
main.bind("foo", new MyBean());
// add routes
main.addRouteBuilder(new MyRouteBuilder());
// run until you terminate the JVM
System.out.println("Starting Camel. Use ctrl + c to terminate the JVM.\n");
main.run();
}
private static class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
from("timer:foo?delay=2000")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
System.out.println("Invoked timer at " + new Date());
}
})
.beanRef("foo");
}
}
public static class MyBean {
public void callMe() {
System.out.println("MyBean.calleMe method has been called");
}
}
}
Refer http://camel.apache.org/running-camel-standalone-and-have-it-keep-running.html for more details.
context.start();
Thread.sleep(10000);
context.stop();
Change this piece of code to give time for camel to move the file.
Your code return some exception?
The problem can be the timeout 1000 is equals 1 second, is a very short time for copy a file, you can try, up the value of timeout or remove.
Follow an example without timeout:
This Class create a RouteBuilder
public class CamelRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("file:/opt/files-camel?noop=true")
.routeId("file-in")
.choice()
.when(header(Exchange.FILE_NAME).endsWith(".xml"))
.to("file:/opt/files-camel/xml?noop=true")
.when(header(Exchange.FILE_NAME).endsWith(".txt"))
.to("file:/opt/files-camel/txt?noop=true")
.end()
.end();
}
}
This Class run a RouteBuilder
public class Launcher {
public static void main(String... args) throws Exception {
Main main = new Main();
main.addRouteBuilder(new CamelRoute());
main.run(args);
}
}
I am using JBoss5.1.x AS, EJB3.0. I am trying to add a job (using Quartz) to my deployment. I am registering a new Service, so it will init the scheduler on application deploy.
My problem is that the service never gets registered when I deploy my app.
My code:
Interface:
public interface ComponentMonitoringService
{
void create() throws Exception;
void start() throws Exception;
void stop();
void destroy();
}
Service:
#Service(objectName = "com.mirs.ecms.timer:service=ServerStartupManager")
#Management(ComponentMonitoringService.class)
public class ServerStartupManager implements ComponentMonitoringService
{
private SchedulerFactory schedulerFactory = null;
private Scheduler scheduler = null;
Logger logger = Logger.getLogger("ecms.log");
public void create() throws Exception
{
}
public void start() throws Exception
{
// Write your startup code
initScheduler();
}
private void initScheduler() throws ParseException, SchedulerException
{
schedulerFactory = new StdSchedulerFactory();
scheduler = schedulerFactory.getScheduler();
JobDetail startECMSJob = new JobDetail("startECMSJob", "group1", StartECMSJob.class);
CronTrigger trigger1 = new CronTrigger("cronTrigger", "TriggersGroup1", "0 0/5 * * * ?");
scheduler.scheduleJob(startECMSJob, trigger1);
scheduler.start();
}
public void stop()
{
try
{
scheduler.shutdown();
}
catch (Exception e)
{
logger.error("ServerStartupManager Failure occured during Manager stop", e);
}
}
public void destroy()
{
}
}
I found a solution.
I was not using the right annotation. I have to use EJB3 annotations.