Escolar Documentos
Profissional Documentos
Cultura Documentos
Camel. They were topics you absolutely needed to know to use Camel. In this next part, well cover in depth the core features of Camel. oull need many of these features when using Camel in real!world applications. In chapter " well take a look at the data in the messages being routed by Camel. In particular, well look at how you can transform this data to other formats using Camel. Camel has great support for integrating beans into your routing applications. In chapter # well look at the many ways beans can be used in Camel applications. In complex enterprise systems, lots of things can go wrong. This is why Camel features an extensive set of error!handling abilities. In chapter $ well discuss these in detail. In chapter % well take a look at another important topic in application development& testing. 'ell look at the testing facilities shipped with Camel. ou can use these features for testing your own Camel applications or applications based on other stacks. Components are the main extension mechanism in Camel. (s such, they include functionality to connect to many different transports, ()Is, and other extensions to Camels core. Chapter * covers the most heavily used components that ship with Camel. The last chapter of this part revisits the important topic of enterprise integration patterns +,I)s- in Camel. .ack in chapter /, we covered some of the simpler ,I)s0 in chapter 1, well look at several of the more complex ,I)s. Licensed to Ian White <ian@biancashouse.com> Licensed to Ian White <ian@biancashouse.com>
61
In this chapter, youll learn all about how Camel can help you with your data transformation challenges. 'ell start with a brief overview of data transformation in Camel and then look at how you can transform data into any custom format you may have. Then well look at some Camel components that are speciali5ed for transforming 647 data and other well!known data formats. 'ell end the chapter by looking into Camels type!converter mechanism, which supports implicitly and explicitly type coercing. (fter reading this chapter, youll know how to tackle any data transformation youre faced with and which Camel solution to leverage.
3.1.1 Data transformation with Camel In Camel, data transformation typically takes places in the six ways listed in table ".1.
Message Message body Message Message body Transform Figure 3.1 Camel
offers many features for transforming data from one form to another.
In this chapter, well cover the first five of the data transformation methods listed in table ".1. 'ell leave the last one for chapter 11.
3.2.1 sing the !essage Translator EIP The 4essage Translator ,I) is illustrated in figure "./. This pattern covers translating a message from one format to another. Its the e8uivalent of the (dapter pattern from the =ang of :our book.
Table 3.1 Six ays data transformation ty!i"ally ta#es !la"e in Camel Transformation $es"ri!tion #ata transformation in
routes $ou "an e%!li"itly enfor"e transformation in the route using the Message Translator or the ontent Enri"her EIPs& This gives you the !ower to do data ma!!ing using regular Java "ode& We'll "over this in se"tion (&)& #ata transformation using "om!onents amel !rovides a range of "om!onents for transformation* su"h as the X+LT "om!onent for XML transformation& We'll dive into this in se"tion (&(& #ata transformation using data formats #ata formats are amel transformers that "ome in !airs to transform data ,a"k and forth ,etween well-known formats& #ata transformation using tem!lates amel !rovides a range of "om!onents for transforming using tem!lates* su"h as -!a"he .elo"ity& We'll look at this in se"tion (&/& #ata ty!e transformation using amel's ty!e"onverter me"hanism amel has an ela,orate ty!e-"onverter me"hanism that a"tivates on demand& This is "onvenient when you need to "onvert from "ommon ty!es su"h as java.lang.Integer to java.lang.String or even from java.io.File to java.lang.String& Ty!e "onverters are "overed in se"tion (&0& Message transformation in "om!onent ada!ters amel's many "om!onents ada!t to various "ommonly used !roto"ols and* as su"h* need to ,e a,le to transform messages as they travel to and from those !roto"ols& 1ften these "om!onents use a "om,ination of "ustom data transformations and ty!e "onverters& This ha!!ens seamlessly* and only "om!onent writers need to worry a,out it& We'll "over writing "ustom "om!onents in "ha!ter 22&
Oriented !oftware by ,rich =amma, >ichard ?elm, >alph 2ohnson, and 2ohn ;lissides. 3ee the @<esign )atternsA 'ikipedia article for more information& http&BBen.wikipedia.orgBwikiB<esignC)atternsC+book-. Camel provides three ways of using this pattern& Dsing a Processor Dsing beans Dsing <transform> 'ell look at them each in turn.
TRA%SF&R'(%) *S(%) A PR&CESS&R
The Processor is a low!level ()I where you work directly on the Camel Exchange instance. It gives you full access to all Camels moving parts from the CamelContext, which you can obtain Exchange using the getCamelContext method. 7ets look at an example. (t >ider (uto )arts youve been asked to generate daily reports of newly received orders to be outputted to a C3; file. The company uses a custom format for order entries, but to make things easy, they already have an ?TT) service that returns a list of orders for whatever date you input. The challenge you face is mapping the returned data from the ?TT) service to a C3; format and writing the report to a file. .ecause you want to get started on a prototype 8uickly, you decide to use the Camel Processor.
import org.apache.camel.Exchange; import org.apache.camel.Processor; public class OrderToCsvProcessor implements Processor { public void process(Exchange exchange) throws Exception { String custom = exchange.getIn() .getBody(String.class);
+isting 3.1 *sing a Processor to translate from a "ustom format to CS, format
Message translator
Figure 3.- (n the 'essage Translator E(P. an in"oming message goes through a translator and "omes out as a translated message.
B
Licensed to Ian White <ian@biancashouse.com>
Transforming data using EIPs and Java 65
String id = custom.substring(0, 9); String customerId = custom.substring(10, 19); String date = custom.substring(20, 29); String items = custom.substring(30); String[] itemIds = items.split("@"); StringBuilder csv = new StringBuilder(); csv.append(id.trim()); csv.append(",").append(date.trim()); csv.append(",").append(customerId.trim()); for (String item : itemIds) { csv.append(",").append(item.trim()); } exchange.getIn().setBody(csv.toString()); } }
:irst you grab the custom format payload from the exchange B. Its a String type, so you pass String in as the parameter to have the payload returned as a String. Then you extract data from the custom format to the local variables C. The custom format could be anything, but in this example its a fixed!length custom format. Then you map the C3; format by building a string with comma!separated values D. :inally, you
replace the custom payload with your new C3; payload E. ou can use the OrderToCsvProcessor from listing ".1 in a Camel route as follows&
from("quartz://report?cron=0+0+6+*+*+?") .to("http://riders.com/orders/cmd=received&date=yesterday") .process(new OrderToCsvProcessor()) .to("file://riders/orders?fileName=report-${header.Date}.csv");
The preceding route uses Euart5 to schedule a Fob to run once a day at % a.m. It then invokes the ?TT) service to retrieve the orders received yesterday, which are returned in the custom format. Gext, it uses OrderToCSVProcessor to map from the custom format to C3; format before writing the result to a file. The e8uivalent route in 3pring 647 is as follows&
<bean id="csvProcessor" class="camelinaction.OrderToCsvProcessor"/> <camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="quartz://report?cron=0+0+6+*+*+?"/> <to uri="http://riders.com/orders/cmd=received&date=yesterday"/> <process ref="csvProcessor"/> <to uri="file://riders/orders?fileName=report-${header.Date}.csv"/> </route> </camelContext>
ou can try this example yourself9weve provided a little unit test with the books source code. =o to the chapter"Btransform directory, and run these 4aven goals&
mvn test -Dtest=OrderToCsvProcessorTest mvn test -Dtest=SpringOrderToCsvProcessorTest
(fter the test runs, a report file is written in the targetBordersBreceived directory.
CSV format
E
Licensed to Ian White <ian@biancashouse.com>
66 CHAPTER 3 Transforming data with Camel
Dsing a processor has one disadvantage& youre re8uired to use the Camel ()I. In the next section, well look at how to avoid this by using a bean.
TRA%SF&R'(%) *S(%) /EA%S
Dsing beans is a great practice because it allows you to use any 2ava code and library you wish. Camel imposes no restrictions whatsoever. Camel can invoke any bean you choose, so you can use existing beans without having to rewrite or recompile them. 7ets try using a bean instead of a Processor.
public class OrderToCsvBean { public static String map(String custom) { String id = custom.substring(0, 9); String customerId = custom.substring(10, 19); String date = custom.substring(20, 29); String items = custom.substring(30); String[] itemIds = items.split("@"); StringBuilder csv = new StringBuilder(); csv.append(id.trim()); csv.append(",").append(date.trim()); csv.append(",").append(customerId.trim()); for (String item : itemIds) { csv.append(",").append(item.trim()); } return csv.toString(); } }
+isting 3.- *sing a bean to translate from a "ustom format to CS, format
C
Licensed to Ian White <ian@biancashouse.com>
Transforming data using EIPs and Java 67
The first noticeable difference between listings ".1 and "./ is that listing "./ doesnt use any Camel imports. This means your bean is totally independent of the Camel ()I. The next difference is that you can name the method signature in listing "./9in this case its a static method named map. The method signature defines the contract, which means that the first parameter, (String custom), is the message body youre going to use for translation. The method returns a String, which means the translated data will be a String type. (t runtime, Camel binds to this method signature. 'e wont go into any more details here0 well cover much more about using beans in chapter #. The actual mapping B is the same as with the processor. (t the end, you return the mapping output C.
ou can try this example from the chapter"Btransform directory by using the following 4aven goals&
mvn test -Dtest=OrderToCsvBeanTest mvn test -Dtest=SpringOrderToCsvBeanTest
It will generate a test report file in the targetBordersBreceived directory. (nother advantage of using beans over processors for mappings is that unit testing is much easier. :or example, listing "./ doesnt re8uire the use of Camel at all, as opposed to listing ".1 where you need to create and pass in an Exchange instance. 'ell leave the beans for now, because theyre covered extensively in the next chapter. .ut you should keep in mind that beans are very useful for doing message transformation.
TRA%SF&R'(%) *S(%) THE TRA%SF&R'01 'ETH&$ FR&' THE 2A,A $S+
Transform() is a method in the 2ava <37 that can be used in Camel routes to transform messages. .y allowing the use of expressions, transform() permits great flexibility,
and using expressions directly within the <37 can sometimes save time. 7ets look at a little example. Licensed to Ian White <ian@biancashouse.com>
68 CHAPTER 3 Transforming data with Camel
3uppose you need to prepare some text for ?T47 formatting by replacing all line breaks with a <br/> tag. This can be done with a built!in Camel expression that searches and replaces using regular expressions&
from("direct:start") .transform(body().regexReplaceAll("\n", "<br/>")) .to("mock:result");
'hat this route does is use the transform() method to tell Camel that the message should be transformed using an expression. Camel provides what is know as the .uilder pattern to build expressions from individual expressions. This is done by chaining together method calls, which is the essence of the .uilder pattern. %&TE :or more information on the .uilder pattern, see the 'ikipedia article& http&BBen.wikipedia.orgBwikiB.uilderCpattern. In this example, you combine body() and regexReplaceAll(). The expression should be read as follows& take the body and perform a regular expression that replaces all new lines +\n- with <br/> tags. Gow youve combined two methods that conform to a compound Camel expression. ou can run this example from chapter"Btransform directly by using the following 4aven goal&
mvn test -Dtest=TransformTest
Camel also allows you to use custom expressions. This is useful when you need to be in full control and have 2ava code at your fingertips. :or example, the previous example could have been implemented as follows&
from("direct:start") .transform(new Expression() { public <T> T evaluate(Exchange exchange, Class<T> type) { String body = exchange.getIn().getBody(String.class); body = body.replaceAll("\n", "<br/>"); body = "<body>" + body + "</body>"; return (T) body; } }) .to("mock:result");
(s you can see, this code uses an inlined Camel Expression that allows you to use 2ava
code in its evaluate method. This follows the same principle as the Camel Processor you saw before.
Gow lets see how you can transform data using 3pring 647.
TRA%SF&R'(%) *S(%) 3TRA%SF&R'4 FR&' SPR(%) 5'+
Dsing Htransform> from 3pring 647 is a bit different than from 2ava <37 because the 647 <37 isnt as powerful. In 3pring 647, the .uilder pattern expressions arent available because with 647 you dont have a real programming language underneath. 'hat you can do instead is invoke a method on a bean or use scripting languages. 7ets see how this works. The following route uses a method call on a bean as the expression&
<bean id="htmlBean" class="camelinaction.HtmlBean"/> <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="direct:start"/> <transform> <method bean="htmlBean" method="toHtml"/> </transform> <to uri="mock:result"/> </route> </camelContext>
:irst, you declare a regular spring bean to be used to transform the message B. Then, in the route, you use <transform> with a <method> call expression to invoke the bean C. The implementation of the htmlBean is very straightforward&
public public body = body = return } } class HtmlBean { static String toHtml(String body) { body.replaceAll("\n", "<br/>"); "<body>" + body + "</body>"; body;
ou can also use scripting languages as expressions in Camel. :or example, you can use =roovy, 4;,7, 2ava3cript, or Camels own scripting language, called 3imple +explained in some detail in appendix (-. 'e wont go in detail on how to use the other scripting languages at this point, but the 3imple language can be used to build strings using placeholders. It pretty much speaks for itself9Im sure youll understand what the following transformation does&
<transform> <simple>Hello ${body} how are you?</simple> </transform>
ou can try the 3pring transformation examples provided in the books source code by running the following 4aven goals from the chapter"Btransform directory&
mvn test -Dtest= SpringTransformMethodTest mvn test -Dtest= SpringTransformScriptTest
Theyre located in the chapter"Btransform directory and are named SpringTransformMethodTest and SpringTransformScriptTest.
Does the transformation
B
Invo es to!tml method on bean
C
Licensed to Ian White <ian@biancashouse.com>
70 CHAPTER 3 Transforming data with Camel
'ere done covering the 4essage Translator ,I), so lets look at the related Content ,nricher ,I).
3.2.2 sing the Content Enricher EIP The Content ,nricher ,I) is illustrated in figure ".". This pattern documents the scenario where a message is enriched with data obtained from another resource. To help understand this pattern, well turn back to >ider (uto )arts. It turns out that the data mapping you did in listing ".1 wasnt sufficient. Irders are also piled up on an :T) server, and your Fob is to somehow merge this information into the existing report. :igure ".# illustrates the scenario.
Basic message Enriched message
Enricher
Resource
Figure 3.3 (n the Content Enri"her E(P. an existing message has data added to it from another sour"e. HTTP server FTP server
Content enricher Quartz scheduler Report (CSV)
File server
Orders (CSV) Transform
Camel
BC D E F G
Figure 3.6 An o7er7ie of the route that generates the orders re!ort. no ith the "ontent enri"her !ulling in data from an FTP ser7er
In figure ".#, a scheduled consumer using Euart5 starts the route every day at % a.m. B. It then pulls data from an ?TT) server, which returns orders in a custom formatC, which is then transformed into C3; format D. (t this point, you have to perform the additional content enrichment step E with the data obtained from the
:T) server F. (fter this, the final report is written to the file server
G.
.efore we dig into the code and see how to implement this, we need to take a step back and look at how the Content ,nricher ,I) is implemented in Camel. Camel provides two operations in the <37 for implementing the pattern& pollEnrich9This operation merges data retrieved from another source using a consumer. enrich9This operation merges data retrieved from another source using a producer. Camel uses the org.apache.camel.processor.AggregationStrategy interface to merge the result from the source with the original message, as follows&
Exchange aggregate(Exchange oldExchange, Exchange newExchange);
This aggregate method is a callback that you must implement. The method has two parameters& the first, named oldExchange, contains the original exchange0 the second, newExchange, is the enriched source. our task is to enrich the message using
2ava code and return the merged result. This may sound a bit confusing, so lets see it in action. To solve the problem at >ider (uto )arts, you need to use pollEnrich because its capable of polling a file from an :T) server.
E%R(CH(%) *S(%) P&++E%R(CH
7isting "." shows how you can use pollEnrich to retrieve the additional orders from the remote :T) server and aggregate this data with the existing message using Camels AggregationStrategy.
from("quartz://report?cron=0+0+6+*+*+?") .to("http://riders.com/orders/cmd=received") .process(new OrderToCSVProcessor()) .pollEnrich("ftp://riders.com/orders/?username=rider&password=secret",
The route is triggered by Euart5 to run at % a.m. every day. ou invoke the ?TT) service to retrieve the orders and transform them to C3; format using a processor. (t this point, you need to enrich the existing data with the orders from the remote :T) server. This is done by using pollEnrich B, which consumes the remote file.
To merge the data, you use AggregationStrategy C. :irst, you check whether any data was consumed or not. If newExchange is null, there is no remote file to consume, and you Fust return the existing data. If there is a remote file, you merge the data by concatenating the existing data with the new data and setting it back on the oldExchange. Then, you return the merged data by returning the oldExchange. To write the C3; report file, you use the file component D. PollEnrich uses a polling consumer to retrieve messages, and it offers three timeout modes& pollEnrich(timeout = -1)9)olls the message and waits until a message arrives. This mode will block until a message exists. pollEnrich(timeout = 0)9Immediately polls the message if any exists0 otherwise null is returned. It will never wait for messages to arrive, so this mode will never block. This is the default mode. pollEnrich(timeout > 0)9)olls the message, and if no message exists, it will wait for one, waiting at most until the timeout triggers. This mode will potentially block. Its a best practice to either use timeout = 0 or to assign a timeout value when using pollEnrich to avoid waiting indefinitely if no message arrives.
"ses pollEnrich
B C
D
Enrich and pollEnrich "an8t a""ess information in the "urrent ex"hange :either enrich nor pollEnrich "an leverage any information from the "urrent e%"hange& This means* for e%am!le* that you "an't store a filename header on the e%"hange for pollEnrich to use to sele"t a !arti"ular file& This may "hange in the future if the amel team "an find a solution&
Gow lets take a 8uick look at how to use enrich with 3pring 6470 its a bit different than when using the 2ava <37.
E%R(CH(%) *S(%) E%R(CH
Enrich is used when you need to enrich the current message with data from another
source using re8uest!response messaging. ( prime example would be to enrich the current message with the reply from a web service call. .ut well look at another example, using 3pring 647 to enrich the current message using the TC) transport&
<bean id="quoteStrategy" class="camelinaction.QuoteStrategy"/> <route> <from uri="activemq:queue:quotes"/> <enrich url="mina:tcp://riders.com:9876?textline=true&sync=true" strategyRef="quoteStrategy"/> <to uri="log:quotes"/> </route>
?ere you use the Camel mina component for TC) transport, configured to use re8uest!response messaging by using sync=true option. To merge the original message with data from the remote server, <enrich> must refer to an AggregationStrategy. This is done using the strategyRef attribute. (s you can see in the example, the
quoteStrategy being referred to is a bean id B, which contains the actual implementation of the AggregationStrategy, where the merging takes place.
ouve seen a lot about how to transform data in Camel, using 2ava code for the actual transformations. Gow lets take a peek into the 647 world and look at the 637T component, which is used for transforming 647 messages using 637T stylesheets.
3.3.1 Transforming "!# with "$#T 637 Transformations +637T- is a declarative 647!based language used to transform 647 documents into other documents. :or example, 637T can be used to transform 647 into ?T47 for web pages or to transform an 647 document into another 647 document with a different structure. 637T is powerful and versatile, but its also a complex language that takes time and effort to fully understand and master. Think twice before deciding to pick up and use 637T. Camel provides 637T as a component in camel!spring.Far because it leverages 3prings resource loading. This means greater flexibility in loading stylesheets because 3pring enables them to be loaded from various locations, such as the classpath, file paths, and over ?TT).
The following route shows an example of how you could use it0 this route is also illustrated in figure ".$.
from("file://rider/inbox") .to("xslt://camelinaction/transform.xsl") .to("activemq:queue:transformed")
The file consumer picks up new files and routes them to the 637T component, which transforms the payload using the stylesheet. (fter the transformation, the message is routed to a 243 producer, which sends the message to the 243 8ueue. Gotice in the preceding code how the D>7 for the 637T component is defined& xslt://camelinaction/ transform.xsl. The part after the scheme is the D>I location of the stylesheet to use. Camel will look in the classpath by default. (s mentioned before, the Camel 637T component leverages 3pring to load the stylesheet. ou can prefix the resource name with any of the three prefixes listed in table "./. 7ets leave the 637T world now and take a look at how you can do 647!to!obFect marshaling with Camel.
Table 3.- Prefixes su!!orted by the 5S+T "om!onent for loading stylesheets Prefix Exam!le $es"ri!tion
Transformed message
BCD
Figure 3.9 A Camel route using an 5S+T "om!onent to transform an 5'+ do"ument before it8s sent to a 2'S :ueue
3.3.2 Transforming "!# with o%&ect marshaling (ny software engineer who has worked with 647 knows that its a challenge to use the low!level 647 ()I that 2ava offers. Instead, people often prefer to work with regular 2ava obFects and use marshaling to transform between 2ava obFects and 647 representations. In Camel, this marshaling process is provided in ready!to!use components known as data formats. 'ell cover data formats in full detail in section ".#, but well take a 8uick look at the 63tream and 2(6. data formats here as we cover 647 transformations using marshaling.
TRA%SF&R'(%) *S(%) 5STREA'
63tream is a simple library for seriali5ing obFects to 647 and back again. To use it, you need camel!xstream.Far on the classpath and the 63tream library itself. 3uppose you need to send messages in 647 format to a shared 243 8ueue, which is then used to integrate two systems. 7ets look at how this can be done.
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> <dataFormats> <xstream id="myXstream"/> </dataFormats> <route> <from uri="direct:foo"/>
'hen using the 647 <37, you can declare the data formats used at the top B of the <camelContext>. .y doing this, you can share the data formats in multiple routes. In the first route, where you send messages to a 243 8ueue, you use marshal which refers to the id from B, so Camel knows that the 63tream data format is being used. ou can also use the 63tream data format directly in the route, which can shorten the syntax a bit, like this&
<route> <from uri="direct:foo"/> <marshal><xstream/></marshal> <to uri="activemq:queue:foo"/> </route>
C,
The same route is a bit shorter to write in the 2ava <37, because you can do it with one line per route&
from("direct:foo").marshal().xstream().to("uri:activemq:queue:foo");
es, using 63tream is that simple. (nd the reverse operation, unmarshaling from 647 to an obFect, is Fust as simple&
+isting 3.6 *sing 5Stream to transform a message into 5'+ Specifies *Stream
C
Licensed to Ian White <ian@biancashouse.com>
76 CHAPTER 3 Transforming data with Camel
<route> <from uri="activemq:queue:foo"/> <unmarshal ref="myXstream"/> <to uri="direct:handleFoo"/> </route>
ouve now seen how easy it is to use 63tream with Camel. 7ets take a look at using
2(6. with Camel.
TRA%SF&R'(%) *S(%) 2A5/
2(6. +2ava (rchitecture for 647 .inding- is a standard specification for 647 binding, and its provided out of the box in the 2ava runtime. 7ike 63tream, it allows you to seriali5e obFects to 647 and back again. Its not as simple, but it does offer more bells and whistles for controlling the 647 output. (nd because its distributed in 2ava, you dont need any special 2(> files on the classpath. Dnlike 63tream, 2(6. re8uires that you do a bit of work to declare the binding between 2ava obFects and the 647 form. This is often done using annotations. 3uppose
you define a model bean to represent an order, as shown in listing ".$, and you want to transform this into 647 before sending it to a 243 8ueue. Then you want to transform it back to the order bean again when consuming from the 243 8ueue. This can be done as shown in listings ".$ and ".%.
package com.acme.order; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class PurchaseOrder { @XmlAttribute private String name; @XmlAttribute private double price; @XmlAttribute private double amount; }
7isting ".$ shows how to use 2(6. annotations to decorate your model obFect +omitting the usual getters and setters-. :irst you define @XmlRootElement B as a class!level
annotation to indicate that this class is an 647 element. Then you define the @XmlAccessorType to let 2(6. access fields directly. To expose the fields of this model obFect as 647 attributes, you mark them with the @XmlAttribute annotation. Dsing 2(6., you should be able to marshal a model obFect into an 647 representation like this&
<purchaseOrder name="Camel in Action" price="4995" amount="1"/>
7isting ".% shows how you can use 2(6. in routes to transform the PurchaseOrder obFect to 647 before its sent to a 243 8ueue, and then back again from 647 to the PurchaseOrder obFect when consuming from the same 243 8ueue.
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring"> <dataFormats> <jaxb id="jaxb" contextPath="camelinaction"/> </dataFormats> <route> <from uri="direct:order"/> <marshal ref="jaxb"/> <to uri="activemq:queue:order"/> </route> <route> <from uri="activemq:queue:order"/> <unmarshal ref="jaxb"/> <to uri="direct:doSomething"/> </route> </camelContext>
:irst you need to declare the 2(6. data format B. Gote that a contextPath attribute is also defined on the 2(6. data format9this is a package name that instructs 2(6. to look in this package for classes that are 2(6.!annotated. The first route then marshals to 647 C and the second route unmarshals to transform the 647 back into the PurchaseOrder obFect D. ou can try this example by running the following 4aven goal from the chapter"B order directory&
mvn test -Dtest=PurchaseOrderJaxbTest
%&TE To tell 2(6. which classes are 2(6.!annotated, you need to drop a special jaxb.index file into the context path. Its a plain text file in which each
line lists the class name. In the preceding example, the file contains a single line with the text PurchaseOrder. Thats the basis of using 647 obFect marshaling with 63tream and 2(6.. .oth of them are implemented in Camel via data formats that are capable of transforming back and forth between various well!known formats.