Declare response queue with specific name for Request/Response pattern in EasyNetQ - easynetq

When using the Request/Response messaging pattern within EasyNetQ I need to declare a private response queue (with a specific name) before sending the message on the request queue?
I presume the framework declares the response queue in the background but how can I give this response queue a specific name?
I don't see any information on this within the documentation at https://github.com/EasyNetQ/EasyNetQ/wiki/Request-Response

This is the default implementation of the naming conventions:
https://github.com/EasyNetQ/EasyNetQ/blob/develop/Source/EasyNetQ/Conventions.cs
So perhaps you can try something like this:
bus.Advanced.Conventions.RpcReturnQueueNamingConvention = () => "MyReturnQueue";

In the lastest EasyNetQ ,bus.Advanced.Conventions.RpcReturnQueueNamingConvention is readonly, can't be set
Maybe you can set queue name when using the RPC method like
bus.Rpc.Respond<RequestMsg, RepsonseMsg>(request => {//...},x=>x.WithQueueName("your queue name"));
or
var msg = bus.Rpc.Request<RequestMsg, RepsonseMsg>(request, x => x.WithQueueName("your queue name"));

Related

How to split a message do some extra processing on one of them and aggregate them back

I need to configure some camel routes based on some configuration files.
All configured routes will need to split a message into one or two sub messages then do some JMS integration work on the first one and then aggregate together the JMS reply with the optional second message. In a simplified picture it will look like below:
message -- > split --> message 1 --> JMS request/reply --> aggregate --> more processing
\--> message 2 /
The aggregation will be done on completion size which I am able to know upfront if it is going to be 1 or 2 depending of the route meta data. When the second message is present no other processing is needed before being merged back with the JMS reply.
Si in short I need a split followed by a routing followed by an aggregation which is quite a common pattern. The only particularity is is that in case the second split message is present I don't need to do anything on it before aggregating it back.
In java DSL it will looks something like this:
from("direct:abc")
// The splitter below will set the JmsIntegration flag
.split().method(MySplitter.class, "split")
.choice()
.when(header("JmsIntegration"))
.inOut("jms:someQueue"))
.otherwise()
// what should I have on here?
.to(???)
.end()
.aggregate(...)to(...);
So my questions would be:
What should I put on the otherwise branch?
What I need in fact is an if: if the split message needs JMS go to JMS and then move to aggregator if it is not just go straight to the aggregator. I am considering creating a dummy processor which will actually do nothing but this seems to me a naive approach.
Am I on a wrong path. If so what would be the alternative
Initially I was thinking about a message enricher but I would not like to sent the original message to the JMS
I also considered putting my aggregation strategy inside my splitter but again I could not put it all together.
Based off your post it looks like you are trying to have the return of your enrichment merge with the original message, but you want to send a custom message to the jms endpoint. I would recommend storing your original message in either a bean or a cache or something of the sort, leveraging all of your conversions with camel and then have your aggregation strategy leverage your storage to return your desired format.
from("direct:abc")
.split().method(MySplitter.class, "split")
.choice()
.when(header("JmsIntegration"))
.beanRef("MyStorageBean", "storeOriginal")
.convertBodyTo(MyJmsFormat.class)
//This aggregation strategy could have a reference
//to your storage bean and retrieve the instance
.enrich("jms:someQueue", myCustomAggreationStrategyInstance)
.otherwise()
.end()
.aggregate(...)
.to("direct:continueProcessing");
Option #2: Based off of your comment saying you needed the "original message that the direct:abc endpoint received this can be simplified a lot. In this example we can use camel's existing Original message store to retrieve the message that was passed into direct:abc. If Your message after the split has a JmsIntegration header we will convert the body to the desired format for the jms call, leverage the enrich statement to make the jms call and a custom aggregator that gives you access to the message used to call the jms endpoint, the message that came back, and the original message direct:abc has. If your flow does not have a JmsIntegration header the message will go to the Otherwise statement in your route which does no additional processing before ending the choice statement and then the spit messages are aggregated back together with whatever custom strategy you need.
from("direct:abc")
.split().method(MySplitter.class, "split")
.choice()
.when(header("JmsIntegration"))
.convertBodyTo(MyJmsFormat.class)
//See aggregationStrategy sample below
.enrich("jms:someQueue", myAggStrat)
.otherwise()
//Non JmsIntegration header messages come here,
//but receive no work and are passed on.
.end()
.aggregate(...)
.to("direct:continueProcessing");
//Your Custom Aggregator
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
//This logic will retrieve the original message passed into direct:abc
Message originalMessage =(Message)exchange.getUnitOfWork().getOriginalInMessage();
//TODO logic for manipulating your exchanges and returning the desired result
}
You said you considered using Enricher, but you don't want to send raw message. You can resolve this neatly by using a pre-JMS route:
from("direct:abc")
.enrich("direct:sendToJms", new MyAggregation());
.to("direct:continue");
from("direct:sendToJms")
// do marshalling or conversion here as necessary
.convertBodyTo(MyJmsRequest.class)
.to("jms:someQueue");
public class MyAggregation implements AggregationStrategy {
public Exchange aggregate(Exchange original, Exchange resource) {
MyBody originalBody = original.getIn().getBody(MyBody.class);
MyJmsResponse resourceResponse = resource.getIn().getBody(MyJmsResponse.class);
Object mergeResult = ... // combine original body and resource response
original.getIn().setBody(mergeResult);
return original;
}
}
Splitter automatically aggregates split exchanges back together. However, default (since 2.3) aggregation strategy is to return the original exchange. You can easily override the default strategy with your own by specifying it directly on the Splitter. Furthermore, if you don't have an alternative flow for your Choice, then it's much easier to use Filter. Example:
from("direct:abc")
.split().method(MySplitter.class, "split").aggregationStrategy(new MyStrategy())
.filter(header("JmsIntegration"))
.inOut("jms:someQueue"))
.end()
.end()
.to(...);
You still need to implement MyStrategy to combine the two messages.

Getting a users mailbox current history Id

I'd like to start syncing a users mailbox going forward so I need the most recent historyId of the users mailbox. There doesn't seem to be a way to get this with one API call.
The gmail.users.history.list endpoint contains a historyId which seems to be what I need, from the docs:
historyId unsigned long The ID of the mailbox's current history record.
However to get a valid response from this endpoint you must provide a startHistoryId as a parameter.
The only alternative I see is to make a request to list the users messages, get the most recent history id from that, then make a request to gmail.users.history.list providing that historyid to get the most recent one.
Other ideas?
Did you check out https://developers.google.com/gmail/api/guides/sync ?
Depending on what your use-case is, to avoid races between your current state and when you start to forward sync, you'll need to provide an appropriate historyId. If there were a "get current history ID" then anything between your previous state and when you got those results would be lost. If you don't have any particular existing state (e.g. only want to get updates and don't care about anything before that) then you can use any historyId returned (e.g. on a message or thread) as you mention.
Small example for C# users (mentioned in comments by #EricDeFriez).
Nuget package Google.Apis.Gmail.v1 must be installed. See also quickstart for .NET developers.
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
var req = service.Users.GetProfile("me");
req.Fields = "historyId";
var res = req.Execute();
Console.WriteLine("HistoryId: " + res.HistoryId);
This answer is related to the Java Gmail API Client Library using a service account.
I found that the gmail.users.getprofile() will not work as the object that it returns is of type Class Gmail.Users.GetProfile which does not have an interface to getting a historyId.
com.google.api.services.gmail.model.Profile actually has a getHistoryId() function, but calling service.users().getProfile() will return a Class Gmail.Users.GetProfileobject instead.
To get around this, I use the history.list() function which will always return the latest historyId as part of its response.
Gmail service = createGmailService(userId); //Authenticate
BigInteger startHistoryId = BigInteger.valueOf(historyId);
ListHistoryResponse response = service.users().history().list("me")
.setStartHistoryId(startHistoryId).setMaxResults(Long.valueOf(1)).execute();
I set the max number of results to be 1 to limit the unnecessary data that I get returned back and I will receive a payload that looks like:
{"history":[{"id":"XXX","messages":[{"id":"XXX","threadId":"XXX"}]}],"historyId":"123456","nextPageToken":"XXX"}
The historyId (123456) will be the current historyId of the user. You can grab that historyId using response.getHistoryId()
You can also see that the latest historyId is given in the response if you use the API tester for Users.history: list
https://developers.google.com/gmail/api/v1/reference/users/history/list

How to take param values from Task Queue url.?

Queue queue = QueueFactory.getDefaultQueue();
queue.add(("/worker").param("key", "ABC"));
how to take key value .? using below code or any other approach.
request.getParameter("key");
Absolutely. The /worker endpoint is configured in your web.xml as a Servlet. The request object will be passed to your Servlet method and you can use the standard methods like the one you have specified i.e. getParameter(...)

Can I use one servlet to receive xmpp messages, and another to send them in App Engine?

Does the required servlet URL mapping (/_ah/xmpp/message/chat/) for the xmpp service restrict me to using only that servlet for both sending and receiving xmpp messages?
My application receives messages, adds them to an 'inQueue' for processing, and once processed, the results are added to an 'outQueue'. Ideally I'd like the worker servlet assigned to the outQueue to send the response.
I am using push queues and the servlets are obviously invoked by an HTTP POST request...
When I try to use the xmpp service to send the message from my outQueue worker ( which is obviously not mapped to /_ah/xmpp/message/chat/ ), it expectedly does nothing.
In the servlet mapped to /_ah/xmpp/message/chat/:
//Generate a Memcache key
String key = generateMemcacheKey(message);
//Serialize the message as xml using getStanza (for now, just put in the senderJID as string)
String senderJIDString = message.getFromJid().getId();
//Cache the message in Memcache
cache.put(key, senderJIDString);
//Enqueue a task for the message
private Queue queue = QueueFactory.getQueue("inQueue");
queue.add(TaskOptions.Builder.withUrl("/xmppParser").param("memcacheKey", key));
In xmppParser servlet doPost method:
//Extract message from memcache
String key = req.getParameter("memcacheKey");
String recipientJIDString = (String)cache.get(key);
//Todo Detect language
//Todo Parse Message into an Imperative accordingly (For now, just reply hello)
//Todo Handle Session status
//Put Imperative into memcache (For now, just put recipientID in)
cache.put(key, recipientJIDString);
//Enqueue appropriately
Queue queue = QueueFactory.getQueue("outQueue");
queue.add(TaskOptions.Builder.withUrl("/responseServlet").param("memcacheKey", key
));
Now I would like this responseServlet to send the reply:
//Get a handler on the memcache
MemcacheService cache = MemcacheServiceFactory.getMemcacheService();
//Extract the key to the response from the request
String key = req.getParameter("memcacheKey");
//Extract the message from the memcache ( For now it's just the JID of the sender)
String recipientJIDString = (String)cache.get(key);
//Parse it into a message (For now just make a simple "I hear you" message)
JID recipientJID = new JID(recipientJIDString);
Message response = new MessageBuilder()
.withMessageType(MessageType.NORMAL)
.withRecipientJids(recipientJID)
.withBody("I hear you")
.build();
//Send the message
XMPPService xmpp = XMPPServiceFactory.getXMPPService();
xmpp.sendMessage(response);
The servlet mappings are all kosher, and the xmpp service is unable to send the message. It raises a null pointer exception, but the memcache viewer confirms the recipientJID is kosher as well... I'm guessing only the servlet mapped to /_ah/xmpp/message/chat/ is able to send messages, or am I wrong?
I am forced to test on the live site itself as XMPP does not seem to be supported by the development server, adding the possibility of my having overlooked some production environment configuration...
Much obliged!
ram

Using DispositionNotification with Javamail

I am working with a set of specialized email servers that are configured to return Message Disposition Notifications (MDNs) upon successful receipt of the message. I have developed a Javamail client that is used to send messages to one of these servers and retrieve returned MDNs from the user's POP3 INBOX folder.
How do I go about getting at the disposition notification body part from the returned MimeMessage I retrieve from the user's inbox? I've found the com.sun.mail.dsn.DispositionNotification class but haven't seen an example of how to correctly create an instance of a DispositionNotification using the constructor:
DispositionNotification(InputStream)
Should I be able get the InputStream from a MimeMessage and use it to create the DispositionNotification, like so?
Message[] msgs = getInboxMessages();
DispositionNotification dn = new DispositionNotification(msgs[0].getInputStream();
Or is there some other way this should be done?
The getContent method on such a message should return a MultipartReport object (a special subclass of the usual MimeMultipart object), from which you can access the parts of the report. The MultipartReport.getReport() method will return either a DeliveryStatus or DispositionNotification object, depending on the type of the report.

Resources