There are plenty maven projects which create Apache Camel OSGi bundles. But there is very few place I can find to simply explain how to create such a kind project from scratch. This blog will exmain the details about this process. Frankly speaking, it may seems very simple, but it took me several hours to get it work. Hopefully, people who are interested in this process do not have to go through the same processes as I did.
Create Maven Project with Apach Camel Routes
Here is the script I created for creating maven project with apache camel route [I use cygwin in my windows environment. If you run dos cmd, you can replace the \ with ^ for line continuation.]:
1 2 3 4 5 6 7 | mvn archetype:generate \ -DarchetypeGroupId=org.apache.camel.archetypes \ -DarchetypeArtifactId=camel-archetype-spring \ -DarchetypeVersion=2.10.4 \ -DgroupId=com.vha.esb.apexus \ -DartifactId=ce-reject-notify \ -Dversion=1.0.0-SNAPSHOT |
1 | chmod 755 generatePoject.sh |
Now you can run the script, it will generate all files with a defaul apache camel route, which simple copy a file from src/data to target/message/uk or target/message/others. Aparatly, apache camel community did an excellent job to make this process go smoothly. After the build process is completed, run the following commands:
1 2 | mvn clean install mvn camel:run |
Import Project to Eclipse
The projects created by the running the script is ready to be imported to eclipse IDE.
Create OSGi Bundle
To create OSGi bundle, we need to instruct maven to build bundle using the org.apache.felix maven plugin. Here is my pom.xml file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | <!--xml version= "1.0" encoding= "UTF-8" ?--> <project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" > <modelversion>4.0.0</modelversion> <groupid>com.vha.esb.apexus</groupid> <artifactid>ce-reject-notify</artifactid> <packaging>bundle</packaging> <version>1.0.0-SNAPSHOT</version> <name>A Camel Spring Route</name> <url>http: //www.myorganization.org</url> <properties> <project.build.sourceencoding>UTF-8</project.build.sourceencoding> <project.reporting.outputencoding>UTF-8</project.reporting.outputencoding> </properties> <dependencies> <dependency> <groupid>org.apache.camel</groupid> <artifactid>camel-core</artifactid> <version>2.10.4</version> </dependency> <dependency> <groupid>org.apache.camel</groupid> <artifactid>camel-spring</artifactid> <version>2.10.4</version> </dependency> <!-- logging --> <dependency> <groupid>org.slf4j</groupid> <artifactid>slf4j-api</artifactid> <version>1.6.6</version> </dependency> <dependency> <groupid>org.slf4j</groupid> <artifactid>slf4j-log4j12</artifactid> <version>1.6.6</version> </dependency> <dependency> <groupid>log4j</groupid> <artifactid>log4j</artifactid> <version>1.2.17</version> </dependency> <!-- testing --> <dependency> <groupid>org.apache.camel</groupid> <artifactid>camel-test-spring</artifactid> <version>2.10.4</version> <scope>test</scope> </dependency> </dependencies> <build> <defaultgoal>install</defaultgoal> <plugins> <plugin> <groupid>org.apache.felix</groupid> <artifactid>maven-bundle-plugin</artifactid> <extensions> true </extensions> <configuration> <manifestlocation>target/META-INF</manifestlocation> <instructions> <bundle-symbolicname>${project.groupId}.${project.artifactId}</bundle-symbolicname> <export-package></export-package> <import-package> org.apache.cxf, org.apache.cxf.binding, org.apache.cxf.binding.corba, org.apache.cxf.binding.soap, org.apache.cxf.binding.soap.spring, org.apache.cxf.bus, org.apache.cxf.bus.resource, org.apache.cxf.bus.spring, org.apache.cxf.buslifecycle, org.apache.cxf.catalog, org.apache.cxf.configuration, org.apache.cxf.configuration.spring, org.apache.cxf.endpoint, org.apache.cxf.headers, org.apache.cxf.management, org.apache.cxf.management.jmx, org.apache.cxf.phase, org.apache.cxf.resource, org.apache.cxf.service.factory, org.apache.cxf.transport, org.apache.cxf.transport.http, org.apache.cxf.transport.http.policy, org.apache.cxf.transport.http_jetty, org.apache.cxf.transport.jms, org.apache.cxf.transports.http, org.apache.cxf.workqueue, org.apache.cxf.wsdl, org.apache.cxf.wsdl11, org.apache.ws.security.action, org.apache.ws.security.processor, org.springframework.beans.factory.config, org.springframework.mail.javamail, * </import-package> </instructions> </configuration> </plugin> <plugin> <groupid>org.apache.maven.plugins</groupid> <artifactid>maven-compiler-plugin</artifactid> <version>2.5.1</version> <configuration> <source>1.6 <target>1.6</target> </configuration> </plugin> <plugin> <groupid>org.apache.maven.plugins</groupid> <artifactid>maven-resources-plugin</artifactid> <version>2.4.3</version> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- allows the route to be ran via 'mvn camel:run' --> <plugin> <groupid>org.apache.camel</groupid> <artifactid>camel-maven-plugin</artifactid> <version>2.10.4</version> </plugin> </plugins> </build> </project> |
1 | <packaging>bundle</packaging> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <plugin> <groupid>org.apache.felix</groupid> <artifactid>maven-bundle-plugin</artifactid> <extensions> true </extensions> <configuration> <manifestlocation>target/META-INF</manifestlocation> <instructions> <bundle-symbolicname>${project.groupId}.${project.artifactId}</bundle-symbolicname> <export-package></export-package> <import-package> org.apache.cxf, org.apache.cxf.binding, org.apache.cxf.binding.corba, org.apache.cxf.binding.soap, org.apache.cxf.binding.soap.spring, org.apache.cxf.bus, org.apache.cxf.bus.resource, org.apache.cxf.bus.spring, org.apache.cxf.buslifecycle, org.apache.cxf.catalog, org.apache.cxf.configuration, org.apache.cxf.configuration.spring, org.apache.cxf.endpoint, org.apache.cxf.headers, org.apache.cxf.management, org.apache.cxf.management.jmx, org.apache.cxf.phase, org.apache.cxf.resource, org.apache.cxf.service.factory, org.apache.cxf.transport, org.apache.cxf.transport.http, org.apache.cxf.transport.http.policy, org.apache.cxf.transport.http_jetty, org.apache.cxf.transport.jms, org.apache.cxf.transports.http, org.apache.cxf.workqueue, org.apache.cxf.wsdl, org.apache.cxf.wsdl11, org.apache.ws.security.action, org.apache.ws.security.processor, org.springframework.beans.factory.config, org.springframework.mail.javamail, * </import-package> </instructions> </configuration> </plugin> |
Now we are readly to deploy the bundle to karaf container. The command is:
1 2 | osgi:install mvn:com.vha.esb.apexus/ce-reject-notify/1.0.0-SNAPSHOT osgi:start 244 |
Now, if your karaf container is at ${karaf_home}, you should see the directory ${karaf_home}/src/data. Now, let's copy the 2 xml files coming with the build to that directory. Shortly, you should see message1.xml and message2.xml are placed at ${karaf_home}/target/messages/uk and ${karaf_home}/target/messages/other directory, respectively.
Understanding Apache Camel Route
The archtetypes: camel-archetype-spring create a default camel route which copy the xml file from one place to anotehr. I add another route using quartz end point as shown blow:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <!--xml version= "1.0" encoding= "UTF-8" ?--> <!-- Configures the Camel Context --> <beans xmlns= "http://www.springframework.org/schema/beans" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:camel= "http://camel.apache.org/schema/spring" xmlns:ctx= "http://www.springframework.org/schema/context" xmlns:osgi= "http://camel.apache.org/schema/osgi" xmlns:osgix= "http://www.springframework.org/schema/osgi-compendium" xsi:schemalocation= " http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/osgi-compendium http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd <bean id= "helloBean" class= "com.ggl.esb.osgi.HelloBean" > <property name= "say" value= "${name.value}" > </property></bean> <osgix:cm-properties id= "preProps" persistent-id= "osgi.spring.demo" > </osgix:cm-properties> <ctx:property-placeholder properties-ref= "preProps" > <!-- here is a sample which processes the input files (leaving them in place - see the 'noop' flag) then performs content based routing on the message using XPath --> <route id= "timerToLog" > <setbody> <method ref= "helloBean" method= "hello" > </method></setbody> <log message= "The message contains ${body}" > <to uri= "mock:result" > </to></log></from></route> <camel:route> <camel:from uri= "file:src/data?noop=true" > <camel:choice> <camel:when> <camel:xpath>/person/city = 'London' </camel:xpath> <camel:log message= "UK message" > <camel:to uri= "file:target/messages/uk" > </camel:to></camel:log></camel:when> <camel:otherwise> <camel:log message= "Other message" > <camel:to uri= "file:target/messages/others" > </camel:to></camel:log></camel:otherwise> </camel:choice> </camel:from></camel:route> </camel:camelcontext> </ctx:property-placeholder></beans> |
The update route shows few things. First, it is a spring configuration file. We can define beans inside the configuraion. Secondly, we can define multiple routes within a camelContext.
The camel configuration file shown above is OK, but not very practical because we hard-coded thte value. Now, i want to explain how to use property files. To use property file, we need to update the came-context.xml file. Here is the list of the file content.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <!--xml version= "1.0" encoding= "UTF-8" ?--> <!-- Configures the Camel Context --> <beans xmlns= "http://www.springframework.org/schema/beans" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:camel= "http://camel.apache.org/schema/spring" xmlns:ctx= "http://www.springframework.org/schema/context" xmlns:osgi= "http://camel.apache.org/schema/osgi" xmlns:osgix= "http://www.springframework.org/schema/osgi-compendium" xsi:schemalocation= " http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/osgi-compendium http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd ...... <bean id= "placeholderConfig" class= "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" > <property name= "location" value= "file:etc/osgi.spring.demo.cfg" > </property></bean> <!-- here is a sample which processes the input files (leaving them in place - see the 'noop' flag) then performs content based routing on the message using XPath --> <propertyplaceholder id= "properties" location= "file:etc/osgi.spring.demo.cfg" > <route id= "timerToLog" > <setbody> <method ref= "helloBean" method= "hello" > </method></setbody> <log message= "The message contains ${body} {{activemq.broker.url}}" > <to uri= "mock:result" > </to></log></from></route> ...... </propertyplaceholder></camel:camelcontext> </beans> |
As you can see, we use spring PropertyPlaceholderConfigurer bean to load file. and in the camel route you use {{my.value}}, where my.value is a variable. I deployed the file osgi.spring.demo.cfg under ${KARAF.HOME}/etc. The ${KARAF.HOME} is the karaf container installation. The file osgi.spring.demo.cfg has the following contents:
1 2 3 | activemq.broker.url=failover:(tcp: //uit-amq-1.corp.vha.com:61616,tcp://uit-amq-2.corp.vha.com:61616) name.value=Gary Liu cron.value=0/5+*+*+*+*+? |
After my new deployment of the bundle, in the karaf log, I can see the following out put every 5 seconds, because in the quartz end point, I have defined the field for second 0/5, which is every 5 seconds.
14:48:50,003 | INFO | amel-21_Worker-2 | rg.apache.camel.util.CamelLogger 176 | 174 - org.apache.camel.camel-core - 2.10.4 | The message contains Gary Liu at 2014-02-12 14:48:50 failover:(tcp://uit-amq-1.corp.vha.com:61616,tcp://uit-amq-2.corp.vha.com:61616) 14:48:55,001 | INFO | amel-21_Worker-3 | rg.apache.camel.util.CamelLogger 176 | 174 - org.apache.camel.camel-core - 2.10.4 | The message contains Gary Liu at 2014-02-12 14:48:55 failover:(tcp://uit-amq-1.corp.vha.com:61616,tcp://uit-amq-2.corp.vha.com:61616)
No comments:
Post a Comment