KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > jms > listener > adapter > MessageListenerAdapter


1 /*
2  * Copyright 2002-2007 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 JavaDoc;
20
21 import javax.jms.Destination JavaDoc;
22 import javax.jms.InvalidDestinationException JavaDoc;
23 import javax.jms.JMSException JavaDoc;
24 import javax.jms.Message JavaDoc;
25 import javax.jms.MessageListener JavaDoc;
26 import javax.jms.MessageProducer JavaDoc;
27 import javax.jms.Session JavaDoc;
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.support.JmsUtils;
34 import org.springframework.jms.support.converter.MessageConversionException;
35 import org.springframework.jms.support.converter.MessageConverter;
36 import org.springframework.jms.support.converter.SimpleMessageConverter;
37 import org.springframework.jms.support.destination.DestinationResolver;
38 import org.springframework.jms.support.destination.DynamicDestinationResolver;
39 import org.springframework.util.Assert;
40 import org.springframework.util.MethodInvoker;
41 import org.springframework.util.ObjectUtils;
42
43 /**
44  * Message listener adapter that delegates the handling of messages to target
45  * listener methods via reflection, with flexible message type conversion.
46  * Allows listener methods to operate on message content types, completely
47  * independent from the JMS API.
48  *
49  * <p>By default, the content of incoming JMS messages gets extracted before
50  * being passed into the target listener method, to let the target method
51  * operate on message content types such as String or byte array instead of
52  * the raw {@link Message}. Message type conversion is delegated to a Spring
53  * JMS {@link MessageConverter}. By default, a {@link SimpleMessageConverter}
54  * {@link org.springframework.jms.support.converter.SimpleMessageConverter102 (102)}
55  * will be used. (If you do not want such automatic message conversion taking
56  * place, then be sure to set the {@link #setMessageConverter MessageConverter}
57  * to <code>null</code>.)
58  *
59  * <p>If a target listener method returns a non-null object (typically of a
60  * message content type such as <code>String</code> or byte array), it will get
61  * wrapped in a JMS <code>Message</code> and sent to the response destination
62  * (either the JMS "reply-to" destination or a
63  * {@link #setDefaultResponseDestination(javax.jms.Destination) specified default
64  * destination}).
65  *
66  * <p><b>Note:</b> The sending of response messages is only available when
67  * using the {@link SessionAwareMessageListener} entry point (typically through a
68  * Spring message listener container). Usage as standard JMS {@link MessageListener}
69  * does <i>not</i> support the generation of response messages.
70  *
71  * <p>This class requires a JMS 1.1+ provider, because it builds on the
72  * domain-independent API. <b>Use the {@link MessageListenerAdapter102
73  * MessageListenerAdapter102} subclass for JMS 1.0.2 providers.</b>
74  *
75  * <p>Find below some examples of method signatures compliant with this
76  * adapter class. This first example handles all <code>Message</code> types
77  * and gets passed the contents of each <code>Message</code> type as an
78  * argument. No <code>Message</code> will be sent back as all of these
79  * methods return <code>void</code>.
80  *
81  * <pre class="code">public interface MessageContentsDelegate {
82  * void handleMessage(String text);
83  * void handleMessage(Map map);
84  * void handleMessage(byte[] bytes);
85  * void handleMessage(Serializable obj);
86  * }</pre>
87  *
88  * This next example handles all <code>Message</code> types and gets
89  * passed the actual (raw) <code>Message</code> as an argument. Again, no
90  * <code>Message</code> will be sent back as all of these methods return
91  * <code>void</code>.
92  *
93  * <pre class="code">public interface RawMessageDelegate {
94  * void handleMessage(TextMessage message);
95  * void handleMessage(MapMessage message);
96  * void handleMessage(BytesMessage message);
97  * void handleMessage(ObjectMessage message);
98  * }</pre>
99  *
100  * This next example illustrates a <code>Message</code> delegate
101  * that just consumes the <code>String</code> contents of
102  * {@link javax.jms.TextMessage TextMessages}. Notice also how the
103  * name of the <code>Message</code> handling method is different from the
104  * {@link #ORIGINAL_DEFAULT_LISTENER_METHOD original} (this will have to
105  * be configured in the attandant bean definition). Again, no <code>Message</code>
106  * will be sent back as the method returns <code>void</code>.
107  *
108  * <pre class="code">public interface TextMessageContentDelegate {
109  * void onMessage(String text);
110  * }</pre>
111  *
112  * This final example illustrates a <code>Message</code> delegate
113  * that just consumes the <code>String</code> contents of
114  * {@link javax.jms.TextMessage TextMessages}. Notice how the return type
115  * of this method is <code>String</code>: This will result in the configured
116  * {@link MessageListenerAdapter} sending a {@link javax.jms.TextMessage} in response.
117  *
118  * <pre class="code">public interface ResponsiveTextMessageContentDelegate {
119  * String handleMessage(String text);
120  * }</pre>
121  *
122  * For further examples and discussion please do refer to the Spring
123  * reference documentation which describes this class (and it's attendant
124  * XML configuration) in detail.
125  *
126  * @author Juergen Hoeller
127  * @since 2.0
128  * @see #setDelegate
129  * @see #setDefaultListenerMethod
130  * @see #setDefaultResponseDestination
131  * @see #setMessageConverter
132  * @see org.springframework.jms.support.converter.SimpleMessageConverter
133  * @see org.springframework.jms.listener.SessionAwareMessageListener
134  * @see org.springframework.jms.listener.AbstractMessageListenerContainer#setMessageListener
135  */

136 public class MessageListenerAdapter implements MessageListener JavaDoc, SessionAwareMessageListener {
137
138     /**
139      * Out-of-the-box value for the default listener method: "handleMessage".
140      */

141     public static final String JavaDoc ORIGINAL_DEFAULT_LISTENER_METHOD = "handleMessage";
142
143
144     /** Logger available to subclasses */
145     protected final Log logger = LogFactory.getLog(getClass());
146
147     private Object JavaDoc delegate;
148
149     private String JavaDoc defaultListenerMethod = ORIGINAL_DEFAULT_LISTENER_METHOD;
150
151     private Object JavaDoc defaultResponseDestination;
152
153     private DestinationResolver destinationResolver = new DynamicDestinationResolver();
154
155     private MessageConverter messageConverter;
156
157
158     /**
159      * Create a new {@link MessageListenerAdapter} with default settings.
160      */

161     public MessageListenerAdapter() {
162         initDefaultStrategies();
163         this.delegate = this;
164     }
165
166     /**
167      * Create a new {@link MessageListenerAdapter} for the given delegate.
168      */

169     public MessageListenerAdapter(Object JavaDoc delegate) {
170         initDefaultStrategies();
171         setDelegate(delegate);
172     }
173
174
175     /**
176      * Set a target object to delegate message listening to.
177      * Specified listener methods have to be present on this target object.
178      * <p>If no explicit delegate object has been specified, listener
179      * methods are expected to present on this adapter instance, that is,
180      * on a custom subclass of this adapter, defining listener methods.
181      */

182     public void setDelegate(Object JavaDoc delegate) {
183         Assert.notNull(delegate, "Delegate must not be null");
184         this.delegate = delegate;
185     }
186
187     /**
188      * Return the target object to delegate message listening to.
189      */

190     protected Object JavaDoc getDelegate() {
191         return this.delegate;
192     }
193
194     /**
195      * Specify the name of the default listener method to delegate to,
196      * for the case where no specific listener method has been determined.
197      * Out-of-the-box value is {@link #ORIGINAL_DEFAULT_LISTENER_METHOD "handleMessage"}.
198      * @see #getListenerMethodName
199      */

200     public void setDefaultListenerMethod(String JavaDoc defaultListenerMethod) {
201         this.defaultListenerMethod = defaultListenerMethod;
202     }
203
204     /**
205      * Return the name of the default listener method to delegate to.
206      */

207     protected String JavaDoc getDefaultListenerMethod() {
208         return this.defaultListenerMethod;
209     }
210
211     /**
212      * Set the default destination to send response messages to. This will be applied
213      * in case of a request message that does not carry a "JMSReplyTo" field.
214      * <p>Response destinations are only relevant for listener methods that return
215      * result objects, which will be wrapped in a response message and sent to a
216      * response destination.
217      * <p>Alternatively, specify a "defaultResponseQueueName" or "defaultResponseTopicName",
218      * to be dynamically resolved via the DestinationResolver.
219      * @see #setDefaultResponseQueueName(String)
220      * @see #setDefaultResponseTopicName(String)
221      * @see #getResponseDestination
222      */

223     public void setDefaultResponseDestination(Destination JavaDoc destination) {
224         this.defaultResponseDestination = destination;
225     }
226
227     /**
228      * Set the name of the default response queue to send response messages to.
229      * This will be applied in case of a request message that does not carry a
230      * "JMSReplyTo" field.
231      * <p>Alternatively, specify a JMS Destination object as "defaultResponseDestination".
232      * @see #setDestinationResolver
233      * @see #setDefaultResponseDestination(javax.jms.Destination)
234      */

235     public void setDefaultResponseQueueName(String JavaDoc destinationName) {
236         this.defaultResponseDestination = new DestinationNameHolder(destinationName, false);
237     }
238
239     /**
240      * Set the name of the default response topic to send response messages to.
241      * This will be applied in case of a request message that does not carry a
242      * "JMSReplyTo" field.
243      * <p>Alternatively, specify a JMS Destination object as "defaultResponseDestination".
244      * @see #setDestinationResolver
245      * @see #setDefaultResponseDestination(javax.jms.Destination)
246      */

247     public void setDefaultResponseTopicName(String JavaDoc destinationName) {
248         this.defaultResponseDestination = new DestinationNameHolder(destinationName, true);
249     }
250
251     /**
252      * Set the DestinationResolver that should be used to resolve response
253      * destination names for this adapter.
254      * <p>The default resolver is a DynamicDestinationResolver. Specify a
255      * JndiDestinationResolver for resolving destination names as JNDI locations.
256      * @see org.springframework.jms.support.destination.DynamicDestinationResolver
257      * @see org.springframework.jms.support.destination.JndiDestinationResolver
258      */

259     public void setDestinationResolver(DestinationResolver destinationResolver) {
260         Assert.notNull(destinationResolver, "DestinationResolver must not be null");
261         this.destinationResolver = destinationResolver;
262     }
263
264     /**
265      * Return the DestinationResolver for this adapter.
266      */

267     protected DestinationResolver getDestinationResolver() {
268         return this.destinationResolver;
269     }
270
271     /**
272      * Set the converter that will convert incoming JMS messages to
273      * listener method arguments, and objects returned from listener
274      * methods back to JMS messages.
275      * <p>The default converter is a {@link SimpleMessageConverter}, which is able
276      * to handle {@link javax.jms.BytesMessage BytesMessages},
277      * {@link javax.jms.TextMessage TextMessages} and
278      * {@link javax.jms.ObjectMessage ObjectMessages}.
279      */

280     public void setMessageConverter(MessageConverter messageConverter) {
281         this.messageConverter = messageConverter;
282     }
283
284     /**
285      * Return the converter that will convert incoming JMS messages to
286      * listener method arguments, and objects returned from listener
287      * methods back to JMS messages.
288      */

289     protected MessageConverter getMessageConverter() {
290         return this.messageConverter;
291     }
292
293
294     /**
295      * Standard JMS {@link MessageListener} entry point.
296      * <p>Delegates the message to the target listener method, with appropriate
297      * conversion of the message argument. In case of an exception, the
298      * {@link #handleListenerException(Throwable)} method will be invoked.
299      * <p><b>Note:</b> Does not support sending response messages based on
300      * result objects returned from listener methods. Use the
301      * {@link SessionAwareMessageListener} entry point (typically through a Spring
302      * message listener container) for handling result objects as well.
303      * @param message the incoming JMS message
304      * @see #handleListenerException
305      * @see #onMessage(javax.jms.Message, javax.jms.Session)
306      */

307     public void onMessage(Message JavaDoc message) {
308         try {
309             onMessage(message, null);
310         }
311         catch (Throwable JavaDoc ex) {
312             handleListenerException(ex);
313         }
314     }
315
316     /**
317      * Spring {@link SessionAwareMessageListener} entry point.
318      * <p>Delegates the message to the target listener method, with appropriate
319      * conversion of the message argument. If the target method returns a
320      * non-null object, wrap in a JMS message and send it back.
321      * @param message the incoming JMS message
322      * @param session the JMS session to operate on
323      * @throws JMSException if thrown by JMS API methods
324      */

325     public void onMessage(Message JavaDoc message, Session JavaDoc session) throws JMSException JavaDoc {
326         Object JavaDoc convertedMessage = extractMessage(message);
327         String JavaDoc methodName = getListenerMethodName(message, convertedMessage);
328
329         if (methodName == null) {
330             Object JavaDoc 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 JavaDoc)) {
338                         throw new javax.jms.IllegalStateException JavaDoc("MessageListenerAdapter cannot handle a " +
339                                 "SessionAwareMessageListener delegate if it hasn't been invoked with a Session itself");
340                     }
341                 }
342                 if (delegate instanceof MessageListener JavaDoc) {
343                     ((MessageListener JavaDoc) delegate).onMessage(message);
344                     return;
345                 }
346             }
347             throw new javax.jms.IllegalStateException JavaDoc("No default listener method specified: " +
348                     "Either specify a non-null value for the 'defaultListenerMethod' property or " +
349                     "override the 'getListenerMethodName' method.");
350         }
351
352         Object JavaDoc[] listenerArguments = buildListenerArguments(convertedMessage);
353         Object JavaDoc result = invokeListenerMethod(methodName, listenerArguments);
354         if (result != null) {
355             handleResult(result, message, session);
356         }
357         else {
358             logger.debug("No result object given - no result to handle");
359         }
360     }
361
362
363     /**
364      * Initialize the default implementations for the adapter's strategies.
365      * @see #setMessageConverter
366      * @see org.springframework.jms.support.converter.SimpleMessageConverter
367      */

368     protected void initDefaultStrategies() {
369         setMessageConverter(new SimpleMessageConverter());
370     }
371
372     /**
373      * Handle the given exception that arose during listener execution.
374      * The default implementation logs the exception at error level.
375      * <p>This method only applies when used as standard JMS {@link MessageListener}.
376      * In case of the Spring {@link SessionAwareMessageListener} mechanism,
377      * exceptions get handled by the caller instead.
378      * @param ex the exception to handle
379      * @see #onMessage(javax.jms.Message)
380      */

381     protected void handleListenerException(Throwable JavaDoc ex) {
382         logger.error("Listener execution failed", ex);
383     }
384
385     /**
386      * Extract the message body from the given JMS message.
387      * @param message the JMS <code>Message</code>
388      * @return the content of the message, to be passed into the
389      * listener method as argument
390      * @throws JMSException if thrown by JMS API methods
391      */

392     protected Object JavaDoc extractMessage(Message JavaDoc message) throws JMSException JavaDoc {
393         MessageConverter converter = getMessageConverter();
394         if (converter != null) {
395             return converter.fromMessage(message);
396         }
397         return message;
398     }
399
400     /**
401      * Determine the name of the listener method that is supposed to
402      * handle the given message.
403      * <p>The default implementation simply returns the configured
404      * default listener method, if any.
405      * @param originalMessage the JMS request message
406      * @param extractedMessage the converted JMS request message,
407      * to be passed into the listener method as argument
408      * @return the name of the listener method (never <code>null</code>)
409      * @throws JMSException if thrown by JMS API methods
410      * @see #setDefaultListenerMethod
411      */

412     protected String JavaDoc getListenerMethodName(Message JavaDoc originalMessage, Object JavaDoc extractedMessage) throws JMSException JavaDoc {
413         return getDefaultListenerMethod();
414     }
415
416     /**
417      * Build an array of arguments to be passed into the target listener method.
418      * Allows for multiple method arguments to be built from a single message object.
419      * <p>The default implementation builds an array with the given message object
420      * as sole element. This means that the extracted message will always be passed
421      * into a <i>single</i> method argument, even if it is an array, with the target
422      * method having a corresponding single argument of the array's type declared.
423      * <p>This can be overridden to treat special message content such as arrays
424      * differently, for example passing in each element of the message array
425      * as distinct method argument.
426      * @param extractedMessage the content of the message
427      * @return the array of arguments to be passed into the
428      * listener method (each element of the array corresponding
429      * to a distinct method argument)
430      */

431     protected Object JavaDoc[] buildListenerArguments(Object JavaDoc extractedMessage) {
432         return new Object JavaDoc[] {extractedMessage};
433     }
434
435     /**
436      * Invoke the specified listener method.
437      * @param methodName the name of the listener method
438      * @param arguments the message arguments to be passed in
439      * @return the result returned from the listener method
440      * @throws JMSException if thrown by JMS API methods
441      * @see #getListenerMethodName
442      * @see #buildListenerArguments
443      */

444     protected Object JavaDoc invokeListenerMethod(String JavaDoc methodName, Object JavaDoc[] arguments) throws JMSException JavaDoc {
445         try {
446             MethodInvoker methodInvoker = new MethodInvoker();
447             methodInvoker.setTargetObject(getDelegate());
448             methodInvoker.setTargetMethod(methodName);
449             methodInvoker.setArguments(arguments);
450             methodInvoker.prepare();
451             return methodInvoker.invoke();
452         }
453         catch (InvocationTargetException JavaDoc ex) {
454             throw new ListenerExecutionFailedException(
455                     "Listener method '" + methodName + "' threw exception", ex.getTargetException());
456         }
457         catch (Throwable JavaDoc ex) {
458             throw new ListenerExecutionFailedException("Failed to invoke target method '" + methodName +
459                     "' with arguments " + ObjectUtils.nullSafeToString(arguments), ex);
460         }
461     }
462
463
464     /**
465      * Handle the given result object returned from the listener method,
466      * sending a response message back.
467      * @param result the result object to handle (never <code>null</code>)
468      * @param request the original request message
469      * @param session the JMS Session to operate on (may be <code>null</code>)
470      * @throws JMSException if thrown by JMS API methods
471      * @see #buildMessage
472      * @see #postProcessResponse
473      * @see #getResponseDestination
474      * @see #sendResponse
475      */

476     protected void handleResult(Object JavaDoc result, Message JavaDoc request, Session JavaDoc session) throws JMSException JavaDoc {
477         if (session != null) {
478             if (logger.isDebugEnabled()) {
479                 logger.debug("Listener method returned result [" + result +
480                         "] - generating response message for it");
481             }
482             Message JavaDoc response = buildMessage(session, result);
483             postProcessResponse(request, response);
484             Destination JavaDoc destination = getResponseDestination(request, response, session);
485             sendResponse(session, destination, response);
486         }
487         else {
488             if (logger.isDebugEnabled()) {
489                 logger.debug("Listener method returned result [" + result +
490                         "]: not generating response message for it because of no JMS Session given");
491             }
492         }
493     }
494
495     /**
496      * Build a JMS message to be sent as response based on the given result object.
497      * @param session the JMS Session to operate on
498      * @param result the content of the message, as returned from the listener method
499      * @return the JMS <code>Message</code> (never <code>null</code>)
500      * @throws JMSException if thrown by JMS API methods
501      * @see #setMessageConverter
502      */

503     protected Message JavaDoc buildMessage(Session JavaDoc session, Object JavaDoc result) throws JMSException JavaDoc {
504         MessageConverter converter = getMessageConverter();
505         if (converter != null) {
506             return converter.toMessage(result, session);
507         }
508         else {
509             if (!(result instanceof Message JavaDoc)) {
510                 throw new MessageConversionException(
511                         "No MessageConverter specified - cannot handle message [" + result + "]");
512             }
513             return (Message JavaDoc) result;
514         }
515     }
516
517     /**
518      * Post-process the given response message before it will be sent.
519      * <p>The default implementation sets the response's correlation id
520      * to the request message's correlation id.
521      * @param request the original incoming JMS message
522      * @param response the outgoing JMS message about to be sent
523      * @throws JMSException if thrown by JMS API methods
524      * @see javax.jms.Message#setJMSCorrelationID
525      */

526     protected void postProcessResponse(Message JavaDoc request, Message JavaDoc response) throws JMSException JavaDoc {
527         response.setJMSCorrelationID(request.getJMSCorrelationID());
528     }
529
530     /**
531      * Determine a response destination for the given message.
532      * <p>The default implementation first checks the JMS Reply-To
533      * {@link Destination} of the supplied request; if that is not <code>null</code>
534      * it is returned; if it is <code>null</code>, then the configured
535      * {@link #resolveDefaultResponseDestination default response destination}
536      * is returned; if this too is <code>null</code>, then an
537      * {@link InvalidDestinationException} is thrown.
538      * @param request the original incoming JMS message
539      * @param response the outgoing JMS message about to be sent
540      * @param session the JMS Session to operate on
541      * @return the response destination (never <code>null</code>)
542      * @throws JMSException if thrown by JMS API methods
543      * @throws InvalidDestinationException if no {@link Destination} can be determined
544      * @see #setDefaultResponseDestination
545      * @see javax.jms.Message#getJMSReplyTo()
546      */

547     protected Destination JavaDoc getResponseDestination(Message JavaDoc request, Message JavaDoc response, Session JavaDoc session)
548             throws JMSException JavaDoc {
549
550         Destination JavaDoc replyTo = request.getJMSReplyTo();
551         if (replyTo == null) {
552             replyTo = resolveDefaultResponseDestination(session);
553             if (replyTo == null) {
554                 throw new InvalidDestinationException JavaDoc("Cannot determine response destination: " +
555                         "Request message does not contain reply-to destination, and no default response destination set.");
556             }
557         }
558         return replyTo;
559     }
560
561     /**
562      * Resolve the default response destination into a JMS {@link Destination}, using this
563      * accessor's {@link DestinationResolver} in case of a destination name.
564      * @return the located {@link Destination}
565      * @throws javax.jms.JMSException if resolution failed
566      * @see #setDefaultResponseDestination
567      * @see #setDefaultResponseQueueName
568      * @see #setDefaultResponseTopicName
569      * @see #setDestinationResolver
570      */

571     protected Destination JavaDoc resolveDefaultResponseDestination(Session JavaDoc session) throws JMSException JavaDoc {
572         if (this.defaultResponseDestination instanceof Destination JavaDoc) {
573             return (Destination JavaDoc) this.defaultResponseDestination;
574         }
575         if (this.defaultResponseDestination instanceof DestinationNameHolder) {
576             DestinationNameHolder nameHolder = (DestinationNameHolder) this.defaultResponseDestination;
577             return getDestinationResolver().resolveDestinationName(session, nameHolder.name, nameHolder.isTopic);
578         }
579         return null;
580     }
581
582     /**
583      * Send the given response message to the given destination.
584      * @param response the JMS message to send
585      * @param destination the JMS destination to send to
586      * @param session the JMS session to operate on
587      * @throws JMSException if thrown by JMS API methods
588      * @see #postProcessProducer
589      * @see javax.jms.Session#createProducer
590      * @see javax.jms.MessageProducer#send
591      */

592     protected void sendResponse(Session JavaDoc session, Destination JavaDoc destination, Message JavaDoc response) throws JMSException JavaDoc {
593         MessageProducer JavaDoc producer = session.createProducer(destination);
594         try {
595             postProcessProducer(producer, response);
596             producer.send(response);
597         }
598         finally {
599             JmsUtils.closeMessageProducer(producer);
600         }
601     }
602
603     /**
604      * Post-process the given message producer before using it to send the response.
605      * <p>The default implementation is empty.
606      * @param producer the JMS message producer that will be used to send the message
607      * @param response the outgoing JMS message about to be sent
608      * @throws JMSException if thrown by JMS API methods
609      */

610     protected void postProcessProducer(MessageProducer JavaDoc producer, Message JavaDoc response) throws JMSException JavaDoc {
611     }
612
613
614     /**
615      * Internal class combining a destination name
616      * and its target destination type (queue or topic).
617      */

618     private static class DestinationNameHolder {
619
620         public final String JavaDoc name;
621
622         public final boolean isTopic;
623
624         public DestinationNameHolder(String JavaDoc name, boolean isTopic) {
625             this.name = name;
626             this.isTopic = isTopic;
627         }
628     }
629
630 }
631
Popular Tags