How to send message to WebSphere MQ using Apche Camel and Receive message from MQ Queue - spring

I didnt see enough examples on web using apache camel with websphere mq to send and receive messages. I had a example code but I got struck at the middle of code. could any one help on this..
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.Producer;
import org.apache.camel.util.IOHelper;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Client that uses the Mesage Endpoint
* pattern to easily exchange messages with the Server.
* <p/>
* Notice this very same API can use for all components in Camel, so if we were using TCP communication instead
* of JMS messaging we could just use <code>camel.getEndpoint("mina:tcp://someserver:port")</code>.
* <p/>
* Requires that the JMS broker is running, as well as CamelServer
*/
public final class CamelClientEndpoint {
private CamelClientEndpoint() {
//Helper class
}
// START SNIPPET: e1
public static void main(final String[] args) throws Exception {
System.out.println("Notice this client requires that the CamelServer is already running!");
AbstractApplicationContext context = new ClassPathXmlApplicationContext("camel-client.xml");
CamelContext camel = context.getBean("camel-client", CamelContext.class);
// get the endpoint from the camel context
Endpoint endpoint = camel.getEndpoint("jms:queue:numbers");
// create the exchange used for the communication
// we use the in out pattern for a synchronized exchange where we expect a response
Exchange exchange = endpoint.createExchange(ExchangePattern.InOut);
// set the input on the in body
// must be correct type to match the expected type of an Integer object
exchange.getIn().setBody(11);
// to send the exchange we need an producer to do it for us
Producer producer = endpoint.createProducer();
// start the producer so it can operate
producer.start();
// let the producer process the exchange where it does all the work in this oneline of code
System.out.println("Invoking the multiply with 11");
producer.process(exchange);
// get the response from the out body and cast it to an integer
int response = exchange.getOut().getBody(Integer.class);
System.out.println("... the result is: " + response);
// stopping the JMS producer has the side effect of the "ReplyTo Queue" being properly
// closed, making this client not to try any further reads for the replies from the server
producer.stop();
// we're done so let's properly close the application context
IOHelper.close(context);
}
}
I got struck at this point of code..
exchange.getIn()
Do I have to use exchange.getOut() to send message?? and How to construct message using string and add headers to it.

Welcome to stackoverflow!
I am still not sure what exactly is the problem you are stuck at and it prevents me (and possibly others as well) in helping you resolve your roadblock.
Perhaps you need to familiarize a bit more on what camel is and how it works. Camel in Action is a great book to help you with that.
If you are unable to get a copy at this point, a preview of the first few chapters of the book is available online and it should give you much better leverage. Source code repository for chapter 2 should give you some more ideas around how to process JMS messages.
In addition to it. Please don't expect full blown solutions from StackOverflow. You may read this page on how to ask a good question

Related

JmsListener called again and again when a error happen in the method

In a spring boot application, I have a class with jms listener.
public class PaymentNotification{
#JmsListener(destination="payment")
public void receive(String payload) throws Exception{
//mapstring conversion
....
paymentEvent = billingService.insert(paymentEvent); //transactional method
//call rest...
billingService.save(paymentEvent);
//send info to jms
}
}
I saw then when a error happen, data is inserted in the database, that ok, but it's like receive method is called again and again... but queue is empty when I check on the server.
If there is an error, I don't want method is called again, Is there something for that.
The JMS Message Headers might contain additional information to help with your processing. In particular JMSRedelivered could be of some value. The Oracle doc states that "If a client receives a message with the JMSRedelivered field set, it is likely, but not guaranteed, that this message was delivered earlier but that its receipt was not acknowledged at that time."
I ran the following code to explore what was available in my configuration (Spring Boot with IBM MQ).
#JmsListener(destination="DEV.QUEUE.1")
public void receive(Message message) throws Exception{
for (Enumeration<String> e = message.getPropertyNames(); e.hasMoreElements();)
System.out.println(e.nextElement());
}
From here I could find JMSXDeliveryCount is available in JMS 2.0. If that property is not available, then you may well find something similar for your own configuration.
One strategy would be to use JMSXDeliveryCount, a vendor specific property or maybe JMSRedelivered (if suitable for your needs) as a way to check before you process the message. Typically, the message would be sent to a specific blackout queue where the redelivery count exceeds a set threshold.
Depending on the messaging provider you are using it might also be possible to configure back out queue processing as properties of the queue.

How to better correlate Spring Integration TCP Inbound and Outbound Adapters within the same application?

I currently have a Spring Integration application which is utilizing a number of TCP inbound and outbound adapter combinations for message handling. All of these adapter combinations utilize the same single MessageEndpoint for request processing and the same single MessagingGateway for response sending.
The MessageEndpoint’s final output channel is a DirectChannel that is also the DefaultRequestChannel of the MessageGateway. This DirectChannel utilizes the default RoundRobinLoadBalancingStrategy which is doing a Round Robin search for the correct Outbound Adapter to send the given response through. Of course, this round robin search does not always find the appropriate Outbound Adapter on first search and when it doesn’t it logs accordingly. Not only is this producing a large amount of unwanted logging but it also raises some performance concerns as I anticipate several hundred inbound/outbound adapter combinations existing at any given time.
I am wondering if there is a way in which I can more closely correlate the inbound and outbound adapters in a way that there is no need for the round robin processing and each response can be sent directly to the corresponding outbound adapter? Ideally, I would like this to be implemented in a way that the use of a single MessageEndpoint and single MessageGateway can be maintained.
Note: Please limit solutions to those which use the Inbound/Outbound Adapter combinations. The use of TcpInbound/TcpOutboundGateways is not possible for my implementation as I need to send multiple responses to a single request and, to my knowledge, this can only be done with the use of inbound/outbound adapters.
To add some clarity, below is a condensed version of the current implementation described. I have tried to clear out any unrelated code just to make things easier to read...
// Inbound/Outbound Adapter creation (part of a service that is used to dynamically create varying number of inbound/outbound adapter combinations)
public void configureAdapterCombination(int port) {
TcpNioServerConnectionFactory connectionFactory = new TcpNioServerConnectionFactory(port);
// Connection Factory registered with Application Context bean factory (removed for readability)...
TcpReceivingChannelAdapter inboundAdapter = new TcpReceivingChannelAdapter();
inboundAdapter.setConnectionFactory(connectionFactory);
inboundAdapter.setOutputChannel(context.getBean("sendFirstResponse", DirectChannel.class));
// Inbound Adapter registered with Application Context bean factory (removed for readability)...
TcpSendingMessageHandler outboundAdapter = new TcpSendingMessageHandler();
outboundAdapter.setConnectionFactory(connectionFactory);
// Outbound Adapter registered with Application Context bean factory (removed for readability)...
context.getBean("outboundResponse", DirectChannel.class).subscribe(outboundAdapter);
}
// Message Endpoint for processing requests
#MessageEndpoint
public class RequestProcessor {
#Autowired
private OutboundResponseGateway outboundResponseGateway;
// Direct Channel which is using Round Robin lookup
#Bean
public DirectChannel outboundResponse() {
return new DirectChannel();
}
// Removed additional, unrelated, endpoints for readability...
#ServiceActivator(inputChannel="sendFirstResponse", outputChannel="sendSecondResponse")
public Message<String> sendFirstResponse(Message<String> message) {
// Unrelated message processing/response generation excluded...
outboundResponseGateway.sendOutboundResponse("First Response", message.getHeaders().get(IpHeaders.CONNECTION_ID, String.class));
return message;
}
// Service Activator that puts second response on the request channel of the Message Gateway
#ServiceActivator(inputChannel = "sendSecondResponse", outputChannel="outboundResponse")
public Message<String> processQuery(Message<String> message) {
// Unrelated message processing/response generation excluded...
return MessageBuilder.withPayload("Second Response").copyHeaders(message.getHeaders()).build();
}
}
// Messaging Gateway for sending responses
#MessagingGateway(defaultRequestChannel="outboundResponse")
public interface OutboundResponseGateway {
public void sendOutboundResponse(#Payload String payload, #Header(IpHeaders.CONNECTION_ID) String connectionId);
}
SOLUTION:
#Artem's suggestions in the comments/answers below seem to do the trick. Just wanted to make a quick note about how I was able to add a replyChannel to each Outbound Adapter on creation.
What I did was create two maps that are being maintained by the application. The first map is populated whenever a new Inbound/Outbound adapter combination is created and it is a mapping of ConnectionFactory name to replyChannel name. The second map is a map of ConnectionId to replyChannel name and this is populated on any new TcpConnectionOpenEvent via an EventListener.
Note that every TcpConnectionOpenEvent will have a ConnectionFactoryName and ConnectionId property defined based on where/how the connection is established.
From there, whenever a new request is received I use theses maps and the 'ip_connectionId' header on the Message to add a replyChannel header to the Message. The first response is sent by manually grabbing the corresponding replyChannel (based on the value of the replyChannel header) from the application's context and sending the response on that channel. The second response is sent via Spring Integration using the replyChannel header on the message as Artem describes in his responses.
This solution was implemented as a quick proof of concept and is just something that worked for my current implementation. Including this to hopefully jumpstart other viewer's own implementations/solutions.
Well, I see now your point about round-robin. You create many similar TCP channel adapters against the same channels. In this case it is indeed hard to distinguish one flow from another because you have a little control over those channels and their subscribers.
On of the solution would be grate with Spring Integration Java DSL and its dynamic flows: https://docs.spring.io/spring-integration/reference/html/dsl.html#java-dsl-runtime-flows
So, you would concentrate only on the flows and won't worry about runtime registration. But since you are not there and you deal just with plain Java & Annotations configuration, it is much harder for you to achieve a goal. But still...
You may be know that there is something like replyChannel header. It is taken into an account when we don't have a outputChannel configured. This way you would be able to have an isolated channel for each flow and the configuration would be really the same for all the flows.
So,
I would create a new channel for each configureAdapterCombination() call.
Propagate this one into that method for replyChannel.subscribe(outboundAdapter);
Use this channel in the beginning of your particular flow to populate it into a replyChannel header.
This way your processQuery() service-activator should go without an outputChannel. It is going to be selected from the replyChannel header for a proper outbound channel adapter correlation.
You don't need a #MessagingGateway for such a scenario since we don't have a fixed defaultRequestChannel any more. In the sendFirstResponse() service method you just take a replyChannel header and send a newly created message manually. Technically it is exactly the same what you try to do with a mentioned #MessagingGateway.
For Java DSL variant I would go with a filter on the PublishSubscribeChannel to discard those messages which don't belong to the current flow. Anyway it is a different story.
Try to figure out how you can have a reply channel per flow when you configure particular configureAdapterCombination().

How can I improve the performance of the JbossFuse (v6.3) DSL route code?

APPLICATION INFO:
Code below: reads from IBM MQ queue and then posts the message to a REST service
(note: reading from the MQ queue is fast and not an issue - rather, it is the post operation performance I am having trouble improving)...
PROBLEM:
Unable to output/post more than 44-47 messages per second...
QUESTION:
How can I improve the performance of the JbossFuse (v6.3) DSL route code below?... (What techniques are available that would make it faster?)
package aaa.bbb.ccc;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.cdi.ContextName;
#ContextName("rest-dsl")
public class Netty4HttpSlowRoutes extends RouteBuilder {
public Netty4HttpSlowRoutes() {
}
private final org.apache.camel.Processor proc1 = new Processor1();
#Override
public void configure() throws Exception {
org.apache.log4j.MDC.put("app.name", "netty4HttpSlow");
System.getProperties().list(System.out);
errorHandler(defaultErrorHandler().maximumRedeliveries(3).log("***FAILED_MESSAGE***"));
from("wmq:queue:mylocalqueue")
.log("inMessage=" + (null==body()?"":body().toString()))
.to("seda:node1?concurrentConsumers=20");
from("seda:node1")
.streamCaching()
.threads(20)
.setHeader(Exchange.HTTP_METHOD, constant(org.apache.camel.component.http4.HttpMethods.POST))
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.toD("netty4-http:http://localhost:7001/MyService/myServiceThing?textline\\=true");
}
}
Just a couple of thoughts. First things first: did you measure the slowness? How much time do you spend in Camel VS how much time you spend sending the HTTP request?
If the REST service is slow there's nothing you can do in Camel. Depending on what the service does, you could try reducing the number of threads.
Try to disable streamCaching since it looks like you're not using it.
Then use a to instead of toD to invoke the service, I see that the URL is always the same. In the docs of ToD I read
By default the Simple language is used to compute the endpoint.
There may be a little overhead while parsing the URI string each time you invoke the route.

How does Spring WebSocket send message to a specific user?

I am reading the book Spring in Action 4 to work with STOMP messaging over WebSocket.
Suppose the user destination prefix is set as "/user" as below:
registry.setUserDestinationPrefix("/user");
Then client subscribes to a destination with below JavaScript code:
stomp.subscribe("/user/queue/notifications", handleNotifications);
Then on the server, the actual destination that the client subscribes to should be derived from its session, maybe like this:
/queue/notifications-user6hr83v6t --- (1)
Then I use the SimpMessagingTemplate to send message to that user:
messaging.convertAndSendToUser( username, "/queue/notifications",
new Notification("You just got mentioned!"));
Then the message will be sent to destination like this:
/user/<username>/queue/notifications ---(2)
Well, the two destinations (1) and (2) look different, how could the message ever reach the client?
The path
/user/<username>/queue/notifications
seems to be the "logical" path which is used in documentation. It is also initially created with convertAndSendToUser method. It is then translated into a technical format which is done in UserDestinationMessageHandler class in this line
UserDestinationResult result = this.destinationResolver.resolveDestination(message);
eg.
Given the subscription:
stompClient.subscribe('/user/queue/reply', function (greeting) { ...
sending a message with
stompClient.send("/app/personal", ...
and intercepting it with
#MessageMapping("/personal")
public void personalMessage(SimpMessageHeaderAccessor headerAccessor, PoCRequestMessage message) {
SimpMessageHeaderAccessor ha = SimpMessageHeaderAccessor
.create(SimpMessageType.MESSAGE);
ha.setSessionId(headerAccessor.getSessionId());
ha.setLeaveMutable(true);
PoCReplyMessage reply = new PoCReplyMessage("Personal Message" + message.getName());
simpMessagingTemplate.convertAndSendToUser(headerAccessor.getSessionId(), "/queue/reply", reply, ha.getMessageHeaders());
}
the destination will be resolved as follows:
source destination: /user/zojdn53y/queue/reply
target destination: /queue/reply-userzojdn53y
this is how the final destination name is resolved.
The target destination is the real name of the queue that is created (at least as long an external message broker is used - didn't check this for a simple in-memory broker but I assume this would be the same).
One important thing to note is that when you want to use an unauthenticated user (most often scenario when experimenting with Websockets) you need to additionally put the message headers in convertAndSendToUser method - this is well described in
Spring WebSocket #SendToSession: send message to specific session

Akka Camel - JMS messages lost - should wait for initialization of Camel?

My experimental application is quite simple, trying what can be done with Actors and Akka.
After JVM start, it creates actor system with couple of plain actors, JMS consumer (akka.camel.Consumer) and JMS producer (akka.camel.Producer). It sends couple of messages between actors and also JMS producer -> JMS server -> JMS consumer. It basically talks to itself via JMS service.
From time to time I was experiencing weird behaviour: it seemed that from time to time, first of messages which where supposed to be sent to JMS server was somehow lost. By looking at my application logs, I could see that applications is trying to send the message but it was never received by JMS server. (For each run I have to start JVM&Application again).
Akka Camel Documentation mentions that it's possible that some components may not be fully initialized at the begining: "Some Camel components can take a while to startup, and in some cases you might want to know when the endpoints are activated and ready to be used."
I tried to implement following to wait for Camel initialization
val system = ActorSystem("actor-system")
val camel = CamelExtension(system)
val jmsConsumer = system.actorOf(Props[JMSConsumer])
val activationFuture = camel.activationFutureFor(jmsConsumer)(timeout = 10 seconds, executor = system.dispatcher)
val result = Await.result(activationFuture,10 seconds)
which seems to help with this issue. (Although, when removing this step now, I'm not able to recreate this issue any more... :/).
My question is whether this is correct way to ensure all components are fully initialized?
Should I use
val future = camel.activationFutureFor(actor)(timeout = 10 seconds, executor = system.dispatcher)
Await.result(future, 10 seconds)
for each akka.camel.Producer and akka.camel.Consumer actor to be sure that everything is initialized properly?
Is that all I should to do, or something else should be done as well? Documentation is not clean on that and it's not easy to test as issue was happening only occasionaly...
You need to initialize the camel JMS component and also Producer before sending any messages.
import static java.util.concurrent.TimeUnit.SECONDS;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;
import akka.dispatch.OnComplete;
ActorRef producer = system.actorOf(new Props(SimpleProducer.class), "simpleproducer");
Timeout timeout = new Timeout(Duration.create(15, SECONDS));
Future<ActorRef> activationFuture = camel.activationFutureFor(producer,timeout, system.dispatcher());
activationFuture.onComplete(new OnComplete<ActorRef>() {
#Override
public void onComplete(Throwable arg0, ActorRef arg1)
throws Throwable {
producer.tell("First!!");
}
},system.dispatcher());

Resources