/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jms.listener.adapter;
import javax.jms.JMSException;
import javax.jms.Session;
import org.springframework.core.MethodParameter;
import org.springframework.jms.support.JmsHeaderMapper;
import org.springframework.jms.support.converter.MessageConversionException;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.core.AbstractMessageSendingTemplate;
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
import org.springframework.messaging.support.MessageBuilder;
/**
* A {@link javax.jms.MessageListener} adapter that invokes a configurable
* {@link InvocableHandlerMethod}.
*
* <p>Wraps the incoming {@link javax.jms.Message} to Spring's {@link Message}
* abstraction, copying the JMS standard headers using a configurable
* {@link JmsHeaderMapper}.
*
* <p>The original {@link javax.jms.Message} and the {@link javax.jms.Session}
* are provided as additional arguments so that these can be injected as
* method arguments if necessary.
*
* @author Stephane Nicoll
* @since 4.1
* @see Message
* @see JmsHeaderMapper
* @see InvocableHandlerMethod
*/
public class MessagingMessageListenerAdapter extends AbstractAdaptableMessageListener {
private InvocableHandlerMethod handlerMethod;
/**
* Set the {@link InvocableHandlerMethod} to use to invoke the method
* processing an incoming {@link javax.jms.Message}.
*/
public void setHandlerMethod(InvocableHandlerMethod handlerMethod) {
this.handlerMethod = handlerMethod;
}
@Override
public void onMessage(javax.jms.Message jmsMessage, Session session) throws JMSException {
Message<?> message = toMessagingMessage(jmsMessage);
if (logger.isDebugEnabled()) {
logger.debug("Processing [" + message + "]");
}
Object result = invokeHandler(jmsMessage, session, message);
if (result != null) {
handleResult(result, jmsMessage, session);
}
else {
logger.trace("No result object given - no result to handle");
}
}
@Override
protected Object preProcessResponse(Object result) {
MethodParameter returnType = this.handlerMethod.getReturnType();
if (result instanceof Message) {
return MessageBuilder.fromMessage((Message<?>) result)
.setHeader(AbstractMessageSendingTemplate.CONVERSION_HINT_HEADER, returnType).build();
}
return MessageBuilder.withPayload(result).setHeader(
AbstractMessageSendingTemplate.CONVERSION_HINT_HEADER, returnType).build();
}
protected Message<?> toMessagingMessage(javax.jms.Message jmsMessage) {
try {
return (Message<?>) getMessagingMessageConverter().fromMessage(jmsMessage);
}
catch (JMSException ex) {
throw new MessageConversionException("Could not convert JMS message", ex);
}
}
/**
* Invoke the handler, wrapping any exception to a {@link ListenerExecutionFailedException}
* with a dedicated error message.
*/
private Object invokeHandler(javax.jms.Message jmsMessage, Session session, Message<?> message) {
try {
return this.handlerMethod.invoke(message, jmsMessage, session);
}
catch (MessagingException ex) {
throw new ListenerExecutionFailedException(
createMessagingErrorMessage("Listener method could not be invoked with incoming message"), ex);
}
catch (Exception ex) {
throw new ListenerExecutionFailedException("Listener method '" +
this.handlerMethod.getMethod().toGenericString() + "' threw exception", ex);
}
}
private String createMessagingErrorMessage(String description) {
StringBuilder sb = new StringBuilder(description).append("\n")
.append("Endpoint handler details:\n")
.append("Method [").append(this.handlerMethod.getMethod()).append("]\n")
.append("Bean [").append(this.handlerMethod.getBean()).append("]\n");
return sb.toString();
}
}