I want to set up my browser similar to the example shown in Spring's example that I bet some of you are familiar with that uses websockets along with stomp to create an interactive webapp. It's here: https://spring.io/guides/gs/messaging-stomp-websocket/
However, instead of the input going directly through messaging and back to the client and outputting "Hello" + name on the page, I need it to go through a series of queues and applications routing it using camel. I can't quite figure out how to connect my system of queues with the browser.
Here is my camel Context currently that starts in a queue named "testQSource". I would like to have the input messages given to the browser by the client sent to testQSource using Stomp and then have it continue on it's way.
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="jms:queue:testQSource"/>
<to uri="myBean"/>
<log message="Routing message from testQSource to testQDestination queue with data ${body}"/>
<to uri="jms:queue:testQDestination"/>
<to uri="finalBean"/>
<log message="message: ${body}"/>
</route>
</camelContext>
<camel:camelContext id="camel-client">
<camel:template id="camelTemplate" />
</camel:camelContext>
<bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
Here is my main class:
public class TestCamelSpring {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("camelspring.xml");
ProducerTemplate camelTemplate = context.getBean("camelTemplate", ProducerTemplate.class);
System.out.println("Message Sending started");
camelTemplate.sendBody("jms:queue:testQSource", "Sample Message");
System.out.println("Message sent");
}
}
Can I just slip the SpringApplication.run into my main function and edit the camelContext or is there something more I need to do? I'm not sure how to send the client input to the testQSource.
I know it is a mouthful, but I've been struggling with this for a while and have hit a bit of a wall. Any and all help would be greatly appreciated!
If you don't want to write the any java code to send the message to message queue, you may consider to setup client camel context by using a timer to trigger the message sending, then you just need to start the Spring context.
<camel:camelContext id="camel-client">
<camel:from uri="timer://foo?fixedRate=true&period=60000" />
<camel:setBody>
<simple>Simple Message!</simple>
</camel:setBody>
<camel:to uri="jms:queue:testQSource" />
</camel:camelContext>
Related
I was able to create a Synchronous service bus using the JMS, but I was not able to turn it to Asynchronous.
I'm trying to post a request to a service asynchronously, so if the service is down, I want the JMS queue keeps the request message and when the service starts up it delivers the message to the service and get back the response.
here is my code
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route >
<from id ="server" uri="jetty:http://0.0.0.0:9500/rsb/toService?matchOnUriPrefix=true&enableMultipartFilter=false&disableStreamCache=false"/>
<wireTap uri="log:test?level=INFO"><body><simple>Enter JMS test route and sending message to queue</simple></body></wireTap>
<!--<to uri="direct:queue"/>-->
<to uri="jms://testqueue?requestTimeout=360000&replyTo=bar&replyToDeliveryPersistent=true&exchangePattern=InOut&acknowledgementModeName=AUTO_ACKNOWLEDGE"/>
</route>
<route id="testqueuelistener" streamCache="true">
<from uri="jms://testqueue?replyToDeliveryPersistent=true&replyTo=bar" />
<wireTap uri="log:test?level=INFO"><body><simple>Message recieved from queue: ${body}</simple></body></wireTap>
<to uri="http://localhost:18402/Home/addUser?bridgeEndpoint=true&throwExceptionOnFailure=false"/>
<to uri="jms:service"/>
</route>
<route >
<from uri="jms:service"/>
<transform>
<simple>${body}</simple>
</transform>
</route>
</camelContext>
The issue is that you are accessing the JMS queue without using a transaction - so as soon as you get the message, it's gone from the queue. You need to use a transaction and only commit (or rollback) the message consumption after you've finished processing it.
The relevant Enterprise Integration Pattern is the transactional client. The JMS component documentation also provides some information about transaction. Finally, chapter 9 of Camel in Action (chapter 12 for the second edition) is dedicated to transactions (and I can't recommend it enough!).
You need to:
Obtain a JMS transaction manager (which transaction manager you use may depend on your specific use case)
Configure the Camel JMS component to use the transaction manager
Use a transaction policy to configure the transactional behavior of your route (or just mark the route as transacted, and use the default policy)
The configuration can look something like:
<!-- Import JMS connection factory -->
<osgi:reference id="jmsConnectionPool" interface="javax.jms.ConnectionFactory" />
<!-- We create a Spring JmsTransactionManager (our transaction manager could also be an
imported OSGi service, like we do for the connection factory; for example an XA transaction
manager) -->
<bean id="jmsTxManager" class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="jmsConnectionPool"/>
</bean>
<!-- We configure the JMS component to use the transaction manager-->
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsConnectionPool" />
<property name="transacted" value="true"/>
<property name="transactionManager" ref="jmsTxManager"/>
</bean>
<!-- Here's an example of a transaction policy -->
<bean id="requiresNew" class="org.apache.camel.spring.spi.SpringTransactionPolicy">
<property name="transactionManager" ref="jtaTransactionManager"/>
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRES_NEW"/>
</bean>
Here's a transacted route:
<route id="myRoute">
<from uri="jms://..." />
<transacted/>
...
</route>
And a route can use a specific transaction policy if we want:
<route id="myRoute">
<from uri="jms://..." />
<transacted ref="requiresNew" />
...
</route>
We are trying to implement a durable subscriber using Spring JMS. Given below is how I've configured the durable subscribers. We are using Jackson message coverter, to convert incoming JSON to java object.
As per my understanding, if we mention destination-type="durableTopic" and acknowledge="transacted" in the jms:listener-container, message re-delivery would happen if exceptions are thrown while processing message in subscriber. However, for us, the message re-delivery is not happening if we encounter exceptions on our subscriber side. I've also given the java code snippet below.
We want to save the message into database. So, we tried a scenario where database is not started. So, here, the exception com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up is thrown, but message re-delivery is not happening after this, whereas, we want the message to be redelivered (2-3 retries at least) for this scenario.
Also, I tried this same configuration and code inside a simple Spring MVC application and there, the messages are getting re-delivered whenever exceptions occur in app. So, not able to understand what is going wrong in this case. Could anybody help us here, identify what is the problem with configuration or code?
Configuration in root-context.xml
<bean id="amqConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<constructor-arg index="0" value="tcp://localhost:61616" />
</bean>
<bean id="messageConverter" class="org.springframework.jms.support.converter.MappingJackson2MessageConverter">
<property name="typeIdPropertyName" value="__type" />
</bean>
<jms:listener-container connection-factory="amqConnectionFactory" destination-type="durableTopic" message-converter="messageConverter" acknowledge="transacted" client-id="svcOrdersSubscriber">
<jms:listener destination="topicOrders" ref="ordersSubscriber" method="receive" subscription="ordersSubscription" />
</jms:listener-container>
<jms:listener-container connection-factory="amqConnectionFactory" destination-type="durableTopic" message-converter="messageConverter" acknowledge="transacted" client-id="svcResultsSubscriber">
<jms:listener destination="topicResults" ref="resultsSubscriber" method="receive" subscription="resultsSubscription" />
</jms:listener-container>
Java code
#Component("ordersSubscriber")
public class OrdersSubscriber {
#Autowired
OrderService orderService;
public void receive(Order order) {
orderService.saveOrders(order);
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
}
The problem got resolved. I was using simple ActiveMQConnectionFactory in my MVC app, and here we were using ActiveMQXAConnectionFactory, but I think since the container was not supporting XA, transactions were not happening. Now, we switched to simple ActiveMQConnectionFactory, and things are working fine.
I have CXF endpoint. I have dedicated route defined for each operation and routing the request to appropriate routes using header.operation name with reciepient list.
For couple operations(routes), I have post request to JMS endpoint which gets processed by another application and response is recieved in another queue. I have to read response message and transform the message. My requesting thread(webservice call) would be waiting for the transformed message.
Currently after posting request, currently I have written my own processor which use spring jms template to read message. I came across few examples such as split routes but not sure how it will work for overall synchronous communication which has in between JMS communication.
You can find a JMX Request/Reply example here:
<bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>
</bean>
<bean id="setResponseProcessor" class="org.apache.camel.itest.jetty.SetResponseProcessor"/>
<camelContext xmlns="http://camel.apache.org/schema/spring" trace="true">
<route>
<from uri="cxf://serverBean"/>
<to uri="jms:responseQueue"/>
</route>
<route>
<from uri="jms:responseQueue"/>
<process ref="setResponseProcessor"/>
</route>
</camelContext>
I'm trying to create an application that gets information from a browser and drops it in a queue. That data is then picked up from the queue and sent through an application for security. The security app should drop it in a different queue when it is done to be picked up by a separate action application.
Could anyone help me along with the routing? Basically, the route I'm looking for is:
Browser/UI -> Qnonsecure -> security app -> QSecure -> action app
What I understand now is the following:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="jms:queue:QnonSecure"/>
<to uri="jms:queue:QSecure"/>
</route>
</camelContext>
How Can I change this to route to and from applications.
How do I send the input from the browser into QnonSecure? Also, where in my code do I call the security app between the QnonSecure and QSecure?
There is more than one possible solution. Take the following route as a starting point:
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="restlet:http://localhost:8081/myApp?restletMethod=post"/>
<to uri="jms:queue:QnonSecure" pattern="InOut" />
<enrich uri="direct:securityApp"/>
<choice>
<when>
<simple>${header.myHeader} == "SECURE"</simple>
<to uri="jms:queue:QSecure" pattern="InOut" />
<to uri="direct:actionApp" />
</when>
<otherwise>
<!-- handle non valid requests -->
</otherwise>
</choice>
</route>
</camelContext>
Steps:
The browser sends a POST request to the Camel restlet component. This could be done via JavaScript, a link and/or just a ordinary submit button.
The body is sent to jms:queue:QnonSecure. As we use the InOut pattern, this is done in a synchronous manner and the response is fetched.
The response of jms:queue:QnonSecure is sent to direct:securityApp where the credentials are tested. If they are correct, the header myHeader is set to SECURE (or any other value).
In the choice statement, myHeader is tested. In the secure case, jms:queue:QSecure and finally direct:actionApp is invoked.
After trying to activate priority with activemq, I was told to try using camel (see here). But I can't get it working, and I'm not even sure how it should work.
I've added the following code, in my spring configuration:
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="jms:queue:myqueue" />
<resequence>
<batch-config batchSize="200" batchTimeout="3000" allowDuplicates="true" reverse="true"/>
<header>JMSPriority</header>
<to uri="mock:result"/>
</resequence>
</route>
</camelContext>
<bean id="jmsConfig" class="org.apache.camel.component.activemq.ActiveMQConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="transacted" value="false"/>
<property name="concurrentConsumers" value="10"/>
</bean>
<bean id="activemq" class="org.apache.camel.component.activemq.ActiveMQComponent">
<property name="configuration" ref="jmsConfig"/>
</bean>
But this configuration doesn't work (nothing is ordered), and I have a few questions:
What does mock:result mean? I couldn't find it in the documentation.
How is camel supposed to re-order the queue, is it done after the messages were created, or when a message is added?
Can it be independent from the spring activemq basic configuration? (I use here the camel ActiveMQComponent)
First, a mock endpoint is for unit testing. You can use it to validate that the expected messages were received:
MockEndpoint resultEndpoint = context.resolveEndpoint("mock:result", MockEndpoint.class);
resultEndpoint.expectedMessageCount(3);
resultEndpoint.expectedBodiesReceived("firstMessageBody", "secondMessageBody", "thirdMessageBody");
resultEndpoint.message(0).header("foo").isEqualTo("bar");
Next, the resequencer is designed to order messages based on some attribute (the header "JMSPriority" in your case) and will perform this over all messages that flow through it over a given timeout period or batch size (by default, the batch size is 100 and the timeout is 1000 ms).
Long story short, you can use the resequencer to order messages (in batches) before they are sent to the queue, in between queues or in between a queue and a consumer...