Monday, February 15, 2010

Configure the camel-cxf endpoint advance features from URI

As you know CXF provides the advance configuration on the CXF endpoints, such as interceptors, features etc.

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.

How can we configure the interceptor or the features on the camel-cxf endpoints by just setting few option parameters?
The key of the answer is you can set the bus of the camel-cxf endpoint by using the URI option bus.
You can set the features or interceptor on the bus as CXF bus configuration does and then set the camel-cxf endpoint URI like this "cxf://Address?Bus=#cxf&...".

Sunday, May 3, 2009

Better OSGi integration test support In Camel

Two weeks ago, James did a great work by adding an OSGi integration test module which was based on Pax Exam.

Then, I did some enhancements for this test module this week.

1. You can use the camel features to install the bundles for you test.
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.

Here is a code example

// using the features to install the camel components
scanFeatures(mavenBundle().groupId("org.apache.camel.karaf"). artifactId("features").versionAsInProject().type("xml/features"),
"camel-core", "camel-osgi", "camel-spring", "camel-test"),


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.

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 OSGiIntegrationTestSupport; if you are big fan of Spring, you can extend the OSGIIntegrationSpringTestSupport, and it will take care of creating the application context in the OSGi plateform.

Thursday, March 12, 2009

Set the properties for Camel Context

If 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.
But if I want to configure the component per camel context, as you know there could be more than one camel context per JVM.
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.

With the java code

Map<String, String> properties = new HashMap<String, String>();
properties.put(CachedOutputStream.THRESHOLD, "1000");
properties.put(CachedOutputStream.TEMP_DIR, "/tmp/camel");
camelContext..setProperties(properties);



With Spring configuration

<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<properties>
<property key="CamelCachedOutputStreamThreshold" value="10000"/>
</properties>
<property key="CamelCachedOutputStreamOutputDirectory" value="/tmp/camel"/>
</properties>
<property key="the key of properties" value="the value as string"/>
</properties>
...
<camelContext>

Monday, February 23, 2009

How to use extra camel componets in servicemix-camel

When 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.

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.
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.

Let me give you a real world issue.

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.
Since the SU is redeployed, Servicemix will create a new class loader to load the SU's lib jars and resources.
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.

Note, In Servicemix4 , we will not get that kind of issue , since the OSGI will help us to manage the relationship of the jars :).

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.

Let me take the latest servicemix-camel as an example

1. Checking out the servicemix-camel component's pom


svn co http://svn.apache.org/repos/asf/servicemix/components/engines/servicemix-camel/trunk/pom.xml


2. If you need camel-rmi component , you just put the dependency into the pom.xml


<dependency>
<groupid>org.apache.camel</groupid>
<artifactid>camel-rmi</artifactid>
<version>${camel-version}</version>
</dependency>


3. Running "mvn install" and copy the servicemix-camel-*.zip into the deploy directory

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.


<dependency>
<groupid>org.apache.camel</groupid>
<artifactid>camel-rmi</artifactid>
<version>${camel-version}</version>
<scope>provided</scope>
</dependency>

Thursday, January 22, 2009

Powerful svn merge

Since I'm always using svnmerge.py to do the merge stuff, I have no chance to go through the svn merge doc.
Now I just found svn merge is so powerful.

If you just want to merge one pic of change from trunk to branch, you don't have to do the
svnmerge.py init

svnmerge.py merge ...

You can just type in you working copy directory

svn merge -c VERSION YOUR_TRUNK_URL [WCPATH]


If you want to revert the change for the svn server side , not just your working copy
svn merge -rVERSION:VERSION-1 SOURCE [WCPATH]

Wednesday, January 21, 2009

What's new in Camel 2.0

I have been asked by lots of friend who are using or going to using Camel, what's new in Camel 2.0.
I just found Claus set up a good wiki page for all these kind informations.
Some high lights includes:

New features:
  • Make more endpoints easily configurable as beans in Spring XML.
  • Improve the DSL
  • ...
API Changes
  • Remove the use of generics on Component, Exchange, Producer, Consumer
  • Change to use verb for EIP action
  • ...


You can find the release notes about Camel 2.0 (Working in progress) here.

Sunday, January 11, 2009

Camel中的几个重要概念之Routes, RouteBuilders 和 Java DSL

Route

一个route就是将一个输入队列中获得的消息,通过一步一步地设置好的逻辑判断(例如过滤器和路由规则)到达一个目标队列中(如果有的话)。Camel为应用开发者提供了两种途径来定义这些路由规则。一个是通过XML来定义路由信息,有关这部分的内容不会在本文档中讨论。另一种方式就是通过Camel所谓的Java DSL(domain-specific language) 来定义。

Introduction to Java DSL


对于许多人来说,要实现一个“domain-specific language” (面向领域的语言)涉及到了一个能够处理这个特定领域语言的关键字以及语法的编译器或者是解释器。对于Camel来说,它没有这么做。在Camel文档中一直都在使用的“Java DSL”而不是 “DSL” ,其目的就是想避免混淆这两个概念。Camel中的“Java DSL”是一个可以像DSL一样被使用的类库,除此之外它还使用了大量Java的语义。你可以看一下下面的例子,在例子下面的备注里, 解释了这个例子的中所用的组件。

Example of Camel's "Java DSL"
RouteBuilder builder = new RouteBuilder() {
public void configure() {
from("queue:a").filter(header("foo").isEqualTo("bar")).to("queue:b");
from("queue:c").choice()
.when(header("foo").isEqualTo("bar")).to("queue:d")
.when(header("foo").isEqualTo("cheese")).to("queue:e")
.otherwise().to("queue:f");
}
};
CamelContext myCamelContext = new DefaultCamelContext();
myCamelContext.addRoutes(builder);

上面例子的第一行创建一个一个RouteBuilder的匿名类的实例,这个匿名类需要实现 configure()方法。
camelContext.addRoutes(RouterBuilder builder) 方法中调用了builder.setContext(this)方法,这样RouteBuilder对象就获得了与之对应的CamelContext的,然后调用builder.configure()方法。在configure方法中,可以调用例如 from(), filter(), choice(), when(),isEqualTo(), otherwise()以及to() 方法。
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中。

Critique of Java DSL

在camel的在线文档中比较了Java DSL与建立在XML基础上的Spring配置文件的在配置routes和endpoint方法优势。特别是Java DSL比 XML 来说要精简很多。还有需要指出的是,现在很多集成开发环境都提供了一个自动补全的功能, 当然这种功能可以编写Java DSL的过程中使用,这也可以大大降低开发者编写Java DSL的难度。

当然在Camel的文档中还忽略了一些内容,就是通过一个解析器来处理存放在外部的DSL。当前Camel并没有提供这也的解析器,并且我也不知道Camel的开发维护人员是否打算做这样一个解析器。我像这个DSL解析器应该提供一个比当前Java DSL更大的一个好处。这个DSL可以通过巴柯斯范式来定义语法,这样Camel的用户可以通过阅读巴柯斯范式来获取书写DSL的知识,而不是像现在需要花费大量的时间通过阅读RouterBuilder类的API来获取。