Camel + Java DSL Fluent builder with real ActiveMQ Broker - apache-camel

I'm trying to implement a WireTap with Java DSL Fluent Builders, which gives the following example code snippet.
from("direct:start")
.to("log:foo")
.wireTap("direct:tap")
.to("mock:result");
This works if I run a mock example (e.g. camel-example-jms-file). However if I take the sample code and try to substitute a real Broker instance and Queue to replace the mock objects it fails with error below.
from("tcp://localhost:61616")
.to("ativemq:atsUpdateQueue")
.wireTap("activemq:fdmCaptureQueue");
Then it fails
org.apache.camel.FailedToCreateRouteException: Failed to create route route2: Route(route2)[[From[tcp://localhost:61616?queue=atsUpdateQue... because of Failed to resolve endpoint: tcp://localhost:61616?queue=atsUpdateQueue due to: No component found with scheme: tcp
I've googled extensively and all the example I've found use the virtual mock queues none seem to illustrate working with a real broker and but I cannot find any documentation on the URI specification for camel.

The important part of the error message describes the problem No component found with scheme: tcp, This is becasuse there is no "tcp" component for camel, however you can use the netty component if you want to interact with a tcp endpoint:
from("netty:tcp://localhost:61616")
more info here - http://camel.apache.org/netty.html

"tcp://localhost:61616" looks like the activemq broker address.
You need to setup the broker address to activemq component in Java DSL
camelContext.addComponent("activemq", activeMQComponent("tcp://localhost:61616"));
or in spring configuration file
<bean id="activemq"
class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="tcp://somehost:61616"/>
</bean>
You can find more information about camel-activemq here

Thank you for the suggestions, while useful in increasing my understanding neither actually resolved my problem. My code was wrong and for the benefit of others I should have been using the following names.
final String sourceQueue = "activemq:queue:atsUpdateQueue";
final String destinationQueue = "activemq:queue:atsEndPoint";
final String wiretapQueue = "activemq:queue:fdmCaptureQueue";
from(sourceQueue).wireTap(wiretapQueue).copy().to(destinationQueue);

Related

Bridging http request with path variable in CAMEL REST

I am trying to bridge Camel REST endpoints to a backend server. Corresponding REST DSL is as follows:
from("rest:get:tt:/{id}")
.toF("%s/%s?bridgeEndpoint=true","http://192.168.1.1:80","jjjj/llll/pppp/{id}");
My expectation is that the request should be forwarded to http://192.168.1.1:80/jjjj/llll/pppp/id But what actually happens is that the request gets forwarded to http://192.168.1.1:80/jjjj/llll/pppp/%7Bid%7D/tt/id
Can any one suggest, what am I doing wrong and how I can achieve the desired behaviour? I am using Spring Boot Camel 2.3.4 which uses Camel 3.5.0 internally.
Mean while, I have found a work around that to use .to() instead of .toF(). With .to(), I achieved desired behavior. Camel route DSL is Something like
from("rest:get:tt:/{id}").to("rest:get:jjjj/llll/pppp/{id}?host=http://192.168.1.1:80")
But question still remains open that why it is not working with .toF().
Seems like you're using {id} syntax for http component uri, but I think it's only recognized by the rest component, so instead of having:
from("rest:get:tt:/{id}")
.toF("%s/%s?bridgeEndpoint=true", "http://192.168.1.1:80", "jjjj/llll/pppp/{id}");
you could try using dynamic endpoint .toD() with simple expression ${header.id}:
from("rest:get:tt:/{id}")
.toD("http://192.168.1.1:80/jjjj/llll/pppp/${header.id}?bridgeEndpoint=true");
Not exactly sure if that's what you're aiming for though

ActiveMQ embedded bridge to Camel JMS bridge

I have an old application which handle JMS messages with ActiveMQ 5.8.0 and some JNDI remote topic connected to this ActiveMQ.
I have a connector like that :
<bean class="org.apache.activemq.network.jms.JmsConnector">
<property name="outboundTopicConnectionFactory" ref="jmsConnectionFactoryTo" />
<property name="outboundClientId" value="${remote.clientId}" />
<property name="jndiOutboundTemplate" ref="jndiTemplateTo" />
<property name="preferJndiDestinationLookup" value="true" />
<property name="inboundTopicBridges">
<list>
<bean class="org.apache.activemq.network.jms.InboundTopicBridge">
<property name="inboundTopicName" value="${remote.topic.to}"/>
<property name="localTopicName" value="${local.topic.to}"/>
<property name="consumerName" value="${remote.consumer.name}"/>
<property name="selector" value="${remote.selector}"/>
</bean>
</list>
</property>
</bean>
It works great, but now, for some technical reasons (strict JMS 1.1), I need to use "ConnectionFactory" instead of "TopicConnectionFactory".
With the actual configuration, I'm stuck because ActiveMQ seems to use "TopicConnectionFactory" instead of "ConnectionFactory", and my new class "MyConnectionFactoryImpl" implements "ConnectionFactory" now :
nested exception is org.springframework.beans.ConversionNotSupportedException:
Failed to convert property value of type 'com.webmethods.jms.impl.MyConnectionFactoryImpl'
to required type 'javax.jms.TopicConnectionFactory'
for property 'outboundTopicConnectionFactory';
nested exception is java.lang.IllegalStateException:
Cannot convert value of type [com.webmethods.jms.impl.MyConnectionFactoryImpl]
to required type [javax.jms.TopicConnectionFactory] for property 'outboundTopicConnectionFactory':
no matching editors or conversion strategy found
In "org.apache.activemq.network.jms.JmsConnector" class, it use everywhere "TopicConnectionFactory", which is not recommended anymore in JMS 1.1.
EDIT :
According to #Justin Bertram, I need to use Camel instead of ActiveMQ embedded bridge. But I can't find any example of XML configuration which I can use to replace my actual two beans JMSConnector. Which is the simple way to do this keeping my XML config files ?
As the documentation for the JMS to JMS Bridge (i.e. org.apache.activemq.network.jms.JmsConnector) states:
ActiveMQ provides bridging functionality to other JMS providers that implement the JMS 1.0.2 and above specification.
In other words, the whole goal of the JMS to JMS Bridge is to use the JMS 1.0.2 interface(s). Changing it so that it only used JMS 1.1 would defeat the purpose.
The documentation also states that you should use Camel instead of the JMS to JMS Bridge:
Warning, try Camel first!
Note that we recommend you look at using Apache Camel for bridging ActiveMQ to or from any message broker (or indeed any other technology, protocol or middleware) as its much easier to:
keep things flexible; its very easy to map different queue/topic to one or more queues or topics on the other provider
perform content based routing, filtering and other Enterprise Integration Patterns
allows you to work with any technology, protocol or middleware, not just JMS providers
Therefore I recommend you use Camel instead of org.apache.activemq.network.jms.JmsConnector.
I would think that having your code return a TopicConnectionFactory would be the simplest solution. Even the JMS 2.0 specification provides the TopicConnectionFactory. No matter what version of ActiveMQ you are using, you certainly have the option of using the TopicConnectionFactory in your code and providing that to your bridge.
Note that the Camel route:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="mqseries:Foo.Bar"/>
<to uri="activemq:Cheese"/>
</route>
</camelContext>
has no error handling. For example, if the 'to' endpoint is down, this route will read from the 'from' endpoint and just throw the messages on the floor. Furthermore, if the 'to' component is not configured to use a caching/pooling connection factory, then a new JMS connection will be created for each message sent. This has poor performance and can result in many sockets in the TIME_WAIT state. Bottom line - beware trivial Camel routes.

How to access a remote web service by Camel CXF endpoint?

I was looking up online how to create a Camel's CXF producer (i.e. create a CXF endpoint that would produce a request to some local/remote web service). Generally, all the examples I could find would list the following steps:
First define the cxfEndpoint attributes:
<cxf:cxfEndpoint
id="orderEndpoint"
address="http://localhost:9000/order/"
serviceClass="camelinaction.order.OrderEndpoint"/>
Then send the request to that endpoint:
...to("cxf:bean:orderEndpoint");
Hmmm. I don't understand the concept. If this is a remote web service, all I usually have is the URL of the WSDL. I can get from it the address of the service... but I don't know what the serviceClass is and I don't have it on my classpath.
So how do I define that cxfEndpoint in case I only have the URL of the WSDL?
Or is there another type of endpoint I should use in that case?
I would suggest looking into WSDL first for cxf. Below are two links that I think should help you out quite a lot and has helped me in the past as well.
http://code.notsoclever.cc/camel-cxf-component-wsdl-first-example/
https://access.redhat.com/documentation/en-US/Fuse_ESB_Enterprise/7.0/html-single/Web_Services_and_Routing_with_Camel_CXF/index.html#ImplWs-WsdlFirst
On the Red Hat site you will need to start at chapter 3.
Hope this helps.

Apache camel to invoke ejb 2

Can I use apache camel to invoke remote ejbs (ejb2.0)? How do I pass parameters to these ejsb? The example given on the camel website is not very clear. Also I'm not using spring. Can someone please help?
To call remote EJBs you can just use Java code, and let Camel call your java code.
If you want to try the camel-ejb component, then you need to configure the component for remote EJBs which is not so easy - there is a JIRA ticket to improve this in a future release.
So I suggest to just use Java code - eg just call these remote EJBs as you would do from regular Java code without using Apache Camel.

Apache Camel: Keeping routing information completely independent of the Java Code

First of all thanks to folks who are currently involved in the development of Camel, I am grateful for all the hard work they have put in.
I am looking for some design advice.
The architecture is something like this:
I have a bunch of Java classes which when instantiated are required to connect to each other and send messages using Apache Camel. The design constraints require me to create a framework such that all routing information, producers, consumers, endpoints etc should be a part of the camel-context.xml.
An individual should have the capability to modify such a file and completely change the existing route without having the Java code available to him.(The Java code would not be provided, only the compiled Jar would be)
For example in One setup,
Bean A ->Bean B->Bean C->file->email.
in another
Bean B->Bean A->Bean C->ftp->file->email
We have tried various approached, but if the originating bean is not implemented as a Java DSL, the messages rate is very high because camel constantly invokes Bean A in the first example and Bean B in the second(they being the source).
Bean A and Bean B originate messages and are event driven. In case the required event occurs, the beans send out a notification message.
My transformations are very simple and I do not require the power of Java DSL at all.
To summarize, I have the following questions:
1) Considering the above constraints, I do I ensure all routing information, including destination addresses, everything is a part of the camel context file?
2) Are there example I can look at for keeping the routing information completely independent of the java code?
3) How do I ensure Camel does not constantly invoke the originating bean?
4) Does Camel constantly invoke just the originating bean or any bean it sends & messages to irrespective of the position of the bean in the entire messaging queue?
I have run out of options trying various ways to set this up. Any help would be appreciated.
Read about hiding the middleware on the Camel wiki pages. This allows you to let clients use an interface to send/receive messages but totally unaware of Camel (no Camel API used at all).
Even better consider buying the Camel in Action book and read chapter 14 which talks about this.
http://www.manning.com/ibsen/
Save 41% on Manning books: Camel in Action or ActiveMQ in Action. Use code s2941. Expires 6th oct. http://www.manning.com/ibsen/
If you consider using ServiceMix of FuseESB, you might want to separate your routes in two parts.
First part would be the Event-driver bean that trigger the route. It could push messages to the ServiceNMR (see http://camel.apache.org/nmr.html).
The other part would be left to the framework users, using Spring DSL. It would just listen to message on the NMR (push by the other route) and do whatever they want with it.
Of course endpoint definition could be propertized using servicemix configuration service (see http://camel.apache.org/properties.html#Properties-UsingBlueprintpropertyplaceholderwithCamelroutes)

Resources