camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Camel > Splitter
Date Wed, 30 Jun 2010 04:48:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1810/9/1/_/styles/combined.css?spaceKey=CAMEL&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/CAMEL/Splitter">Splitter</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~davsclaus">Claus
Ibsen</a>
    </h4>
        <br/>
                         <h4>Changes (1)</h4>
                                 
    
<div id="page-diffs">
            <table class="diff" cellpadding="0" cellspacing="0">
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >| {{org.apache.camel.splitSize}} |
int | Camel 1.6.2: The total number of Exchanges that was splitted. This header is not applied
for stream based splitting. |  <br>| {{CamelSplitIndex}} | int | Camel 2.0: A split
counter that increases for each Exchange being split. The counter starts from 0. | <br></td></tr>
            <tr><td class="diff-unchanged" >| {{CamelSplitSize}} | int | Camel
2.0: The total number of Exchanges that was splitted. This header is not applied for stream
based splitting. | <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">|
{{CamelSplitComplete}} | boolean | *Camel 2.4:* Whether or not this Exchange is the last.
| <br></td></tr>
            <tr><td class="diff-unchanged" > <br>h4. Parallel execution
of distinct &#39;parts&#39; <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
        </table>
</div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h3><a name="Splitter-Splitter"></a>Splitter</h3>

<p>The <a href="http://www.enterpriseintegrationpatterns.com/Sequencer.html" class="external-link"
rel="nofollow">Splitter</a> from the <a href="/confluence/display/CAMEL/Enterprise+Integration+Patterns"
title="Enterprise Integration Patterns">EIP patterns</a> allows you split a message
into a number of pieces and process them individually</p>

<p><span class="image-wrap" style=""><img src="http://www.enterpriseintegrationpatterns.com/img/Sequencer.gif"
style="border: 0px solid black" /></span></p>

<p>As of Camel 2.0, you need to specify a Splitter as <tt>split()</tt>.
In earlier versions of Camel, you need to use <tt>splitter()</tt>.</p>
<div class='panelMacro'><table class='tipMacro'><colgroup><col width='24'><col></colgroup><tr><td
valign='top'><img src="/confluence/images/icons/emoticons/check.gif" width="16" height="16"
align="absmiddle" alt="" border="0"></td><td><b>What does the splitter
return?</b><br />The <a href="/confluence/display/CAMEL/Splitter" title="Splitter">Splitter</a>
will by default return the <b>last</b> splitted message. You can override this
by suppling your own strategy as an <tt>AggregationStrategy</tt>. There is a sample
on this page (Split aggregate request/reply sample). Notice its the same strategy as the <a
href="/confluence/display/CAMEL/Aggregator" title="Aggregator">Aggregator</a> supports.
This <a href="/confluence/display/CAMEL/Splitter" title="Splitter">Splitter</a>
can be viewed as having a build in light weight <a href="/confluence/display/CAMEL/Aggregator"
title="Aggregator">Aggregator</a>.</td></tr></table></div>
  

<h4><a name="Splitter-Example"></a>Example</h4>

<p>The following example shows how to take a request from the <b>queue:a</b>
endpoint the split it into pieces using an <a href="/confluence/display/CAMEL/Expression"
title="Expression">Expression</a>, then forward each piece to <b>queue:b</b></p>

<p><b>Using the <a href="/confluence/display/CAMEL/Fluent+Builders" title="Fluent
Builders">Fluent Builders</a></b></p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">RouteBuilder builder = <span class="code-keyword">new</span>
RouteBuilder() {
    <span class="code-keyword">public</span> void configure() {
        errorHandler(deadLetterChannel(<span class="code-quote">"mock:error"</span>));

        from(<span class="code-quote">"seda:a"</span>).split(body(<span class="code-object">String</span>.class).tokenize(<span
class="code-quote">"\n"</span>)).to(<span class="code-quote">"seda:b"</span>);
    }
};
</pre>
</div></div>

<p>The splitter can use any <a href="/confluence/display/CAMEL/Expression" title="Expression">Expression</a>
language so you could use any of the <a href="/confluence/display/CAMEL/Languages+Supported"
title="Languages Supported">Languages Supported</a> such as <a href="/confluence/display/CAMEL/XPath"
title="XPath">XPath</a>, <a href="/confluence/display/CAMEL/XQuery" title="XQuery">XQuery</a>,
<a href="/confluence/display/CAMEL/SQL" title="SQL">SQL</a> or one of the <a
href="/confluence/display/CAMEL/Scripting+Languages" title="Scripting Languages">Scripting
Languages</a> to perform the split. e.g.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
from(<span class="code-quote">"activemq:my.queue"</span>).split(xpath(<span
class="code-quote">"<span class="code-comment">//foo/bar"</span>)).convertBodyTo(<span
class="code-object">String</span>.class).to(<span class="code-quote">"file://some/directory"</span>)</span>
</pre>
</div></div>

<p><b>Using the <a href="/confluence/display/CAMEL/Spring+XML+Extensions" title="Spring
XML Extensions">Spring XML Extensions</a></b></p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml"><span class="code-tag">&lt;camelContext errorHandlerRef=<span
class="code-quote">"errorHandler"</span> streamCache=<span class="code-quote">"false"</span>
id=<span class="code-quote">"camel"</span> xmlns=<span class="code-quote">"http://camel.apache.org/schema/spring"</span>&gt;</span>
    <span class="code-tag">&lt;route&gt;</span>
        <span class="code-tag">&lt;from uri=<span class="code-quote">"seda:a"</span>/&gt;</span>
        <span class="code-tag">&lt;split&gt;</span>
            <span class="code-tag">&lt;xpath&gt;</span>/invoice/lineItems<span
class="code-tag">&lt;/xpath&gt;</span>
            <span class="code-tag">&lt;to uri=<span class="code-quote">"seda:b"</span>/&gt;</span>
        <span class="code-tag">&lt;/split&gt;</span>
    <span class="code-tag">&lt;/route&gt;</span>
<span class="code-tag">&lt;/camelContext&gt;</span>
</pre>
</div></div>

<p>For further examples of this pattern in use you could look at one of the <a href="http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/SplitterTest.java?view=markup"
class="external-link" rel="nofollow">junit test case</a></p>

<p><b>Using Tokenizer from <a href="/confluence/display/CAMEL/Spring+XML+Extensions"
title="Spring XML Extensions">Spring XML Extensions</a></b><br/>
<b>Avaiaible as of Camel 2.0</b></p>

<p>You can use the tokenizer expression in the Spring DSL to split bodies or headers
using a token. This is a common use-case, so we provided a special <b>tokenizer</b>
tag for this.<br/>
In the sample below we split the body using a @ as separator. You can of course use comma
or space or even a regex pattern, also set regex=true.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml"><span class="code-tag">&lt;camelContext id=<span
class="code-quote">"camel"</span> xmlns=<span class="code-quote">"http://camel.apache.org/schema/spring"</span>&gt;</span>
    <span class="code-tag">&lt;route&gt;</span>
        <span class="code-tag">&lt;from uri=<span class="code-quote">"direct:start"</span>/&gt;</span>
        <span class="code-tag">&lt;split&gt;</span>
            <span class="code-tag">&lt;tokenize token=<span class="code-quote">"@"</span>/&gt;</span>
            <span class="code-tag">&lt;to uri=<span class="code-quote">"mock:result"</span>/&gt;</span>
        <span class="code-tag">&lt;/split&gt;</span>
    <span class="code-tag">&lt;/route&gt;</span>
<span class="code-tag">&lt;/camelContext&gt;</span>
</pre>
</div></div>

<p>Splitting the body in Spring XML is a bit harder as you need to use the <a href="/confluence/display/CAMEL/Simple"
title="Simple">Simple</a> language to dictate this</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
<span class="code-tag">&lt;split&gt;</span>
   <span class="code-tag">&lt;simple&gt;</span>${body}<span class="code-tag">&lt;/simple&gt;</span>
   <span class="code-tag">&lt;to uri=<span class="code-quote">"mock:result"</span>/&gt;</span>
<span class="code-tag">&lt;/split&gt;</span>
</pre>
</div></div>

<h4><a name="Splitter-MessageHeaders"></a>Message Headers</h4>
<p>The following headers is set on each Exchange that are split:</p>
<div class='table-wrap'>
<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> header </th>
<th class='confluenceTh'> type </th>
<th class='confluenceTh'> description </th>
</tr>
<tr>
<td class='confluenceTd'> <tt>org.apache.camel.splitCounter</tt> </td>
<td class='confluenceTd'> int </td>
<td class='confluenceTd'> Camel 1.x: A split counter that increases for each Exchange
being split. The counter starts from 0. </td>
</tr>
<tr>
<td class='confluenceTd'> <tt>org.apache.camel.splitSize</tt> </td>
<td class='confluenceTd'> int </td>
<td class='confluenceTd'> Camel 1.x: The total number of Exchanges that was splitted.
This header is not applied for stream based splitting. </td>
</tr>
</tbody></table>
</div>


<h4><a name="Splitter-Exchangeproperties"></a>Exchange properties</h4>
<p>The following properties is set on each Exchange that are split:</p>
<div class='table-wrap'>
<table class='confluenceTable'><tbody>
<tr>
<th class='confluenceTh'> header </th>
<th class='confluenceTh'> type </th>
<th class='confluenceTh'> description </th>
</tr>
<tr>
<td class='confluenceTd'> <tt>org.apache.camel.splitCounter</tt> </td>
<td class='confluenceTd'> int </td>
<td class='confluenceTd'> Camel 1.6.2: A split counter that increases for each Exchange
being split. The counter starts from 0. </td>
</tr>
<tr>
<td class='confluenceTd'> <tt>org.apache.camel.splitSize</tt> </td>
<td class='confluenceTd'> int </td>
<td class='confluenceTd'> Camel 1.6.2: The total number of Exchanges that was splitted.
This header is not applied for stream based splitting. </td>
</tr>
<tr>
<td class='confluenceTd'> <tt>CamelSplitIndex</tt> </td>
<td class='confluenceTd'> int </td>
<td class='confluenceTd'> Camel 2.0: A split counter that increases for each Exchange
being split. The counter starts from 0. </td>
</tr>
<tr>
<td class='confluenceTd'> <tt>CamelSplitSize</tt> </td>
<td class='confluenceTd'> int </td>
<td class='confluenceTd'> Camel 2.0: The total number of Exchanges that was splitted.
This header is not applied for stream based splitting. </td>
</tr>
<tr>
<td class='confluenceTd'> <tt>CamelSplitComplete</tt> </td>
<td class='confluenceTd'> boolean </td>
<td class='confluenceTd'> <b>Camel 2.4:</b> Whether or not this Exchange
is the last. </td>
</tr>
</tbody></table>
</div>


<h4><a name="Splitter-Parallelexecutionofdistinct%27parts%27"></a>Parallel
execution of distinct 'parts'</h4>

<p>If you want to execute all parts in parallel you can use special notation of <tt>split()</tt>
with two arguments, where the second one is a <b>boolean</b> flag if processing
should be parallel. e.g.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
XPathBuilder xPathBuilder = <span class="code-keyword">new</span> XPathBuilder(<span
class="code-quote">"<span class="code-comment">//foo/bar"</span>); 
</span>from(<span class="code-quote">"activemq:my.queue"</span>).split(xPathBuilder,
<span class="code-keyword">true</span>).to(<span class="code-quote">"activemq:my.parts"</span>);
</pre>
</div></div>

<p>In <b>Camel 2.0</b> the boolean option has been refactored into a builder
method <tt>parallelProcessing</tt> so its easier to understand what the route
does when we use a method instead of true|false.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
XPathBuilder xPathBuilder = <span class="code-keyword">new</span> XPathBuilder(<span
class="code-quote">"<span class="code-comment">//foo/bar"</span>); 
</span>from(<span class="code-quote">"activemq:my.queue"</span>).split(xPathBuilder).parallelProcessing().to(<span
class="code-quote">"activemq:my.parts"</span>);
</pre>
</div></div>

<h4><a name="Splitter-Streambased"></a>Stream based</h4>
<p><b>Available as of Camel 1.5</b></p>

<p>You can split streams by enabling the streaming mode using the <tt>streaming</tt>
builder method.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
    from(<span class="code-quote">"direct:streaming"</span>).split(body().tokenize(<span
class="code-quote">","</span>)).streaming().to(<span class="code-quote">"activemq:my.parts"</span>);
</pre>
</div></div>

<h4><a name="Splitter-Specifyingacustomaggregationstrategy"></a>Specifying
a custom aggregation strategy </h4>
<p><b>Available as of Camel 2.0</b></p>

<p>This is specified similar to the <a href="/confluence/display/CAMEL/Aggregator"
title="Aggregator">Aggregator</a>.</p>

<h4><a name="Splitter-SpecifyingacustomThreadPoolExecutor"></a>Specifying
a custom ThreadPoolExecutor</h4>

<p>You can customize the underlying ThreadPoolExecutor used in the parallel splitter.
In the Java DSL try something like this:</p>

<p><b>Camel 1.x:</b></p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
XPathBuilder xPathBuilder = <span class="code-keyword">new</span> XPathBuilder(<span
class="code-quote">"<span class="code-comment">//foo/bar"</span>); 
</span>ThreadPoolExecutor threadPoolExecutor = <span class="code-keyword">new</span>
ThreadPoolExecutor(8, 16, 0L, TimeUnit.MILLISECONDS, <span class="code-keyword">new</span>
LinkedBlockingQueue());
from(<span class="code-quote">"activemq:my.queue"</span>).split(xPathBuilder,
<span class="code-keyword">true</span>, threadPoolExecutor).to(<span class="code-quote">"activemq:my.parts"</span>);
</pre>
</div></div>

<p>In the Spring XML try this:</p>

<p><b>Available as of Camel 1.6.0</b></p>
<div class="code panel" style="border-width: 1px;"><div class="codeHeader panelHeader"
style="border-bottom-width: 1px;"><b>Spring DSL</b></div><div class="codeContent
panelContent">
<pre class="code-xml"><span class="code-tag">&lt;camelContext id=<span
class="code-quote">"camel"</span> xmlns=<span class="code-quote">"http://camel.apache.org/schema/spring"</span>&gt;</span>
  <span class="code-tag">&lt;route&gt;</span>
    <span class="code-tag">&lt;from uri=<span class="code-quote">"direct:parallel-custom-pool"</span>/&gt;</span>
    <span class="code-tag">&lt;split executorServiceRef=<span class="code-quote">"myThreadPoolExecutor"</span>&gt;</span>
      <span class="code-tag">&lt;xpath&gt;</span>/invoice/lineItems<span
class="code-tag">&lt;/xpath&gt;</span>
      <span class="code-tag">&lt;to uri=<span class="code-quote">"mock:result"</span>/&gt;</span>
    <span class="code-tag">&lt;/split&gt;</span>
  <span class="code-tag">&lt;/route&gt;</span>
<span class="code-tag">&lt;/camelContext&gt;</span>

&lt;!-- There's an easier way of specifying constructor args, just can't remember it
     at the moment... old Spring syntax will do for now! --&gt;
<span class="code-tag">&lt;bean id=<span class="code-quote">"myThreadPoolExecutor"</span>
class=<span class="code-quote">"java.util.concurrent.ThreadPoolExecutor"</span>&gt;</span>
  <span class="code-tag">&lt;constructor-arg index=<span class="code-quote">"0"</span>
value=<span class="code-quote">"8"</span>/&gt;</span>
  <span class="code-tag">&lt;constructor-arg index=<span class="code-quote">"1"</span>
value=<span class="code-quote">"16"</span>/&gt;</span>
  <span class="code-tag">&lt;constructor-arg index=<span class="code-quote">"2"</span>
value=<span class="code-quote">"0"</span>/&gt;</span>
  <span class="code-tag">&lt;constructor-arg index=<span class="code-quote">"3"</span>
value=<span class="code-quote">"MILLISECONDS"</span>/&gt;</span>
  <span class="code-tag">&lt;constructor-arg index=<span class="code-quote">"4"</span>&gt;</span><span
class="code-tag">&lt;bean class=<span class="code-quote">"java.util.concurrent.LinkedBlockingQueue"</span>/&gt;</span><span
class="code-tag">&lt;/constructor-arg&gt;</span>
<span class="code-tag">&lt;/bean&gt;</span>
</pre>
</div></div>

<p><b>Camel 2.x:</b></p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
XPathBuilder xPathBuilder = <span class="code-keyword">new</span> XPathBuilder(<span
class="code-quote">"<span class="code-comment">//foo/bar"</span>); 
</span>ThreadPoolExecutor threadPoolExecutor = <span class="code-keyword">new</span>
ThreadPoolExecutor(8, 16, 0L, TimeUnit.MILLISECONDS, <span class="code-keyword">new</span>
LinkedBlockingQueue());
from(<span class="code-quote">"activemq:my.queue"</span>).split(xPathBuilder).parallelProcessing().executeService(threadPoolExecutor).to(<span
class="code-quote">"activemq:my.parts"</span>);
</pre>
</div></div>

<h4><a name="Splitter-UsingaPojotodothesplitting"></a>Using a Pojo to do
the splitting</h4>
<p>As the <a href="/confluence/display/CAMEL/Splitter" title="Splitter">Splitter</a>
can use any <a href="/confluence/display/CAMEL/Expression" title="Expression">Expression</a>
to do the actual splitting we leverage this fact and use a <b>method</b> expression
to invoke a <a href="/confluence/display/CAMEL/Bean" title="Bean">Bean</a> to
get the splitted parts.<br/>
The <a href="/confluence/display/CAMEL/Bean" title="Bean">Bean</a> should return
a value that is iterable such as: <tt>java.util.Collection, java.util.Iterator</tt>
or an array. </p>

<p>In the route we define the <a href="/confluence/display/CAMEL/Expression" title="Expression">Expression</a>
as a method call to invoke our <a href="/confluence/display/CAMEL/Bean" title="Bean">Bean</a>
that we have registered with the id mySplitterBean in the <a href="/confluence/display/CAMEL/Registry"
title="Registry">Registry</a>.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">from(<span class="code-quote">"direct:body"</span>)
        <span class="code-comment">// here we use a POJO bean mySplitterBean to <span
class="code-keyword">do</span> the split of the payload
</span>        .split().method(<span class="code-quote">"mySplitterBean"</span>,
<span class="code-quote">"splitBody"</span>)
        .to(<span class="code-quote">"mock:result"</span>);
from(<span class="code-quote">"direct:message"</span>)
        <span class="code-comment">// here we use a POJO bean mySplitterBean to <span
class="code-keyword">do</span> the split of the message 
</span>        <span class="code-comment">// with a certain header value
</span>        .split().method(<span class="code-quote">"mySplitterBean"</span>,
<span class="code-quote">"splitMessage"</span>)
        .to(<span class="code-quote">"mock:result"</span>);
</pre>
</div></div>

<p>And the logic for our <a href="/confluence/display/CAMEL/Bean" title="Bean">Bean</a>
is as simple as. Notice we use Camel <a href="/confluence/display/CAMEL/Bean+Binding" title="Bean
Binding">Bean Binding</a> to pass in the message body as a String object. </p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-keyword">public</span> class MySplitterBean
{

    /**
     * The split body method returns something that is iteratable such as a java.util.List.
     *
     * @param body the payload of the incoming message
     * @<span class="code-keyword">return</span> a list containing each part splitted
     */
    <span class="code-keyword">public</span> List&lt;<span class="code-object">String</span>&gt;
splitBody(<span class="code-object">String</span> body) {
        <span class="code-comment">// since <span class="code-keyword">this</span>
is based on an unit test you can of cause
</span>        <span class="code-comment">// use different logic <span class="code-keyword">for</span>
splitting as Camel have out
</span>        <span class="code-comment">// of the box support <span class="code-keyword">for</span>
splitting a <span class="code-object">String</span> based on comma
</span>        <span class="code-comment">// but <span class="code-keyword">this</span>
is <span class="code-keyword">for</span> show and tell, since <span class="code-keyword">this</span>
is java code
</span>        <span class="code-comment">// you have the full power how you like
to split your messages
</span>        List&lt;<span class="code-object">String</span>&gt;
answer = <span class="code-keyword">new</span> ArrayList&lt;<span class="code-object">String</span>&gt;();
        <span class="code-object">String</span>[] parts = body.split(<span
class="code-quote">","</span>);
        <span class="code-keyword">for</span> (<span class="code-object">String</span>
part : parts) {
            answer.add(part);
        }
        <span class="code-keyword">return</span> answer;
    }
    
    /**
     * The split message method returns something that is iteratable such as a java.util.List.
     *
     * @param header the header of the incoming message with the name user
     * @param body the payload of the incoming message
     * @<span class="code-keyword">return</span> a list containing each part splitted
     */
    <span class="code-keyword">public</span> List&lt;Message&gt; splitMessage(@Header(value
= <span class="code-quote">"user"</span>) <span class="code-object">String</span>
header, @Body <span class="code-object">String</span> body) {
        <span class="code-comment">// we can leverage the Parameter Binding Annotations
 
</span>        <span class="code-comment">// http://camel.apache.org/parameter-binding-annotations.html
</span>        <span class="code-comment">// to access the message header and
body at same time, 
</span>        <span class="code-comment">// then create the message that we want,
splitter will
</span>        <span class="code-comment">// take care <span class="code-keyword">rest</span>
of them.
</span>        <span class="code-comment">// *NOTE* <span class="code-keyword">this</span>
feature requires Camel version &gt;= 1.6.1
</span>        List&lt;Message&gt; answer = <span class="code-keyword">new</span>
ArrayList&lt;Message&gt;();
        <span class="code-object">String</span>[] parts = header.split(<span
class="code-quote">","</span>);
        <span class="code-keyword">for</span> (<span class="code-object">String</span>
part : parts) {
            DefaultMessage message = <span class="code-keyword">new</span> DefaultMessage();
            message.setHeader(<span class="code-quote">"user"</span>, part);
            message.setBody(body);
            answer.add(message);
        }
        <span class="code-keyword">return</span> answer;
    }
}
</pre>
</div></div>

<h4><a name="Splitter-Splitaggregaterequest%2Freplysample"></a>Split aggregate
request/reply sample</h4>
<p>This sample shows how you can split an <a href="/confluence/display/CAMEL/Exchange"
title="Exchange">Exchange</a>, process each splitted message, aggregate and return
a combined response to the original caller using request/reply.</p>

<p>The route below illustrates this and how the split supports a <b>aggregationStrategy</b>
to hold the in progress processed messages:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-comment">// <span class="code-keyword">this</span>
routes starts from the direct:start endpoint
</span><span class="code-comment">// the body is then splitted based on @ separator
</span><span class="code-comment">// the splitter in Camel supports InOut as well
and <span class="code-keyword">for</span> that we need
</span><span class="code-comment">// to be able to aggregate what response we
need to send back, so we provide our
</span><span class="code-comment">// own strategy with the class MyOrderStrategy.
</span>from(<span class="code-quote">"direct:start"</span>)
    .split(body().tokenize(<span class="code-quote">"@"</span>), <span class="code-keyword">new</span>
MyOrderStrategy())
        <span class="code-comment">// each splitted message is then send to <span
class="code-keyword">this</span> bean where we can process it
</span>        .to(<span class="code-quote">"bean:MyOrderService?method=handleOrder"</span>)
        <span class="code-comment">// <span class="code-keyword">this</span>
is important to end the splitter route as we <span class="code-keyword">do</span>
not want to <span class="code-keyword">do</span> more routing
</span>        <span class="code-comment">// on each splitted message
</span>    .end()
    <span class="code-comment">// after we have splitted and handled each message we
want to send a single combined
</span>    <span class="code-comment">// response back to the original caller,
so we let <span class="code-keyword">this</span> bean build it <span class="code-keyword">for</span>
us
</span>    <span class="code-comment">// <span class="code-keyword">this</span>
bean will receive the result of the aggregate strategy: MyOrderStrategy
</span>    .to(<span class="code-quote">"bean:MyOrderService?method=buildCombinedResponse"</span>)
</pre>
</div></div>

<p>And the OrderService bean is as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-keyword">public</span> <span
class="code-keyword">static</span> class MyOrderService {

    <span class="code-keyword">private</span> <span class="code-keyword">static</span>
<span class="code-object">int</span> counter;

    /**
     * We just handle the order by returning a id line <span class="code-keyword">for</span>
the order
     */
    <span class="code-keyword">public</span> <span class="code-object">String</span>
handleOrder(<span class="code-object">String</span> line) {
        LOG.debug(<span class="code-quote">"HandleOrder: "</span> + line);
        <span class="code-keyword">return</span> <span class="code-quote">"(id="</span>
+ ++counter + <span class="code-quote">",item="</span> + line + <span class="code-quote">")"</span>;
    }

    /**
     * We use the same bean <span class="code-keyword">for</span> building the
combined response to send
     * back to the original caller
     */
    <span class="code-keyword">public</span> <span class="code-object">String</span>
buildCombinedResponse(<span class="code-object">String</span> line) {
        LOG.debug(<span class="code-quote">"BuildCombinedResponse: "</span> +
line);
        <span class="code-keyword">return</span> <span class="code-quote">"Response["</span>
+ line + <span class="code-quote">"]"</span>;
    }
}
</pre>
</div></div>

<p>And our custom <b>aggregationStrategy</b> that is responsible for holding
the in progress aggregated message that after the splitter is ended will be sent to the <b>buildCombinedResponse</b>
method for final processing before the combined response can be returned to the waiting caller.</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">/**
 * This is our own order aggregation strategy where we can control
 * how each splitted message should be combined. As we <span class="code-keyword">do</span>
not want to
 * loos any message we copy from the <span class="code-keyword">new</span> to
the old to preserve the
 * order lines as <span class="code-object">long</span> we process them
 */
<span class="code-keyword">public</span> <span class="code-keyword">static</span>
class MyOrderStrategy <span class="code-keyword">implements</span> AggregationStrategy
{

    <span class="code-keyword">public</span> Exchange aggregate(Exchange oldExchange,
Exchange newExchange) {
        <span class="code-comment">// put order together in old exchange by adding the
order from <span class="code-keyword">new</span> exchange
</span>
        <span class="code-keyword">if</span> (oldExchange == <span class="code-keyword">null</span>)
{
            <span class="code-comment">// the first time we aggregate we only have the
<span class="code-keyword">new</span> exchange,
</span>            <span class="code-comment">// so we just <span class="code-keyword">return</span>
it
</span>            <span class="code-keyword">return</span> newExchange;
        }

        <span class="code-object">String</span> orders = oldExchange.getIn().getBody(<span
class="code-object">String</span>.class);
        <span class="code-object">String</span> newLine = newExchange.getIn().getBody(<span
class="code-object">String</span>.class);

        LOG.debug(<span class="code-quote">"Aggregate old orders: "</span> + orders);
        LOG.debug(<span class="code-quote">"Aggregate <span class="code-keyword">new</span>
order: "</span> + newLine);

        <span class="code-comment">// put orders together separating by semi colon
</span>        orders = orders + <span class="code-quote">";"</span> + newLine;
        <span class="code-comment">// put combined order back on old to preserve it
</span>        oldExchange.getIn().setBody(orders);

        <span class="code-comment">// <span class="code-keyword">return</span>
old as <span class="code-keyword">this</span> is the one that has all the orders
gathered until now
</span>        <span class="code-keyword">return</span> oldExchange;
    }
}
</pre>
</div></div>

<p>So lets run the sample and see how it works.<br/>
We send an <a href="/confluence/display/CAMEL/Exchange" title="Exchange">Exchange</a>
to the <b>direct:start</b> endpoint containing a IN body with the String value:
<tt>A&#64;B&#64;C</tt>. The flow is:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
HandleOrder: A
HandleOrder: B
Aggregate old orders: (id=1,item=A)
Aggregate <span class="code-keyword">new</span> order: (id=2,item=B)
HandleOrder: C
Aggregate old orders: (id=1,item=A);(id=2,item=B)
Aggregate <span class="code-keyword">new</span> order: (id=3,item=C)
BuildCombinedResponse: (id=1,item=A);(id=2,item=B);(id=3,item=C)
Response to caller: Response[(id=1,item=A);(id=2,item=B);(id=3,item=C)]
</pre>
</div></div>

<h3><a name="Splitter-Stopprocessingincaseofexception"></a>Stop processing
in case of exception</h3>
<p><b>Available as of Camel 2.1</b></p>

<p>The <a href="/confluence/display/CAMEL/Splitter" title="Splitter">Splitter</a>
will by default continue to process the entire <a href="/confluence/display/CAMEL/Exchange"
title="Exchange">Exchange</a> even in case of one of the splitted message will thrown
an exception during routing.<br/>
For example if you have an <a href="/confluence/display/CAMEL/Exchange" title="Exchange">Exchange</a>
with 1000 rows that you split and route each sub message. During processing of these sub messages
an exception is thrown at the 17th. What Camel does by default is to process the remainder
983 messages. You have the chance to remedy or handle this in the <tt>AggregationStrategy</tt>.</p>

<p>But sometimes you just want Camel to stop and let the exception be propagated back,
and let the Camel error handler handle it. You can do this in Camel 2.1 by specifying that
it should stop in case of an exception occurred. This is done by the <tt>stopOnException</tt>
option as shown below:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
    from(<span class="code-quote">"direct:start"</span>)
        .split(body().tokenize(<span class="code-quote">","</span>)).stopOnException()
            .process(<span class="code-keyword">new</span> MyProcessor())
            .to(<span class="code-quote">"mock:split"</span>);
</pre>
</div></div>

<p>And using XML DSL you specify it as follows:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-xml">
        <span class="code-tag">&lt;route&gt;</span>
            <span class="code-tag">&lt;from uri=<span class="code-quote">"direct:start"</span>/&gt;</span>
            <span class="code-tag">&lt;split stopOnException=<span class="code-quote">"true"</span>&gt;</span>
                <span class="code-tag">&lt;tokenize token=<span class="code-quote">","</span>/&gt;</span>
                <span class="code-tag">&lt;process ref=<span class="code-quote">"myProcessor"</span>/&gt;</span>
                <span class="code-tag">&lt;to uri=<span class="code-quote">"mock:split"</span>/&gt;</span>
            <span class="code-tag">&lt;/split&gt;</span>
        <span class="code-tag">&lt;/route&gt;</span>
</pre>
</div></div>
<h4><a name="Splitter-UsingThisPattern"></a>Using This Pattern</h4>

<p>If you would like to use this EIP Pattern then please read the <a href="/confluence/display/CAMEL/Getting+Started"
title="Getting Started">Getting Started</a>, you may also find the <a href="/confluence/display/CAMEL/Architecture"
title="Architecture">Architecture</a> useful particularly the description of <a
href="/confluence/display/CAMEL/Endpoint" title="Endpoint">Endpoint</a> and <a
href="/confluence/display/CAMEL/URIs" title="URIs">URIs</a>. Then you could try out
some of the <a href="/confluence/display/CAMEL/Examples" title="Examples">Examples</a>
first before trying this pattern out.</p>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/CAMEL/Splitter">View Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=49410&revisedVersion=38&originalVersion=37">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CAMEL/Splitter?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message