I have a simply camel MINA server using the JAVA DSL, and I am running like the example documented here:
Running Camel standalone and have it keep running in JAVA
MINA 2 Component
I am trying to create a sample application hosted at "mina:tcp://localhost:9991" (aka MyApp_B) that sends a very simple message to a server hosted at "mina:tcp://localhost:9990" (aka MyApp_A).
I want is to send a simple message containing a String in the header (which is "Hellow World!") and with the address in the body.
public class MyApp_B extends Main{
public static final String MINA_HOST = "mina:tcp://localhost:9991";
public static void main(String... args) throws Exception {
MyApp_B main = new MyApp_B();
main.enableHangupSupport();
main.addRouteBuilder(
new RouteBuilder(){
#Override
public void configure() throws Exception {
from("direct:start")
.setHeader("order", constant("Hello World!"))
.setBody(constant(MINA_HOST))
.to("mina:tcp://localhost:9990");
}
}
);
System.out.println("Starting Camel MyApp_B. Use ctrl + c to terminate the JVM.\n");
main.run();
}
}
public class MainApp_A {
public static void main(String... args) throws Exception {
Main main = new Main();
main.enableHangupSupport();
main.addRouteBuilder(new RouteBuilder(){
#Override
public void configure() throws Exception {
from("mina:tcp://localhost:9990").bean(MyRecipientListBean.class,
"updateServers").to("direct:debug");
from("direct:debug").process(new Processor() {
public void process(Exchange exchange) throws Exception {
System.out.println("Received order: " +
exchange.getIn().getBody());
}
});
}
});
main.run(args);
}
}
Bean used by MyApp_A:
public class MyRecipientListBean {
public final static String REMOVE_SERVER = "remove";
public final static String ADD_SERVER = "add";
private Set<String> servers = new HashSet<String>();
public void updateServers(#Body String serverURI,
#Header("order") String order){
System.out.println("===============================================\n");
System.out.println("Received " + order + "request from server " + serverURI + "\n");
System.out.println("===============================================\n");
if(order.equals(ADD_SERVER))
servers.add(serverURI);
else if(order.equals(REMOVE_SERVER))
servers.remove(serverURI);
}
}
I have done this code, however, the servers on the other side don't seem to receive anything. Therefore I have 2 questions:
Am I doing something wrong?
Is there a better way to send simple message using Camel?
MyApp_A does NOT send any messages. You need to send a message to the direct endpoint to start the route.
You can also change direct to a timer component to have it trigger every X second etc.
Added latest comment as requested:
yes and the direct route is also running. Its just that to send a
message to direct, you need to do that using Camel. direct is an
internal Camel component for sending messages between its endpoint
(routes). To send a message to it, you can use the producer template.
See chapter 7, section 7.7 in the Camel in Action book.
Related
I'm going to read files from SFTP location line by line:
#Override
public void configure() {
from(sftpLocationUrl)
.routeId("route-name")
.split(body().tokenize("\n"))
.streaming()
.bean(service, "build")
.to(String.format("activemq:%s", queueName));
}
But this application will be deployed on two nodes, and I think that in this case, I can get an unstable and unpredictable application work because the same lines of the file can be read twice.
Is there a way to avoid such duplicates in this case?
Camel has some (experimental) clustering capabilities - see here.
In your particular case, you could model a route which is taking the leadership when starting the directory polling, preventing thereby other nodes from picking the (same or other) files.
soluion is active passive mode . “In active/passive mode, you have a single master instance polling for files, while all the other instances (slaves) are passive. For this strategy to work, some kind of locking mechanism must be in use to ensure that only the node holding the lock is the master and all other nodes are on standby.”
it can implement with hazelcast, consul or zookeper
public class FileConsumerRoute extends RouteBuilder {
private int delay;
private String name;
public FileConsumerRoute(String name, int delay) {
this.name = name;
this.delay = delay;
}
#Override
public void configure() throws Exception {
// read files from the shared directory
from("file:target/inbox" +
"?delete=true")
// setup route policy to be used
.routePolicyRef("myPolicy")
.log(name + " - Received file: ${file:name}")
.delay(delay)
.log(name + " - Done file: ${file:name}")
.to("file:target/outbox");
}}
ServerBar
public class ServerBar {
private Main main;
public static void main(String[] args) throws Exception {
ServerBar bar = new ServerBar();
bar.boot();
}
public void boot() throws Exception {
// setup the hazelcast route policy
ConsulRoutePolicy routePolicy = new ConsulRoutePolicy();
// the service names must be same in the foo and bar server
routePolicy.setServiceName("myLock");
routePolicy.setTtl(5);
main = new Main();
// bind the hazelcast route policy to the name myPolicy which we refer to from the route
main.bind("myPolicy", routePolicy);
// add the route and and let the route be named Bar and use a little delay when processing the files
main.addRouteBuilder(new FileConsumerRoute("Bar", 100));
main.run();
}
}
Server Foo
public class ServerFoo {
private Main main;
public static void main(String[] args) throws Exception {
ServerFoo foo = new ServerFoo();
foo.boot();
}
public void boot() throws Exception {
// setup the hazelcast route policy
ConsulRoutePolicy routePolicy = new ConsulRoutePolicy();
// the service names must be same in the foo and bar server
routePolicy.setServiceName("myLock");
routePolicy.setTtl(5);
main = new Main();
// bind the hazelcast route policy to the name myPolicy which we refer to from the route
main.bind("myPolicy", routePolicy);
// add the route and and let the route be named Bar and use a little delay when processing the files
main.addRouteBuilder(new FileConsumerRoute("Foo", 100));
main.run();
}}
Source : Camel In Action 2nd Edition
I am trying to run a simple re-sequence program using Apache Camel. This program uses the Java DSL to re-sequence incoming Java messages. When I run this program the messages are written to the folder but do not appear to be in any particular order based on the header value or the alphabetical order of the single word in the message body. The files Camel creates are out of order still as if the resequence DSL function did nothing.
How can I get this program to actually order the messages like the Arrays.sort() method would do? Also, how can I get this program to resequence and then aggregate the messages in the correct sort order to a single file?
Here is the program... I call the main Camel route via the other class that has the main method.
import org.apache.camel.builder.RouteBuilder;
public class SortThoseMessages extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:pointA")
.resequence(header("grocery"))
.to("file:target/pointB");
}
}
The class below has main and produces the messages into the queue, pointA.
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.ProducerTemplate;
public class NewSequenceMain {
public static void main(String[] args) {
CamelContext c = new DefaultCamelContext();
try {
c.addRoutes(new SortThoseMessages());
ProducerTemplate template = c.createProducerTemplate();
c.start();
template.sendBodyAndHeader("direct:pointA", "apple", "grocery", 1);
template.sendBodyAndHeader("direct:pointA", "orange", "grocery", 3);
template.sendBodyAndHeader("direct:pointA", "bannanna", "grocery", 2);
Thread.sleep(5000);
c.stop();
} catch(Exception ex) {
System.err.println("Exception thrown -> " + ex);
System.err.println("Now printing stacktrace...");
ex.printStackTrace();
}
}
}
The messages maybe re-sequenced inside the Camel route but not when written to file. To see the re-sequence call the aggregator Java DSL to see the message bodies in the sequence order specified. The messages in the program posted are ordered according to the number of the header. The method call on the ProducerTemplate object reference sets the header as the integer in the last argument to the sendBodyAndHeader() method call.
To see the re-sequencing take effect in a single file as the destination of the Camel route please check out the example below:
import org.apache.camel.builder.RouteBuilder;
public class ReorganizingMessages extends RouteBuilder {
#Override
public void configure() throws Exception {
from("direct:pointA")
.resequence(header("grocery"))
.to("log://org.apache.camel.howto?showAll=true&multiline=true")
.aggregate().constant(true).completionTimeout(100L).
aggregationStrategy(new StringAggregator())
.to("file:target/pointB");
}
}
The code above uses a custom aggregator Java bean that can be seen below.
import org.apache.camel.Exchange;
import org.apache.camel.processor.aggregate.AggregationStrategy;
public class StringAggregator implements AggregationStrategy {
#Override
public Exchange aggregate(Exchange old, Exchange new1) {
if (old == null) {
return new1;
}
String oldBody = old.getIn().getBody(String.class);
String newBody = new1.getIn().getBody(String.class);
old.getIn().setBody(oldBody + " " + newBody);
return old;
}
}
I'm on this problem: can't get my apache camel batch run. Here is the code:
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.main.Main;
public class Launch {
private Main main;
public static void main(String[] args) {
Launch l = new Launch();
System.out.println(System.getProperty("from") +" -> "+System.getProperty("to"));
try {
l.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
public void execute() throws Exception {
main = new Main();
main.enableHangupSupport();
main.addRouteBuilder(new FromFileToFile());
main.run();
}
private static class FromFileToFile extends RouteBuilder {
#Override
public void configure() throws Exception {
onException(Exception.class).handled(true).process(new Processor() {
public void process(Exchange arg0) throws Exception {
arg0.getException().printStackTrace();
}
});
from(System.getProperty("from") + "")
.filter(body().contains("DOTHIS"))
.process(new Processor() {
public void process(Exchange arg0) throws Exception {
System.out.println(arg0.getIn().getBody()
.toString());
}
}).to(System.getProperty("to"))
.to(System.getProperty("to") + ".BAK");
}
}
}
I don't want to use the Thread.sleep(...) workaround. I simply copied and modified the source stuff posted on this official docs page. When I run my dummy program using Eclipse, application simply hangs. I can't figure out what's wrong.
Your application doesn't probably hang, it just won't do anything. :)
You have defined filter that checks if Camel Message body contains word "DOTHIS". When you consume file with File consumer the body will be of type GenericFile. Then when your filter checks for that string it surely won't find it since the body is not string.
Solution: Convert file body to string first and then your filter will work and you get the result you were expecting. Conversion can be done like this
from(System.getProperty("from") + "")
.convertBodyTo(String.class, "UTF-8")
.filter(body().contains("DOTHIS"))
You might also want to increase logging level so you can get the grasp of what's going on in your route.
It was a problem about path. I passed arguments as options like this:
file://Users/francesco/..
As I'm using windows I must specify uri like this
file:///C:/Users/francesco/..
The batch doesn't hangs, it continues to poll directory for new files to consumes.
I understand that I need to call the stop() method using the endpoint.
But I am not sure how to call it.
Here's my code
public class Publish {
public static void main(String[] args) {
String address = "http://localhost:8483/cal";
Object implementor = new CalWebserviceImpl();
Endpoint endpoint = Endpoint.publish(address, implementor);
System.out.println(endpoint.isPublished());
endpoint.stop();
} // main
}
And this is the error I get:
Exception in thread "main" com.sun.xml.internal.ws.server.ServerRtException: Server Runtime Error: java.net.BindException: Address already in use: bind
at com.sun.xml.internal.ws.transport.http.server.ServerMgr.createContext(ServerMgr.java:117)
I assume that I am getting the error message because I am trying to (re-)publish the endpoint before stopping it.
I tried to create a new endpoint reference and use it to stop it.
Endpoint ep = Endpoint.create(implementor);
ep.stop();
But I am getting the same error message.
I am just unclear how to call the stop() the service. Please advise. Thank you!
Edit:
Here's another unsuccessful attempt:
package com.website.test;
import javax.xml.ws.Endpoint;
public class Unpublish {
Endpoint ep = null;
public static void main(String[] args) {
Unpublish up = new Unpublish();
up.run();
} // main
public void run(){
String address = "http://localhost:8483/cal";
Object implementor = new CalWebserviceImpl();
// my service is already running, I believe it's publish here that's causing the issue
ep = Endpoint.publish(address, implementor);
startWebService();
}
private void startWebService() {
if(ep.isPublished()){
System.out.println("Endpoint webservice is running!");
}
else{
ep.stop();
System.out.println("Endpoint webservice stopped!");
}
}
}
I would like to test a singleton actor using java in Scala IDE build of Eclipse SDK (Build id: 3.0.2-vfinal-20131028-1923-Typesafe) and Akka is 2.3.1.
public class WorkerTest {
static ActorSystem system;
#BeforeClass
public static void setup() {
system = ActorSystem.create("ClusterSystem");
}
#AfterClass
public static void teardown() {
JavaTestKit.shutdownActorSystem(system);
system = null;
}
#Test
public void testWorkers() throws Exception {
new JavaTestKit(system) {{
system.actorOf(ClusterSingletonManager.defaultProps(
Props.create(ClassSingleton.class), "class",
PoisonPill.getInstance(),"backend"), "classsingleton");
ActorRef selection = system.actorOf(ClusterSingletonProxy.defaultProps("user/classsingleton/class", "backend"), "proxy");
System.out.println(selection);
}};
}
}
the ClassSingleton.java:
public class ClassSingleton extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
public ClassSingleton() {
System.out.println("Constructor is done");
}
public static Props props() {
return Props.create(ClassOperator.class);
}
#Override
public void preStart() throws Exception {
ActorRef selection = getSelf();
System.out.println("ClassSingleton ActorRef... " + selection);
}
#Override
public void onReceive(Object message) {
}
#Override
public void postStop() throws Exception {
System.out.println("postStop ... ");
}
}
The ClassSingleton actor is doing nothing, the printout is:
Actor[akka://ClusterSystem/user/proxy#-893814405] only, which is printed from the ClusterSingletonProxy. No exception and Junit is done, green flag. In debugging ClassSingleton is not called (including contructor and preStart()). Sure it is me, but what is the mistake? Even more confusing that the same ClassSingleton ClusterSingletonManager code is working fine outside of javatestkit and junit.
I suspect that the cluster setup might be reponsible, so I tried to include and exclude the following code (no effect). However I would like to understand why we need it, if we need it (it is from an example code).
Many thanks for your help.
Address clusterAddress = Cluster.get(system).selfAddress();
Cluster.get(system).join(clusterAddress);
Proxy pattern standard behavior is to locate the oldest node and deploy the 'real' actor there and the proxy actors are started on all nodes. I suspect that the cluster configuration did not complete and thus why your actor never got started.
The join method makes the node to become a member of the cluster. So if no one joins the cluster the actor with proxy cannot be created.
The question is are your configuration files that are read during junit test have all the information to create a cluster? Seed-nodes? Is the port set to the same as the seed node?