Documentation
- Architecture
- Tutorials
- Cookbook
- Books
- Components
- Camel DSL
- Enterprise Integration Patterns
- SOA Patterns
- Manual
- User Guide
Architecture
The following links are to the individual parts of the Architecture.
- AOP
- Async
- Asynchronous Routing Engine
- BacklogTracer
- BAM
- Batch Consumer
- Binding
- BrowsableEndpoint
- CamelContext
- Camel-Core
- CEP
- Clustering and loadbalancing
- Component
- Data Format
- Debugger
- Delay Interceptor
- Dependency Injection
- Dozer Type Conversion
- DSL
- Endpoint
- Error Handler
- Exchange
- Exchange Pattern
- Expression
- Injector
- Intercept
- Inversion Of Control With Smart Defaults
- Languages
- Lifecycle
- OnCompletion
- Pluggable Class Resolvers
- Predicate
- Processor
- ProcessorFactory
- Registry
- RouteBuilder
- RoutePolicy
- Routes
- RX
- Security
- ServicePool
- Stream caching
- Threading Model
- ToAsync
- Tracer
- Transport
- Type Converter
- URIs
- UuidGenerator
- Xml Configuration
1.Bean component
http://camel.apache.org/bean.html
camelContext xmlns="http://camel.apache.org/schema/spring"><route><from uri="direct:start"/><to uri="myBean"/><to uri="mock:results"/></route></camelContext><bean id="myBean" class="org.apache.camel.spring.bind.ExampleBean"/>
What happens is that when the exchange is routed to the myBean Camel will use theBean Binding to invoke the bean.
The source for the bean is just a plain POJO:
public class ExampleBean {
public String sayHello(String name) {
return "Hello " + name + "!";
}
}
Camel will use Bean Binding to invoke the sayHello method, by converting the Exchange's In body to theString
http://camel.apache.org/bean-binding.html
Bean Binding in Camel defines both which methods are invoked and also how the Message is converted into the parameters of the method when it is invoked.
Choosing the method to invoke
The binding of a Camel Message to a bean method call can occur in different ways, in the following order of importance:
- if the message contains the header CamelBeanMethodName then that method is invoked, converting the body to the type of the method's argument.
- From Camel 2.8 onwards you can qualify parameter types to select exactly which method to use among overloads with the same name (see below for more details).
- From Camel 2.9 onwards you can specify parameter values directly in the method option (see below for more details).
- you can explicitly specify the method name in the DSL or when using POJO Consuming or POJO Producing
- if the bean has a method marked with the @Handler
- if the bean can be converted to a Processor using the Type Converter mechanism, then this is used to process the message. The ActiveMQ component uses this mechanism to allow any JMS MessageListener to be invoked directly by Camel without having to write any integration glue code. You can use the same mechanism to integrate Camel into any other messaging/remoting frameworks.
- if the body of the message can be converted to a BeanInvocation (the default payload used by the ProxyHelper) component - then that is used to invoke the method and pass its arguments
- otherwise the type of the body is used to find a matching method; an error is thrown if a single method cannot be chosen unambiguously.
- you can also use Exchange as the parameter itself, but then the return type must be void.
- if the bean class is private (or package-private), interface methods will be preferred (fromCamel 2.9 onwards) since Camel can't invoke class methods on such beans
In cases where Camel cannot choose a method to invoke, an AmbiguousMethodCallException
By default the return value is set on the outbound message body.
The BeanProcessor uses the input message to bind its body to the first parameter
of the method , which happens to be the String name parameter. Camel does this
by creating an expression that type-converts the input message body to the String
type. This ensures that when Camel invokes the echo method , the parameter
matches the expected type.
Working with multiple parameters
Using multiple parameters is more complex than using single parameters. It’s gener-ally a good idea to follow these rules of thumb:
■
Use the first parameter as the message body, which may or may not use the
@Body annotation.
■
Use either a built-in type or add Camel annotations for subsequent parameters.
In our experience, it becomes complicated when multiple parameters don’t follow
these guidelines, but Camel will make its best attempt to adapt the parameters to
the method signature
Binding using built-in types
Let’s look at a couple of examples using the types from table 4.2. First, suppose you
add a second parameter that’s one of the built-in types to the echo method:
public string echo(String echo, CamelContext context)
In this example, you bind the CamelContext, which gives you access to all the moving
parts of Camel.
Or you could bind the registry, in case you need to look up some beans:
public string echo(String echo, Registry registry) {
OtherBean other = registry.lookup("other", OtherBean.class);
...
}
You aren’t restricted to having only one additional parameter; you can have as many
as you like. For example, you could bind both the CamelContext and the registry:
public string echo(String echo, CamelContext context, Registry registry)
Binding using Camel annotations
ith the help of Camel annotations, you can bind the Exchange to the method signa-ture as follows:
public String orderStatus(@Header("customerId") Integer customerId,
@Body Integer orderId)
Notice how you can use the @Header annotation to bind the message header to the
first parameter and @Body to bind the message body to the second parameter.
Binding using Camel language annotations
For example, suppose the message contains the fol-lowing XML document:
<order customerId="123">
<status>in progress</status>
</order>
By using XPath expressions, you can extract parts of the document and bind them to
parameters, like this:
public void updateStatus(@XPath("/order/@customerId") Integer customerId,
@XPath("/order/status/text()") String status)
2.
Type Converter
http://camel.apache.org/type-converter.html
Its very common when routing messages from one endpoint to another to need to convert the body payloads from one type to another such as to convert to and from the following common types
- File
- String
- byte[] and ByteBuffer
- InputStream and OutputStream
- Reader and Writer
- Document and Source
- ...
The Message interface defines a helper method to allow conversions to be done via thegetBody(Class) method.
So in an endpoint you can convert a body to another type via
Message message = exchange.getIn();
Document document = message.getBody(Document.class);
How Type Conversion works
The type conversion strategy is defined by the TypeConverter interface which can be customized on a CamelContext.
The default implementation, DefaultTypeConverter uses pluggable strategies to load type converters via TypeConverterLoader. The default strategy, AnnotationTypeConverterLoader uses a discovery mechanism to find converters.
TypeConverterRegistry
New in Camel 2.0
Exposed the TypeConverterRegistry from CamelContext so end users more easily will be able to add type converters at runtime. This is also usable in situations where the default discovering of type converters fails, on platforms with classloading issues.
To access the registry you get it from the CamelContext
CamelContext context = ...
context.getTypeConverterRegistry()
Add type converter at runtime
The following sample demonstrates how to add a type converter at runtime:
// add our own type converter manually that converts from String -> MyOrder using MyOrderTypeConverter
context.getTypeConverterRegistry().addTypeConverter(MyOrder.class, String.class, new MyOrderTypeConverter());
And our type converter is implemented as:
private static class MyOrderTypeConverter extends TypeConverterSupport {
@SuppressWarnings("unchecked")
public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
// converter from value to the MyOrder bean
MyOrder order = new MyOrder();
order.setId(Integer.parseInt(value.toString()));
return (T) order;
}
}
And then we can convert from String to MyOrder as we are used to with the type converter:
MyOrder order = context.getTypeConverter().convertTo(MyOrder.class,"123");
Discovering Type Converters
The AnnotationTypeConverterLoader will search the classpath for a file called META-INF/services/org/apache/camel/TypeConverter. The contents are expected to be comma separated package names. These packages are then recursively searched for any objects with the@Converter annotation. Then any method marked with @Converter is assumed to be a conversion method; where the parameter is the from value and the return is the to value.
e.g. the following shows how to register a converter from File -> InputStream
@Converter
public class IOConverter {
@Converter
public static InputStream toInputStream(File file) throws FileNotFoundException {
return new BufferedInputStream(new FileInputStream(file));
}
}
Static methods are invoked; non-static methods require an instance of the converter object to be created (which is then cached). If a converter requires configuration you can plug in an Injector interface to the DefaultTypeConverter which can construct and inject converter objects via Spring or Guice.
We have most of the common converters for common Java types in the org.apache.camel.converter package and its children.
Writing your own Type Converters
Use FQN In Camel 2.8 the TypeConverter file now supports specifying the FQN class name. This is recommended to be used. See below for more details |
You are welcome to write your own converters. Remember to use the @Converter annotations on the classes and methods you wish to use. Then add the packages to a file calledMETA-INF/services/org/apache/camel/TypeConverter in your jar. Remember to make sure that :-
- static methods are encouraged to reduce caching; but instance methods are fine, particularly if you want to allow optional dependency injection to customize the converter
- converter methods should be thread safe and reentrant
Examples of TypeConverter file
The file in the JAR: META-INF/services/org/apache/camel/TypeConverter
com.foo
com.bar
Each line in the file is package name. This tells Camel to go scan those packages for any classes which has been annotated with the @Converter.
Improved TypeConverter by using FQN class names
Available as of Camel 2.8
In Camel 2.8 we improved the type converter loader to support specifying the FQN class name of the converter classes. This has a much better advantage as it avoids having to scan packages for @Converter classes. Instead it loads the @Converter class directly. This is highly recommend approach to use going forward.
Examples of TypeConverter file
The file in the JAR: META-INF/services/org/apache/camel/TypeConverter
com.foo.MyConverter
com.bar.MyOtherConverter
com.bar.YetOtherConverter
As you can see each line in the file now contains a FQN class name. This is the recommended approach.
Encoding support for byte[] and String Conversion
Available in Camel 1.5
Since Java provides converting the byte[] to String and String to byte[] with thecharset name parameter. You can define the charset name by setting the exchange property nameExchange.CHARSET_NAME with the charset name, such as"UTF-8" or"iso-8859-1".
Exchange parameter
Available in Camel 1.5
The type converter accepts the Exchange as an optional 2nd parameter. This is usable if the type converter for instance needs information from the current exchange. For instance combined with the encoding support its possible for type converters to convert with the configured encoding. An example from camel-core for the byte[] -> String
@Converter
public static String toString(byte[] data, Exchange exchange) {
if (exchange != null) {
String charsetName = exchange.getProperty(Exchange.CHARSET_NAME, String.class);
if (charsetName != null) {
try {
return new String(data, charsetName);
} catch (UnsupportedEncodingException e) {
LOG.warn("Can't convert the byte to String with the charset " + charsetName, e);
}
}
}
return new String(data);
}
3.JMS message converter
Message Mapping between JMS and Camel
Camel automatically maps messages between javax.jms.Message and org.apache.camel.Message.
When sending a JMS message, Camel converts the message body to the following JMS message types:
Body Type | JMS Message | Comment |
String | javax.jms.TextMessage | |
org.w3c.dom.Node | javax.jms.TextMessage | The DOM will be converted to String. |
Map | javax.jms.MapMessage | |
java.io.Serializable | javax.jms.ObjectMessage | |
byte[] | javax.jms.BytesMessage | |
java.io.File | javax.jms.BytesMessage | |
java.io.Reader | javax.jms.BytesMessage | |
java.io.InputStream | javax.jms.BytesMessage | |
java.nio.ByteBuffer | javax.jms.BytesMessage | |
When receiving a JMS message, Camel converts the JMS message to the following body type:
JMS Message | Body Type |
javax.jms.TextMessage | String |
javax.jms.BytesMessage | byte[] |
javax.jms.MapMessage | Map<String, Object> |
javax.jms.ObjectMessage | Object |
Disabling auto-mapping of JMS messages
You can use the mapJmsMessage option to disable the auto-mapping above. If disabled, Camel will not try to map the received JMS message, but instead uses it directly as the payload. This allows you to avoid the overhead of mapping and let Camel just pass through the JMS message. For instance, it even allows you to route javax.jms.ObjectMessage JMS messages with classes you do not have on the classpath.
Using a custom MessageConverter
You can use the messageConverter option to do the mapping yourself in a Springorg.springframework.jms.support.converter.MessageConverter
For example, in the route below we use a custom message converter when sending a message to the JMS order queue:
from("file://inbox/order").to("jms:queue:order?messageConverter=#myMessageConverter");
You can also use a custom message converter when consuming from a JMS destination.
Controlling the mapping strategy selected
You can use the jmsMessageType option on the endpoint URL to force a specific message type for all messages.
In the route below, we poll files from a folder and send them as javax.jms.TextMessage
from("file://inbox/order").to("jms:queue:order?jmsMessageType=Text");
You can also specify the message type to use for each messabe by setting the header with the keyCamelJmsMessageType. For example:
from("file://inbox/order").setHeader("CamelJmsMessageType", JmsMessageType.Text).to("jms:queue:order");
The possible values are defined in the enum class, org.apache.camel.jms.JmsMessageType.
4.Active MQ component
http://camel.apache.org/activemq.html
setup the activemq Camel component as follows:
<bean id="jmsConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
<bean id="pooledConnectionFactory"
class="org.apache.activemq.pool.PooledConnectionFactory" init-method="start" destroy-method="stop">
<property name="maxConnections" value="8" />
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
<bean id="jmsConfig"
class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="concurrentConsumers" value="10"/>
</bean>
<bean id="activemq"
class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig"/>
</bean>
Invoking MessageListener POJOs in a Camel route
The ActiveMQ component also provides a helper Type Converter from a JMS MessageListener to a Processor. This means that the Bean component is capable of invoking any JMS MessageListener bean directly inside any route.
So for example you can create a MessageListener in JMS like this:
public class MyListener implements MessageListener {
public void onMessage(Message jmsMessage) {
// ...
}
}
Then use it in your Camel route as follows
from("file://foo/bar").
bean(MyListener.class);
That is, you can reuse any of the Camel Components and easily integrate them into your JMS MessageListener
Using ActiveMQ Destination Options
Available as of ActiveMQ 5.6
You can configure the Destination Options in the endpoint uri, using the "destination." prefix. For example to mark a consumer as exclusive, and set its prefetch size to 50, you can do as follows:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="file://src/test/data?noop=true"/>
<to uri="activemq:queue:foo"/>
</route>
<route>
<!-- use consumer.exclusive ActiveMQ destination option, notice we have to prefix with destination. -->
<from uri="activemq:foo?destination.consumer.exclusive=true&destination.consumer.prefetchSize=50"/>
<to uri="mock:results"/>
</route>
</camelContext>