Apache Camel merge two files from different routes

Dinesh Arora picture Dinesh Arora · Jan 16, 2014 · Viewed 9k times · Source

Here's what I am trying to do. I have to read two files that has this content

<Person>
<Requestor>Dinesh</Requestor>
</Person>

To do this I created a route

<route id="getPerson">
    <from uri="file:src/main/resources/xml?noop=true"/>
    </route>

Next I need to read another file called Address

<Address>
  <City>New York </City>
</Address>

Here is my second route

<route id="getAddress">
    <from uri="file:src/main/resources/xmlAddress?noop=true"/>
    </route>

How do I merge these two xmls into one Using Enricher or Aggregate to make the final xml message look like this

<Person>
  <Requestor>Dinesh</Requestor>
  <Address>
     <City>New York</City>
  </Address>
</Person>

Any ideas? I tried following the documentation but all it says is send to some web service uri.

The above scenario is toned down version of what I actually want to do. The real life situation for me is to do this- Step 1. Read an xml file, Step 2: Call a web service and get the response. Step 3: Merge Response in Step 2 and add it o Xml body in Step 1

EDIT 1: I can write the custom AggregatorStartegy class. I wrote something like this

public class AggregationStrategy implements org.apache.camel.processor.aggregate.AggregationStrategy{

@Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
    newExchange.getOut().setBody("<all>" 
              + oldExchange.getIn().getBody(String.class) 
              + newExchange.getIn().getBody(String.class) 
              + "</all>");
            return newExchange;
}

   }

What I am struggling with is how to write write the Spring xml where I can tell here is my message or file 1+ message or file 2, go join them. Here's how my actual context.xml looks like

<camelContext id="myCamel" xmlns="http://camel.apache.org/schema/spring">
<route>
    <from uri="file:src/main/resources/xmlPerson?noop=true"/>

    <camel:to uri="direct:enrichMessage"></camel:to>
</route> 
<route  >
    <from uri="file:src/main/resources/xmlAddress?noop=true"/> 
    <log message="**************RESPONSE FROM CATASK DSS:: \n ${body}" id="log_output"/>
    <camel:to uri="direct:enrichMessage"></camel:to> 

</route>
 <route id="enrichMessage">
    <from uri="direct:enrichMessage"/>
    <camel:enrich strategyRef="aggregationBean" />
    <log message="**************MERGED RESPONSE :: \n ${body}"/>
</route>

Answer

Dinesh Arora picture Dinesh Arora · Jan 17, 2014

I finally figured it out. my initial understanding was that we can have two messages in hand and merge them for Ex - Route 1 final message -

Dinesh

Route 2 final message -

<Address>
  <city>New York</city>
</Address>

My understanding was that after having the two messages above I could just build an aggregationStartegy and merge them. Well my assumption was wrong. The way enricher works is that it has one message in hand and before it gets the message from second route, we need to tell Camel that - "Hey before you get the message the Route 2, here's the message from Route 1. When you fetch the message from Route 1, use my aggregation strategy class to merge them"."

So I was expecting the following out after using the Enricher

<Person>
   <name>Dinesh</name>
</Person>
<Address>
  <city>New York</city>
</Address>

BUT I was not sure how to do it. Here's what I was doing and it was wrong approach

<route id="getPerson">
<from uri="file:src/data/catask/person?noop=true" />
<to uri="direct:enrich"/> 
</route>

<route id="getAddress">
<from uri="file:src/data/catask/address?noop=true" />
<to uri="direct:enrich"/>
</route>

<route id="enrich">
<from uri="direct:enrich"/>
<enrich strategyRef="aggregationBean"/>
<log message="After Merge ... ${body}"/> 
</route>

<bean id="aggregationBean" class="com.mycompany.camel.canadatask.AggregationStrategy"/>  

My Java class looked like this

public class AggregationStrategy implements   
     org.apache.camel.processor.aggregate.AggregationStrategy{



@Override
public Exchange aggregate(Exchange message,Exchange resource) {
    String old = resource.getIn().getBody(String.class);
    System.out.println("OLD:: \n"+old);
    String newMsg = message.getIn().getBody(String.class);
    System.out.println("NEW:: \n"+newMsg);
    System.out.println("MERGED::" + old + newMsg);
    message.getIn().setBody(old+newMsg);
            return message;
}

  }

Now of course the above code did not work. I later realized the mistake, my understanding about enricher was wrong.

The correct implementation is like this -

<route id="getPerson">
   <from uri="file:src/data/catask/person?noop=true" />
   <pollEnrich strategyRef="aggregationBean" uri="file:src/data/catask/address?noop=true"/> 
   <log message="After Merge ... ${body}"/>
 </route>

<bean id="aggregationBean" class="com.mycompany.camel.canadatask.AggregationStrategy"/>  

The java code remained the same -

public class AggregationStrategy implements   
     org.apache.camel.processor.aggregate.AggregationStrategy{



@Override
public Exchange aggregate(Exchange message,Exchange resource) {
    String old = resource.getIn().getBody(String.class);
    System.out.println("OLD:: \n"+old);
    String newMsg = message.getIn().getBody(String.class);
    System.out.println("NEW:: \n"+newMsg);
    System.out.println("MERGED::" + old + newMsg);
    message.getIn().setBody(old+newMsg);
            return message;
}

  }