camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Camel > Camel 2.x - Debugger API
Date Thu, 08 Jul 2010 12:47: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/Camel+2.x+-+Debugger+API">Camel
2.x - Debugger API</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~davsclaus">Claus
Ibsen</a>
    </h4>
        <br/>
                         <h4>Changes (3)</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" >The processing is based on a {{before}}
and {{after}} callback when the [Exchange] is being routed and thus a [Processor] is invoked.
<br> <br></td></tr>
            <tr><td class="diff-changed-lines" >The event is based on the <span
class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">[EventNotifer]</span>
<span class="diff-added-words"style="background-color: #dfd;">{{EventNotifier}}</span>
emitting events such as {{ExchangeCreatedEvent}}, {{ExchangeFailureEvent}} etc. This allows
you to have breakpoints when a given Exchange has failed. Or when they are done, so you can
inspect the result etc. <br></td></tr>
            <tr><td class="diff-unchanged" > <br>There is a {{org.apache.camel.impl.BreakpointSupport}}
class which can be used to extend, to avoid implementing all the methods from the interface.
<br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >h3. Single step <br> <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">TODO:
bla bla <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">In
the Java editor the debugger is capable of single stepping when a breakpoint is hit. The idea
in Camel is that you want to single step an [Exchange] so you can step through how its routed
and follow it from the 3rd party tooling.  <br> <br>The {{Debugger}} has API for
single stepping. For example to single step the first message arrived in Camel you can do
<br>{code} <br>        context.getDebugger().addSingleStepBreakpoint(breakpoint);
<br>{code} <br> <br>However what if you have multiple routes or the likes
and only want to single step from route X, well you can just add a {{Condition}}: <br>
<br>This {{beerCondition}} will only match [Exchange] coming from the {{beer}} route:
<br>{code} <br>        beerCondition = new ConditionSupport() { <br>   
        public boolean matchProcess(Exchange exchange, Processor processor, ProcessorDefinition
definition) { <br>                return &quot;beer&quot;.equals(exchange.getFromRouteId());
<br>            } <br>        }; <br>{code} <br> <br>So you
just provide the condition when adding the breakpoint: <br>{code} <br> <br>
       // we only want to single step the beer route <br>        context.getDebugger().addSingleStepBreakpoint(breakpoint,
beerCondition); <br>{code} <br> <br>And the routes could be as follows:
<br>{code} <br>            public void configure() throws Exception { <br>
               // use debugger <br>                context.setDebugger(new DefaultDebugger());
<br> <br>                from(&quot;direct:start&quot;).routeId(&quot;foo&quot;).to(&quot;log:foo&quot;).to(&quot;log:bar&quot;).to(&quot;mock:result&quot;);
<br> <br>                from(&quot;direct:beer&quot;).routeId(&quot;beer&quot;).to(&quot;log:beer&quot;).to(&quot;mock:result&quot;);
<br>            } <br>{code} <br> <br>Which will cause the debugger
to only single step when a message arrives on {{beer}} route: <br>{code} <br>
   public void testDebug() throws Exception { <br>        // we only want to single
step the beer route <br>        context.getDebugger().addSingleStepBreakpoint(breakpoint,
beerCondition); <br> <br>        getMockEndpoint(&quot;mock:result&quot;).expectedBodiesReceived(&quot;Hello
World&quot;, &quot;Carlsberg&quot;); <br> <br>        template.sendBody(&quot;direct:start&quot;,
&quot;Hello World&quot;); <br>        template.sendBody(&quot;direct:beer&quot;,
&quot;Carlsberg&quot;); <br> <br>        assertMockEndpointsSatisfied();
<br> <br>        assertEquals(2, logs.size()); <br>        assertEquals(&quot;Single
stepping at log:beer with body: Carlsberg&quot;, logs.get(0)); <br>        assertEquals(&quot;Single
stepping at mock:result with body: Carlsberg&quot;, logs.get(1)); <br>    } <br>{code}
<br> <br>h2. Notes <br>- The single step feature should only allow one _active_
at any time. So if there is already a single step message in process other messages should
be disregarded from debugging <br>- Should other breakpoints be active during single
step? In case you have another breakpoint somewhere which may get triggered? <br>- Should
we add a fluent builder syntax for sugar, so its easier to use common conditions? <br>
<br> <br>h2. Use cases <br> <br></td></tr>
        </table>
</div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h2><a name="Camel2.x-DebuggerAPI-Camel2.xDebuggerAPI"></a>Camel
2.x - Debugger API</h2>
<p><b>Available as of Camel 2.4</b></p>

<p>There is a new <tt>org.apache.camel.spi.Debugger</tt> API which allows
3rd party to attach a debugger tooling to debug <a href="/confluence/display/CAMEL/Exchange"
title="Exchange">Exchange</a>s in Camel routes.<br/>
There is a default implementation in <b>camel-core</b> as the <tt>org.apache.camel.impl.DefaultDebugger</tt>.
</p>

<h3><a name="Camel2.x-DebuggerAPI-Enabling"></a>Enabling</h3>
<p>You can enable the debugger from the <tt>CamelContext</tt> using the
<tt>setDebugger</tt>. We may add a nicer API for this in the future.</p>

<h3><a name="Camel2.x-DebuggerAPI-Breakpoint"></a>Breakpoint</h3>
<p>There is a <tt>org.apache.camel.spi.Breakpoint</tt> API in which the
3rd party tooling implement logic what should happen when the breakpoint is hit. </p>

<p>The breakpoint can be invoked in 2 kind of styles in Camel:</p>
<ul class="alternate" type="square">
	<li>processing based</li>
	<li>event based</li>
</ul>


<p>The processing is based on a <tt>before</tt> and <tt>after</tt>
callback when the <a href="/confluence/display/CAMEL/Exchange" title="Exchange">Exchange</a>
is being routed and thus a <a href="/confluence/display/CAMEL/Processor" title="Processor">Processor</a>
is invoked.</p>

<p>The event is based on the <tt>EventNotifier</tt> emitting events such
as <tt>ExchangeCreatedEvent</tt>, <tt>ExchangeFailureEvent</tt> etc.
This allows you to have breakpoints when a given Exchange has failed. Or when they are done,
so you can inspect the result etc.</p>

<p>There is a <tt>org.apache.camel.impl.BreakpointSupport</tt> class which
can be used to extend, to avoid implementing all the methods from the interface.</p>

<h3><a name="Camel2.x-DebuggerAPI-Condition"></a>Condition</h3>
<p>There is a <tt>org.apache.camel.spi.Condition</tt> API in which the 3rd
party tooling can provide conditions when the breakpoints should apply. For example a conditional
breakpoint which only triggers if the message body is a certain message / type etc.</p>

<p>The condition can be invoked in 2 kind of styles in Camel:</p>
<ul class="alternate" type="square">
	<li>processing based</li>
	<li>event based</li>
</ul>


<p>Where there is a <tt>match</tt> method for each style.</p>

<p>There is a <tt>org.apache.camel.impl.ConditionSupport</tt> class which
can be used to extend, to avoid implementing all the methods from the interface.</p>

<h3><a name="Camel2.x-DebuggerAPI-Example"></a>Example</h3>

<p>For example we can have this breakpoint</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">

        breakpoint = <span class="code-keyword">new</span> BreakpointSupport()
{
            <span class="code-keyword">public</span> void beforeProcess(Exchange
exchange, Processor processor, ProcessorDefinition definition) {
                <span class="code-object">String</span> body = exchange.getIn().getBody(<span
class="code-object">String</span>.class);
                logs.add(<span class="code-quote">"Breakpoint at "</span> + definition
+ <span class="code-quote">" with body: "</span> + body);
            }
        }
</pre>
</div></div>

<p>In which we want to trigger when the message contains Camel. So we can create this
<tt>Condition</tt>:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
        camelCondition = <span class="code-keyword">new</span> ConditionSupport()
{
            <span class="code-keyword">public</span> <span class="code-object">boolean</span>
matchProcess(Exchange exchange, Processor processor, ProcessorDefinition definition) {
                <span class="code-keyword">return</span> body().contains(<span
class="code-quote">"Camel"</span>).matches(exchange);
            }
        };
</pre>
</div></div>

<p>And to use this we just tell the <tt>Debugger</tt> 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> void testDebug() <span class="code-keyword">throws</span>
Exception {
        context.getDebugger().addBreakpoint(breakpoint, camelCondition);

        getMockEndpoint(<span class="code-quote">"mock:result"</span>).expectedBodiesReceived(<span
class="code-quote">"Hello World"</span>, <span class="code-quote">"Hello Camel"</span>);

        template.sendBody(<span class="code-quote">"direct:start"</span>, <span
class="code-quote">"Hello World"</span>);
        template.sendBody(<span class="code-quote">"direct:start"</span>, <span
class="code-quote">"Hello Camel"</span>);

        assertMockEndpointsSatisfied();

        assertEquals(2, logs.size());
        assertEquals(<span class="code-quote">"Breakpoint at To[log:foo] with body:
Hello Camel"</span>, logs.get(0));
        assertEquals(<span class="code-quote">"Breakpoint at To[mock:result] with body:
Hello Camel"</span>, logs.get(1));
    }
</pre>
</div></div>

<p>Which then will only invoke the breakpoint callback for the <tt>"Hello Camel"</tt>
message.</p>


<h3><a name="Camel2.x-DebuggerAPI-Singlestep"></a>Single step</h3>

<p>In the Java editor the debugger is capable of single stepping when a breakpoint is
hit. The idea in Camel is that you want to single step an <a href="/confluence/display/CAMEL/Exchange"
title="Exchange">Exchange</a> so you can step through how its routed and follow it
from the 3rd party tooling. </p>

<p>The <tt>Debugger</tt> has API for single stepping. For example to single
step the first message arrived in Camel you can do</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
        context.getDebugger().addSingleStepBreakpoint(breakpoint);
</pre>
</div></div>

<p>However what if you have multiple routes or the likes and only want to single step
from route X, well you can just add a <tt>Condition</tt>:</p>

<p>This <tt>beerCondition</tt> will only match <a href="/confluence/display/CAMEL/Exchange"
title="Exchange">Exchange</a> coming from the <tt>beer</tt> route:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
        beerCondition = <span class="code-keyword">new</span> ConditionSupport()
{
            <span class="code-keyword">public</span> <span class="code-object">boolean</span>
matchProcess(Exchange exchange, Processor processor, ProcessorDefinition definition) {
                <span class="code-keyword">return</span> <span class="code-quote">"beer"</span>.equals(exchange.getFromRouteId());
            }
        };
</pre>
</div></div>

<p>So you just provide the condition when adding the breakpoint:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">

        <span class="code-comment">// we only want to single step the beer route
</span>        context.getDebugger().addSingleStepBreakpoint(breakpoint, beerCondition);
</pre>
</div></div>

<p>And the routes could be 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> void configure() <span
class="code-keyword">throws</span> Exception {
                <span class="code-comment">// use debugger
</span>                context.setDebugger(<span class="code-keyword">new</span>
DefaultDebugger());

                from(<span class="code-quote">"direct:start"</span>).routeId(<span
class="code-quote">"foo"</span>).to(<span class="code-quote">"log:foo"</span>).to(<span
class="code-quote">"log:bar"</span>).to(<span class="code-quote">"mock:result"</span>);

                from(<span class="code-quote">"direct:beer"</span>).routeId(<span
class="code-quote">"beer"</span>).to(<span class="code-quote">"log:beer"</span>).to(<span
class="code-quote">"mock:result"</span>);
            }
</pre>
</div></div>

<p>Which will cause the debugger to only single step when a message arrives on <tt>beer</tt>
route:</p>
<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
    <span class="code-keyword">public</span> void testDebug() <span class="code-keyword">throws</span>
Exception {
        <span class="code-comment">// we only want to single step the beer route
</span>        context.getDebugger().addSingleStepBreakpoint(breakpoint, beerCondition);

        getMockEndpoint(<span class="code-quote">"mock:result"</span>).expectedBodiesReceived(<span
class="code-quote">"Hello World"</span>, <span class="code-quote">"Carlsberg"</span>);

        template.sendBody(<span class="code-quote">"direct:start"</span>, <span
class="code-quote">"Hello World"</span>);
        template.sendBody(<span class="code-quote">"direct:beer"</span>, <span
class="code-quote">"Carlsberg"</span>);

        assertMockEndpointsSatisfied();

        assertEquals(2, logs.size());
        assertEquals(<span class="code-quote">"Single stepping at log:beer with body:
Carlsberg"</span>, logs.get(0));
        assertEquals(<span class="code-quote">"Single stepping at mock:result with body:
Carlsberg"</span>, logs.get(1));
    }
</pre>
</div></div>

<h2><a name="Camel2.x-DebuggerAPI-Notes"></a>Notes</h2>
<ul class="alternate" type="square">
	<li>The single step feature should only allow one <em>active</em> at any
time. So if there is already a single step message in process other messages should be disregarded
from debugging</li>
	<li>Should other breakpoints be active during single step? In case you have another
breakpoint somewhere which may get triggered?</li>
	<li>Should we add a fluent builder syntax for sugar, so its easier to use common conditions?</li>
</ul>



<h2><a name="Camel2.x-DebuggerAPI-Usecases"></a>Use cases</h2>

    </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/Camel+2.x+-+Debugger+API">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=23332117&revisedVersion=2&originalVersion=1">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/CAMEL/Camel+2.x+-+Debugger+API?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message