camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Camel > Resequencer
Date Thu, 25 Feb 2010 05:45:00 GMT
<html>
<head>
    <base href="http://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1519/1/1/_/styles/combined.css?spaceKey=CAMEL&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background-color: white" bgcolor="white">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
     <h2><a href="http://cwiki.apache.org/confluence/display/CAMEL/Resequencer">Resequencer</a></h2>
     <h4>Page <b>edited</b> by             <a href="http://cwiki.apache.org/confluence/display/~mrt1nz">Martin
Krasser</a>
    </h4>
     
          <br/>
     <div class="notificationGreySide">
         <h3><a name="Resequencer-Resequencer"></a>Resequencer</h3>

<p>The <a href="http://www.enterpriseintegrationpatterns.com/Resequencer.html" rel="nofollow">Resequencer</a>
from the <a href="/confluence/display/CAMEL/Enterprise+Integration+Patterns" title="Enterprise
Integration Patterns">EIP patterns</a> allows you to reorganise messages based on
some comparator. By default in Camel we use an <a href="/confluence/display/CAMEL/Expression"
title="Expression">Expression</a> to create the comparator; so that you can compare
by a message header or the body or a piece of a message etc.</p>

<p><img src="http://www.enterpriseintegrationpatterns.com/img/Resequencer.gif" align="absmiddle"
border="0" /></p>

<p>Camel supports two resequencing algorithms:</p>

<ul>
	<li><b>Batch resequencing</b> collects messages into a batch, sorts the
messages and sends them to their output.</li>
	<li><b>Stream resequencing</b> re-orders (continuous) message streams based
on the detection of gaps between messages.</li>
</ul>


<h3><a name="Resequencer-BatchResequencing"></a>Batch Resequencing</h3>

<p>The following example shows how to use the batch-processing resequencer so that messages
are sorted in order of the <b>body()</b> expression. That is messages are collected
into a batch (either by a maximum number of messages per batch or using a timeout) then they
are sorted in order and then sent out to their output.</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">from(<span class="code-quote">"direct:start"</span>).resequencer(body()).to(<span
class="code-quote">"mock:result"</span>);
</pre>
</div></div>

<p>This is equvalent to </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>).resequence(body()).batch().to(<span
class="code-quote">"mock:result"</span>);
</pre>
</div></div>

<p>The batch-processing resequencer can be further configured via the <tt>size()</tt>
and <tt>timeout()</tt> methods.</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>).resequence(body()).batch().size(300).timeout(4000L).to(<span
class="code-quote">"mock:result"</span>)
</pre>
</div></div>

<p>This sets the batch size to 300 and the batch timeout to 4000 ms (by default, the
batch size is 100 and the timeout is 1000 ms). Alternatively, you can provide a configuration
object.</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>).resequence(body()).batch(<span
class="code-keyword">new</span> BatchResequencerConfig(300, 4000L)).to(<span class="code-quote">"mock:result"</span>)
</pre>
</div></div>


<p>So the above example will reorder messages from endpoint <b>direct:a</b>
in order of their bodies, to the endpoint <b>mock:result</b>. Typically you'd
use a header rather than the body to order things; or maybe a part of the body. So you could
replace this expression with</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
resequencer(header(<span class="code-quote">"JMSPriority"</span>))
</pre>
</div></div>

<p>for example to reorder messages using their JMS priority.</p>

<p>You can of course use many different <a href="/confluence/display/CAMEL/Expression"
title="Expression">Expression</a> languages 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 various <a href="/confluence/display/CAMEL/Scripting+Languages"
title="Scripting Languages">Scripting Languages</a>.</p>

<p>You can also use multiple expressions; so you could for example sort by priority
first then some other custom header</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
resequence(header(<span class="code-quote">"JMSPriority"</span>), header(<span
class="code-quote">"MyCustomerRating"</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 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;resequence&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>
      &lt;!-- 
        batch-config can be ommitted for default (batch) resequencer settings
      --&gt;
      <span class="code-tag">&lt;batch-config batchSize=<span class="code-quote">"300"</span>
batchTimeout=<span class="code-quote">"4000"</span> /&gt;</span>
    <span class="code-tag">&lt;/resequence&gt;</span>
  <span class="code-tag">&lt;/route&gt;</span>
<span class="code-tag">&lt;/camelContext&gt;</span>
</pre>
</div></div>

<h3><a name="Resequencer-StreamResequencing"></a>Stream Resequencing</h3>

<p>The next example shows how to use the stream-processing resequencer. Messages are
re-ordered based on their sequence numbers given by a <tt>seqnum</tt> header using
gap detection and timeouts on the level of individual messages. </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">from(<span class="code-quote">"direct:start"</span>).resequencer(header(<span
class="code-quote">"seqnum"</span>)).stream().to(<span class="code-quote">"mock:result"</span>);
</pre>
</div></div>

<p>The stream-processing resequencer can be further configured via the <tt>capacity()</tt>
and <tt>timeout()</tt> methods.</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>).resequence(header(<span
class="code-quote">"seqnum"</span>)).stream().capacity(5000).timeout(4000L).to(<span
class="code-quote">"mock:result"</span>)
</pre>
</div></div>

<p>This sets the resequencer's capacity to 5000 and the timeout to 4000 ms (by default,
the capacity is 100 and the timeout is 1000 ms). Alternatively, you can provide a configuration
object.</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>).resequence(header(<span
class="code-quote">"seqnum"</span>)).stream(<span class="code-keyword">new</span>
StreamResequencerConfig(5000, 4000L)).to(<span class="code-quote">"mock:result"</span>)
</pre>
</div></div>

<p>The stream-processing resequencer algorithm is based on the detection of gaps in
a message stream rather than on a fixed batch size. Gap detection in combination with timeouts
removes the constraint of having to know the number of messages of a sequence (i.e. the batch
size) in advance. Messages must contain a unique sequence number for which a predecessor and
a successor is known. For example a message with the sequence number 3 has a predecessor message
with the sequence number 2 and a successor message with the sequence number 4. The message
sequence 2,3,5 has a gap because the sucessor of 3 is missing. The resequencer therefore has
to retain message 5 until message 4 arrives (or a timeout occurs). </p>

<p>If the maximum time difference between messages (with successor/predecessor relationship
with respect to the sequence number) in a message stream is known, then the resequencer's
timeout parameter should be set to this value. In this case it is guaranteed that all messages
of a stream are delivered in correct order to the next processor. The lower the timeout value
is compared to the out-of-sequence time difference the higher is the probability for out-of-sequence
messages delivered by this resequencer. Large timeout values should be supported by sufficiently
high capacity values. The capacity parameter is used to prevent the resequencer from running
out of memory. </p>

<p>By default, the stream resequencer expects <tt>long</tt> sequence numbers
but other sequence numbers types can be supported as well by providing a custom comparator
via the <tt>comparator()</tt> method</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
ExpressionResultComparator&lt;Exchange&gt; comparator = <span class="code-keyword">new</span>
MyComparator();
from(<span class="code-quote">"direct:start"</span>).resequence(header(<span
class="code-quote">"seqnum"</span>)).stream().comparator(comparator).to(<span
class="code-quote">"mock:result"</span>);
</pre>
</div></div>

<p>or via a <tt>StreamResequencerConfig</tt> object.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
ExpressionResultComparator&lt;Exchange&gt; comparator = <span class="code-keyword">new</span>
MyComparator();
StreamResequencerConfig config = <span class="code-keyword">new</span> StreamResequencerConfig(100,
1000L, comparator);
from(<span class="code-quote">"direct:start"</span>).resequence(header(<span
class="code-quote">"seqnum"</span>)).stream(config).to(<span class="code-quote">"mock:result"</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 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;resequence&gt;</span>
      <span class="code-tag">&lt;simple&gt;</span>in.header.seqnum<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;stream-config capacity=<span class="code-quote">"5000"</span>
timeout=<span class="code-quote">"4000"</span>/&gt;</span>
    <span class="code-tag">&lt;/resequence&gt;</span>
  <span class="code-tag">&lt;/route&gt;</span>
<span class="code-tag">&lt;/camelContext&gt;</span>
</pre>
</div></div>

<h3><a name="Resequencer-FurtherExamples"></a>Further Examples</h3>

<p>For further examples of this pattern in use you could look at the <a href="http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/ResequencerTest.java?view=markup"
rel="nofollow">batch-processing resequencer junit test case</a> and the <a href="http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/StreamResequencerTest.java?view=markup"
rel="nofollow">stream-processing resequencer junit test case</a></p>

<h4><a name="Resequencer-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="http://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
       </div>

       <a href="http://cwiki.apache.org/confluence/display/CAMEL/Resequencer">View Online</a>
       |
       <a href="http://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=55179&revisedVersion=13&originalVersion=12">View
Change</a>
              |
       <a href="http://cwiki.apache.org/confluence/display/CAMEL/Resequencer?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message