I am developing a service where I need to subscribe to JMS Queues dynamically with Camel JMS 2.17.0.
So I create a listening route at runtime using a bean:
// Bean: createCustomListenerNow
String endpoint = "jms:queue:" + queueName +
"&testConnectionOnStartup=true&exceptionListener=#listenerBuilder";
// camelContext.addRoutes uses this RouteBuilder
#Override
public void configure() throws Exception {
from(endpoint)
.id(id)
.to("seda:processReply");
}
My actual broker is Websphere MQ and I may get an exception if my account doesn't have the right permissions. Unfortunately this happens after my route has been built.
My route goes like this:
<route>
<from uri="direct:mock" />
<to uri="bean:createCustomListenerNow" /> <!-- I want to block here until subscription is OK -->
<to uri="bean:doSomethingThatRequiresTheListenerToBeProperlyRunning" />
</route>
Is there a way to "block" until the JMS component creates a new connections and successfully subscribes? I didn't manage to find a callback or a simple way to get this information.
What I do now is registering a javax.jms.ExceptionListener and waiting for a JMSException. If the exception is not thrown before a timeout I suppose the subscription did succeed.
I don't think this approach is rock-solid, any suggestion is appreciated.
I cannot block until I receive a message on the listener because it can arrive hours later and I need to finish processing the current Exchange with a reply like "Setup of listener is ok" or "Setup of listener failed".
Related
My application consists of many OSGi bundles running inside JBoss Fuse 6.2.1. Each bundle has a Camel route consuming from an ActiveMQ endpoint. Data is exchanged using VirtualTopics.
ProducerBundle publishes to topic VirtualTopic.MyTopic
ConsumerBundle A consumes from queue Consumer.A.VirtualTopic.MyTopic
ConsumerBundle B consumes from queue Consumer.B.VirtualTopic.MyTopic
ConsumerBundle C consumes from queue Consumer.C.VirtualTopic.MyTopic
At a certain moment in time Consumer C is closed, its bundle uninstalled and will never come back. Howewer, messages are still enqueued into Consumer.C.VirtualTopic.MyTopic queue.
How do I destroy such queue?
ActiveMQ pauses the Producer when the queue fills up, and I cannot set a small time to live on the message as other consumers may take a while to process each message. I cannot modify the VirtualTopic structure. I have full access to
ActiveMQ configuration and Camel routes.
Are there any other options to handle the situation?
<!-- producer route -->
<route id="ProducerRoute"/>
<from uri="direct:trigger"/>
<to uri="activemq:topic:VirtualTopic.MyTopic"/>
</route>
<!-- each consumer route -->
<route id="ConsumerARoute">
<from uri="activemq:Consumer.A.VirtualTopic.MyTopic"/>
<to uri="bean:myProcessor"/>
</route>
Look at the Apache ActiveMQ documentation how you can delete inactive queues/topics such as: http://activemq.apache.org/delete-inactive-destinations.html
I went for the aggressive solution: I hook into OSGi bundle lifecycle, when it is stopped I use JMX MBeanServer to destroy the now unneeded queues.
Since my bundle is managed using blueprint, I opted for a bean with a destroy method.
Here's an example implementation:
My bean
package org.darugna.osgi;
import javax.management.MBeanServer;
import javax.management.ObjectName;
public class QueueDestroyer {
private static final String[] QUEUES_TO_DESTROY = {
"Consumer.A.VirtualTopic.MyTopic"
};
private MBeanServer mBeanServer;
public void setMbeanServer(MBeanServer mBeanServer) {
this.mBeanServer = mBeanServer;
}
public void destroy() throws Exception {
ObjectName brokerName = new ObjectName("org.apache.activemq:type=Broker,brokerName=amq");
for (String queueName : QUEUES_TO_DESTROY) {
Object returnValue = mBeanServer.invoke(brokerName,
"removeQueue",
new Object[]{queueName},
new String[]{String.class.getName()});
}
}
}
Blueprint.xml
<blueprint>
<reference id="mbeanServer" interface="javax.management.MBeanServer"
availability="mandatory"/>
<bean id="queueDestroyer" class="org.darugna.osgi.QueueDestroyer"
destroy-method="destroy">
<property name="mbeanServer" ref="mbeanServer"/>
</bean>
<camelContext>
<route>
<from uri="activemq:Consumer.A.VirtualTopic.MyTopic"/>
<to uri="bean:myProcessor"/>
</route>
<camelContext>
</blueprint>
I had a similar situation, but I couldn't use the Claus's suggestion because in my broker there are other queues that have no consumer and I doesn't want to delete them.
In my case I'm running a JBoss Fuse 6.1.0 with fabric (I think that is the same with newer version of Fuse): I just removed the consumer (in my case I just removed the profile with the consumer) and after that I deleted the queue with the delete button in the hawtio console.
I am new to camel, i am trying to use camel cxf component to create a soap webservice. I started with a samples from camel in action. I have configured a route using cxf component and added a processor to process the request. I received the request in the bean i used to process the service but i cant able to send the response back to the client. Thanks in advance
This is the route i used :
<route>
<from uri="cxf:bean:orderEndpoint" />
<setExchangePattern pattern="InOut"/>
<to uri="bean:productService" />
</route>
This is the cxf endpoint i have configured,
<cxf:cxfEndpoint id="orderEndpoint"
address="/"
serviceClass="camelws.ws.ProductService"/>
This is the bean i used:
#Service("productService")
public class ProductServiceImpl {
public Product getProducts(){
System.out.println("Inside webservices method....");
Product product = new Product();
product.setName("test product");
product.setPrice("3242");
return product;
}
}
Sysout statement is printed on the console but i am getting a soap response with empty body.
below is my response when i hit http://localhost:9080// from browser:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body/>
</soap:Envelope>
You should implement a Processor, intercept and process your message using something like that :
public class MyProcessor implements Processor {
public void process(Exchange exchange) throws Exception {
...
// Set your response here
exchange.getOut().setBody(product);
}
}
Then reference your processor in your route.
Your response is what you have in your route body after your rote ends, so you must create your massege response object before route ends.
I am new to Apache Camel. I am able to send JMS message from one queue to another queue. I would like to know how to handle the exception. I learned onException, But it is not working for me.
I changed my jms queue to jms1. However, when I execute the code i get an exception.
My expectation is whenever I get exception my bean class should be invoked, but it is not.
Exception:
org.apache.camel.RuntimeCamelException:
org.apache.camel.FailedToCreateRouteException: Failed to create route
route1 at: >>> To[jms1:queue:FinalQSource] <<< in route:
Route[[From[jms:queue:testQSource]] -> [OnException[[class j...
because of Failed to resolve endpoint: jms1://queue:FinalQSource due
to: No component found with scheme: jms1
Code
<camelContext id="jmsContext" xmlns="http://camel.apache.org/schema/spring">
<onException>
<exception>org.apache.camel.RuntimeCamelException</exception>
<exception>org.apache.camel.ResolveEndpointFailedException</exception>
<!-- <handled><constant>true</constant></handled> -->
<bean ref="exceptionListener" method="orderFailed" />
</onException>
<route>
<from uri="jms:queue:testQSource" />
<to uri="jms1:queue:FinalQSource" /><!--
</route>
</camelContext>
This will not work as the exception is being thrown by camel when it tries to parse your route. The onException block will only catch exceptions that are thrown during execution of your route.
To test exception handling use the proper camel testing guide - http://camel.apache.org/testing.html
I would recommend mocking one of your endpoints to return an exception, example here - https://github.com/christian-posta/camel-sandbox/blob/master/one-off/src/test/java/posta/TestMockExceptions.java
MockEndpoint mockException = MockEndpoint.resolve(context, "mock:exception");
mockException.whenAnyExchangeReceived(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("i got here...");
throw new RuntimeException("fail!");
}
});
I want to use Camel to take a message from ActiveMQ and then, based on the message contents (a protobuf), send one or more messages to Twitter. I've written a bean that is called from within a route and which uses injection to send multiple messages to a "direct:xyz" endpoint.
However, Camel is complaining at runtime that:
2012-11-16 09:56:33,376 | WARN | ication.twitter] | DirectProducer | 160 - org.apache.camel.camel-core - 2.10.2 | No consumers available on endpoint: Endpoint[direct://twitter] to process: Exchange[Message: hello world]
If I instead inject directly to the Twitter endpoint from within the bean, it works fine. However, in order to ease testing, simplify configuration etc, I'd like to keep the actual Twitter config separate, hence wanting to send to a separate route.
The camel context config looks like:-
<camelContext id="NotificationTwitter"
trace="false" xmlns="http://camel.apache.org/schema/blueprint">
<dataFormats>
<protobuf id="notificationProto" instanceClass="org.abc.schemas.protobuf.NotificationDef$NotificationMsg" />
</dataFormats>
<route id="TwitterPreparation">
<from uri="activemq:notification.twitter" />
<unmarshal ref="notificationProto" />
<log logName="abc" loggingLevel="INFO"
message="Twitter request received: ${body}" />
<bean ref="NotificationTweeter" method="createTweets" />
</route>
<route id="Twitter">
<from uri="direct:twitter" />
<log logName="abc" loggingLevel="INFO"
message="Tweeting: ${body}" />
<to uri="twitter://timeline/user?consumerKey=itsasecret&consumerSecret=itsasecret&accessToken=itsasecret&accessTokenSecret=itsasecret" />
</route>
</camelContext>
The bean looks like:-
public class NotificationTweeter {
#EndpointInject(uri = "direct:twitter")
private ProducerTemplate producerTemplate;
public void createTweets(NotificationMsg notification) {
String tweet = notification.getMessageDetail().getTitle();
try {
// only send tweets where the notification message contains the Twitter mechanism
for (MechanismMsg mechanism : notification.getMechanismList()) {
if (mechanism.getType() == MechanismTypeEnum.TWITTER) {
// Cycle round the recipients
for (RecipientMsg recipient : mechanism.getRecipientList()) {
tweet = "#" + recipient.getIdentifier() + " " + tweet;
producerTemplate.sendBody(tweet);
}
// TODO exceptions if no recipients found, etc
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I've had this problem in other routes (it's certainly not related to the Twitter feature) but have just worked around it. This time, however, I'd like to actually understand what the issue is! Any help gratefully received, thanks.
According to your setup, it might also depend on the CamelContext you have picked up. I got the same error message because I was sending messages on a route that existed in another CamelContext than the one I actually was using.
(Although the previous answer was already accepted, this might be the working solution for other people searching for that error message.)
It sounds like a problem with the startup ordering of your routes. See more detail here http://camel.apache.org/configuring-route-startup-ordering-and-autostartup.html
You can configure the "direct" route to start before the other route, then that issue should be resolved.
For others coming here, this error can also be caused by an OSGI error for a dependency that has not been deployed.
A bit late to the party but this error happened to me when I had two separate blueprint files, one for normal running and one for test. In my test I was referring to the test blueprint but noticed that the normal one was also automatically started which caused errors.
In the documentation http://camel.apache.org/blueprint-testing.html it says you can disable certain bundles from starting up. That helped me in my case.
This can also be caused by having a . in the route name. Replace my.Route.Name with myRouteName fixed the issue for me.
We are trying with ServiceA calling ServiceB as soon as bundle loads during the SericeMix startup. Service2 having activemq endpoints we need to invoke a method of that particular service. I tried by spring init-method attribute in the bean tag which helps in auto trigger a method in ServiceA in that method I am calling the serviceB’s method. I am getting Exception like No Consumer available for the endpoint. I assume that as soon as the Service1 is up it is not getting the instance of the service2 which needs to get initialized using #Produce annotation activemq endpoint. The same services work fine in the other normal scenarios.
Exception:
Caused by: org.apache.camel.CamelExchangeException: No consumers available on endpoint: Endpoint[direct://ServiceB]. Exchange[Message: BeanInvocation public java.lang.String java.lang.Object.toString() with null]]
at org.apache.camel.component.direct.DirectProducer.process(DirectProducer.java:46)
at org.apache.camel.component.bean.CamelInvocationHandler.invoke(CamelInvocationHandler.java:64)
... 35 more
I am copy pasting the Code Block for your reference.
public class ServiceA{
#Produce(uri = "direct:ServiceB") //Active MQ endpoint
private ServiceB serviceB;
public void start()
{
Object obj = serviceB.getData(); }
. . .
.....
}
}
**bundle-context.xml**
//Changes for method to auto trigger during spring bean load
<bean id="serviceA" class="com.test.serviceA" init-method="start">
</bean>
**bundle-context-camel.xml**
<osgi:camelContext id="ServiceA"
xmlns="http://camel.apache.org/schema/spring">
<template id="producerTemplate" />
<!-- These routes are outbound to other services -->
<route>
<from uri="ServiceB" />
<bean ref="enrichOutboundExchangeRef" />
<to uri="activemq:ServiceB?transferException=true" />
</route>
..............
</osgi:camelContext>
Or is their anyother way if i need to achieve this requirement? where i can load a service(consumes other services) automatically during the servicemix bootup.
You can use seda instead of direct as it's queue based and thus consumers can come and go.
Also try using springs depends-on attribute
<bean id="serviceA" depends-on="myCamel" .../>
<osgi:camelContext id="myCamel" ...>
We tried the above approach but we still we are getting exceptions, we resolved it by adding a listener to the onCamelContextStarted() during th init of the serviceA.
Thanks
Ravi
If you are getting "no consumers available on endpoint", it means that messages are being routed to an endpoint that hasn't been initialized. I recommend decoupling the services using a JMS queue between them. That way serviceA can put messages in the queue (independent of serviceB's availability) and serviceB can then act as a polling consumer against that queue whenever its ready.