org.springframework.jms.listener.adapter
public class: MessageListenerAdapter [javadoc |
source]
java.lang.Object
org.springframework.jms.listener.adapter.MessageListenerAdapter
All Implemented Interfaces:
SessionAwareMessageListener, SubscriptionNameProvider, javax.jms.MessageListener
Direct Known Subclasses:
MessageListenerAdapter102
Message listener adapter that delegates the handling of messages to target
listener methods via reflection, with flexible message type conversion.
Allows listener methods to operate on message content types, completely
independent from the JMS API.
NOTE: This class requires a JMS 1.1+ provider, because it builds
on the domain-independent API. Use the MessageListenerAdapter102 subclass for JMS 1.0.2 providers.
By default, the content of incoming JMS messages gets extracted before
being passed into the target listener method, to let the target method
operate on message content types such as String or byte array instead of
the raw Message . Message type conversion is delegated to a Spring
JMS MessageConverter . By default, a SimpleMessageConverter
(102)
will be used. (If you do not want such automatic message conversion taking
place, then be sure to set the MessageConverter
to null.)
If a target listener method returns a non-null object (typically of a
message content type such as String or byte array), it will get
wrapped in a JMS Message and sent to the response destination
(either the JMS "reply-to" destination or a
specified default
destination ).
Note: The sending of response messages is only available when
using the SessionAwareMessageListener entry point (typically through a
Spring message listener container). Usage as standard JMS MessageListener
does not support the generation of response messages.
Find below some examples of method signatures compliant with this
adapter class. This first example handles all Message types
and gets passed the contents of each Message type as an
argument. No Message will be sent back as all of these
methods return void.
public interface MessageContentsDelegate {
void handleMessage(String text);
void handleMessage(Map map);
void handleMessage(byte[] bytes);
void handleMessage(Serializable obj);
}
This next example handles all
Message types and gets
passed the actual (raw)
Message as an argument. Again, no
Message will be sent back as all of these methods return
void.
public interface RawMessageDelegate {
void handleMessage(TextMessage message);
void handleMessage(MapMessage message);
void handleMessage(BytesMessage message);
void handleMessage(ObjectMessage message);
}
This next example illustrates a
Message delegate
that just consumes the
String contents of
TextMessages . Notice also how the
name of the
Message handling method is different from the
original (this will have to
be configured in the attandant bean definition). Again, no
Message
will be sent back as the method returns
void.
public interface TextMessageContentDelegate {
void onMessage(String text);
}
This final example illustrates a
Message delegate
that just consumes the
String contents of
TextMessages . Notice how the return type
of this method is
String: This will result in the configured
MessageListenerAdapter sending a
javax.jms.TextMessage in response.
public interface ResponsiveTextMessageContentDelegate {
String handleMessage(String text);
}
For further examples and discussion please do refer to the Spring
reference documentation which describes this class (and it's attendant
XML configuration) in detail.
| Field Summary |
|---|
| public static final String | ORIGINAL_DEFAULT_LISTENER_METHOD | Out-of-the-box value for the default listener method: "handleMessage". |
| protected final Log | logger | Logger available to subclasses |
| Method from org.springframework.jms.listener.adapter.MessageListenerAdapter Summary: |
|---|
|
buildListenerArguments, buildMessage, extractMessage, getDefaultListenerMethod, getDelegate, getDestinationResolver, getListenerMethodName, getMessageConverter, getResponseDestination, getSubscriptionName, handleListenerException, handleResult, initDefaultStrategies, invokeListenerMethod, onMessage, onMessage, postProcessProducer, postProcessResponse, resolveDefaultResponseDestination, sendResponse, setDefaultListenerMethod, setDefaultResponseDestination, setDefaultResponseQueueName, setDefaultResponseTopicName, setDelegate, setDestinationResolver, setMessageConverter |
| Method from org.springframework.jms.listener.adapter.MessageListenerAdapter Detail: |
protected Object[] buildListenerArguments(Object extractedMessage) {
return new Object[] {extractedMessage};
}
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.
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 single method argument, even if it is an array, with the target
method having a corresponding single argument of the array's type declared.
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. |
protected Message buildMessage(Session session,
Object result) throws JMSException {
MessageConverter converter = getMessageConverter();
if (converter != null) {
return converter.toMessage(result, session);
}
else {
if (!(result instanceof Message)) {
throw new MessageConversionException(
"No MessageConverter specified - cannot handle message [" + result + "]");
}
return (Message) result;
}
}
Build a JMS message to be sent as response based on the given result object. |
protected Object extractMessage(Message message) throws JMSException {
MessageConverter converter = getMessageConverter();
if (converter != null) {
return converter.fromMessage(message);
}
return message;
}
Extract the message body from the given JMS message. |
protected String getDefaultListenerMethod() {
return this.defaultListenerMethod;
}
Return the name of the default listener method to delegate to. |
protected Object getDelegate() {
return this.delegate;
}
Return the target object to delegate message listening to. |
protected DestinationResolver getDestinationResolver() {
return this.destinationResolver;
}
Return the DestinationResolver for this adapter. |
protected String getListenerMethodName(Message originalMessage,
Object extractedMessage) throws JMSException {
return getDefaultListenerMethod();
}
Determine the name of the listener method that is supposed to
handle the given message.
The default implementation simply returns the configured
default listener method, if any. |
protected MessageConverter getMessageConverter() {
return this.messageConverter;
}
Return the converter that will convert incoming JMS messages to
listener method arguments, and objects returned from listener
methods back to JMS messages. |
protected Destination getResponseDestination(Message request,
Message response,
Session session) throws JMSException {
Destination replyTo = request.getJMSReplyTo();
if (replyTo == null) {
replyTo = resolveDefaultResponseDestination(session);
if (replyTo == null) {
throw new InvalidDestinationException("Cannot determine response destination: " +
"Request message does not contain reply-to destination, and no default response destination set.");
}
}
return replyTo;
}
Determine a response destination for the given message.
The default implementation first checks the JMS Reply-To
Destination of the supplied request; if that is not null
it is returned; if it is null, then the configured
default response destination
is returned; if this too is null, then an
InvalidDestinationException is thrown. |
public String getSubscriptionName() {
if (this.delegate instanceof SubscriptionNameProvider) {
return ((SubscriptionNameProvider) this.delegate).getSubscriptionName();
}
else {
return this.delegate.getClass().getName();
}
}
|
protected void handleListenerException(Throwable ex) {
logger.error("Listener execution failed", ex);
}
Handle the given exception that arose during listener execution.
The default implementation logs the exception at error level.
This method only applies when used as standard JMS MessageListener .
In case of the Spring SessionAwareMessageListener mechanism,
exceptions get handled by the caller instead. |
protected void handleResult(Object result,
Message request,
Session session) throws JMSException {
if (session != null) {
if (logger.isDebugEnabled()) {
logger.debug("Listener method returned result [" + result +
"] - generating response message for it");
}
Message response = buildMessage(session, result);
postProcessResponse(request, response);
Destination destination = getResponseDestination(request, response, session);
sendResponse(session, destination, response);
}
else {
if (logger.isWarnEnabled()) {
logger.warn("Listener method returned result [" + result +
"]: not generating response message for it because of no JMS Session given");
}
}
}
Handle the given result object returned from the listener method,
sending a response message back. |
protected void initDefaultStrategies() {
setMessageConverter(new SimpleMessageConverter());
}
Initialize the default implementations for the adapter's strategies. |
protected Object invokeListenerMethod(String methodName,
Object[] arguments) throws JMSException {
try {
MethodInvoker methodInvoker = new MethodInvoker();
methodInvoker.setTargetObject(getDelegate());
methodInvoker.setTargetMethod(methodName);
methodInvoker.setArguments(arguments);
methodInvoker.prepare();
return methodInvoker.invoke();
}
catch (InvocationTargetException ex) {
Throwable targetEx = ex.getTargetException();
if (targetEx instanceof JMSException) {
throw (JMSException) targetEx;
}
else {
throw new ListenerExecutionFailedException(
"Listener method '" + methodName + "' threw exception", targetEx);
}
}
catch (Throwable ex) {
throw new ListenerExecutionFailedException("Failed to invoke target method '" + methodName +
"' with arguments " + ObjectUtils.nullSafeToString(arguments), ex);
}
}
Invoke the specified listener method. |
public void onMessage(Message message) {
try {
onMessage(message, null);
}
catch (Throwable ex) {
handleListenerException(ex);
}
}
Standard JMS MessageListener entry point.
Delegates the message to the target listener method, with appropriate
conversion of the message argument. In case of an exception, the
#handleListenerException(Throwable) method will be invoked.
Note: Does not support sending response messages based on
result objects returned from listener methods. Use the
SessionAwareMessageListener entry point (typically through a Spring
message listener container) for handling result objects as well. |
public void onMessage(Message message,
Session session) throws JMSException {
// Check whether the delegate is a MessageListener impl itself.
// In that case, the adapter will simply act as a pass-through.
Object delegate = getDelegate();
if (delegate != this) {
if (delegate instanceof SessionAwareMessageListener) {
if (session != null) {
((SessionAwareMessageListener) delegate).onMessage(message, session);
return;
}
else if (!(delegate instanceof MessageListener)) {
throw new javax.jms.IllegalStateException("MessageListenerAdapter cannot handle a " +
"SessionAwareMessageListener delegate if it hasn't been invoked with a Session itself");
}
}
if (delegate instanceof MessageListener) {
((MessageListener) delegate).onMessage(message);
return;
}
}
// Regular case: find a handler method reflectively.
Object convertedMessage = extractMessage(message);
String methodName = getListenerMethodName(message, convertedMessage);
if (methodName == null) {
throw new javax.jms.IllegalStateException("No default listener method specified: " +
"Either specify a non-null value for the 'defaultListenerMethod' property or " +
"override the 'getListenerMethodName' method.");
}
// Invoke the handler method with appropriate arguments.
Object[] listenerArguments = buildListenerArguments(convertedMessage);
Object result = invokeListenerMethod(methodName, listenerArguments);
if (result != null) {
handleResult(result, message, session);
}
else {
logger.trace("No result object given - no result to handle");
}
}
Spring SessionAwareMessageListener entry point.
Delegates the message to the target listener method, with appropriate
conversion of the message argument. If the target method returns a
non-null object, wrap in a JMS message and send it back. |
protected void postProcessProducer(MessageProducer producer,
Message response) throws JMSException {
}
|
protected void postProcessResponse(Message request,
Message response) throws JMSException {
String correlation = request.getJMSCorrelationID();
if (correlation == null) {
correlation = request.getJMSMessageID();
}
response.setJMSCorrelationID(correlation);
}
Post-process the given response message before it will be sent.
The default implementation sets the response's correlation id
to the request message's correlation id, if any; otherwise to the
request message id. |
protected Destination resolveDefaultResponseDestination(Session session) throws JMSException {
if (this.defaultResponseDestination instanceof Destination) {
return (Destination) this.defaultResponseDestination;
}
if (this.defaultResponseDestination instanceof DestinationNameHolder) {
DestinationNameHolder nameHolder = (DestinationNameHolder) this.defaultResponseDestination;
return getDestinationResolver().resolveDestinationName(session, nameHolder.name, nameHolder.isTopic);
}
return null;
}
|
protected void sendResponse(Session session,
Destination destination,
Message response) throws JMSException {
MessageProducer producer = session.createProducer(destination);
try {
postProcessProducer(producer, response);
producer.send(response);
}
finally {
JmsUtils.closeMessageProducer(producer);
}
}
Send the given response message to the given destination. |
public void setDefaultListenerMethod(String defaultListenerMethod) {
this.defaultListenerMethod = defaultListenerMethod;
}
Specify the name of the default listener method to delegate to,
for the case where no specific listener method has been determined.
Out-of-the-box value is "handleMessage" . |
public void setDefaultResponseDestination(Destination destination) {
this.defaultResponseDestination = destination;
}
Set the default destination to send response messages to. This will be applied
in case of a request message that does not carry a "JMSReplyTo" field.
Response destinations are only relevant for listener methods that return
result objects, which will be wrapped in a response message and sent to a
response destination.
Alternatively, specify a "defaultResponseQueueName" or "defaultResponseTopicName",
to be dynamically resolved via the DestinationResolver. |
public void setDefaultResponseQueueName(String destinationName) {
this.defaultResponseDestination = new DestinationNameHolder(destinationName, false);
}
Set the name of the default response queue to send response messages to.
This will be applied in case of a request message that does not carry a
"JMSReplyTo" field.
Alternatively, specify a JMS Destination object as "defaultResponseDestination". |
public void setDefaultResponseTopicName(String destinationName) {
this.defaultResponseDestination = new DestinationNameHolder(destinationName, true);
}
Set the name of the default response topic to send response messages to.
This will be applied in case of a request message that does not carry a
"JMSReplyTo" field.
Alternatively, specify a JMS Destination object as "defaultResponseDestination". |
public void setDelegate(Object delegate) {
Assert.notNull(delegate, "Delegate must not be null");
this.delegate = delegate;
}
Set a target object to delegate message listening to.
Specified listener methods have to be present on this target object.
If no explicit delegate object has been specified, listener
methods are expected to present on this adapter instance, that is,
on a custom subclass of this adapter, defining listener methods. |
public void setDestinationResolver(DestinationResolver destinationResolver) {
Assert.notNull(destinationResolver, "DestinationResolver must not be null");
this.destinationResolver = destinationResolver;
}
Set the DestinationResolver that should be used to resolve response
destination names for this adapter.
The default resolver is a DynamicDestinationResolver. Specify a
JndiDestinationResolver for resolving destination names as JNDI locations. |
public void setMessageConverter(MessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
|