Camel

Content:

  1. Introduction
  2. What it is
  3. Concept
  4. Example
    1. Setup
    2. Shared code
    3. Java configuration
    4. XML configuration
    5. Result
  5. Conclusion

Introduction:

Apache Camel is an open source project from Apache.

It is an interesting project for Java developers. So this article should act as an appetizer.

Disclaimer: I have not worked that much with Camel, so I may have missed some cool features.

What it is:

Question: what is Camel?

Answer: Camel is a routing framework.

Question: what is a routing framework?

Answer: a routing framework is a library/framework that via confguration route messages between different in and out endpoints/channels and does conversion betweem different message formats.

Question: how is that different from an ESB?

Camel is a library/framework intended to be used in applications. An ESB is an application. It is possible to build an ESB on top of Camel. In fact several ESB's are build on top of Camel including: Apache ServiceMix, Redhat Fuse and Mulesoft Mule.

The Camel documentation put it this way:

Is Camel an ESB?

Typically vendors claim practically everything is an ESB these days, so the answer is probably yes :smile:

However our view is that an ESB is more of a container of integration components, so we view Apache ServiceMix to be a true ESB based around OSGi (and optionally JBI) to provide a standards based integration platform of components.

We view Camel as being a rule based routing & mediation engine which can be used inside a full blown ESB, a message broker or a web services smart client. Though if you want to, you could consider that Camel is a small, lightweight embeddable ESB since it can provide many of the common ESB services like smart routing, transformation, mediation, monitoring, orchestration, etc.

It may be adding to the confusion that Camel is really the only product of its kind. There are no alternatives in the Java world. There is nothing like it in the .NET world or the native world.

Concept:

Camel is built on 3 main pieces:

Graphical Camel looks like:

Camel generic view

Camels functionality is configured via a DSL. Camel suppors tmultiple DSL's. The two most common are Java code and XML (Spring).

Camel comes with a large number of components that supports:

Example:

Let us look at an example to see how it works in practice.

Setup:

We will work with the following in channels:

We will work with the following out channels:

We will work with the following routers:

Graphical the above look like:

Camel generic view

This may not be a realistic example, but it shows several likely channel/endpoint types and message format conversions.

In this setup everything is converted to and from XML. This is not a given. It could be a different format like JSON. Or different paths could use different formats.

Shared code:

Binary decoder:

package routing.demo;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;

@ChannelHandler.Sharable
public class MyDecoder extends MessageToMessageDecoder<ByteBuf> {
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> res) throws Exception {
        if(msg.isReadable()) {
            ByteBuffer bb = ByteBuffer.allocate(1000);
            bb.order(ByteOrder.BIG_ENDIAN);
            msg.getBytes(msg.readerIndex(), bb);
            bb.rewind();
            int ival = bb.getInt();
            short len = bb.getShort();
            byte[] xsval = new byte[len];
            bb.get(xsval);
            String sval = new String(xsval, "UTF-8");
            res.add(String.format("<data><ival>%d</ival><sval>%s</sval></data>", ival, sval));
        } else {
            res.add(null);
        }
    }
}

Custom Java code:

package routing.demo;

public class MyBean {
    public void something(String data) {
        System.out.println("**** MyBean.something Start ****");
        System.out.println(data);
        System.out.println("**** MyBean.something Finish ****");
    }
}

CSV to XML converter:

package routing.demo.supp;

import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;

import routing.demo.convert.ConvertCSV2XML;

public class CSV2XML implements Processor {
    private String rootname;
    private String fieldnames;
    private char delim;
    private char quote;
    public CSV2XML(String rootname, String fieldnames, char delim, char quote) {
        super();
        this.rootname = rootname;
        this.fieldnames = fieldnames;
        this.delim = delim;
        this.quote = quote;
    }
    @Override
    public void process(Exchange exchange) throws Exception {
        Message msg = exchange.getMessage();
        String csv = msg.getBody(String.class);
        String xml = ConvertCSV2XML.convert(csv, rootname, fieldnames, delim, quote);
        msg.setBody(xml);
    }
}

JSON to XML converter:

package routing.demo.supp;

import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;

import routing.demo.convert.ConvertJSON2XML;

public class JSON2XML implements Processor {
    private String rootname;
    public JSON2XML(String rootname) {
        super();
        this.rootname = rootname;
    }
    @Override
    public void process(Exchange exchange) throws Exception {
        Message msg = exchange.getMessage();
        String json = msg.getBody(String.class);
        String xml = ConvertJSON2XML.convert(json, rootname);
        msg.setBody(xml);
    }
}

XML to CSV converter:

package routing.demo.supp;

import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;

import routing.demo.convert.ConvertXML2CSV;

public class XML2CSV implements Processor {
    private char delim;
    private char quote;
    public XML2CSV(char delim, char quote) {
        super();
        this.delim = delim;
        this.quote = quote;
    }
    @Override
    public void process(Exchange exchange) throws Exception {
        Message msg = exchange.getMessage();
        String xml = msg.getBody(String.class);
        String csv = ConvertXML2CSV.convert(xml, delim, quote);
        msg.setBody(csv);
    }
}

XML to JSON converter:

package routing.demo.supp;

import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;

import routing.demo.convert.ConvertXML2JSON;

public class XML2JSON implements Processor {
    @Override
    public void process(Exchange exchange) throws Exception {
        Message msg = exchange.getMessage();
        String xml = msg.getBody(String.class);
        String json = ConvertXML2JSON.convert(xml);
        msg.setBody(json);
    }
}

Text truncater:

package routing.demo.supp;

import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;

import routing.demo.convert.ConvertTruncater;

public  class Truncater implements Processor {
    private int maxlen;
    private String suffix;
    public Truncater(int maxlen, String suffix) {
        this.maxlen = maxlen;
        this.suffix = suffix;
    }
    @Override
    public void process(Exchange exchange) throws Exception {
        Message msg = exchange.getMessage();
        String text = msg.getBody(String.class);
        text = ConvertTruncater.convert(text, maxlen, suffix) + "\r\n";
        msg.setBody(text);
    }
}

Note that Camel does come with builtin XML, JSON and CSV functionality. I just did not like it and chose to use my own code for converting between the formats.

Java configuration:

Here is how the main program look with configuration in Java:

package routing.demo;

import org.apache.activemq.ActiveMQConnectionFactory;

import org.apache.camel.CamelContext;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.spi.Registry;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import routing.demo.supp.CSV2XML;
import routing.demo.supp.JSON2XML;
import routing.demo.supp.Truncater;
import routing.demo.supp.XML2CSV;
import routing.demo.supp.XML2JSON;

public class TestJavaConfig {
    @SuppressWarnings("serial")
    public static void main(String[] args) throws Exception {
        CamelContext ctx = new DefaultCamelContext();
        Registry reg = ctx.getRegistry();
        reg.bind("MyDecoder", new MyDecoder()); // decoder for binary/socket in channel
        reg.bind("MyAMQ", new ActiveMQConnectionFactory("tcp://localhost:61616")); // MQ connection factory
        reg.bind("MyDB", new MysqlDataSource() { { setServerName("localhost"); setDatabaseName("Test"); setUser("root"); setPassword(""); } } ); // DB data source
        reg.bind("MyBean", new MyBean()); // bean for Java code out channel
        ctx.addRoutes(new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                // **** in channels ****
                // binary/socket in channel:
                from("netty:tcp://0.0.0.0:9999?decoders=#MyDecoder") // listen port 9999, accept connection, read message, convert from binary to XML
                    .setHeader("channel", constant("socket")) // set channel header
                    .multicast().to("file:/work/camel/out?fileName=socket.log&fileExist=Append&appendChars=\r\n", // log to in channel log file
                                    "direct:some"); // route to some out channels
                // CSV/file in channel:
                from("file:/work/camel/in") // watch directory and read CSV files
                    .split().tokenize("\r\n", 1)  // split file into lines
                    .setHeader("channel", constant("file")) // set channel header
                    .multicast().to("file:/work/camel/out?fileName=file.log&fileExist=Append&appendChars=\r\n", // log to in channel log file
                                    "direct:csv2xml"); // route to CSV to XML converter (that will route to all out channels)
                // XML/MQ in channel:
                from("jms:queue:in_q?connectionFactory=MyAMQ") // receive from queue in_q
                    .setHeader("channel", constant("mq")) // set channel header
                    .multicast().to("file:/work/camel/out?fileName=mq.log&fileExist=Append&appendChars=\r\n", // log to in channel log file
                                    "direct:all"); // route to all out channels
                // JSON/HTTP in channel:
                from("jetty:http://0.0.0.0:8888/demo") // expose web service on port 8888 and receive requests
                    .convertBodyTo(String.class) // extract HTTP request body
                    .setHeader("channel", constant("http")) // set channel header
                    .multicast().to("file:/work/camel/out?fileName=http.log&fileExist=Append&appendChars=\r\n", // log to in channel log file
                                    "direct:json2xml"); // route to JSON to XML converter (that will route to all out channels)
                // **** routing ****
                from("direct:csv2xml")
                    .process(new CSV2XML("data", "ival,sval", ',', '"')) // convert CSV to XML
                    .to("direct:all"); // route to all out channels
                from("direct:json2xml")
                    .process(new JSON2XML("data")) // convert JSON to XML
                    .to("direct:all"); // route to all out channels
                from("direct:all")
                    .multicast().to("direct:db", // route to database out channel
                                    "direct:websvc", // route to web service out channel
                                    "direct:mq", // route to MQ out channel
                                    "direct:java", // route to Java code out channel
                                    "direct:log", // route to log out channel
                                    "direct:out"); // route to output out channel
                from("direct:some")
                    .multicast().to("direct:db", // route to database out channel
                                    "direct:log", // route to log out channel
                                    "direct:out"); // route to output out channel
                // **** out channels ****
                // database out channel:
                from("direct:db")
                    .process(new XML2CSV(',','"')).transform(simple("${headers.channel},${body}")) // convert from XML to CSV and add channel as first field
                    .to("sql:insert into data(channel,ival,sval) values (#,#,#)?dataSource=MyDB"); // insert into database using CSV for parameters
                // web service out channel:
                from("direct:websvc")
                    .process(new XML2JSON()) // convert from XML to JSON
                    .to("http://localhost/svclog.ashx?bridgeEndpoint=true"); // call web service
                // MQ out channel:
                from("direct:mq")
                    .to("jms:queue:out_q?connectionFactory=MyAMQ&exchangePattern=InOnly"); // send to queue out_q
                // Java code out channel:
                from("direct:java")
                    .to("bean:MyBean?method=something"); // call method something in bean class
                // log out channel:
                from("direct:log")
                    .to("file:/work/camel/out?fileName=router.log&fileExist=Append&appendChars=\r\n"); // log (routed XML)
                // output out channel:
                from("direct:out")
                    .process(new Truncater(40, "...")) // truncate to max. 40 characters
                    .to("stream:out"); // output
            }
        });
        ctx.start();
        System.out.print("Press enter to exit");
        System.in.read();
        ctx.stop();
        ctx.close();
    }
}

I hope that the comments make it understandable.

XML configuration:

Here is how the main program look with configuration in Spring XML:

package routing.demo;

import org.apache.camel.CamelContext;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class TestXmlConfig {
    public static void main(String[] args) throws Exception {
        @SuppressWarnings("resource")
        ApplicationContext app = new FileSystemXmlApplicationContext("C:/work/camel/SpringConfig.xml");
        CamelContext ctx = (CamelContext)app.getBean("camel");
        ctx.start();
        System.out.print("Press enter to exit");
        System.in.read();
        ctx.stop();
        ctx.close();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:camel="http://camel.apache.org/schema/spring"
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd  
                            http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
                            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
    <bean id="CSV2XML" class="routing.demo.supp.CSV2XML"> <!-- processor to convert from CSV to XML -->
        <constructor-arg index="0" value="data"/>
        <constructor-arg index="1" value="ival,sval"/>
        <constructor-arg index="2" value=","/>
        <constructor-arg index="3" value='"'/>
    </bean>
    <bean id="JSON2XML" class="routing.demo.supp.JSON2XML"> <!-- processor to convert from JSON to XML -->
        <constructor-arg index="0" value="data"/>
    </bean>
    <bean id="XML2CSV" class="routing.demo.supp.XML2CSV"> <!-- processor to convert from XML to CSV -->
        <constructor-arg index="0" value=","/>
        <constructor-arg index="1" value='"'/>
    </bean>
    <bean id="XML2JSON" class="routing.demo.supp.XML2JSON"/> <!-- processor to convert from XML to JSON -->
    <bean id="Truncater" class="routing.demo.supp.Truncater"> <!-- processor to truncate text -->
        <constructor-arg index="0" value="40"/>
        <constructor-arg index="1" value="..."/>
    </bean>
    <bean id="MyDecoder" class="routing.demo.MyDecoder"/> <!-- decoder for binary/socket in channel -->
    <bean id="MyAMQ" class="org.apache.activemq.ActiveMQConnectionFactory"> <!-- MQ connection factory -->
        <constructor-arg index="0" value="tcp://localhost:61616"/>
    </bean>
    <bean id="MyDB" class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource"> <!-- DB data source -->
        <property name="serverName" value="localhost"/>
        <property name="databaseName" value="Test"/>
        <property name="user" value="root"/>
        <property name="password" value=""/>
    </bean>
    <bean id="MyBean" class="routing.demo.MyBean"/> <!-- bean for Java code out channel -->
    <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
        <!-- **** in channels **** -->
        <!-- binary/socket in channel: -->
        <route>
            <from uri="netty:tcp://0.0.0.0:9999?decoders=#MyDecoder"/> <!-- listen port 9999, accept connection, read message, convert from binary to XML -->
            <setHeader name="channel"><constant>socket</constant></setHeader> <!-- set channel header -->
            <multicast>
                <to uri="file:/work/camel/out?fileName=socket.log&fileExist=Append&appendChars=\r\n"/> <!-- log to in channel log file -->
                <to uri="direct:some"/> <!-- route to some out channels -->
            </multicast>
        </route>
        <!-- CSV/file in channel: -->
        <route>
            <from uri="file:/work/camel/in"/> <!-- watch directory and read CSV files -->
            <split>
                <tokenize token="\r\n"/> <!-- split file into lines -->
                <setHeader name="channel"><constant>file</constant></setHeader> <!-- set channel header -->
                <multicast>
                    <to uri="file:/work/camel/out?fileName=file.log&fileExist=Append&appendChars=\r\n"/> <!-- log to in channel log file -->
                    <to uri="direct:csv2xml"/> <!-- route to CSV to XML converter (that will route to all out channels) -->
                </multicast>
            </split>
        </route>
        <!-- XML/MQ in channel: -->
        <route>
            <from uri="jms:queue:in_q?connectionFactory=MyAMQ"/> <!-- receive from queue in_q -->
            <setHeader name="channel"><constant>mq</constant></setHeader> <!-- set channel header -->
            <multicast>
                <to uri="file:/work/camel/out?fileName=mq.log&fileExist=Append&appendChars=\r\n"/> <!-- log to in channel log file -->
                <to uri="direct:all"/> <!-- route to all out channels -->
            </multicast>
        </route>
        <!-- JSON/HTTP in channel: -->
        <route>
            <from uri="jetty:http://0.0.0.0:8888/demo"/> <!-- expose web service on port 8888 and receive requests -->
            <convertBodyTo type="String"/> <!-- extract HTTP request body -->
            <setHeader name="channel"><constant>http</constant></setHeader> <!-- set channel header -->
            <multicast>
                <to uri="file:/work/camel/out?fileName=http.log&fileExist=Append&appendChars=\r\n"/> <!-- log to in channel log file -->
                <to uri="direct:json2xml"/> <!-- route to JSON to XML converter (that will route to all out channels) -->
            </multicast>
        </route>
        <!-- **** routing **** -->
        <route>
            <from uri="direct:csv2xml"/>
            <process ref="CSV2XML"/> <!-- convert CSV to XML -->
            <to uri="direct:all"/> <!-- route to all out channels -->
        </route>
        <route>
            <from uri="direct:json2xml"/>
            <process ref="JSON2XML"/> <!-- convert JSON to XML -->
            <to uri="direct:all"/> <!-- route to all out channels -->
        </route>
        <route>
            <from uri="direct:all"/>
            <multicast>
                <to uri="direct:db"/> <!-- route to database out channel -->
                <to uri="direct:websvc"/> <!-- route to web service out channel -->
                <to uri="direct:mq"/> <!-- route to MQ out channel -->
                <to uri="direct:java"/> <!-- route to Java code out channel -->
                <to uri="direct:log"/> <!-- route to log out channel -->
                <to uri="direct:out"/> <!-- route to output out channel -->
           </multicast>
        </route>
        <route>
            <from uri="direct:some"/>
            <multicast>
                <to uri="direct:db"/> <!-- route to database out channel -->
                <to uri="direct:log"/> <!-- route to log out channel -->
                <to uri="direct:out"/> <!-- route to output out channel -->
           </multicast>
        </route>
        <!-- **** out channels **** -->
        <!-- database out channel: -->
        <route>
            <from uri="direct:db"/>
            <process ref="XML2CSV"/><transform><simple>${headers.channel},${body}</simple></transform> <!-- convert from XML to CSV and add channel as first field -->
            <to uri="sql:insert into data(channel,ival,sval) values (#,#,#)?dataSource=MyDB"/> <!-- insert into database using CSV for parameters -->
        </route>
        <!-- web service out channel: -->
        <route>
            <from uri="direct:websvc"/>
            <process ref="XML2JSON"/> <!-- convert from XML to JSON -->
            <to uri="http://localhost/svclog.ashx?bridgeEndpoint=true"/> <!-- call web service -->
        </route>
        <!-- MQ out channel: -->
        <route>
            <from uri="direct:mq"/>
            <to uri="jms:queue:out_q?connectionFactory=MyAMQ&exchangePattern=InOnly"/> <!-- send to queue out_q -->
        </route>
        <!-- Java code out channel: -->
        <route>
            <from uri="direct:java"/>
            <to uri="bean:MyBean?method=something"/> <!-- call method something in bean class -->
        </route>
        <!-- log out channel: -->
        <route>
            <from uri="direct:log"/>
            <to uri="file:/work/camel/out?fileName=router.log&fileExist=Append&appendChars=\r\n"/> <!-- log (routed XML) -->
        </route>
        <!-- output out channel: -->
        <route>
            <from uri="direct:out"/>
            <process ref="Truncater"/> <!-- truncate to max. 40 characters -->
            <to uri="stream:out"/> <!-- output -->
        </route>
    </camelContext>
</beans>

Again I hope that the comments make it understandable.

Result:

Database:

mysql> SELECT * FROM data;
+----+---------+------+-----------+
| id | channel | ival | sval      |
+----+---------+------+-----------+
|  1 | file    |    1 | File #1   |
|  2 | file    |    2 | File #2   |
|  3 | file    |    3 | File #3   |
|  4 | http    |    1 | HTTP #1   |
|  5 | http    |    2 | HTTP #2   |
|  6 | http    |    3 | HTTP #3   |
|  7 | mq      |    1 | MQ #1     |
|  8 | mq      |    2 | MQ #2     |
|  9 | mq      |    3 | MQ #3     |
| 10 | socket  |    3 | Socket #3 |
| 11 | socket  |    1 | Socket #1 |
| 12 | socket  |    2 | Socket #2 |
+----+---------+------+-----------+
12 rows in set (0.00 sec)

Web service log file:

{ "ival": 1, "sval": "File #1" }
{ "ival": 2, "sval": "File #2" }
{ "ival": 3, "sval": "File #3" }
{ "ival": 1, "sval": "HTTP #1" }
{ "ival": 2, "sval": "HTTP #2" }
{ "ival": 3, "sval": "HTTP #3" }
{ "ival": 1, "sval": "MQ #1" }
{ "ival": 2, "sval": "MQ #2" }
{ "ival": 3, "sval": "MQ #3" }

MQ listener output:

<?xml version="1.0" ?><data><ival>1</ival><sval>HTTP #1</sval></data>
<?xml version="1.0" ?><data><ival>1</ival><sval>File #1</sval></data>
<?xml version="1.0" ?><data><ival>2</ival><sval>File #2</sval></data>
<?xml version="1.0" ?><data><ival>2</ival><sval>HTTP #2</sval></data>
<?xml version="1.0" ?><data><ival>3</ival><sval>File #3</sval></data>
<?xml version="1.0" ?><data><ival>3</ival><sval>HTTP #3</sval></data>
<data><ival>1</ival><sval>MQ #1</sval></data>
<data><ival>2</ival><sval>MQ #2</sval></data>
<data><ival>3</ival><sval>MQ #3</sval></data>
<?xml version="1.0" ?><data><ival>1</ival><sval>File #1</sval></data>
<?xml version="1.0" ?><data><ival>2</ival><sval>File #2</sval></data>
<?xml version="1.0" ?><data><ival>3</ival><sval>File #3</sval></data>
<?xml version="1.0" ?><data><ival>1</ival><sval>HTTP #1</sval></data>
<?xml version="1.0" ?><data><ival>2</ival><sval>HTTP #2</sval></data>
<?xml version="1.0" ?><data><ival>3</ival><sval>HTTP #3</sval></data>
<data><ival>1</ival><sval>MQ #1</sval></data>
<data><ival>2</ival><sval>MQ #2</sval></data>
<data><ival>3</ival><sval>MQ #3</sval></data>

Java code output:

**** MyBean.something Start ****
<?xml version="1.0" ?><data><ival>1</ival><sval>File #1</sval></data>
**** MyBean.something Finish ****
**** MyBean.something Start ****
<?xml version="1.0" ?><data><ival>2</ival><sval>File #2</sval></data>
**** MyBean.something Finish ****
**** MyBean.something Start ****
<?xml version="1.0" ?><data><ival>3</ival><sval>File #3</sval></data>
**** MyBean.something Finish ****
**** MyBean.something Start ****
<?xml version="1.0" ?><data><ival>1</ival><sval>HTTP #1</sval></data>
**** MyBean.something Finish ****
**** MyBean.something Start ****
<?xml version="1.0" ?><data><ival>2</ival><sval>HTTP #2</sval></data>
**** MyBean.something Finish ****
**** MyBean.something Start ****
<?xml version="1.0" ?><data><ival>3</ival><sval>HTTP #3</sval></data>
**** MyBean.something Finish ****
**** MyBean.something Start ****
<data><ival>1</ival><sval>MQ #1</sval></data>
**** MyBean.something Finish ****
**** MyBean.something Start ****
<data><ival>2</ival><sval>MQ #2</sval></data>
**** MyBean.something Finish ****
**** MyBean.something Start ****
<data><ival>3</ival><sval>MQ #3</sval></data>
**** MyBean.something Finish ****

Log file:

<?xml version="1.0" ?><data><ival>1</ival><sval>File #1</sval></data>
<?xml version="1.0" ?><data><ival>2</ival><sval>File #2</sval></data>
<?xml version="1.0" ?><data><ival>3</ival><sval>File #3</sval></data>
<?xml version="1.0" ?><data><ival>1</ival><sval>HTTP #1</sval></data>
<?xml version="1.0" ?><data><ival>2</ival><sval>HTTP #2</sval></data>
<?xml version="1.0" ?><data><ival>3</ival><sval>HTTP #3</sval></data>
<data><ival>1</ival><sval>MQ #1</sval></data>
<data><ival>2</ival><sval>MQ #2</sval></data>
<data><ival>3</ival><sval>MQ #3</sval></data>
<data><ival>3</ival><sval>Socket #3</sval></data>
<data><ival>1</ival><sval>Socket #1</sval></data>
<data><ival>2</ival><sval>Socket #2</sval></data>

Output:

<?xml version="1.0" ?><data><ival>1</iva...
<?xml version="1.0" ?><data><ival>2</iva...
<?xml version="1.0" ?><data><ival>3</iva...
<?xml version="1.0" ?><data><ival>1</iva...
<?xml version="1.0" ?><data><ival>2</iva...
<?xml version="1.0" ?><data><ival>3</iva...
<data><ival>1</ival><sval>MQ #1</sval></...
<data><ival>2</ival><sval>MQ #2</sval></...
<data><ival>3</ival><sval>MQ #3</sval></...
<data><ival>3</ival><sval>Socket #3</sva...
<data><ival>1</ival><sval>Socket #1</sva...
<data><ival>2</ival><sval>Socket #2</sva...

Conclusion:

Camel is a super cool technology. Most real coders will have fun exploring its capabilities.

And I would not hesitate utilizing Camel if I were to create an ESB-like application.

But for all other types of applications I am a bit skeptical about using Camel. I just don't see the need for the features of Camel.

Article history:

Version Date Description
1.0 May 17th 2020 Initial version

Other articles:

See list of all articles here

Comments:

Please send comments to Arne Vajhøj