001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.jms.core;
018:
019: import javax.jms.Connection;
020: import javax.jms.ConnectionFactory;
021: import javax.jms.Destination;
022: import javax.jms.JMSException;
023: import javax.jms.Message;
024: import javax.jms.MessageConsumer;
025: import javax.jms.MessageProducer;
026: import javax.jms.Queue;
027: import javax.jms.QueueConnection;
028: import javax.jms.QueueConnectionFactory;
029: import javax.jms.QueueSender;
030: import javax.jms.QueueSession;
031: import javax.jms.Session;
032: import javax.jms.Topic;
033: import javax.jms.TopicConnection;
034: import javax.jms.TopicConnectionFactory;
035: import javax.jms.TopicPublisher;
036: import javax.jms.TopicSession;
037:
038: import org.springframework.jms.connection.JmsResourceHolder;
039: import org.springframework.jms.support.converter.SimpleMessageConverter102;
040:
041: /**
042: * A subclass of {@link JmsTemplate} for the JMS 1.0.2 specification, not relying
043: * on JMS 1.1 methods like JmsTemplate itself. This class can be used for JMS
044: * 1.0.2 providers, offering the same API as JmsTemplate does for JMS 1.1 providers.
045: *
046: * <p>You must specify the domain (or style) of messaging to be either
047: * Point-to-Point (Queues) or Publish/Subscribe (Topics), using the
048: * {@link #setPubSubDomain "pubSubDomain" property}.
049: * Point-to-Point (Queues) is the default domain.
050: *
051: * <p>The "pubSubDomain" property is an important setting due to the use of similar
052: * but separate class hierarchies in the JMS 1.0.2 API. JMS 1.1 provides a new
053: * domain-independent API that allows for easy mix-and-match use of Point-to-Point
054: * and Publish/Subscribe styles.
055: *
056: * <p>This template uses a
057: * {@link org.springframework.jms.support.destination.DynamicDestinationResolver}
058: * and a {@link org.springframework.jms.support.converter.SimpleMessageConverter102}
059: * as default strategies for resolving a destination name and converting a message,
060: * respectively.
061: *
062: * @author Mark Pollack
063: * @author Juergen Hoeller
064: * @since 1.1
065: * @see #setConnectionFactory
066: * @see #setPubSubDomain
067: * @see javax.jms.Queue
068: * @see javax.jms.Topic
069: * @see javax.jms.QueueSession
070: * @see javax.jms.TopicSession
071: * @see javax.jms.QueueSender
072: * @see javax.jms.TopicPublisher
073: * @see javax.jms.QueueReceiver
074: * @see javax.jms.TopicSubscriber
075: */
076: public class JmsTemplate102 extends JmsTemplate {
077:
078: /**
079: * Create a new JmsTemplate102 for bean-style usage.
080: * <p>Note: The ConnectionFactory has to be set before using the instance.
081: * This constructor can be used to prepare a JmsTemplate via a BeanFactory,
082: * typically setting the ConnectionFactory via setConnectionFactory.
083: * @see #setConnectionFactory
084: */
085: public JmsTemplate102() {
086: super ();
087: }
088:
089: /**
090: * Create a new JmsTemplate102, given a ConnectionFactory.
091: * @param connectionFactory the ConnectionFactory to obtain Connections from
092: * @param pubSubDomain whether the Publish/Subscribe domain (Topics) or
093: * Point-to-Point domain (Queues) should be used
094: * @see #setPubSubDomain
095: */
096: public JmsTemplate102(ConnectionFactory connectionFactory,
097: boolean pubSubDomain) {
098: this ();
099: setConnectionFactory(connectionFactory);
100: setPubSubDomain(pubSubDomain);
101: afterPropertiesSet();
102: }
103:
104: /**
105: * Initialize the default implementations for the template's strategies:
106: * DynamicDestinationResolver and SimpleMessageConverter102.
107: * @see #setDestinationResolver
108: * @see #setMessageConverter
109: * @see org.springframework.jms.support.destination.DynamicDestinationResolver
110: * @see org.springframework.jms.support.converter.SimpleMessageConverter102
111: */
112: protected void initDefaultStrategies() {
113: setMessageConverter(new SimpleMessageConverter102());
114: }
115:
116: /**
117: * In addition to checking if the connection factory is set, make sure
118: * that the supplied connection factory is of the appropriate type for
119: * the specified destination type: QueueConnectionFactory for queues,
120: * and TopicConnectionFactory for topics.
121: */
122: public void afterPropertiesSet() {
123: super .afterPropertiesSet();
124:
125: // Make sure that the ConnectionFactory passed is consistent.
126: // Some provider implementations of the ConnectionFactory interface
127: // implement both domain interfaces under the cover, so just check if
128: // the selected domain is consistent with the type of connection factory.
129: if (isPubSubDomain()) {
130: if (!(getConnectionFactory() instanceof TopicConnectionFactory)) {
131: throw new IllegalArgumentException(
132: "Specified a Spring JMS 1.0.2 template for topics "
133: + "but did not supply an instance of TopicConnectionFactory");
134: }
135: } else {
136: if (!(getConnectionFactory() instanceof QueueConnectionFactory)) {
137: throw new IllegalArgumentException(
138: "Specified a Spring JMS 1.0.2 template for queues "
139: + "but did not supply an instance of QueueConnectionFactory");
140: }
141: }
142: }
143:
144: /**
145: * This implementation overrides the superclass method to accept either
146: * a QueueConnection or a TopicConnection, depending on the domain.
147: */
148: protected Connection getConnection(JmsResourceHolder holder) {
149: return holder
150: .getConnection(isPubSubDomain() ? (Class) TopicConnection.class
151: : QueueConnection.class);
152: }
153:
154: /**
155: * This implementation overrides the superclass method to accept either
156: * a QueueSession or a TopicSession, depending on the domain.
157: */
158: protected Session getSession(JmsResourceHolder holder) {
159: return holder
160: .getSession(isPubSubDomain() ? (Class) TopicSession.class
161: : QueueSession.class);
162: }
163:
164: /**
165: * This implementation overrides the superclass method to use JMS 1.0.2 API.
166: */
167: protected Connection createConnection() throws JMSException {
168: if (isPubSubDomain()) {
169: return ((TopicConnectionFactory) getConnectionFactory())
170: .createTopicConnection();
171: } else {
172: return ((QueueConnectionFactory) getConnectionFactory())
173: .createQueueConnection();
174: }
175: }
176:
177: /**
178: * This implementation overrides the superclass method to use JMS 1.0.2 API.
179: */
180: protected Session createSession(Connection con) throws JMSException {
181: if (isPubSubDomain()) {
182: return ((TopicConnection) con).createTopicSession(
183: isSessionTransacted(), getSessionAcknowledgeMode());
184: } else {
185: return ((QueueConnection) con).createQueueSession(
186: isSessionTransacted(), getSessionAcknowledgeMode());
187: }
188: }
189:
190: /**
191: * This implementation overrides the superclass method to use JMS 1.0.2 API.
192: */
193: protected MessageProducer doCreateProducer(Session session,
194: Destination destination) throws JMSException {
195: if (isPubSubDomain()) {
196: return ((TopicSession) session)
197: .createPublisher((Topic) destination);
198: } else {
199: return ((QueueSession) session)
200: .createSender((Queue) destination);
201: }
202: }
203:
204: /**
205: * This implementation overrides the superclass method to use JMS 1.0.2 API.
206: */
207: protected MessageConsumer createConsumer(Session session,
208: Destination destination, String messageSelector)
209: throws JMSException {
210:
211: if (isPubSubDomain()) {
212: return ((TopicSession) session).createSubscriber(
213: (Topic) destination, messageSelector,
214: isPubSubNoLocal());
215: } else {
216: return ((QueueSession) session).createReceiver(
217: (Queue) destination, messageSelector);
218: }
219: }
220:
221: /**
222: * This implementation overrides the superclass method to use JMS 1.0.2 API.
223: */
224: protected void doSend(MessageProducer producer, Message message)
225: throws JMSException {
226: if (isPubSubDomain()) {
227: if (isExplicitQosEnabled()) {
228: ((TopicPublisher) producer).publish(message,
229: getDeliveryMode(), getPriority(),
230: getTimeToLive());
231: } else {
232: ((TopicPublisher) producer).publish(message);
233: }
234: } else {
235: if (isExplicitQosEnabled()) {
236: ((QueueSender) producer).send(message,
237: getDeliveryMode(), getPriority(),
238: getTimeToLive());
239: } else {
240: ((QueueSender) producer).send(message);
241: }
242: }
243: }
244:
245: /**
246: * This implementation overrides the superclass method to avoid using
247: * JMS 1.1's Session <code>getAcknowledgeMode()</code> method.
248: * The best we can do here is to check the setting on the template.
249: * @see #getSessionAcknowledgeMode()
250: */
251: protected boolean isClientAcknowledge(Session session)
252: throws JMSException {
253: return (getSessionAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
254: }
255:
256: }
|