Showing posts with label Apache Camel. Show all posts
Showing posts with label Apache Camel. Show all posts

Sunday, May 4, 2014

Apache Camel - EIP Pattern Splitter

The Splitter from the EIP patterns allows you split a message into a number of pieces and process them individually.

You need to specify a Splitter as split(). In earlier versions of Camel, you need to use splitter()

I have given samples how we can implement splitter with Java DSL

Sample 1 - Split the Message Body with @ sign.

 CamelContext context = new DefaultCamelContext();

  ProducerTemplate camelTemplate = context.createProducerTemplate();

  context.addRoutes(new RouteBuilder() {

   @Override
   public void configure() throws Exception {
    // this routes starts from the direct:start endpoint
    // the body is then splitted based on @ separator
    // the splitter in Camel supports InOut as well and for that we
    // need
    // to be able to aggregate what response we need to send back,
    // so we provide our
    // own strategy with the class AggregationStrategy.
    from("direct:start")
      .split(body().tokenize("@"), new AggregationStrategy())
      // each splitted message is then send to this bean where
      // we can process it
      .to("bean:common.SearchRequestService?method=handleOrder")
      // this is important to end the splitter route as we do
      // not want to do more routing
      // on each splitted message
      .end()
      // after we have splitted and handled each message we
      // want to send a single combined
      // response back to the original caller, so we let this
      // bean build it for us
      // this bean will receive the result of the aggregate
      // strategy: AggregationStrategy
      .to("bean:common.SearchRequestService?method=buildCombinedResponse");

   }
  });
  context.start();
  camelTemplate.sendBodyAndHeader("direct:start", "A@B@C",
    "searchCriteria", "headingValue");

  context.stop();

AggregationStrategy Class aggregate method.
 public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
  // put hotel search criteria together in old exchange 
  // by adding the search criteria from new exchange

  if (oldExchange == null) {
   // the first time we aggregate we only have the new exchange,
   // so we just return it
   return newExchange;
  }

  String requests = oldExchange.getIn().getBody(String.class);
  String newLine = newExchange.getIn().getBody(String.class);

  logger.info("Aggregate old requests: " + requests);
  logger.info("Aggregate new requests: " + newLine);

  // put Request together separating by semi colon
  requests = requests + ";" + newLine;
  // put combined Request back on old to preserve it
  oldExchange.getIn().setBody(requests);

  // return old as this is the one that has all the Request gathered until
  // now
  return oldExchange;
 }
Sample 2 - Split the message with split().method()
  CamelContext context = new DefaultCamelContext();

  ProducerTemplate camelTemplate = context.createProducerTemplate();
  context.addRoutes(new RouteBuilder() {
   @Override
   public void configure() throws Exception {
    from("direct:start").to("log:+++before+++?showHeaders=true")
      .split().method(MySplitterBean.class, "splitBody")
      .streaming().to("log:+++after+++?showHeaders=true")
      .choice().when(header("foo").contains("bar"))
      .to("mock:mock").otherwise().to("mock:error");
   }
  });
  context.start();
  camelTemplate.sendBodyAndHeader("direct:start", "msg1,msg2", "foo",
    "bar");

Wednesday, April 9, 2014

Apache Camel - Request / Reply Pattern with Java DSL

Apache camel is a powerful tool yet  a lightweight integration framework. This implements all EIPs an  you can easily integrate different applications using the required patterns.  You can use Java, Spring XML, Scala or Groovy. Almost every technology you can imagine is available, for example HTTP, FTP, JMS, EJB, JPA, RMI, JMS, JMX, LDAP, Netty, and many, many more (of course most ESBs also offer support for them).

You can get more information on Apache camel by going through the following link - Apache Camel

There are many ways that we can use message routing and below article will illustrate one of the ways to use Request / Reply Pattern with Java DSL. Here I'm using Active MQ as my message Broker.

Apache ActiveMQ is one of the the most popular and powerful open source messaging and Integration Patterns server. Apache ActiveMQ is fast, supports many Cross Language Clients and Protocols, comes with easy to use Enterprise Integration Patterns. I like this because it has lot of features and useful tools. Also the latest ActiveMQ (5.9.0) is bundle with the hawtio web console which you can monitor all your queues.

Hawtio itself you can monitor all your camel Contexts, Routers, ActiveMQ Queues ect.

You can get more information on Apache ActiveMQ by going through following link - Apache ActiveMQ

Now lets check the Sample code.

Producer Sample

 public void myMethod() throws Exception {
  // TODO Auto-generated method stub

  CamelContext context = null;
  ProducerTemplate camelTemplate = null;
  
  context = new DefaultCamelContext();
  context.getProperties().put(Exchange.LOG_DEBUG_BODY_STREAMS, "true");
  
  // Connect to embedded ActiveMQComponent JMS broker
  ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
    "failover:(tcp://localhost:61616,tcp://localhost:61617)?randomize=true"
      + "&priorityBackup=true&timeout=40000");
  context.addComponent("jms",
    JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));

  //Create the Template
  camelTemplate = context.createProducerTemplate();
  Object response = camelTemplate
    .requestBodyAndHeader(
      "jms:myQueue.queue?exchangePattern=InOut&requestTimeout=40000&timeToLive=40000"
        + "&asyncConsumer=true&asyncStartListener=true&concurrentConsumers=10"
        + "&useMessageIDAsCorrelationID=true",
        "mBodyMsg", "HeaderString", "HeaderValue");
  
  camelTemplate.stop();
  context.stop();

 }

If you are implementing InOut pattern you need ensure that processed data set back to the same message queue.
In order to achieve this you need to ensure that there is a RouteBuilder implemented which listen to the
above queue and process data. And also set the response back to the same Queue.

Below given the RouteBuilder Configure method implementation.

 @Override
 public void configure() throws Exception {

  CamelContext context = null;

  try {
   // create CamelContext
   context = new DefaultCamelContext();
   ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
     "failover:(tcp://localhost:61616,tcp://localhost:61617)?randomize=true&priorityBackup=true");

   context.addComponent("jms",
     JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));

   context.addRoutes(new RouteBuilder() {
    public void configure() {
     // Error Handler with deadLetterChannel
     errorHandler(deadLetterChannel("jms:queue:dead"));
     GenerateRandomNumber.getInstance();
     int num = GenerateRandomNumber.randInt(1, 100000);
     from("jms:myQueue.queue")
       .setHeader("JMSMessageID", constant("ID : " + num))
       .setHeader("JMSReplyTo",
         constant("myQueue.queue"))
       .process(new RequestProcess());
    }
   });
   context.start();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
  }
 }

Data Processing will happen in the RequestProcess class which should be extend with the Apache camel Processor. Below given the process method implementation.
 public void process(Exchange exchange) throws Exception {
  String body = exchange.getIn().getBody(String.class);
  /***
   * Process data and get the response and set the resposen to the Exchage
   * body.
   */
  exchange.getOut().setBody(body + 
    "response; ID : " + exchange.getExchangeId());
 }