tag:blogger.com,1999:blog-66351723484529104042024-02-20T09:39:12.542+08:00Willem's BlogWillemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.comBlogger17125tag:blogger.com,1999:blog-6635172348452910404.post-45366765815187649582014-04-01T11:11:00.002+08:002015-01-13T10:01:39.885+08:00New components in Camel 2.13.0Camel 2.13.0 was out for about a week, I hope it's not too late to share the high lights of Camel 2.13.0 in my blog :)<br />
<br />
There are about 7 new added components: <a href="http://camel.apache.org/hdfs2.html" target="_blank">camel-hdfs2</a>, <a href="http://camel.apache.org/infinispan.html" target="_blank">camel-infinispan</a>, <a href="http://camel.apache.org/jgroups.html" target="_blank">camel-jgroups</a>, camel-kafka, <a href="http://camel.apache.org/optaplanner.html" target="_blank">camel-optaplanner</a>, <a href="http://camel.apache.org/splunk.html" target="_blank">camel-splunk</a>, <a href="http://camel.apache.org/aws-swf.html" target="_blank">camel-swf</a>.<br />
<br />
It is interesting that the most of these components are for Cloud or BigData. But I want to brief these new added component differently.<br />
<br />
As main contributor of Apache Camel, it's amazing to see the power of
community which drives us to know more and more interesting projects, <a href="http://camel.apache.org/optaplanner.html" target="_blank">camel-optaplanner</a>, <a href="http://camel.apache.org/splunk.html" target="_blank">camel-splunk</a>, camel-kafka are these components. It comes from community contribution and keeps shaping by the hands from the community. <br />
<br />
Now Apache Camel hosts more than 100 components. As Camel wants to give the
user full control of integration choice, Camel even provides components of
same functions which are implemented by different third party projects.<a href="http://camel.apache.org/infinispan.html" target="_blank"> camel-infinispan</a> is a memory cache component which is much like
<a href="http://camel.apache.org/hazelcast-component.html" target="_blank">camel-hazelcast</a>. <br />
<br />
Apache Camel cannot host some third part components due to <a href="http://www.apache.org/legal/3party.html" target="_blank">the license issue,</a> so we created <a href="https://code.google.com/a/apache-extras.org/p/camel-extra/" target="_blank">camel-extra </a>to give a home for these components. It's good to see more and more third part projects move to<a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank"> ASLv2</a>, which means we can host these kind of components in Apache Camel. <a href="http://camel.apache.org/jgroups.html" target="_blank">camel-jgroups</a> is part of Apache Camel now. <br />
<br />
We also did some bug fixing and enhancement, you can find more information in the <a href="http://camel.apache.org/camel-2130-release.html" target="_blank">release note</a> and <a href="https://issues.apache.org/jira/secure/ReleaseNote.jspa?version=12324786&styleName=Html&projectId=12311211" target="_blank">the JIRA report</a>. <br />
<br />
<br />
<br />
<br />Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com1tag:blogger.com,1999:blog-6635172348452910404.post-17001813134260527692013-09-12T21:25:00.000+08:002013-09-14T10:19:08.289+08:00Apache Camel 2.12.0 Camel 2.12.0 was released this week. Now I just want to spend few minutes to introduce some high lights of this release.<br />
<br />
First it is amazing that we added about 16 new components in Camel 2.12.0, and most of these components were contributed from the user who write these components for their daily work.<br />
<br />
<a href="http://camel.apache.org/disruptor.html" target="_blank">camel-disruptor</a> is leveraging<a href="https://github.com/LMAX-Exchange/disruptor" target="_blank"> LMAX Disruptor</a> to provide the <a href="http://www.eecs.harvard.edu/~mdw/proj/seda/" target="_blank">SEDA</a> behavior in Camel, you can treat it as the replacement of the <a href="http://camel.apache.org/seda.html" target="_blank">camel-seda</a>. The big difference between camel-disruptor and <a href="http://camel.apache.org/seda.html" target="_blank">camel-seda</a> is that camel-disruptor is using the disruptor's ring buffer to store the message and <a href="http://camel.apache.org/seda.html" target="_blank">camel-seda</a> is using JDK memory queue to to store the message. If you have lots of worker thread need to be coordinated with the message flow, you can consider to use <a href="http://camel.apache.org/disruptor.html" target="_blank">camel-disruptor </a>to save you lots of time.<br />
<br />
Lots of camel user are interesting about integrating their application with the social network API, now we have <a href="http://camel.apache.org/yammer.html" target="_blank">camel-yammer</a>, <a href="http://camel.apache.org/facebook.html" target="_blank">camel-facebook</a> to help you interact with these social network system. If your boss wants you to use camel to write some integration code with <a href="http://www.salesforce.com/" target="_blank">salesforce</a>, the <a href="http://camel.apache.org/salesforce.html" target="_blank">camel-salesforce</a> could be your first choice.<br />
<br />
For the other components, one of them is supporting new version of third part library, such as <a href="http://camel.apache.org/quartz2.html" target="_blank">camel-quartz2</a>, some of them are supporting other protocol such as <a href="http://camel.apache.org/rabbitmq.html" target="_blank">camel-rabbitmq</a>, <a href="http://camel.apache.org/stomp.html" target="_blank">camel-stomp,</a> <a href="http://camel.apache.org/netty-http.html" target="_blank">camel-netty-http</a>.<br />
<br />
There are also some improvements on the camel-core side to make camel more easy to use<br />
<br />
<ul>
<li>Reduced stack-frames in use during routing, that also makes Camel's
stack traces being logged much less verbose. This also allows people to
easier debug the internals of Camel as less <tt>AsyncCallback</tt> callbacks are in use during routing. </li>
<li>Easy to use <a href="http://camel.apache.org/message-history.html" shape="rect" title="Message History">Message History</a> out of the box. And included message history as "route stack-trace" when exceptions logged by <a href="http://camel.apache.org/error-handler.html" shape="rect" title="Error Handler">Error Handler</a> to make it easier for end users to spot where the exception occurred.</li>
<li><a href="http://camel.apache.org/stream-caching.html" target="_blank">Stream caching</a> configuration become easier by using StreamCachingStrategy which allows spool directory per Camel Context instead of shared per JVM. And you can see the stream insight at run time by using JMX management.</li>
<li>Polling Consumers such as<a href="http://camel.apache.org/file2.html" target="_blank"> File</a>, and <a href="http://camel.apache.org/ftp2.html" target="_blank">FTP</a> now supports using custom scheduler.Providing a new Quartz2, and Spring based out of the box, that allows to use CRON based scheduler.</li>
<li>New class <tt>org.apache.camel.util.toolbox.AggregationStrategies</tt> as a starting point to obtain commonly used Aggregation Strategies for Multicast, Splitter, Aggregator, etc. EIPs.</li>
<li>New <tt>FlexibleAggregationStrategy</tt>
serving as a one-stop to perform typical aggregation strategy logic
out-of-the-box: filtering results, storing them in properties, headers
or bodies, as a list, casting results, etc.</li>
<li>Camel 2.12.0 also supports to setup the AggregationStrategy in POJO way. </li>
<li>Added support for XML Encryption 1.1 algorithms in the <a href="http://camel.apache.org/xmlsecurity-dataformat.html" shape="rect" title="XMLSecurity DataFormat">XMLSecurity data format</a>. It is now possible to specify stronger digest algorithms when using RSA OAEP Key Transport algorithms.</li>
</ul>
If you want to go through the detail changes, you can find more information from the <a href="http://camel.apache.org/camel-2120-release.html" target="_blank">release note </a>and <a href="https://issues.apache.org/jira/secure/ReleaseNote.jspa?version=12323968&projectId=12311211" target="_blank">change log</a>.<br />
<br />Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com2tag:blogger.com,1999:blog-6635172348452910404.post-90664749097458069212011-01-27T18:08:00.001+08:002014-03-28T20:21:36.700+08:00How to map the SOAP fault message with a custom exception?I was working on some customer issues about throwing a SOAP fault back to the client in CXF recently. It made me think it's a common issue that I should blog about it.<br />
First, what does the SOAP Fault message look like ?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7KA6xFBWOlsdU-QWC_2a2V1jT6J3VQpK44YVpmsOVRUsILn7kcrgtlu_JB7sjLxnv0x2i7V578u7fR4Defr0pB_6Eak3FH_eBf7Ncrrs0M97ubcwDEp-X2Xqs_MugOa1qdlzBdqUDDuqo/s1600/Screen+shot+2011-01-27+at+5.17.33+PM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7KA6xFBWOlsdU-QWC_2a2V1jT6J3VQpK44YVpmsOVRUsILn7kcrgtlu_JB7sjLxnv0x2i7V578u7fR4Defr0pB_6Eak3FH_eBf7Ncrrs0M97ubcwDEp-X2Xqs_MugOa1qdlzBdqUDDuqo/s1600/Screen+shot+2011-01-27+at+5.17.33+PM.png" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Just like the SOAP message, the SOAP fault has a generic message structure, it consists of faultcode, faultstring and detail elements. <br />
<br />
How can SOAP fault message turn into a custom Exception that you can you can use in the Java world? The key is the child element of the detail element.<br />
From the upper example, you can see there an UnknownPersonFault element in the detail element, and this Fault message will be mapped to the<span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"> </span><b><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;">UnknownPersonFault</span></b> exception as we want when the CXF client receives this message.<br />
<br />
Let's take a look at the UnknowPersonFault Java code to see how this part works.<br />
<br />
<blockquote>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">package</span> org.apache.camel.wsdl_first;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">import</span> javax.xml.ws.WebFault;</div>
<div style="color: #4200ff; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #777777;">@WebFault</span><span style="color: black;">(name = </span>"UnknownPersonFault"<span style="color: black;">, targetNamespace = </span>"http://camel.apache.org/wsdl-first/types"<span style="color: black;">)</span></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> <span style="color: #9e0067;">class</span> UnknownPersonFault <span style="color: #9e0067;">extends</span> Exception {</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> <span style="color: #9e0067;">static</span> <span style="color: #9e0067;">final</span> <span style="color: #9e0067;">long</span> <span style="color: #1000d1;">serialVersionUID</span> = 20110126200613L;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">private</span> org.apache.camel.wsdl_first.types.UnknownPersonFault <span style="color: #1000d1;">unknownPersonFault</span>;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> UnknownPersonFault() {</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">super</span>();</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
}</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> UnknownPersonFault(String message) {</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">super</span>(message);</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
}</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> UnknownPersonFault(String message, Throwable cause) {</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">super</span>(message, cause);</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
}</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> UnknownPersonFault(String message, org.apache.camel.wsdl_first.types.UnknownPersonFault unknownPersonFault) {</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">super</span>(message);</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">this</span>.<span style="color: #1000d1;">unknownPersonFault</span> = unknownPersonFault;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
}</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> UnknownPersonFault(String message, org.apache.camel.wsdl_first.types.UnknownPersonFault unknownPersonFault, Throwable cause) {</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">super</span>(message, cause);</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">this</span>.<span style="color: #1000d1;">unknownPersonFault</span> = unknownPersonFault;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
}</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> org.apache.camel.wsdl_first.types.UnknownPersonFault getFaultInfo() {</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">return</span> <span style="color: #9e0067;">this</span>.<span style="text-decoration: underline;">unknownPersonFault</span>;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
}</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
}</div>
<div>
<br /></div>
</blockquote>
Wait a minute, why there is another UnknownPersonFault? Let's dig into the new found one.<br />
<blockquote>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">package</span> org.apache.camel.wsdl_first.types;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">import</span> javax.xml.bind.annotation.XmlAccessType;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">import</span> javax.xml.bind.annotation.XmlAccessorType;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">import</span> javax.xml.bind.annotation.XmlElement;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">import</span> javax.xml.bind.annotation.XmlRootElement;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">import</span> javax.xml.bind.annotation.XmlType;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
/**</div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* <span style="color: #9290b0;"><p></span>Java class for anonymous complex type.</div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* </div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* <span style="color: #9290b0;"><p></span>The following schema fragment specifies the expected content contained within this class.</div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* </div>
<div style="color: #9290b0; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #496fcf;"> * </span><pre></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* &lt;complexType></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* &lt;complexContent></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* &lt;sequence></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* &lt;element name="personId" type="{http://www.w3.org/2001/XMLSchema}string"/></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* &lt;/sequence></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* &lt;/restriction></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* &lt;/complexContent></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* &lt;/complexType></div>
<div style="color: #9290b0; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #496fcf;"> * </span></pre></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* </div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* </div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
*/</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #777777;">@XmlAccessorType</span>(XmlAccessType.<span style="color: #1000d1;">FIELD</span>)</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #777777;">@XmlType</span>(name = <span style="color: #4200ff;">""</span>, propOrder = {</div>
<div style="color: #4200ff; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: black;"> </span>"personId"</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
})</div>
<div style="color: #4200ff; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #777777;">@XmlRootElement</span><span style="color: black;">(name = </span>"UnknownPersonFault"<span style="color: black;">)</span></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> <span style="color: #9e0067;">class</span> UnknownPersonFault {</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #777777;">@XmlElement</span>(required = <span style="color: #9e0067;">true</span>)</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">protected</span> String <span style="color: #1000d1;">personId</span>;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #496fcf;">/**</span></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* Gets the value of the personId property.</div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* </div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* <span style="color: #8bafcd;">@return</span></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* possible object is</div>
<div style="color: #5248cf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #496fcf;"> * </span>{@link String }</div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* </div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
*/</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> String getPersonId() {</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">return</span> <span style="color: #1000d1;">personId</span>;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
}</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #496fcf;">/**</span></div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* Sets the value of the personId property.</div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* </div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* <span style="color: #8bafcd;">@param</span> value</div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* allowed object is</div>
<div style="color: #5248cf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #496fcf;"> * </span>{@link String }</div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
* </div>
<div style="color: #496fcf; font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
*/</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">public</span> <span style="color: #9e0067;">void</span> setPersonId(String value) {</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">this</span>.<span style="color: #1000d1;">personId</span> = value;</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
}</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px; min-height: 15.0px;">
<br /></div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
}</div>
<div>
<br /></div>
</blockquote>
Oh, this one is the real UnknownPersonFault which can be used by JAXB to marshal and unmarshal the message. And it is wrapped by an exception which is annotated with @WebFault. This @WebFault will be helpful when CXF wants to create a custom exception from a SOAP fault message. Because CXF can look up the detail child element QName for it.<br />
<br />
And when CXF tries to marshal this custom exception, it can easily write the detail child element by marshaling the exception.getFaultInfo().So when we throw the exception from the SEI , we should use the wrapped exception instead of the JAXB annotated class which is not a real exception, and you also need to pass the JAXB fault class instance into the exception to fill the detail element like this.<br />
<blockquote>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
org.apache.camel.wsdl_first.types.UnknownPersonFault faultDetail = <span style="color: #9e0067;">new</span> org.apache.camel.wsdl_first.types.UnknownPersonFault();</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
faultDetail.setPersonId(<span style="color: #4200ff;">""</span>);</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
UnknownPersonFault fault = <span style="color: #9e0067;">new</span> UnknownPersonFault(<span style="color: #4200ff;">"Get the null value of person name"</span>, faultDetail);</div>
<div style="font: 11.0px Monaco; margin: 0.0px 0.0px 0.0px 0.0px;">
<span style="color: #9e0067;">throw</span> fault;</div>
</blockquote>
<br />
If the detail element has no child element, the CXF client will just create a common <span class="Apple-style-span" style="border-collapse: collapse; font-family: Arial, sans-serif;"> </span><span class="Apple-style-span" style="border-collapse: collapse; font-size: 12px;"><b><span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"><span class="Apple-style-span" style="font-size: small;">SOAPFaultException</span>, </span></b></span>because it has no idea about how to map the SOAP Fault message into a custom exception.Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com4tag:blogger.com,1999:blog-6635172348452910404.post-46912884831059265632010-10-13T15:03:00.001+08:002010-10-13T16:45:46.772+08:00The Book review of OSGi in ActionAfter finished the technical proofreading of <a href="http://www.manning.com/ibsen/">Camel in Action</a>, I finally got some time to write a review of <a href="http://www.manning.com/hall/">OSGi in Action</a>.<br />
<br />
Just like the <a href="http://www.manning.com/ibsen/">Camel in Action</a>, Manning invited the committers of Apache project to write the OSGi book. As you know <a href="http://felix.apache.org/">Apache Felix</a> is an OSGi specification implementation, so the writers have the first-hand real world experience of the technology. They tell you not only what you can do with OSGi but also why the OSGi was designed as it is.<br />
<br />
The <a href="http://www.manning.com/hall/Hall_MEAP_01.pdf">first chapter</a> of this book is free for download, with it you can have brief overview what is OSGi, and see the simple example with it.<br />
<br />
If you take a look at the Chapter2, you can get the a deep understand for the OSGi modularity. Why the modularity is so important to software development, what's the shortcoming of the Java package, and how OSGi make a great improvement by creating a bundle with the metadata. With this fundamental knowledge you will grasp the sprit of OSGi modularity. <br />
<br />
In Chapter3, the writer give us a whole lifecycle picture of the bundle which is another key part of OSGi. By leveraging this lifecycle API, your bundle isn't a set of classes, they can interact with each other by using the services at the runtime. In Chapter4, you can know how OSGi dynamically works to bring all the services work together.<br />
<br />
I highly recommend you to go through the first 4 chapters of the <a href="http://www.manning.com/hall/">OSGi in Action</a> even if you have some working experience of the OSGi. The writer draws a whole picture of the OSGi technology by give a good explanation from three perspective of OSGi, modularity, lifecycle and services. These information can guide you a right direction when you feel lost in OSGi world.<br />
<br />
If you need to build a bundle yourself, or you need to fix the weird exceptions of bundles, please take a good look at the Chapter5 and 6. They can tell you how the bundle metadata works, and what the fragment bundles are and what they can do.<br />
<br />
Testing and debugging are a daily part of development, but OSGi has some unique characteristics that makes these tasks more difficult using your normal java development experience. There are some tools and framework can help to do it better. Chapter7 and 8 can definitely give you the handy testing and debugging experiences.<br />
<br />
When you deploy the bundle into OSGi platform, there are still some tips you should know about. Chapter 9, 10 can tell you how to manage the bundles and application. By knowing these information, you will have confidences to export to the OSGi jungle and successfully battle the OSGi runtime monster. <br />
<br />
If you want to know how to design or architect your OSGi application, there are some general ideas of of the component orientation things you should know in Chapter11, and you can make the best usage of the OSGi by applying the component orientation principles. <br />
<br />
I really love the first 10 chapters, they help me greatly in understanding more about the OSGi. The other part of this book covered some advance topics, such as the Blueprint, iPOJO, launching and embedding an OSGi Framework, security, web application etc. They are the interesting topics, but they are too complexed to be covered with just few sections. OSGi Enterprise specifications are also working on these areas, you can get some basic idea about these topics by reading the chapter 12,13,14,15. <br />
<br />
If you want to visit the OSGi world and have some success there, <a href="http://www.manning.com/hall/">OSGi in Action</a> could be a good choice for you :)Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com2tag:blogger.com,1999:blog-6635172348452910404.post-8673816615133831832010-09-30T16:46:00.002+08:002010-11-22T11:45:54.511+08:00CXF Continuation API EnhancementFrom Web 2.0, there are more and more long time connections are used by client to access the back end system, and they will consume lots of thread if the server is working on per thread per request mode. Jetty 6 introduced the <a href="http://docs.codehaus.org/display/JETTY/Continuations">Continuation API</a> to resolve the this problem.<br />
<br />
Few years ago CXF provides the same kind of <a href="http://sberyozkin.blogspot.com/2008/12/continuations-in-cxf.html">continuation API</a> to let the user have a chance to release the request thread if the response is not ready. This feature is very important if you want to keep your application with a good performance and good scalability.<br />
<br />
<br />
As we did some house clean up from Camel 2.4.0 to make sure the Camel component has the best usage of the <a href="https://cwiki.apache.org/CAMEL/asynchronous-routing-engine.html">Camel Async Route Engine</a>, I did some work on camel-cxf recently. I just found current CXF continuation which suspending is implemented by throw the runtime exception. This implementation has a shortcoming which cannot call the other framework's async API after continuation suspend is called as <a href="http://blogs.webtide.com/gregw/entry/continuations_to_continue">Jetty7 does</a>. This will introduce a situation that continuation resume will be called before the continuation suspend is called.<br />
To avoid this bad situation which will make suspended continuation never resumed, I had to write my Camel code like this<br />
<br />
<blockquote>private Object asyncInvoke(Exchange cxfExchange, final Continuation continuation) {<br />
synchronized (continuation) {<br />
if (continuation.isNew()) {<br />
final org.apache.camel.Exchange camelExchange = perpareCamelExchange(cxfExchange);<br />
<br />
// use the asynchronous API to process the exchange<br />
boolean sync = getAsyncProcessor().process(camelExchange, new AsyncCallback() {<br />
public void done(boolean doneSync) {<br />
// make sure the continuation resume will not be called before the suspend method in other thread<br />
synchronized (continuation) {<br />
if (LOG.isTraceEnabled()) {<br />
LOG.trace("Resuming continuation of exchangeId: "<br />
+ camelExchange.getExchangeId());<br />
}<br />
// resume processing after both, sync and async callbacks<br />
continuation.setObject(camelExchange);<br />
continuation.resume();<br />
}<br />
}<br />
});<br />
// just need to avoid the continuation.resume is called<br />
// before the continuation.suspend is called<br />
if (continuation.getObject() != camelExchange && !sync) {<br />
// Now we don't set up the timeout value<br />
if (LOG.isTraceEnabled()) {<br />
LOG.trace("Suspending continuation of exchangeId: "<br />
+ camelExchange.getExchangeId());<br />
}<br />
// The continuation could be called before the suspend<br />
// is called<br />
continuation.suspend(0);<br />
} else {<br />
// just set the response back, as the invoking thread is<br />
// not changed<br />
if (LOG.isTraceEnabled()) {<br />
LOG.trace("Processed the Exchange : " + camelExchange.getExchangeId());<br />
}<br />
setResponseBack(cxfExchange, camelExchange);<br />
}<br />
<br />
}<br />
if (continuation.isResumed()) {<br />
org.apache.camel.Exchange camelExchange = (org.apache.camel.Exchange)continuation<br />
.getObject();<br />
setResponseBack(cxfExchange, camelExchange);<br />
<br />
}<br />
}<br />
return null;<br />
}<br />
<br />
</blockquote><br />
<br />
As you know CXF has lot of interceptor which can chained together as a SOAP stack and doing the WS* work, if we can suspend the interceptor chain, it will be easy for us to resume it from other thread. You can find a handy example from <a href="https://svn.apache.org/repos/asf/cxf/trunk/rt/core/src/main/java/org/apache/cxf/interceptor/OneWayProcessorInterceptor.java">OneWayProcessorInterceptor</a>.<br />
My enhancement on CXF continuation API by introducing a suspend status into CXF PhaseInterceptorChain. The implementation of the CXF continuation API set the status of PhaseInterceptorChain, then the interceptor calling thread will be broke out after the interceptor handle method returns. Now my Camel code would be more easy to understand <br />
<br />
<blockquote>private Object asyncInvoke(Exchange cxfExchange, final Continuation continuation) {<br />
if (continuation.isNew()) {<br />
final org.apache.camel.Exchange camelExchange = perpareCamelExchange(cxfExchange);<br />
// Now we don't set up the timeout value<br />
if (LOG.isTraceEnabled()) {<br />
LOG.trace("Suspending continuation of exchangeId: "<br />
+ camelExchange.getExchangeId());<br />
}<br />
// now we could call the suspend here<br />
continuation.suspend(0);<br />
<br />
// use the asynchronous API to process the exchange<br />
getAsyncProcessor().process(camelExchange, new AsyncCallback() {<br />
public void done(boolean doneSync) {<br />
if (LOG.isTraceEnabled()) {<br />
LOG.trace("Resuming continuation of exchangeId: "<br />
+ camelExchange.getExchangeId());<br />
}<br />
// resume processing after both, sync and async callbacks<br />
continuation.setObject(camelExchange);<br />
continuation.resume();<br />
}<br />
});<br />
<br />
}<br />
if (continuation.isResumed()) {<br />
org.apache.camel.Exchange camelExchange = (org.apache.camel.Exchange)continuation<br />
.getObject();<br />
setResponseBack(cxfExchange, camelExchange);<br />
<br />
}<br />
return null;<br />
}<br />
</blockquote><br />
<a href="https://issues.apache.org/jira/browse/CXF-2982
">The enhanced CXF continuation API patch</a> is committed into CXF trunk and it is part of <a href="http://fusesource.com/products/enterprise-cxf/">Fuse Service FrameWork</a> 2.3.0 now.Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com1tag:blogger.com,1999:blog-6635172348452910404.post-10189049302062074312010-02-15T11:16:00.001+08:002011-02-09T10:23:04.642+08:00Configure the camel-cxf endpoint advance features from URIAs you know CXF provides the advance configuration on the CXF endpoints, such as interceptors, features etc.<br />
<br />
In camel-cxf we leverage the CXF configuration which is based on the Spring to provide the same thing as CXF does, but in Camel we have the classical URI configuration which means you can configure the endpoint's by using the URI parameters. URI is easy way for the user as it support the DSL and Spring configuration smoothly, and you can deal with the URI as string to add your customer properties.<br />
<br />
How can we configure the interceptor or the features on the camel-cxf endpoints by just setting few option parameters?<br />
The key of the answer is you can set the bus of the camel-cxf endpoint by using the URI option bus.<br />
You can set the features or interceptor on the bus as <a href="http://cxf.apache.org/docs/bus-configuration.html">CXF bus configuration</a> does and then set the camel-cxf endpoint URI like this "cxf://Address?Bus=#cxf&...".Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com1tag:blogger.com,1999:blog-6635172348452910404.post-11889192293738367802009-05-03T15:30:00.004+08:002009-05-03T15:53:32.607+08:00Better OSGi integration test support In CamelTwo weeks ago, James did a great work by <a href="http://macstrac.blogspot.com/2009/04/if-you-are-using-osgi-then-give-pax.html">adding an OSGi integration test module</a> which was based on <a href="http://wiki.ops4j.org/display/paxexam/Pax+Exam">Pax Exam</a>. <br /><br />Then, I did some enhancements for this test module this week.<br /><br />1. You can use the camel features to install the bundles for you test.<br />Instead of adding the camel-xxx module dependency in the POM for the Pax Exam plugin to setup the bundles list, we can leverage the camel features to setup the bundles that we may use in the integration test.<br /><br />Here is a code example<br /><br /><blockquote>// using the features to install the camel components <br />scanFeatures(mavenBundle().groupId("org.apache.camel.karaf"). artifactId("features").versionAsInProject().type("xml/features"), <br /> "camel-core", "camel-osgi", "camel-spring", "camel-test"),<br /></blockquote><br /><br />You can keep on adding the features that you need such as "camel-jms", "camel-jetty", and don't need to any modification on the module's pom.xml.<br /><br />2. I added the OSGi version of the Camel TestSupport classes, so you could write the test more easily. If you are using the traditional Java DSL to setup the route rule, you just extend the <a href="http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/OSGiIntegrationTestSupport.java?view=markup">OSGiIntegrationTestSupport</a>; if you are big fan of Spring, you can extend the <a href="http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/OSGiIntegrationSpringTestSupport.java?view=markup">OSGIIntegrationSpringTestSupport</a>, and it will take care of creating the application context in the OSGi plateform.Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com0tag:blogger.com,1999:blog-6635172348452910404.post-27310767776870727022009-03-12T09:20:00.003+08:002009-03-12T09:41:24.586+08:00Set the properties for Camel ContextIf you want to do customer configuration on the inner component of Camel 2.0, how can you achieve that? You may say to use the system properties is a easy way.<br />But if I want to configure the component per camel context, as you know there could be more than one camel context per JVM.<br />I just introduced a property configuration per camel context in the Camel 2.0, so you want to configure the cachedOutputStream of Camel , you can do it like this.<br /><br />With the java code<br /><blockquote><br />Map<String, String> properties = new HashMap<String, String>();<br />properties.put(CachedOutputStream.THRESHOLD, "1000");<br />properties.put(CachedOutputStream.TEMP_DIR, "/tmp/camel");<br />camelContext..setProperties(properties);<br /></blockquote><br /><br /><br />With Spring configuration<br /><blockquote><br /><camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"><br /><properties><br /><property key="CamelCachedOutputStreamThreshold" value="10000"/><br /></properties><br /><property key="CamelCachedOutputStreamOutputDirectory" value="/tmp/camel"/><br /></properties><br /><property key="the key of properties" value="the value as string"/><br /></properties><br />...<br /><camelContext><br /></blockquote>Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com4tag:blogger.com,1999:blog-6635172348452910404.post-36477808800663776262009-02-23T16:33:00.015+08:002009-02-25T08:44:50.263+08:00How to use extra camel componets in servicemix-camelWhen I was doing the spring clean up work for fuse ESB 3.x. I came across the issues of using the extra camel components within ESB3.x's servicemix-camel component.<br /><br />Since Servicemix3's has same hierarchies of the class loaders with the J2EE application server, and the components the class loader is separated with the SU's. And Camel has lots of components, we just include the camel-core and camel-spring components in the servicemix-camel by default. When the user want to use other camel component, they always add the camel-xxx component into their SU lib.<br />In this way if there is a class which is loaded from the different SU classloader and registered into the camel-core's registry by servicemix-camel component , we will faced on the typical class cast exception in Servicemix3. Basically this exception is caused by the same class is loaded by different class loader.<br /><br />Let me give you <a href="http://fusesource.com/issues/browse/ESB-243">a real world issue</a>.<br /><br />In this case, when the SU redeployed, it will create a new deployer which will create a application context with the class loader of servicemix-camel component, and then using the SU's class loader to create a camel context.<br />Since the SU is redeployed, Servicemix will create a new class loader to load the SU's lib jars and resources.<br />When the SU initial the rmi component, boom , we meet the situation of same component loaded with different class loader, The class cast exception is thrown out.<br /><br />Note, In Servicemix4 , we will not get that kind of issue , since the OSGI will help us to manage the relationship of the jars :).<br /><br />The solution is putting the camel-xxx component and third part jars into servicemix-camel component's lib. You need to check out the servicemix-camel component's pom.xml and recompile the servicemix-camel component by adding the camel-xxx component dependency.<br /><br />Let me take the latest servicemix-camel as an example<br /><br />1. Checking out the servicemix-camel component's pom<br /><br /><br /><blockquote>svn co http://svn.apache.org/repos/asf/servicemix/components/engines/servicemix-camel/trunk/pom.xml</blockquote><br /><br />2. If you need camel-rmi component , you just put the dependency into the pom.xml<br /><br /><blockquote><br /><dependency><br /><groupid>org.apache.camel</groupid><br /><artifactid>camel-rmi</artifactid><br /><version>${camel-version}</version><br /></dependency><br /></blockquote><br /><br />3. Running "mvn install" and copy the servicemix-camel-*.zip into the deploy directory<br /><br />4. Write your servicemix-camel SU, make sure you don't include any camel relates jars into the SU's lib, you can use the <scope>provided</scope> to not packing the artifact.<br /><br /><blockquote><br /><dependency><br /><groupid>org.apache.camel</groupid><br /><artifactid>camel-rmi</artifactid><br /><version>${camel-version}</version><br /><scope>provided</scope><br /></dependency><br /></blockquote>Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com0tag:blogger.com,1999:blog-6635172348452910404.post-80281738677690485382009-01-22T12:15:00.003+08:002009-01-22T12:21:53.323+08:00Powerful svn mergeSince I'm always using <a href="http://www.orcaware.com/svn/wiki/Svnmerge.py">svnmerge.py</a> to do the merge stuff, I have no chance to go through the <a href="http://svnbook.red-bean.com/en/1.0/re16.html">svn merge</a> doc.<br />Now I just found svn merge is so powerful.<br /><br />If you just want to merge one pic of change from trunk to branch, you don't have to do the <blockquote>svnmerge.py init<br /><br />svnmerge.py merge ...</blockquote><br />You can just type in you working copy directory<br /><blockquote><br /><span style="color: rgb(51, 102, 255);">svn merge -c VERSION YOUR_TRUNK_URL [WCPATH]</span></blockquote><br /><br />If you want to revert the change for the svn server side , not just your working copy<br /><blockquote style="color: rgb(51, 102, 255);">svn merge -rVERSION:VERSION-1 SOURCE [WCPATH]</blockquote>Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com0tag:blogger.com,1999:blog-6635172348452910404.post-3227542989903645882009-01-21T09:19:00.003+08:002009-02-24T16:24:52.232+08:00What's new in Camel 2.0I have been asked by lots of friend who are using or going to using Camel, what's new in Camel 2.0.<br />I just found <a href="http://davsclaus.blogspot.com/">Claus</a> set up <a href="http://cwiki.apache.org/confluence/display/CAMEL/Camel+2.0+Design">a good wiki page</a> for all these kind informations.<br />Some high lights includes:<br /><br />New features:<br /><ul><li>Make more endpoints easily configurable as beans in Spring XML.</li><li>Improve the DSL</li><li>...<br /></li></ul>API Changes<br /><ul><li>Remove the use of generics on Component, Exchange, Producer, Consumer</li><li>Change to use verb for EIP action</li><li>...<br /></li></ul><br /><br />You can find the<a href="http://cwiki.apache.org/confluence/display/CAMEL/Camel+2.0.0+Release"> release notes</a> about Camel 2.0 (Working in progress) here.Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com0tag:blogger.com,1999:blog-6635172348452910404.post-65523822955561676162009-01-11T19:42:00.001+08:002009-01-11T19:44:45.736+08:00Camel中的几个重要概念之Routes, RouteBuilders 和 Java DSL<span style="font-weight:bold;">Route</span><br /><br />一个route就是将一个输入队列中获得的消息,通过一步一步地设置好的逻辑判断(例如过滤器和路由规则)到达一个目标队列中(如果有的话)。Camel为应用开发者提供了两种途径来定义这些路由规则。一个是通过XML来定义路由信息,有关这部分的内容不会在本文档中讨论。另一种方式就是通过Camel所谓的Java DSL(domain-specific language) 来定义。<br /><span style="font-weight:bold;"><br />Introduction to Java DSL</span><br /><br />对于许多人来说,要实现一个“domain-specific language” (面向领域的语言)涉及到了一个能够处理这个特定领域语言的关键字以及语法的编译器或者是解释器。对于Camel来说,它没有这么做。在Camel文档中一直都在使用的“Java DSL”而不是 “DSL” ,其目的就是想避免混淆这两个概念。Camel中的“Java DSL”是一个可以像DSL一样被使用的类库,除此之外它还使用了大量Java的语义。你可以看一下下面的例子,在例子下面的备注里, 解释了这个例子的中所用的组件。<br /><br />Example of Camel's "Java DSL"<br />RouteBuilder builder = new RouteBuilder() {<br /> public void configure() {<br /> from("queue:a").filter(header("foo").isEqualTo("bar")).to("queue:b");<br /> from("queue:c").choice()<br /> .when(header("foo").isEqualTo("bar")).to("queue:d")<br /> .when(header("foo").isEqualTo("cheese")).to("queue:e")<br /> .otherwise().to("queue:f");<br /> }<br />};<br />CamelContext myCamelContext = new DefaultCamelContext();<br />myCamelContext.addRoutes(builder);<br /><br />上面例子的第一行创建一个一个RouteBuilder的匿名类的实例,这个匿名类需要实现 configure()方法。<br />camelContext.addRoutes(RouterBuilder builder) 方法中调用了builder.setContext(this)方法,这样RouteBuilder对象就获得了与之对应的CamelContext的,然后调用builder.configure()方法。在configure方法中,可以调用例如 from(), filter(), choice(), when(),isEqualTo(), otherwise()以及to() 方法。<br />RouteBuilder.from(String uri) 方法会调用与之对应的CamelContext的getEndpoint(uri)方法来获得指定的Endpoint,并用一个FromBuilder包装这个Endpoint。这样 FromBuilder.filter(Predicate predicate) 方法就会创建一个在header("foo").isEqualTo("bar")这个表达式基础创建的Predicate(所谓的条件)创建一个FilterProcessor对象。就这样, 通过定义这些操作我们逐渐构建出了一个Route对象(使用RouterBuilder进行包装的)并且将这个Route对象添加进了与RouteBuilder所关联的CamelContext中。<br /><br /><span style="font-weight:bold;">Critique of Java DSL</span><br /><br />在camel的在线文档中比较了Java DSL与建立在XML基础上的Spring配置文件的在配置routes和endpoint方法优势。特别是Java DSL比 XML 来说要精简很多。还有需要指出的是,现在很多集成开发环境都提供了一个自动补全的功能, 当然这种功能可以编写Java DSL的过程中使用,这也可以大大降低开发者编写Java DSL的难度。<br /><br />当然在Camel的文档中还忽略了一些内容,就是通过一个解析器来处理存放在外部的DSL。当前Camel并没有提供这也的解析器,并且我也不知道Camel的开发维护人员是否打算做这样一个解析器。我像这个DSL解析器应该提供一个比当前Java DSL更大的一个好处。这个DSL可以通过巴柯斯范式来定义语法,这样Camel的用户可以通过阅读巴柯斯范式来获取书写DSL的知识,而不是像现在需要花费大量的时间通过阅读RouterBuilder类的API来获取。Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com0tag:blogger.com,1999:blog-6635172348452910404.post-61280908429601795182009-01-11T19:41:00.000+08:002009-01-11T19:42:19.506+08:00Camel中的几个重要概念之 Processor<span style="font-weight:bold;">Processor</span><br /><br />Processor接口是用来表示一个处理消息的类, 这个接口的定义如下。<br /><br />Processor<br />package org.apache.camel;<br />public interface Processor {<br /> void process(Exchange exchange) throws Exception;<br />}<br /><br />注意Process()方法中的参数是一个Exchange而不是一个Message。 这样的定义提供了更大的灵活性。例如我们可以在Process方法中调用exchange.getIn()来获取输入的消息,并处理它。 如果在处理过程中发生了错误,我们可以通过调用 exchange.setException() 设置这个异常。<br /><br />对于一个应用开发这来说,他们可以通过实现Process接口来实现他们的业务逻辑。然后,在Camel内部库中, 这里有很多类通过实现了Process接口来提供EIP book中设计模式的实现。例如 ChoiceProcessor就实现了一个消息路由的模式。它通过使用和if-then-else相当的定义来完成一个消息从一个输入队列到多个输出队列的路由。另一个例子就是FilterProcessor,当通过这个Processor的处理的消息不能满足某个条件时,这个消息将被抛弃。Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com0tag:blogger.com,1999:blog-6635172348452910404.post-57829094071595803122009-01-11T19:38:00.002+08:002009-01-11T19:41:10.363+08:00Camel中的几个重要概念之 Message和Exchange<span style="font-weight:bold;">Message</span><br /><br />Message 接口提供了一个对单个消息的抽象,这些消息可以是一个请求,回复或者是一个异常。<br />对于每个Camel是支持的通讯技术来说,都需要提供一个Message接口的实现。例如JmsMessage就提供了一个Message接口的JMS实现. 在message接口中提供一个get/set方法来访问message id, body 以及message中每个单独header。<br />而exchange接口则表示了对message exchange的抽象, 也就是说一个请求消息以及与之对应的应答消息或者异常消息肯定会与一个Exchange相关联。对于Camel来说,请求和应答以及异常消息都分别被称为in, out 以及 fault message。<br />对于每个Camel所支持的通信技术来说来说,都需要一个实现了Exchang接口的的类。 例如JmsExchange 类就提供了一个Exchange接口的JMS实现。对于Exchange接口来说它提供的公共的API很有限。 但是对于实现Exchange的具体的类来说,它可以添加很多与其支持的通讯协议相关操作。<br />应用层的程序应该很少直接访问Exchange(或者是实现Exchange的类)。由于Camel很多类都大量使用了有关(Exchange)的泛型定义,所有你会在很多的类和方法中看到Exchange接口的身影。Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com0tag:blogger.com,1999:blog-6635172348452910404.post-64273051774885266172009-01-11T19:25:00.004+08:002009-01-22T22:46:03.869+08:00Camel中的几个重要概念之 Components<span style="font-weight: bold;">Components</span><br /><br />Component 是一个容易混淆的名词,可能使用EndpointFactory会更合适,因为Component是创建Endpoint实力的工厂类。例如如果一个Camel应用使用了几个JMS 队列,那么这个应用首先需要创建一个叫JmsComponent(实现了Component接口)的实例,然后应用会调用这个JMSComponent对象的createEndpoint()方法来创建一个JmsEndpoint对象(这个对象实现了Endpoint接口)。事实上,应用代码并没直接调用Component.createEndoint() 方法,而是CamelContext对象通过找到对应的Component对象(我马上会在后续的文章中介绍),并调用createEndpoint() 方法来实现的。<br /><br />myCamelContext.getEndpoint("pop3://john.smith@mailserv.example.com?password=myPassword");<br /><br />在getEndpoint()中使用的参数就是URI。这个URI的前缀(: 之前的那部分内容)描述了一个组件的名字,CamelContext对象内部维护着一个组件名字与Component对象的映射表。对于上面给定的URI例子来说,CamelContext对象会根据pop3前缀找到MailComponent类,然后CamelContext对会调用MailComponent的createEndpoint("pop3://john.smith@mailserv.example.com?password=myPassword") 方法。在createEndpoint()方法中, 将把URI分割成一段段小的参数,这些小参数将被用来设置生成的Endpoint对象。<br /><br />在上一段中, 我提到的CamelContext对象维护了一个组件名到Component对象的映射表。但这个映射表是如何产生的呢?这里可以在通过代码调用CamelContext.addComponent(String componentName, Component component)来实现。 下面的例子就是展示了如何给一个MailComponent对象注册上三个不同的名字。<br />Component mailComponent = new org.apache.camel.component.mail.MailComponent();<br />myCamelContext.addComponent("pop3", mailComponent);<br />myCamelContext.addComponent("imap", mailComponent);<br />myCamelContext.addComponent("smtp", mailComponent);<br /><br />第二个方法也是最常用的方法,就是通过CamelContext对象来实现一个懒初始化。这个方法依赖于一套Camel内部的定义Component发现规则, 开发者只要在实现Component接口的时候按照这一规则设置,就可以保证CamelContext能够正常发现这一Component。这里我们假设你所写的Class名字为 com.example.myproject.FooComponent, 并且你想让Camel自动将这个component和"foo”这个名字相对应。为了做到这一点,你需要先写一个叫做"META-INF/services/org/apache/camel/component/foo" 属性文件, 注意这个文件没有".properties"作为后缀名,在这个属性文件中只有一个class的条目,而这个条目的只就是你所写的类的全名。如下所示<br /><br />META-INF/services/org/apache/camel/component/foo<br />class=com.example.myproject.FooComponent<br /><br />如果你还想让Camel将上面的类和”bar” 这个名字联系起来,那你需要在同样的目录下在创建一个相同内容叫bar的文件。一旦完成了这些配置, 你可以把 com.example.myproject.FooComponent class和这些配置文件一同打成一个jar 包,然后把这个jar包放你的CLASSPATH中。这样Camel就会通过分析这些属性文件的class 项目,通过使用reflectionAPI创建这个指定的类的实例。<br /><br />正如我在Endpoint中说描述的, Camel提供了对多种通信协议一个开箱即用的支持。这种支持是建立在实现了Component接口的类以及让CamelContext对象自动建立映射关系的配置文件基础之上的。<br /><br />在这一节的开始, 我使用的这个例子来调用CamelContext.getEndpoint()。<br />myCamelContext.getEndpoint("pop3://john.smith@mailserv.example.com?password=myPassword");<br /><br />在最开始举这个例子的时候,我说这个getEndpoint()方法的参数是一个URI。我这么说是因为Camel的在线问答以及Camel的源代码就把这个参数声明为一个URI。在现实生活中,这个参数是按照URL来定义的。这是因为Camel会从参数中通过一个简单的算法查找第一:来分析出组件名。为了了解其中的奥妙,大家可以回想一下我在前面 URL,URI,URN和IRI是什么中谈到的 一个URI可以是URL或者URN。 现在让我们来看一下下面的getEndpoint()调用。<br />myCamelContext.getEndpoint("pop3:...");<br />myCamelContext.getEndpoint("jms:...");<br />myCamelContext.getEndpoint("urn:foo:...");<br />myCamelContext.getEndpoint("urn:bar:...");<br /><br />Camel会先找出这些component的标识,例如 "pop3", "jms", "urn" 和 "urn"。如果"urn:foo" 和"urn:bar" 能够别用来识别component,或者是使用"foo" 和"bar" (这一可以跳过这个"urn:"前缀)。所以在实际的编程中,大家更喜欢使用URL来制定一个Endpoint(使用"<scheme>:..."来描述的字符串)而不是用一个URN( 使用"urn:<scheme>:..."来描述的字符串)。正因为我们没有安全按照URN的规定的参数来调用getEndpoint() 方法, 所以这个方法的参数更像一个URL而不是一个URI。</scheme></scheme>Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com0tag:blogger.com,1999:blog-6635172348452910404.post-49254127046959789022009-01-11T19:17:00.003+08:002009-01-11T19:25:16.767+08:00Camel 中的几个重要概念之 CamelContext与CamelTemplate<span style="font-weight: bold;">CamelContext</span><br /><br />CamelContext是对Camel 运行时的一个抽象, 一般来说一个应用里面会有一个CamelContext 对象。一个典型的Camel 应用按照下面几个步骤执行。<br /><ol><li>创建一个CamelContext对象。</li><li>向CamelContext对象中添加Endpoints或者是Components</li><li>向CamelContext对象中添加路由(routes)规则</li><li>调用CamelContext的start() 方法,这样可以启动Camel内部有关消息发送,接收,处理所使用的线程。 </li><li>当调用CamelContext的stop() 方法时,Camel 会将妥善关闭所有endpoint和Camel内部的线程。注意在调用CamelContext.start() 方法时并不一定阻塞, 而是在启动完每个Comonent和Endpoint的内部线程后start() 方法返回。而CamelContext.stop()方法会等待所有Endpoint和Component的内部线程都结束后 stop() 方法才返回。如果你没有在你的Camel 应用程序中调用CamelContext.start() 方法,那么由于内部线程并没有被创建那些消息将不会被处理。 如果你没有在你的Camel应用程序中调用CamelContext.stop()方法,那你你的应用将不会正常退出。如果你在一个JUnit 测试没有调用CamelContext.stop()方法,这可能会造成消息不能被完整地处理,而导致测试运行失败。</li></ol><br /><span style="font-weight: bold;">CamelTemplate</span><br /><br />Camel曾经使用一个叫CamelClient的类来发送消息, 后来为了和其他的open-source项目类似功能的模块例如Spring中 TransactionTemplate 和 JmsTemplate, 命名一致而改名为CamelTemplate。<br />这个CamelTemplate(注现在已经改名为ProducerTemplate)类对CamelContext进行了一个简单的封装。在CamelTemplate中有向一个Endpoint(将在Endpoint中讨论)发送Message或者Exchange的方法, 这部分的内容将在 Message和Exchange中进行讨论。 CamelTemplate提供了一条向Camel内部路由中的Endpoint发送消息的道路, 这样消息就可以在Camel内部的路由规则(参考 Routes,RouteBuilders 和JAVA DSL)里面流动而到达指定的目标节点了。Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com0tag:blogger.com,1999:blog-6635172348452910404.post-59378838118855565042009-01-11T18:53:00.008+08:002009-01-11T19:47:59.744+08:00Camel中的几个重要概念之 Endpoint前段时间和一些朋友聊过<a href="http://cwiki.apache.org/CAMEL">Apache Camel</a>, 他们都反映一个问题就是有关Camel构架的介绍文档很少。其实在Camel发行包中所带的文档<a href="http://cwiki.apache.org/CAMEL/manual.html">Camel Manual</a> 就有一段对Camel内部设计有一个比较好的介绍。我在这里把其中<a href="http://cwiki.apache.org/CAMEL/book-getting-started.html">大部分的内容</a>翻译成了中文,希望能对大家了解Camel有所帮助。<br /><br /><span style="font-weight: bold;">Endpoint</span><br />Endpoint这个词以前经常被用来描述进程间通信。例如,在客户端与服务器之间的通讯,客户端是一个Endpoint和服务器是另外一个Endpoint。根据不同的情况下,一个Endpoint可能指的地址,如一个TCP通信的(主机:端口)对,也可能是指与这个地址相对应的一个软件实体。例如,如果大家使用“ www.example.com:80 ”来描述一个Endpoint。这些Endpoint可能是指实际的端口上的主机名称(即地址) ,也可能是指与地址相关的的网页服务器(即在这个地址之上运行的软件地址) 。通常情况下,这种地址和在这个地址之上运行的软件之前的区别并不是一个重要问题。<br /><br />一些中间件技术可以使一些软件实体的绑定在相同的物理地址上。例如, CORBA是一种面向对象的远程过程调用( RPC )的中间件标准。如果一个CORBA的服务器进程包含几个对象,客户端可以与这些在同一物理地址(主机:端口)之上的任意对象进行通讯 ,但当客户端想与特定对象进行通讯是, 需要指定这个对象的逻辑地址(在CORBA中称为IOR)。 IOR是由物理地址(主机:端口) ,以及一个唯一识别的对象在其服务器进程标识所组成。 (IOR还包含了与此本次讨论无关其他一些额外的信息。)当谈论CORBA的时候,有些人可能会使用“endpoint”来描述CORBA的服务器的物理地址,而其他人可能使用Endpoint来描述一个CORBA对象的逻辑地址,和其他人可能会使用这个词来描述下面这些:<br /><br /><ul><li>CORBA的服务器进程的物理地址(主机:端口)</li><li>CORBA对象的逻辑地址(主机:端口加上编号)</li><li>CORBA的服务器进程(相对重量级的软件实体)</li><li>一个基于CORBA对象(一个轻量级的软件实体)</li></ul><br />正因为如此,你可以看到Endpoint这个词至少在两方面是模糊的。首先,它可能是指一个地址或联络软件实体在该地址。其次,粒度上可能是模糊的:一个重量级与轻量级的软件实体,或物理地址与逻辑地址。了解了Endpoint这个名词在不同场景下的不同描述可以帮助我们更好地理解为什么Camel中的Endpoint。<br /><br />Camel中的Endpoint支持许多不同的通信技术。以下是Camel所支持Endpoint。<br /><br /><ul><li>一个JMS队列。</li><li>一个Web服务。</li><li>一个文件。文件可能听起来不是一个典型的Endoint端点。但是你可以这么想,一些应用系统会把信息写到一个文件中,然后另一个应用程序可能读取该文件获得这一信息。 </li><li>一个FTP服务器。</li><li>一个电子邮件地址。客户可以发送邮件到电子邮件地址,和一台服务器可以读取的这个从邮件服务器传入的邮件。</li><li>一个POJO (普通旧Java对象)。</li></ul>Willemhttp://www.blogger.com/profile/12054483373037780138noreply@blogger.com0