For an IoT project I am working on I am researching a next, enhanced, version of our “Socket Handler” which is over 5 years of age and has evolved in a big beast doing apart from handling socket connections with IoT devices also in thread processing that has become a real pain to manage.
For my total rewrite I am looking into Apache Camel as a routing and transformation toolkit and understand how this can help us split processing steps into micro-services, loosely coupled through message queues.
One thing that I have trouble understanding however is how I can implement the following logic “the Apache Camel way”:
An IoT device sends an initial message which contains its id, some extra headers and a message payload.
Apart from extracting the message payload and routing it to a channel, I also need to use the device Id to check a message queue, named after the device id, for any commands that have to go to the device over the same socket connection that received the initial message.
Although it seems that Netty4, which is included in Camel, can deal with synchronous duplex comms, I cannot see how the above logic can be implemented in the Camel Netty4 component. Camel Routing seems to be one way only.
Is there a correct way to do this or should I forget about using camel for this and just use Netty4 bare?
It is possible to reproduce a full duplex communication by using two Camel routes :
thanks by using reuseChannel property
As this full duplex communication will be realised thanks to two different Camel routes, sync property must be set to false.
Here the first route:
from("netty4:tcp://{{tcpAddress}}:{{tcpPort}}?decoders=#length-decoder,#string-decoder&encoders=#length-encoder,#bytearray-encoder&sync=false&reuseChannel=true") .bean("myMessageService", "receiveFromTCP").to("jms:queue:<name>")
This first route will create a TCP/IP consumer thanks to a server socket (it is also possible to use a client socket thanks to property clientMode)
As we want to reuse the just created connection, it is important to initialize decoders but also encoders that will be used later thanks to a bean (see further). This bean will be responsible of sending data by using the Channel created in this first route (Netty Channel contains a pipeline for decoding / encoding messages before receiving from / sending to TCP/IP.
Now, we want to send back some data to the parter connected to the consumer (from) endpoint of the first route. Since we are not able to do it thanks to classical producer endpoint (to), we use a bean object :
from("jsm:queue:<name>").bean("myMessageService", "sendToTCP");
Here the bean code :
public class MessageService {
private Channel openedChannel;
public void sendToTCP(final Exchange exchange) {
// opened channel will use encoders before writing on the socket already
// created in the first route
openedChannel.writeAndFlush(exchange.getIn().getBody());
}
public void receiveFromTCP(final Exchange exchange) {
// record the channel created in the first route.
this.openedChannel = exchange.getProperty(NettyConstants.NETTY_CHANNEL, Channel.class);
}
}
Of course,
the same bean instance is used in the two routes, you need to use a registry to do so :
SimpleRegistry simpleRegistry = new SimpleRegistry();
simpleRegistry.put("myMessageService", new MessageService());
Since the bean is used in two different asynchronous routes, you will have to deal with some unexected situations, by for example protecting the access of openedChannel member, or dealing with unexpected deconnexion.
This post helped me a lot to find this solution :
how-to-send-a-response-back-over-a-established-tcp-connection-in-async-mode-usin
reuseChannel property documentation
After end of camel route, exchange's body and headers will back to requester as response.
Related
I am new to the concepts of Camel and I would like someone to confirm my findings so far.
Please correct if wrong
The way I see it, Camel has Components, which can have several communication interfaces called Endpoints. A Component can communicate with another component by sending a message to on of its Endpoints, which then will use a Processor to deliver it to the destination. I also read about Routes but I am not sure what they are used for because they seem to overlap in function with Processors (aka, they seem to be the same thing?)
Camel Routes and Endpoints
http://java.dzone.com/articles/open-source-integration-apache
Please confirm if correct
So far I believe that a Component (C1) in machine A can use an Endpoint (E1) to communicate with another component (C2) using its endpoint (E2) in machine B, by using websockets:
http://camel.apache.org/how-do-i-configure-endpoints.html
I would be grateful if someone could enlighten me in the first question or confirm my second one. Also, is there a better way to communicate between machines that doesn't involve using webscokets?
Thanks in advance, Pedro.
A Route is what connects endpoints and processors together. When you define a route in Camel it starts with a Component that exposes a communication Endpoint, invokes processors that implement the business logic of the route, and then can output the Exchange (the message being processed) to another Endpoint that is exposed by another Component.
Certain components allow Camel routes to communicate with endpoints in different machines. For example, the JMS component can be used to communicate with other machines via JMS messages. However, some components are limited to communicating with endpoints within the same VM like the SEDA component.
Camel provides many different ways to send data between machines (Here is a list of a few of them off the top of my head):
AMQP
JMS
Amazon SQS
HTTP
Mina
Netty
Take a look at the Camel Components page for a complete list: http://camel.apache.org/components.html
The need is to have a Camel (Mina/Netty) based TCP server running on a specific port, which allows multiple TCP clients to connect to it. The content to be streamed is available in files and the TCP server has to send each line in the text files to one of the connected clients (round robin).
Can someone help me with the outline of a camel route to achieve this?
Also it is possible to throttle the streaming speed for example 100 msg/sec per connected client?
Thanks in advance.
MK
I have done something like this. Well not quite exactly to what you want but I can make some suggestions on how to get started.
Lets use the MINA component for this route as I had some issues with the Netty component see this link Exception thrown from Apache Camel Netty Consumer When more than one client sends data. Apparently this has been fixed but as my project got cancelled I never tested it again.
So from your description this will be a text line based protocol a simple route for this would look like this in the DSL
<route>
<from uri="mina2:tcp://localhost:5555?textline=true"/>
<to uri="bean:fileProcessing"/>
</route>
This route will open a listening socket on the localhost on port 5555. The route is also setup to use a textline codec. A textline codec is essentially a line of text terminated end of line character i.e. \n. If you are going to be using some other protocol you will need to look into the following items:
ProtocolEncoder—The ProtocolEncoder handles the task of taking an input
payload and putting bytes onto the TCP channel.
ProtocolDecoder—The ProtocolDecoder interprets the custom
binary protocol message to something your application can understand.
ProtocolCodecFactory— This creates the encoder and decoder.
You could implement some logic in the fileProcessing bean to send the replies back. There is a catch however the clients will have to request when they are ready to get a new line. From my understanding this follows a request reply scenario. However from what I have seen the route is only active when there is a message coming in from the client to the server.
There might be a way to initiate the sending from the server but you will need to experiment with that by yourself on getting it done I have not done anything like that myself.
Critical reading would be the following.
Mina Documentation
Blog Entry On Using MINA
My suggestion is to start with a basic route like this and then expand your logic and then come back with problems you might encounter.
UPDATE:
So I did a little research on this and it does not appear possible to send events from the server to the client without following one of the following patterns InOnly and InOut.
Try just using MINA or Netty then.
Does Camel provide anything out of the box which tells if it is able to connect all endpoints?
These endpoints could be MQ, webservice etc.
If not then I have to write a servlet which will send test request to all the endpoints. I will be using multicast or splitter for this implementation.
From my experience Camel will only provide warning logs if a from() endpoint is not available since it is constantly trying to read from them. Every other endpoint won't be accessed until the exchange tries to use that endpoint. If your goal is to test if various resources are alive I believe you would need to create your own testing program. I don't think this will be implemented as a feature because typically applications build in error handling if a resource is down and definte appropriate behaviors.
If we're talking about producers, then no. If your route is sending messages to an amq or http4 endpoint for instance, camel with not automatically send TCP-packets on these connections for monitoring purposes. A common way to handle failure of external endpoints is by using "circuit breakers". Take a look at https://camel.apache.org/load-balancer.html. A more robust alternative, imho, is Netflix's Hystrix.
If you have a polling consumer, say a from:ftp://.. then the polling consumer will poll messages every n-th millisecond, and you'll get an error if the connection is broken.
I need to implement a consumer to an XML-RPC based service over TCP. Upon establishing a connection to the server, it requires that
Authentication credentials be sent by the client
An event subscription request be sent by the client, and finally
The client is to switch into a "receiving" mode where messages will be sent asynchronously
When the client is no longer interested in receiving more events, the client ought to "unwind" steps 1-3.
So, I would like to use Apache Camel to implement the client, with an obvious entry endpoint of a Mina Component ("mina:tcp://host:_port_?textline=true&decoderMaxLineLength=10240&sync=true"). My question is, how would I go about implementing steps 1, 2, and 4 above? How would I go about performing those "handshake" steps before the processor in my RouteBuilder gets call? Is this even possible with Camel or will I have to write a straight Mina client to handle this. Are there better options for dealing with this type of integration scenario?
Thank you.
-Santi
This is a really good tutorial on implementing a session handshaking protocol with Netty, which is quite similar to Mina. You could implement this with Camel's Netty Component or draw on the tutorial to build the same with Mina.
it's maybe too late but others may be need the answer.
the key point is you need to use a Processor. something like this
from("mina:tcp:////host:_port_?textline=true&decoderMaxLineLength=10240&sync=true")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
String inboundMessage = exchange.getIn().getBody(String.class);
String outboundMessage = "echo:"+inboundMessage;
exchange.getOut().setBody(outboundMessage);
}
}).to(""mock:result"");
the outboundMessage will be a reply to form end point mina:tcp:////host:_port_?textline=true&decoderMaxLineLength=10240&sync=true
First of all thanks to folks who are currently involved in the development of Camel, I am grateful for all the hard work they have put in.
I am looking for some design advice.
The architecture is something like this:
I have a bunch of Java classes which when instantiated are required to connect to each other and send messages using Apache Camel. The design constraints require me to create a framework such that all routing information, producers, consumers, endpoints etc should be a part of the camel-context.xml.
An individual should have the capability to modify such a file and completely change the existing route without having the Java code available to him.(The Java code would not be provided, only the compiled Jar would be)
For example in One setup,
Bean A ->Bean B->Bean C->file->email.
in another
Bean B->Bean A->Bean C->ftp->file->email
We have tried various approached, but if the originating bean is not implemented as a Java DSL, the messages rate is very high because camel constantly invokes Bean A in the first example and Bean B in the second(they being the source).
Bean A and Bean B originate messages and are event driven. In case the required event occurs, the beans send out a notification message.
My transformations are very simple and I do not require the power of Java DSL at all.
To summarize, I have the following questions:
1) Considering the above constraints, I do I ensure all routing information, including destination addresses, everything is a part of the camel context file?
2) Are there example I can look at for keeping the routing information completely independent of the java code?
3) How do I ensure Camel does not constantly invoke the originating bean?
4) Does Camel constantly invoke just the originating bean or any bean it sends & messages to irrespective of the position of the bean in the entire messaging queue?
I have run out of options trying various ways to set this up. Any help would be appreciated.
Read about hiding the middleware on the Camel wiki pages. This allows you to let clients use an interface to send/receive messages but totally unaware of Camel (no Camel API used at all).
Even better consider buying the Camel in Action book and read chapter 14 which talks about this.
http://www.manning.com/ibsen/
Save 41% on Manning books: Camel in Action or ActiveMQ in Action. Use code s2941. Expires 6th oct. http://www.manning.com/ibsen/
If you consider using ServiceMix of FuseESB, you might want to separate your routes in two parts.
First part would be the Event-driver bean that trigger the route. It could push messages to the ServiceNMR (see http://camel.apache.org/nmr.html).
The other part would be left to the framework users, using Spring DSL. It would just listen to message on the NMR (push by the other route) and do whatever they want with it.
Of course endpoint definition could be propertized using servicemix configuration service (see http://camel.apache.org/properties.html#Properties-UsingBlueprintpropertyplaceholderwithCamelroutes)