Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » jms » listener » adapter » [javadoc | source]
    1   /*
    2    * Copyright 2002-2008 the original author or authors.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    * Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   
   17   package org.springframework.jms.listener.adapter;
   18   
   19   import java.lang.reflect.InvocationTargetException;
   20   
   21   import javax.jms.Destination;
   22   import javax.jms.InvalidDestinationException;
   23   import javax.jms.JMSException;
   24   import javax.jms.Message;
   25   import javax.jms.MessageListener;
   26   import javax.jms.MessageProducer;
   27   import javax.jms.Session;
   28   
   29   import org.apache.commons.logging.Log;
   30   import org.apache.commons.logging.LogFactory;
   31   
   32   import org.springframework.jms.listener.SessionAwareMessageListener;
   33   import org.springframework.jms.listener.SubscriptionNameProvider;
   34   import org.springframework.jms.support.JmsUtils;
   35   import org.springframework.jms.support.converter.MessageConversionException;
   36   import org.springframework.jms.support.converter.MessageConverter;
   37   import org.springframework.jms.support.converter.SimpleMessageConverter;
   38   import org.springframework.jms.support.destination.DestinationResolver;
   39   import org.springframework.jms.support.destination.DynamicDestinationResolver;
   40   import org.springframework.util.Assert;
   41   import org.springframework.util.MethodInvoker;
   42   import org.springframework.util.ObjectUtils;
   43   
   44   /**
   45    * Message listener adapter that delegates the handling of messages to target
   46    * listener methods via reflection, with flexible message type conversion.
   47    * Allows listener methods to operate on message content types, completely
   48    * independent from the JMS API.
   49    *
   50    * <p><b>NOTE:</b> This class requires a JMS 1.1+ provider, because it builds
   51    * on the domain-independent API. <b>Use the {@link MessageListenerAdapter102
   52    * MessageListenerAdapter102} subclass for JMS 1.0.2 providers.</b>
   53    *
   54    * <p>By default, the content of incoming JMS messages gets extracted before
   55    * being passed into the target listener method, to let the target method
   56    * operate on message content types such as String or byte array instead of
   57    * the raw {@link Message}. Message type conversion is delegated to a Spring
   58    * JMS {@link MessageConverter}. By default, a {@link SimpleMessageConverter}
   59    * {@link org.springframework.jms.support.converter.SimpleMessageConverter102 (102)}
   60    * will be used. (If you do not want such automatic message conversion taking
   61    * place, then be sure to set the {@link #setMessageConverter MessageConverter}
   62    * to <code>null</code>.)
   63    *
   64    * <p>If a target listener method returns a non-null object (typically of a
   65    * message content type such as <code>String</code> or byte array), it will get
   66    * wrapped in a JMS <code>Message</code> and sent to the response destination
   67    * (either the JMS "reply-to" destination or a
   68    * {@link #setDefaultResponseDestination(javax.jms.Destination) specified default
   69    * destination}).
   70    *
   71    * <p><b>Note:</b> The sending of response messages is only available when
   72    * using the {@link SessionAwareMessageListener} entry point (typically through a
   73    * Spring message listener container). Usage as standard JMS {@link MessageListener}
   74    * does <i>not</i> support the generation of response messages.
   75    *
   76    * <p>Find below some examples of method signatures compliant with this
   77    * adapter class. This first example handles all <code>Message</code> types
   78    * and gets passed the contents of each <code>Message</code> type as an
   79    * argument. No <code>Message</code> will be sent back as all of these
   80    * methods return <code>void</code>.
   81    *
   82    * <pre class="code">public interface MessageContentsDelegate {
   83    *    void handleMessage(String text);
   84    *    void handleMessage(Map map);
   85    *    void handleMessage(byte[] bytes);
   86    *    void handleMessage(Serializable obj);
   87    * }</pre>
   88    *
   89    * This next example handles all <code>Message</code> types and gets
   90    * passed the actual (raw) <code>Message</code> as an argument. Again, no
   91    * <code>Message</code> will be sent back as all of these methods return
   92    * <code>void</code>.
   93    *
   94    * <pre class="code">public interface RawMessageDelegate {
   95    *    void handleMessage(TextMessage message);
   96    *    void handleMessage(MapMessage message);
   97    *    void handleMessage(BytesMessage message);
   98    *    void handleMessage(ObjectMessage message);
   99    * }</pre>
  100    *
  101    * This next example illustrates a <code>Message</code> delegate
  102    * that just consumes the <code>String</code> contents of
  103    * {@link javax.jms.TextMessage TextMessages}. Notice also how the
  104    * name of the <code>Message</code> handling method is different from the
  105    * {@link #ORIGINAL_DEFAULT_LISTENER_METHOD original} (this will have to
  106    * be configured in the attandant bean definition). Again, no <code>Message</code>
  107    * will be sent back as the method returns <code>void</code>.
  108    *
  109    * <pre class="code">public interface TextMessageContentDelegate {
  110    *    void onMessage(String text);
  111    * }</pre>
  112    *
  113    * This final example illustrates a <code>Message</code> delegate
  114    * that just consumes the <code>String</code> contents of
  115    * {@link javax.jms.TextMessage TextMessages}. Notice how the return type
  116    * of this method is <code>String</code>: This will result in the configured
  117    * {@link MessageListenerAdapter} sending a {@link javax.jms.TextMessage} in response.
  118    *
  119    * <pre class="code">public interface ResponsiveTextMessageContentDelegate {
  120    *    String handleMessage(String text);
  121    * }</pre>
  122    *
  123    * For further examples and discussion please do refer to the Spring
  124    * reference documentation which describes this class (and it's attendant
  125    * XML configuration) in detail.
  126    *
  127    * @author Juergen Hoeller
  128    * @since 2.0
  129    * @see #setDelegate
  130    * @see #setDefaultListenerMethod
  131    * @see #setDefaultResponseDestination
  132    * @see #setMessageConverter
  133    * @see org.springframework.jms.support.converter.SimpleMessageConverter
  134    * @see org.springframework.jms.listener.SessionAwareMessageListener
  135    * @see org.springframework.jms.listener.AbstractMessageListenerContainer#setMessageListener
  136    */
  137   public class MessageListenerAdapter implements MessageListener, SessionAwareMessageListener, SubscriptionNameProvider {
  138   
  139   	/**
  140   	 * Out-of-the-box value for the default listener method: "handleMessage".
  141   	 */
  142   	public static final String ORIGINAL_DEFAULT_LISTENER_METHOD = "handleMessage";
  143   
  144   
  145   	/** Logger available to subclasses */
  146   	protected final Log logger = LogFactory.getLog(getClass());
  147   
  148   	private Object delegate;
  149   
  150   	private String defaultListenerMethod = ORIGINAL_DEFAULT_LISTENER_METHOD;
  151   
  152   	private Object defaultResponseDestination;
  153   
  154   	private DestinationResolver destinationResolver = new DynamicDestinationResolver();
  155   
  156   	private MessageConverter messageConverter;
  157   
  158   
  159   	/**
  160   	 * Create a new {@link MessageListenerAdapter} with default settings.
  161   	 */
  162   	public MessageListenerAdapter() {
  163   		initDefaultStrategies();
  164   		this.delegate = this;
  165   	}
  166   
  167   	/**
  168   	 * Create a new {@link MessageListenerAdapter} for the given delegate.
  169   	 * @param delegate the delegate object
  170   	 */
  171   	public MessageListenerAdapter(Object delegate) {
  172   		initDefaultStrategies();
  173   		setDelegate(delegate);
  174   	}
  175   
  176   
  177   	/**
  178   	 * Set a target object to delegate message listening to.
  179   	 * Specified listener methods have to be present on this target object.
  180   	 * <p>If no explicit delegate object has been specified, listener
  181   	 * methods are expected to present on this adapter instance, that is,
  182   	 * on a custom subclass of this adapter, defining listener methods.
  183   	 */
  184   	public void setDelegate(Object delegate) {
  185   		Assert.notNull(delegate, "Delegate must not be null");
  186   		this.delegate = delegate;
  187   	}
  188   
  189   	/**
  190   	 * Return the target object to delegate message listening to.
  191   	 */
  192   	protected Object getDelegate() {
  193   		return this.delegate;
  194   	}
  195   
  196   	/**
  197   	 * Specify the name of the default listener method to delegate to,
  198   	 * for the case where no specific listener method has been determined.
  199   	 * Out-of-the-box value is {@link #ORIGINAL_DEFAULT_LISTENER_METHOD "handleMessage"}.
  200   	 * @see #getListenerMethodName
  201   	 */
  202   	public void setDefaultListenerMethod(String defaultListenerMethod) {
  203   		this.defaultListenerMethod = defaultListenerMethod;
  204   	}
  205   
  206   	/**
  207   	 * Return the name of the default listener method to delegate to.
  208   	 */
  209   	protected String getDefaultListenerMethod() {
  210   		return this.defaultListenerMethod;
  211   	}
  212   
  213   	/**
  214   	 * Set the default destination to send response messages to. This will be applied
  215   	 * in case of a request message that does not carry a "JMSReplyTo" field.
  216   	 * <p>Response destinations are only relevant for listener methods that return
  217   	 * result objects, which will be wrapped in a response message and sent to a
  218   	 * response destination.
  219   	 * <p>Alternatively, specify a "defaultResponseQueueName" or "defaultResponseTopicName",
  220   	 * to be dynamically resolved via the DestinationResolver.
  221   	 * @see #setDefaultResponseQueueName(String)
  222   	 * @see #setDefaultResponseTopicName(String)
  223   	 * @see #getResponseDestination
  224   	 */
  225   	public void setDefaultResponseDestination(Destination destination) {
  226   		this.defaultResponseDestination = destination;
  227   	}
  228   
  229   	/**
  230   	 * Set the name of the default response queue to send response messages to.
  231   	 * This will be applied in case of a request message that does not carry a
  232   	 * "JMSReplyTo" field.
  233   	 * <p>Alternatively, specify a JMS Destination object as "defaultResponseDestination".
  234   	 * @see #setDestinationResolver
  235   	 * @see #setDefaultResponseDestination(javax.jms.Destination)
  236   	 */
  237   	public void setDefaultResponseQueueName(String destinationName) {
  238   		this.defaultResponseDestination = new DestinationNameHolder(destinationName, false);
  239   	}
  240   
  241   	/**
  242   	 * Set the name of the default response topic to send response messages to.
  243   	 * This will be applied in case of a request message that does not carry a
  244   	 * "JMSReplyTo" field.
  245   	 * <p>Alternatively, specify a JMS Destination object as "defaultResponseDestination".
  246   	 * @see #setDestinationResolver
  247   	 * @see #setDefaultResponseDestination(javax.jms.Destination)
  248   	 */
  249   	public void setDefaultResponseTopicName(String destinationName) {
  250   		this.defaultResponseDestination = new DestinationNameHolder(destinationName, true);
  251   	}
  252   
  253   	/**
  254   	 * Set the DestinationResolver that should be used to resolve response
  255   	 * destination names for this adapter.
  256   	 * <p>The default resolver is a DynamicDestinationResolver. Specify a
  257   	 * JndiDestinationResolver for resolving destination names as JNDI locations.
  258   	 * @see org.springframework.jms.support.destination.DynamicDestinationResolver
  259   	 * @see org.springframework.jms.support.destination.JndiDestinationResolver
  260   	 */
  261   	public void setDestinationResolver(DestinationResolver destinationResolver) {
  262   		Assert.notNull(destinationResolver, "DestinationResolver must not be null");
  263   		this.destinationResolver = destinationResolver;
  264   	}
  265   
  266   	/**
  267   	 * Return the DestinationResolver for this adapter.
  268   	 */
  269   	protected DestinationResolver getDestinationResolver() {
  270   		return this.destinationResolver;
  271   	}
  272   
  273   	/**
  274   	 * Set the converter that will convert incoming JMS messages to
  275   	 * listener method arguments, and objects returned from listener
  276   	 * methods back to JMS messages.
  277   	 * <p>The default converter is a {@link SimpleMessageConverter}, which is able
  278   	 * to handle {@link javax.jms.BytesMessage BytesMessages},
  279   	 * {@link javax.jms.TextMessage TextMessages} and
  280   	 * {@link javax.jms.ObjectMessage ObjectMessages}.
  281   	 */
  282   	public void setMessageConverter(MessageConverter messageConverter) {
  283   		this.messageConverter = messageConverter;
  284   	}
  285   
  286   	/**
  287   	 * Return the converter that will convert incoming JMS messages to
  288   	 * listener method arguments, and objects returned from listener
  289   	 * methods back to JMS messages.
  290   	 */
  291   	protected MessageConverter getMessageConverter() {
  292   		return this.messageConverter;
  293   	}
  294   
  295   
  296   	/**
  297   	 * Standard JMS {@link MessageListener} entry point.
  298   	 * <p>Delegates the message to the target listener method, with appropriate
  299   	 * conversion of the message argument. In case of an exception, the
  300   	 * {@link #handleListenerException(Throwable)} method will be invoked.
  301   	 * <p><b>Note:</b> Does not support sending response messages based on
  302   	 * result objects returned from listener methods. Use the
  303   	 * {@link SessionAwareMessageListener} entry point (typically through a Spring
  304   	 * message listener container) for handling result objects as well.
  305   	 * @param message the incoming JMS message
  306   	 * @see #handleListenerException
  307   	 * @see #onMessage(javax.jms.Message, javax.jms.Session)
  308   	 */
  309   	public void onMessage(Message message) {
  310   		try {
  311   			onMessage(message, null);
  312   		}
  313   		catch (Throwable ex) {
  314   			handleListenerException(ex);
  315   		}
  316   	}
  317   
  318   	/**
  319   	 * Spring {@link SessionAwareMessageListener} entry point.
  320   	 * <p>Delegates the message to the target listener method, with appropriate
  321   	 * conversion of the message argument. If the target method returns a
  322   	 * non-null object, wrap in a JMS message and send it back.
  323   	 * @param message the incoming JMS message
  324   	 * @param session the JMS session to operate on
  325   	 * @throws JMSException if thrown by JMS API methods
  326   	 */
  327   	public void onMessage(Message message, Session session) throws JMSException {
  328   		// Check whether the delegate is a MessageListener impl itself.
  329   		// In that case, the adapter will simply act as a pass-through.
  330   		Object delegate = getDelegate();
  331   		if (delegate != this) {
  332   			if (delegate instanceof SessionAwareMessageListener) {
  333   				if (session != null) {
  334   					((SessionAwareMessageListener) delegate).onMessage(message, session);
  335   					return;
  336   				}
  337   				else if (!(delegate instanceof MessageListener)) {
  338   					throw new javax.jms.IllegalStateException("MessageListenerAdapter cannot handle a " +
  339   							"SessionAwareMessageListener delegate if it hasn't been invoked with a Session itself");
  340   				}
  341   			}
  342   			if (delegate instanceof MessageListener) {
  343   				((MessageListener) delegate).onMessage(message);
  344   				return;
  345   			}
  346   		}
  347   
  348   		// Regular case: find a handler method reflectively.
  349   		Object convertedMessage = extractMessage(message);
  350   		String methodName = getListenerMethodName(message, convertedMessage);
  351   		if (methodName == null) {
  352   			throw new javax.jms.IllegalStateException("No default listener method specified: " +
  353   					"Either specify a non-null value for the 'defaultListenerMethod' property or " +
  354   					"override the 'getListenerMethodName' method.");
  355   		}
  356   
  357   		// Invoke the handler method with appropriate arguments.
  358   		Object[] listenerArguments = buildListenerArguments(convertedMessage);
  359   		Object result = invokeListenerMethod(methodName, listenerArguments);
  360   		if (result != null) {
  361   			handleResult(result, message, session);
  362   		}
  363   		else {
  364   			logger.trace("No result object given - no result to handle");
  365   		}
  366   	}
  367   
  368   	public String getSubscriptionName() {
  369   		if (this.delegate instanceof SubscriptionNameProvider) {
  370   			return ((SubscriptionNameProvider) this.delegate).getSubscriptionName();
  371   		}
  372   		else {
  373   			return this.delegate.getClass().getName();
  374   		}
  375   	}
  376   
  377   
  378   	/**
  379   	 * Initialize the default implementations for the adapter's strategies.
  380   	 * @see #setMessageConverter
  381   	 * @see org.springframework.jms.support.converter.SimpleMessageConverter
  382   	 */
  383   	protected void initDefaultStrategies() {
  384   		setMessageConverter(new SimpleMessageConverter());
  385   	}
  386   
  387       /**
  388   	 * Handle the given exception that arose during listener execution.
  389   	 * The default implementation logs the exception at error level.
  390   	 * <p>This method only applies when used as standard JMS {@link MessageListener}.
  391   	 * In case of the Spring {@link SessionAwareMessageListener} mechanism,
  392   	 * exceptions get handled by the caller instead.
  393   	 * @param ex the exception to handle
  394   	 * @see #onMessage(javax.jms.Message)
  395   	 */
  396   	protected void handleListenerException(Throwable ex) {
  397   		logger.error("Listener execution failed", ex);
  398   	}
  399   
  400   	/**
  401   	 * Extract the message body from the given JMS message.
  402   	 * @param message the JMS <code>Message</code>
  403   	 * @return the content of the message, to be passed into the
  404   	 * listener method as argument
  405   	 * @throws JMSException if thrown by JMS API methods
  406   	 */
  407   	protected Object extractMessage(Message message) throws JMSException {
  408   		MessageConverter converter = getMessageConverter();
  409   		if (converter != null) {
  410   			return converter.fromMessage(message);
  411   		}
  412   		return message;
  413   	}
  414   
  415   	/**
  416   	 * Determine the name of the listener method that is supposed to
  417   	 * handle the given message.
  418   	 * <p>The default implementation simply returns the configured
  419   	 * default listener method, if any.
  420   	 * @param originalMessage the JMS request message
  421   	 * @param extractedMessage the converted JMS request message,
  422   	 * to be passed into the listener method as argument
  423   	 * @return the name of the listener method (never <code>null</code>)
  424   	 * @throws JMSException if thrown by JMS API methods
  425   	 * @see #setDefaultListenerMethod
  426   	 */
  427   	protected String getListenerMethodName(Message originalMessage, Object extractedMessage) throws JMSException {
  428   		return getDefaultListenerMethod();
  429   	}
  430   
  431   	/**
  432   	 * Build an array of arguments to be passed into the target listener method.
  433   	 * Allows for multiple method arguments to be built from a single message object.
  434   	 * <p>The default implementation builds an array with the given message object
  435   	 * as sole element. This means that the extracted message will always be passed
  436   	 * into a <i>single</i> method argument, even if it is an array, with the target
  437   	 * method having a corresponding single argument of the array's type declared.
  438   	 * <p>This can be overridden to treat special message content such as arrays
  439   	 * differently, for example passing in each element of the message array
  440   	 * as distinct method argument.
  441   	 * @param extractedMessage the content of the message
  442   	 * @return the array of arguments to be passed into the
  443   	 * listener method (each element of the array corresponding
  444   	 * to a distinct method argument)
  445   	 */
  446   	protected Object[] buildListenerArguments(Object extractedMessage) {
  447   		return new Object[] {extractedMessage};
  448   	}
  449   
  450   	/**
  451   	 * Invoke the specified listener method.
  452   	 * @param methodName the name of the listener method
  453   	 * @param arguments the message arguments to be passed in
  454   	 * @return the result returned from the listener method
  455   	 * @throws JMSException if thrown by JMS API methods
  456   	 * @see #getListenerMethodName
  457   	 * @see #buildListenerArguments
  458   	 */
  459   	protected Object invokeListenerMethod(String methodName, Object[] arguments) throws JMSException {
  460   		try {
  461   			MethodInvoker methodInvoker = new MethodInvoker();
  462   			methodInvoker.setTargetObject(getDelegate());
  463   			methodInvoker.setTargetMethod(methodName);
  464   			methodInvoker.setArguments(arguments);
  465   			methodInvoker.prepare();
  466   			return methodInvoker.invoke();
  467   		}
  468   		catch (InvocationTargetException ex) {
  469   			Throwable targetEx = ex.getTargetException();
  470   			if (targetEx instanceof JMSException) {
  471   				throw (JMSException) targetEx;
  472   			}
  473   			else {
  474   				throw new ListenerExecutionFailedException(
  475   						"Listener method '" + methodName + "' threw exception", targetEx);
  476   			}
  477   		}
  478   		catch (Throwable ex) {
  479   			throw new ListenerExecutionFailedException("Failed to invoke target method '" + methodName +
  480   					"' with arguments " + ObjectUtils.nullSafeToString(arguments), ex);
  481   		}
  482   	}
  483   
  484   
  485   	/**
  486   	 * Handle the given result object returned from the listener method,
  487   	 * sending a response message back.
  488   	 * @param result the result object to handle (never <code>null</code>)
  489   	 * @param request the original request message
  490   	 * @param session the JMS Session to operate on (may be <code>null</code>)
  491   	 * @throws JMSException if thrown by JMS API methods
  492   	 * @see #buildMessage
  493   	 * @see #postProcessResponse
  494   	 * @see #getResponseDestination
  495   	 * @see #sendResponse
  496   	 */
  497   	protected void handleResult(Object result, Message request, Session session) throws JMSException {
  498   		if (session != null) {
  499   			if (logger.isDebugEnabled()) {
  500   				logger.debug("Listener method returned result [" + result +
  501   						"] - generating response message for it");
  502   			}
  503   			Message response = buildMessage(session, result);
  504   			postProcessResponse(request, response);
  505   			Destination destination = getResponseDestination(request, response, session);
  506   			sendResponse(session, destination,  response);
  507   		}
  508   		else {
  509   			if (logger.isWarnEnabled()) {
  510   				logger.warn("Listener method returned result [" + result +
  511   						"]: not generating response message for it because of no JMS Session given");
  512   			}
  513   		}
  514   	}
  515   
  516   	/**
  517   	 * Build a JMS message to be sent as response based on the given result object.
  518   	 * @param session the JMS Session to operate on
  519   	 * @param result the content of the message, as returned from the listener method
  520   	 * @return the JMS <code>Message</code> (never <code>null</code>)
  521   	 * @throws JMSException if thrown by JMS API methods
  522   	 * @see #setMessageConverter
  523   	 */
  524   	protected Message buildMessage(Session session, Object result) throws JMSException {
  525   		MessageConverter converter = getMessageConverter();
  526   		if (converter != null) {
  527   			return converter.toMessage(result, session);
  528   		}
  529   		else {
  530   			if (!(result instanceof Message)) {
  531   				throw new MessageConversionException(
  532   						"No MessageConverter specified - cannot handle message [" + result + "]");
  533   			}
  534   			return (Message) result;
  535   		}
  536   	}
  537   
  538   	/**
  539   	 * Post-process the given response message before it will be sent.
  540   	 * <p>The default implementation sets the response's correlation id
  541   	 * to the request message's correlation id, if any; otherwise to the
  542   	 * request message id.
  543   	 * @param request the original incoming JMS message
  544   	 * @param response the outgoing JMS message about to be sent
  545   	 * @throws JMSException if thrown by JMS API methods
  546   	 * @see javax.jms.Message#setJMSCorrelationID
  547   	 */
  548   	protected void postProcessResponse(Message request, Message response) throws JMSException {
  549   		String correlation = request.getJMSCorrelationID();
  550   		if (correlation == null) {
  551   			correlation = request.getJMSMessageID();
  552   		}
  553   		response.setJMSCorrelationID(correlation);
  554   	}
  555   
  556   	/**
  557   	 * Determine a response destination for the given message.
  558   	 * <p>The default implementation first checks the JMS Reply-To
  559   	 * {@link Destination} of the supplied request; if that is not <code>null</code>
  560   	 * it is returned; if it is <code>null</code>, then the configured
  561   	 * {@link #resolveDefaultResponseDestination default response destination}
  562   	 * is returned; if this too is <code>null</code>, then an
  563   	 * {@link InvalidDestinationException} is thrown.
  564   	 * @param request the original incoming JMS message
  565   	 * @param response the outgoing JMS message about to be sent
  566   	 * @param session the JMS Session to operate on
  567   	 * @return the response destination (never <code>null</code>)
  568   	 * @throws JMSException if thrown by JMS API methods
  569   	 * @throws InvalidDestinationException if no {@link Destination} can be determined
  570   	 * @see #setDefaultResponseDestination
  571   	 * @see javax.jms.Message#getJMSReplyTo()
  572   	 */
  573   	protected Destination getResponseDestination(Message request, Message response, Session session)
  574   			throws JMSException {
  575   
  576   		Destination replyTo = request.getJMSReplyTo();
  577   		if (replyTo == null) {
  578   			replyTo = resolveDefaultResponseDestination(session);
  579   			if (replyTo == null) {
  580   				throw new InvalidDestinationException("Cannot determine response destination: " +
  581   						"Request message does not contain reply-to destination, and no default response destination set.");
  582   			}
  583   		}
  584   		return replyTo;
  585   	}
  586   
  587   	/**
  588   	 * Resolve the default response destination into a JMS {@link Destination}, using this
  589   	 * accessor's {@link DestinationResolver} in case of a destination name.
  590   	 * @return the located {@link Destination}
  591   	 * @throws javax.jms.JMSException if resolution failed
  592   	 * @see #setDefaultResponseDestination
  593   	 * @see #setDefaultResponseQueueName
  594   	 * @see #setDefaultResponseTopicName
  595   	 * @see #setDestinationResolver
  596   	 */
  597   	protected Destination resolveDefaultResponseDestination(Session session) throws JMSException {
  598   		if (this.defaultResponseDestination instanceof Destination) {
  599   			return (Destination) this.defaultResponseDestination;
  600   		}
  601   		if (this.defaultResponseDestination instanceof DestinationNameHolder) {
  602   			DestinationNameHolder nameHolder = (DestinationNameHolder) this.defaultResponseDestination;
  603   			return getDestinationResolver().resolveDestinationName(session, nameHolder.name, nameHolder.isTopic);
  604   		}
  605   		return null;
  606   	}
  607   
  608   	/**
  609   	 * Send the given response message to the given destination.
  610   	 * @param response the JMS message to send
  611   	 * @param destination the JMS destination to send to
  612   	 * @param session the JMS session to operate on
  613   	 * @throws JMSException if thrown by JMS API methods
  614   	 * @see #postProcessProducer
  615   	 * @see javax.jms.Session#createProducer
  616   	 * @see javax.jms.MessageProducer#send
  617   	 */
  618   	protected void sendResponse(Session session, Destination destination, Message response) throws JMSException {
  619   		MessageProducer producer = session.createProducer(destination);
  620   		try {
  621   			postProcessProducer(producer, response);
  622   			producer.send(response);
  623   		}
  624   		finally {
  625   			JmsUtils.closeMessageProducer(producer);
  626   		}
  627   	}
  628   
  629   	/**
  630   	 * Post-process the given message producer before using it to send the response.
  631   	 * <p>The default implementation is empty.
  632   	 * @param producer the JMS message producer that will be used to send the message
  633   	 * @param response the outgoing JMS message about to be sent
  634   	 * @throws JMSException if thrown by JMS API methods
  635   	 */
  636   	protected void postProcessProducer(MessageProducer producer, Message response) throws JMSException {
  637   	}
  638   
  639   
  640   	/**
  641   	 * Internal class combining a destination name
  642   	 * and its target destination type (queue or topic).
  643   	 */
  644   	private static class DestinationNameHolder {
  645   
  646   		public final String name;
  647   
  648   		public final boolean isTopic;
  649   
  650   		public DestinationNameHolder(String name, boolean isTopic) {
  651   			this.name = name;
  652   			this.isTopic = isTopic;
  653   		}
  654   	}
  655   
  656   }

Save This Page
Home » spring-framework-2.5.6-with-dependencies » org.springframework » jms » listener » adapter » [javadoc | source]