Chapter 6. XML IO DSL
Chapter 6. XML IO DSL The xml-io-dsl is the Camel optimized XML DSL with a very fast and low overhead XML parser. It is a source code generated parser that is Camel specific and can only parse Camel .xml route files (not classic Spring <beans> XML files). We recommend that you use xml-io-dsl instead of xml-jaxb-dsl for Camel XML DSL. It works with all Camel runtimes. Note When you are using XML IO DSL, the camel-spring-boot application will by default look for xml files in src/main/resources/camel/*.xml . You can configure this behavior by providing a different path in the camel.springboot.routes-include-pattern property: camel.springboot.routes-include-pattern=/path/to/*.xml 6.1. Example The following my-route.xml source file can be loaded and run with Camel CLI or Camel K: my-route.xml <routes xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="timer:tick"/> <setBody> <constant>Hello Camel K!</constant> </setBody> <to uri="log:info"/> </route> </routes> Tip You can omit the xmlns namespace. If there is only a single route, you can use <route> as the root XML tag instead of <routes> . Running with Camel K kamel run my-route.xml Running with Camel CLI camel run my-route.xml You can use xml-io-dsl to declare some beans to be bound to the Camel Registry. You can declare and Beans define their properties (including nested properties) in XML. For example: Bean declaration and definition <camel> <bean name="beanFromProps" type="com.acme.MyBean"> <properties> <property key="field1" value="f1_p" /> <property key="field2" value="f2_p" /> <property key="nested.field1" value="nf1_p" /> <property key="nested.field2" value="nf2_p" /> </properties> </bean> </camel> While keeping all the benefits of fast XML parser used by xml-io-dsl , Camel can also process XML elements declared in other XML namespaces and process them separately. With this mechanism it is possible to include XML elements using Spring's http://www.springframework.org/schema/beans namespace. This brings the flexibility of Spring Beans into Camel main without actually running any Spring Application Context (or Spring Boot). When elements from Spring namespace are found, they are used to populate and configure an instance of org.springframework.beans.factory.support.DefaultListableBeanFactory and leverage Spring dependency injection to wire the beans together. These beans are then exposed through normal Camel Registry and may be used by Camel routes. Here's an example camel.xml file, which defines both the routes and beans used (referred to) by the route definition: camel.xml <camel> <beans xmlns="http://www.springframework.org/schema/beans"> <bean id="messageString" class="java.lang.String"> <constructor-arg index="0" value="Hello"/> </bean> <bean id="greeter" class="org.apache.camel.main.app.Greeter"> <description>Spring Bean</description> <property name="message"> <bean class="org.apache.camel.main.app.GreeterMessage"> <property name="msg" ref="messageString"/> </bean> </property> </bean> </beans> <route id="my-route"> <from uri="direct:start"/> <bean ref="greeter"/> <to uri="mock:finish"/> </route> </camel> A my-route route is referring to greeter bean which is defined using Spring <bean> element. More examples can be found on the Apache Camel JBang page. 6.2. Using beans with constructors When you want to create beans with constructor arguments, from Camel 4.1 onwards you can add them as XML tags. For example: Camel 4.1+: Beans with constructor tags <camel> <bean name="beanFromProps" type="com.acme.MyBean"> <constructors> <constructor index="0" value="true"/> <constructor index="1" value="Hello World"/> </constructors> <!-- and you can still have properties --> <properties> <property key="field1" value="f1_p" /> <property key="field2" value="f2_p" /> <property key="nested.field1" value="nf1_p" /> <property key="nested.field2" value="nf2_p" /> </properties> </bean> </camel> If you use Camel 4.0, you must put then constructor arguments in the type attribute: Camel 4.0: Beans with constructor arguments in the type attribute <bean name="beanFromProps" type="com.acme.MyBean(true, 'Hello World')"> <properties> <property key="field1" value="f1_p" /> <property key="field2" value="f2_p" /> <property key="nested.field1" value="nf1_p" /> <property key="nested.field2" value="nf2_p" /> </properties> </bean> 6.3. Creating beans from factory method A bean can also be created from a public static factory method: Factory method XML <bean name="myBean" type="com.acme.MyBean" factoryMethod="createMyBean"> <constructors> <constructor index="0" value="true"/> <constructor index="1" value="Hello World"/> </constructors> </bean> When you use a factoryMethod , you must provide constructor tags for the arguments. For example, this means that the class com.acme.MyBean should be as follows: Factory method public class MyBean { public static MyBean createMyBean(boolean important, String message) { MyBean answer = ... // create and configure the bean return answer; } } Note You must make the factory method public static in the created class. 6.4. Creating beans from builder classes You can create a bean created from another builder class as shown below: Builder XML <bean name="myBean" type="com.acme.MyBean" builderClass="com.acme.MyBeanBuilder" builderMethod="createMyBean"> <properties> <property key="id" value="123"/> <property key="name" value="Acme"/> </constructors> </bean> Note You must make the builder class public with a no-arg default constructor. You can then use the builder class to create the actual bean by using fluent builder style configuration. Set the properties on the builder class, and create the bean by invoking the builderMethod at the end. You invocate this method via Java reflection. 6.5. Creating beans from factory bean You can create a bean from a factory bean as shown below: Factory XML <bean name="myBean" type="com.acme.MyBean" factoryBean="com.acme.MyHelper" factoryMethod="createMyBean"> <constructors> <constructor index="0" value="true"/> <constructor index="1" value="Hello World"/> </constructors> </bean> Tip You can also use factoryBean to refer to an existing bean by bean id instead of the FQN classname. When you use a factoryBean the, you must provide arguments as constructor tags. For example, the class com.acme.MyHelper should be as follows: Factory bean public class MyHelper { public static MyBean createMyBean(boolean important, String message) { MyBean answer = ... // create and configure the bean return answer; } } Note You must make the factory method public static . 6.6. Creating beans using script language If you have advanced use-cases, you can inline a script language, such as groovy, java, javascript, and so on, to create the bean. With scripting, you can be more flexible and use a bit of programming to create and configure the bean: Scripting <bean name="myBean" type="com.acme.MyBean" scriptLanguage="groovy"> <script> // some groovy script here to create the bean bean = ... ... return bean </script> </bean> Note When you use script , the constructors, factory bean, and factory method are not used. 6.7. Using init and destroy methods on beans If you need to do initialization and cleanup work before you use a bean, you can use the initMethod and destroyMethod which are triggered as appropriate by Camel. Those methods must be public void and have no arguments, as shown below: Initialization and cleanup methods public class MyBean { public void initMe() { // do init work here } public void destroyMe() { // do cleanup work here } } You also have to declare those methods in the XML DSL as follows: Initialization and cleanup XML <bean name="myBean" type="com.acme.MyBean" initMethod="initMe" destroyMethod="destroyMe"> <constructors> <constructor index="0" value="true"/> <constructor index="1" value="Hello World"/> </constructors> </bean> Both initMethod and destroyMethod are optional, so a bean does not have to have both. 6.8. REST and routes in the same XML IO DSL file You can have both REST and routes in the same DSL file: REST and routes in the same XML IO DSL file <camel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://camel.apache.org/schema/spring" xsi:schemaLocation=" http://camel.apache.org/schema/spring https://camel.apache.org/schema/spring/camel-spring.xsd"> <rest id="rest"> <post id="post" path="start"> <to uri="direct:start"/> </post> </rest> <route> <from uri="direct:start"/> <to uri="amqp:queue:Test.Broker.StreamMessage?jmsMessageType=Stream&amp;disableReplyTo=true"/> </route> </camel>
<routes xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="timer:tick"/> <setBody> <constant>Hello Camel K!</constant> </setBody> <to uri="log:info"/> </route> </routes> kamel run my-route.xml camel run my-route.xml <camel> <bean name="beanFromProps" type="com.acme.MyBean"> <properties> <property key="field1" value="f1_p" /> <property key="field2" value="f2_p" /> <property key="nested.field1" value="nf1_p" /> <property key="nested.field2" value="nf2_p" /> </properties> </bean> </camel> <camel> <beans xmlns="http://www.springframework.org/schema/beans"> <bean id="messageString" class="java.lang.String"> <constructor-arg index="0" value="Hello"/> </bean> <bean id="greeter" class="org.apache.camel.main.app.Greeter"> <description>Spring Bean</description> <property name="message"> <bean class="org.apache.camel.main.app.GreeterMessage"> <property name="msg" ref="messageString"/> </bean> </property> </bean> </beans> <route id="my-route"> <from uri="direct:start"/> <bean ref="greeter"/> <to uri="mock:finish"/> </route> </camel> <camel> <bean name="beanFromProps" type="com.acme.MyBean"> <constructors> <constructor index="0" value="true"/> <constructor index="1" value="Hello World"/> </constructors> <!-- and you can still have properties --> <properties> <property key="field1" value="f1_p" /> <property key="field2" value="f2_p" /> <property key="nested.field1" value="nf1_p" /> <property key="nested.field2" value="nf2_p" /> </properties> </bean> </camel> <bean name="beanFromProps" type="com.acme.MyBean(true, 'Hello World')"> <properties> <property key="field1" value="f1_p" /> <property key="field2" value="f2_p" /> <property key="nested.field1" value="nf1_p" /> <property key="nested.field2" value="nf2_p" /> </properties> </bean> <bean name="myBean" type="com.acme.MyBean" factoryMethod="createMyBean"> <constructors> <constructor index="0" value="true"/> <constructor index="1" value="Hello World"/> </constructors> </bean> public class MyBean { public static MyBean createMyBean(boolean important, String message) { MyBean answer = // create and configure the bean return answer; } } <bean name="myBean" type="com.acme.MyBean" builderClass="com.acme.MyBeanBuilder" builderMethod="createMyBean"> <properties> <property key="id" value="123"/> <property key="name" value="Acme"/> </constructors> </bean> <bean name="myBean" type="com.acme.MyBean" factoryBean="com.acme.MyHelper" factoryMethod="createMyBean"> <constructors> <constructor index="0" value="true"/> <constructor index="1" value="Hello World"/> </constructors> </bean> public class MyHelper { public static MyBean createMyBean(boolean important, String message) { MyBean answer = // create and configure the bean return answer; } } <bean name="myBean" type="com.acme.MyBean" scriptLanguage="groovy"> <script> // some groovy script here to create the bean bean = return bean </script> </bean> public class MyBean { public void initMe() { // do init work here } public void destroyMe() { // do cleanup work here } } <bean name="myBean" type="com.acme.MyBean" initMethod="initMe" destroyMethod="destroyMe"> <constructors> <constructor index="0" value="true"/> <constructor index="1" value="Hello World"/> </constructors> </bean> <camel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://camel.apache.org/schema/spring" xsi:schemaLocation=" http://camel.apache.org/schema/spring https://camel.apache.org/schema/spring/camel-spring.xsd"> <rest id="rest"> <post id="post" path="start"> <to uri="direct:start"/> </post> </rest> <route> <from uri="direct:start"/> <to uri="amqp:queue:Test.Broker.StreamMessage?jmsMessageType=Stream&amp;disableReplyTo=true"/> </route> </camel>