Spring AMQP - MessageListenerAdapter - pass additional arguments - rabbitmq

To create a SimpleMessageListenerContainer, I do something like this.
SimpleMessageConsumer simpleMessageConsumer = new SimpleMessageConsumer();
MessageListenerAdapter adapter =
new CustomMessageListenerAdapater(simpleMessageConsumer);
adapter.setDefaultListenerMethod("consume");
adapter.setMessageConverter(new SimpleMessageConverter());
SimpleMessageListenerContainer
container =
new SimpleMessageListenerContainer(connectionFactory);
container.setMessageListener(adapter);
My SimpleMessageConsumer
public void consume(String message){
log.info(message);
}
I noticed in the spring-amqp-refrence that the "annotated
listener endpoint infrastructure" allows you to conveniently pass additional Message properties into your consumer like so :
#RabbitListener(queues = "myQueue")
public void processOrder(Order order, #Header("order_type") String orderType) {
...
}
Can that be done using consumer creation approach I mention above? I want to access to some of the headers of the Message object. I know that I can make my consumer implement the MessageListener or the ChannelAwareMessageListener and have access to the entire Message object. However, I dont want the whole Message object, since I like the convenience of using the ContentTypeDelegatingMessageConverter with the Jackson2JsonMessageConverter to do conversion to my desired type(in my real app), before my consumer delegated method is triggered.

public class CustomMessageListenerAdapter extends MessageListenerAdapter {
public CustomMessageListenerAdapter(Object delegate) {
super(delegate);
}
#Override
protected Object invokeListenerMethod(String methodName, Object[] arguments,
Message originalMessage) throws Exception {
Object[] modifiedArguments = new Object[arguments.length+1];
System.arraycopy(arguments, 0, modifiedArguments,
0, arguments.length);
//add the original message with headers
modifiedArguments[arguments.length] = originalMessage;
return super.invokeListenerMethod(methodName, modifiedArguments, originalMessage);
}
}
and my Message consumer now has an additional argument - the original message
public class SimpleMessageConsumer {
private static final Logger log = LoggerFactory.getLogger(SimpleMessageConsumer.class);
public void consume(String messageConverted, Message originalMessage){
log.info(originalMessage.toString());
}
}
My Bean Configuration looks something like this:
SimpleMessageConsumer simpleMessageConsumer = new SimpleMessageConsumer();
MessageListenerAdapter adapter =
new CustomMessageListenerAdapter(simpleMessageConsumer);
adapter.setDefaultListenerMethod("consume");
adapter.setMessageConverter(messageConverter());
//container
SimpleMessageListenerContainer
container =
new SimpleMessageListenerContainer(connectionFactory);
container.setMessageListener(adapter);

You need to use a MessagingMessageConverter with the payloadConverter as the mentioned Jackson2JsonMessageConverter and then in your CustomMessageListenerAdapater you override there a:
/**
* Build an array of arguments to be passed into the target listener method. Allows for multiple method arguments to
* be built from a single message object.
* <p>
* The default implementation builds an array with the given message object as sole element. This means that the
* extracted message will always be passed into a <i>single</i> method argument, even if it is an array, with the
* target method having a corresponding single argument of the array's type declared.
* <p>
* This can be overridden to treat special message content such as arrays differently, for example passing in each
* element of the message array as distinct method argument.
* #param extractedMessage the content of the message
* #return the array of arguments to be passed into the listener method (each element of the array corresponding to
* a distinct method argument)
*/
protected Object[] buildListenerArguments(Object extractedMessage) {
casting that extractedMessage to the Message<?> and extract desired headers if that.

Related

In my service integration, I found a NullPointerException when instantiating class of another service

I cannot seem to figure out in my service integration why my instantiation of the class of another service returns null even when I can see the class in the jar in the library.
Please see my code here:
public class OAuthFacadeClientImpl implements OAuthFacadeClient {
/**
* oauth facade
*/
private OAuthFacade supergwOauthFacade;
/** LOGGER */
private static final Logger LOGGER = LoggerFactory.getLogger(OAuthFacadeClientImpl.class);
#Override
public AccessTokenRevokeResult revokeToken(String merchantId, String userId,
String scope) {
AccessTokenRevokeRequest revokeRequest = new AccessTokenRevokeRequest();
revokeRequest.setAccessToken(userId);
revokeRequest.setClientId(merchantId);
revokeRequest.setExtRequestId(scope);
LogUtil.info(LOGGER, "revokeRequest value = " + revokeRequest);
AccessTokenRevokeResult revokeResult = supergwOauthFacade
.revokeToken(revokeRequest.getClientId(), revokeRequest.getAccessToken(),
revokeRequest.getExtRequestId());
SALResultChecker.checkAndAssert(revokeResult);
return revokeResult;
}
/**
* Setter method for property <tt>oAuthFacade</tt>.
*
* #param oAuthFacade value to be assigned to property miniAppQueryFacade
*/
public void setOAuthFacade(OAuthFacade oAuthFacade) {
this.supergwOauthFacade = oAuthFacade;
}
}
Breakpoints of my code upon debugging
You basically need to instantiate an object of type OAuthFacade prior to using this method revokeToken(...) and feed that reference using your setter method (e.i., setOAuthFacade(...)) so that supergwOauthFacade will not point to nothing and avoid getting NullPointerException. Good LUCK

Spring messaging with models in different packages

Here's what I'm trying to do:
Application 1 (consumer)
com.producer.model.Event - simple serialisable model (id, name)
Application 2 (producer)
com.consumer.integration.model.Event - simple serialisable model (id, name)
Serialisation configuration
#Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
Now when I produce a message
#Override
public void publishEvent(Event event) {
log.debug("Publish event Event : {}", event);
jmsTemplate.convertAndSend(eventTopic, event);
}
The consumer
#Override
#JmsListener(destination = "${jmsConfig.eventTopic}", containerFactory = "topicListenerFactory")
public void handleEvent(Event event) {
log.debug("Received an event {}", event);
}
The consumer side complains that the packages of the models are different.
MessageConversionException: Failed to resolve type id [com.producer.model.Event]
...
Caused by: java.lang.ClassNotFoundException: com.producer.model.Event
So deserialisation fails in the consumer because it can't find the package passed on with _type value.
Why do we even need to pass any package related info? It leaks information that is not needed...
What is the correct way to handle these situations. It should be quite a usual case?
EDIT:
With the help of Gary Russell I got it solved. Here's what you'd want to do.
Define a mapper in the producer AND the consumer with desired typings:
#Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
HashMap<String, Class<?>> typeIdMappings = new HashMap<>();
typeIdMappings.put(Event.class.getSimpleName(), Event.class);
converter.setTypeIdMappings(typeIdMappings);
converter.setTypeIdPropertyName("_type");
return converter;
}
It's important that
setTypeIdPropertyName matches in the consumer and the producer
setTypeIdMappings keys match in the consumer and the producer
This way you could match multiple objects between two services with one mapper.
See
/**
* Specify mappings from type ids to Java classes, if desired.
* This allows for synthetic ids in the type id message property,
* instead of transferring Java class names.
* <p>Default is no custom mappings, i.e. transferring raw Java class names.
* #param typeIdMappings a Map with type id values as keys and Java classes as values
*/
public void setTypeIdMappings(Map<String, Class<?>> typeIdMappings) {
On the producer side map the source class to a type id and on the consumer side map the type id to the destination class.
(That's why it's called MappingJackson...).

log4net using ThreadContext.Properties in wcf PerSession service

I would like to use the following in my wcf service to log the user in the log message:
log4net.ThreadContext.Properties["user"] = this.currentUser.LoginName;
I have the service set up to run in InstanceContextMode.PerSession. In the initial call to the wcf service I am setting this ThreadContext property to the current user that is logged in but each subsequent call does not log this property.
I'm pretty sure that for each call to the service it's running the task on a different thread even though it's set to use PerSession. I assume it's using a thread pool to process the requests.
Is there a way to set this so that I don't have to do it in every wcf method?
I ran into the same problem and this is how I got it to work. You can use GlobalContext since it will be evaluated for each call anyway.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService
{
//static constructor
static MyService()
{
log4net.Config.XmlConfigurator.Configure();
log4net.GlobalContext.Properties["user"] = new UserLogHelper();
}
...
}
Then you have to define a simple class:
private class UserLogHelper
{
public override string ToString()
{
var instanceContext = OperationContext.Current.InstanceContext;
var myServiceInstance = instanceContext.GetServiceInstance() as MyService;
return myServiceInstance?.currentUser?.LoginName;
}
}
Log4net supports "calculated context values". By using this you could write a class like this:
public class UserNameContext
{
public override string ToString()
{
string userName = ...; // get the name of the current user
return userName;
}
}
If you add this to the global context you can access the property in your appenders (like you are used to). The 'ToString' method will be executed every time and thus you get the correct user name.
More on context values can be found in this great tutorial:
http://www.beefycode.com/post/Log4Net-Tutorial-pt-6-Log-Event-Context.aspx

Will WCF use the same ParameterInspector instance to handle BeforeCall and AfterCall?

If I create a class that implements IParameterInspector, and insert it into the WCF pipline using a custom ServiceBehavior, will the same instance of the class be used when invoking BeforeCall and AfterCall? In other words, can I establish state about the current invocation during BeforeCall that I can access in AfterCall, and be sure that the response will come to the same instance?
Note _stateValue in the sample code below? Can I depend on a mechanism like this?
class OperationParameterInspector : IParameterInspector
{
public int _stateValue;
public object BeforeCall(string operationName, object[] inputs)
{
_stateValue = (int) inputs[0];
return null;
}
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
int originalInput = _stateValue;
return;
}
}
Passing state related to a particular call is the purpose of the return value from BeforeCall and the correlationState argument of AfterCall. The WCF infrastructure ensures that whatever object you return from BeforeCall is then passed into AfterCall via the correlationState, after the operation has completed.
As your subsequent comment suggests, the problem with using instance state in the inspector object is that instances may be shared between concurrent requests in some scenarios. However, I don't think there are any scenarios where a single operation request would be served by different parameter inspector objects in BeforeCall and AfterCall.

Decoupling Silverlight client from service reference generated class

I am researching Prism v2 by going thru the quickstarts. And I have created a WCF service with the following signature:
namespace HelloWorld.Silverlight.Web
{
[ServiceContract(Namespace = "http://helloworld.org/messaging")]
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class HelloWorldMessageService
{
private string message = "Hello from WCF";
[OperationContract]
public void UpdateMessage(string message)
{
this.message = message;
}
[OperationContract]
public string GetMessage()
{
return message;
}
}
}
When I add a service reference to this service in my silverlight project it generates an interface and a class:
[System.ServiceModel.ServiceContractAttribute
(Namespace="http://helloworld.org/messaging",
ConfigurationName="Web.Services.HelloWorldMessageService")]
public interface HelloWorldMessageService {
[System.ServiceModel.OperationContractAttribute
(AsyncPattern=true,
Action="http://helloworld.org/messaging/HelloWorldMessageService/UpdateMessage",
ReplyAction="http://helloworld.org/messaging/HelloWorldMessageService/UpdateMessageResponse")]
System.IAsyncResult BeginUpdateMessage(string message, System.AsyncCallback callback, object asyncState);
void EndUpdateMessage(System.IAsyncResult result);
[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://helloworld.org/messaging/HelloWorldMessageService/GetMessage", ReplyAction="http://helloworld.org/messaging/HelloWorldMessageService/GetMessageResponse")]
System.IAsyncResult BeginGetMessage(System.AsyncCallback callback, object asyncState);
string EndGetMessage(System.IAsyncResult result);
}
public partial class HelloWorldMessageServiceClient : System.ServiceModel.ClientBase<HelloWorld.Core.Web.Services.HelloWorldMessageService>, HelloWorld.Core.Web.Services.HelloWorldMessageService {
{
// implementation
}
I'm trying to decouple my application by passing around the interface instead of the concrete class. But I'm having difficulty finding examples of how to do this. When I try and call EndGetMessage and then update my UI I get an exception about updating the UI on the wrong thread. How can I update the UI from a background thread?
I tried but I get UnauthorizedAccessException : Invalid cross-thread access.
string messageresult = _service.EndGetMessage(result);
Application.Current.RootVisual.Dispatcher.BeginInvoke(() => this.Message = messageresult );
The exception is thrown by Application.Current.RootVisual.
Here is something I like doing... The service proxy is generated with an interface
HelloWorldClient : IHelloWorld
But the problem is that IHelloWorld does not include the Async versions of the method. So, I create an async interface:
public interface IHelloWorldAsync : IHelloWorld
{
void HelloWorldAsync(...);
event System.EventHandler<HelloWorldEventRgs> HelloWorldCompleted;
}
Then, you can tell the service proxy to implement the interface via partial:
public partial class HelloWorldClient : IHelloWorldAsync {}
Because the HelloWorldClient does, indeed, implement those async methods, this works.
Then, I can just use IHelloWorldAsync everywhere and tell the UnityContainer to use HelloWorldClient for IHelloWorldAsync interfaces.
Ok, I have been messing with this all day and the solution is really much more simple than that. I originally wanted to call the methods on the interface instead of the concreate class. The interface generated by proxy class generator only includes the BeginXXX and EndXXX methods and I was getting an exception when I called EndXXX.
Well, I just finished reading up on System.Threading.Dispatcher and I finally understand how to use it. Dispatcher is a member of any class that inherits from DispatcherObject, which the UI elements do. The Dispatcher operates on the UI thread, which for most WPF applications there is only 1 UI thread. There are exceptions, but I believe you have to do this explicitly so you'll know if you're doing it. Otherwise, you've only got a single UI thread. So it is safe to store a reference to a Dispatcher for use in non-UI classes.
In my case I'm using Prism and my Presenter needs to update the UI (not directly, but it is firing IPropertyChanged.PropertyChanged events). So what I have done is in my Bootstrapper when I set the shell to Application.Current.RootVisual I also store a reference to the Dispatcher like this:
public class Bootstrapper : UnityBootstrapper
{
protected override IModuleCatalog GetModuleCatalog()
{
// setup module catalog
}
protected override DependencyObject CreateShell()
{
// calling Resolve instead of directly initing allows use of dependency injection
Shell shell = Container.Resolve<Shell>();
Application.Current.RootVisual = shell;
Container.RegisterInstance<Dispatcher>(shell.Dispatcher);
return shell;
}
}
Then my presenter has a ctor which accepts IUnityContainer as an argument (using DI) then I can do the following:
_service.BeginGetMessage(new AsyncCallback(GetMessageAsyncComplete), null);
private void GetMessageAsyncComplete(IAsyncResult result)
{
string output = _service.EndGetMessage(result);
Dispatcher dispatcher = _container.Resolve<Dispatcher>();
dispatcher.BeginInvoke(() => this.Message = output);
}
This is sooooo much simpler. I just didn't understand it before.
Ok, so my real problem was how to decouple my dependency upon the proxy class created by my service reference. I was trying to do that by using the interface generated along with the proxy class. Which could have worked fine, but then I would have also had to reference the project which owned the service reference and so it wouldn't be truly decoupled. So here's what I ended up doing. It's a bit of a hack, but it seems to be working, so far.
First here's my interface definition and an adapter class for the custom event handler args generated with my proxy:
using System.ComponentModel;
namespace HelloWorld.Interfaces.Services
{
public class GetMessageCompletedEventArgsAdapter : System.ComponentModel.AsyncCompletedEventArgs
{
private object[] results;
public GetMessageCompletedEventArgsAdapter(object[] results, System.Exception exception, bool cancelled, object userState) :
base(exception, cancelled, userState)
{
this.results = results;
}
public string Result
{
get
{
base.RaiseExceptionIfNecessary();
return ((string)(this.results[0]));
}
}
}
/// <summary>
/// Create a partial class file for the service reference (reference.cs) that assigns
/// this interface to the class - then you can use this reference instead of the
/// one that isn't working
/// </summary>
public interface IMessageServiceClient
{
event System.EventHandler<GetMessageCompletedEventArgsAdapter> GetMessageCompleted;
event System.EventHandler<AsyncCompletedEventArgs> UpdateMessageCompleted;
void GetMessageAsync();
void GetMessageAsync(object userState);
void UpdateMessageAsync(string message);
void UpdateMessageAsync(string message, object userState);
}
}
Then I just needed to create a partial class which extends the proxy class generated by the service reference:
using System;
using HelloWorld.Interfaces.Services;
using System.Collections.Generic;
namespace HelloWorld.Core.Web.Services
{
public partial class HelloWorldMessageServiceClient : IMessageServiceClient
{
#region IMessageServiceClient Members
private event EventHandler<GetMessageCompletedEventArgsAdapter> handler;
private Dictionary<EventHandler<GetMessageCompletedEventArgsAdapter>, EventHandler<GetMessageCompletedEventArgs>> handlerDictionary
= new Dictionary<EventHandler<GetMessageCompletedEventArgsAdapter>, EventHandler<GetMessageCompletedEventArgs>>();
/// <remarks>
/// This is an adapter event which allows us to apply the IMessageServiceClient
/// interface to our MessageServiceClient. This way we can decouple our modules
/// from the implementation
/// </remarks>
event EventHandler<GetMessageCompletedEventArgsAdapter> IMessageServiceClient.GetMessageCompleted
{
add
{
handler += value;
EventHandler<GetMessageCompletedEventArgs> linkedhandler = new EventHandler<GetMessageCompletedEventArgs>(HelloWorldMessageServiceClient_GetMessageCompleted);
this.GetMessageCompleted += linkedhandler;
handlerDictionary.Add(value, linkedhandler);
}
remove
{
handler -= value;
EventHandler<GetMessageCompletedEventArgs> linkedhandler = handlerDictionary[value];
this.GetMessageCompleted -= linkedhandler;
handlerDictionary.Remove(value);
}
}
void HelloWorldMessageServiceClient_GetMessageCompleted(object sender, GetMessageCompletedEventArgs e)
{
if (this.handler == null)
return;
this.handler(sender, new GetMessageCompletedEventArgsAdapter(new object[] { e.Result }, e.Error, e.Cancelled, e.UserState));
}
#endregion
}
}
This is an explicit implementation of the event handler so I can chain together the events. When user registers for my adapter event, I register for the actual event fired. When the event fires I fire my adapter event. So far this "Works On My Machine".
Passing around the interface (once you have instantiated the client) should be as simply as using HelloWorldMessageService instead of the HelloWorldMessageServiceClient class.
In order to update the UI you need to use the Dispatcher object. This lets you provide a delegate that is invoked in the context of the UI thread. See this blog post for some details.
You can make this much simpler still.
The reason the proxy works and your copy of the contract does not is because WCF generates the proxy with code that "Posts" the callback back on the calling thread rather than making the callback on the thread that is executing when the service call returns.
A much simplified, untested, partial implementation to give you the idea of how WCF proxies work looks something like:
{
var state = new
{
CallingThread = SynchronizationContext.Current,
Callback = yourCallback
EndYourMethod = // assign delegate
};
yourService.BeginYourMethod(yourParams, WcfCallback, state);
}
private void WcfCallback(IAsyncResult asyncResult)
{
// Read the result object data to get state
// Call EndYourMethod and block until the finished
state.Context.Post(state.YourCallback, endYourMethodResultValue);
}
The key is the storing of the syncronizationContext and calling the Post method. This will get the callback to occur on the same thread as Begin was called on. It will always work without involving the Dispatcher object provided you call Begin from your UI thread. If you don't then you are back to square one with using the Dispatcher, but the same problem will occur with a WCF proxy.
This link does a good job of explaining how to do this manually:
http://msdn.microsoft.com/en-us/library/dd744834(VS.95).aspx
Just revisiting old posts left unanswered where I finally found an answer. Here's a post I recently wrote that goes into detail about how I finally handled all this:
http://www.developmentalmadness.com/archive/2009/11/04/mvvm-with-prism-101-ndash-part-6-commands.aspx