001 package com.mockrunner.mock.jms;
002
003 import java.io.Serializable;
004 import java.util.ArrayList;
005 import java.util.Collections;
006 import java.util.List;
007
008 import javax.jms.BytesMessage;
009 import javax.jms.Destination;
010 import javax.jms.InvalidDestinationException;
011 import javax.jms.JMSException;
012 import javax.jms.MapMessage;
013 import javax.jms.Message;
014 import javax.jms.MessageConsumer;
015 import javax.jms.MessageListener;
016 import javax.jms.MessageProducer;
017 import javax.jms.ObjectMessage;
018 import javax.jms.Queue;
019 import javax.jms.QueueBrowser;
020 import javax.jms.Session;
021 import javax.jms.StreamMessage;
022 import javax.jms.TemporaryQueue;
023 import javax.jms.TemporaryTopic;
024 import javax.jms.TextMessage;
025 import javax.jms.Topic;
026 import javax.jms.TopicSubscriber;
027
028 import com.mockrunner.jms.GenericTransmissionManager;
029 import com.mockrunner.jms.MessageManager;
030 import com.mockrunner.jms.QueueTransmissionManager;
031 import com.mockrunner.jms.TopicTransmissionManager;
032 import com.mockrunner.jms.TransmissionManagerWrapper;
033
034 /**
035 * Mock implementation of JMS <code>Session</code>.
036 *
037 * Please note that this implementation does not
038 * implement transaction isolation at the moment.
039 * Messages are immediately sent. If acknowledge
040 * mode is AUTO_ACKNOWLEDGE or DUPS_OK_ACKNOWLEDGE,
041 * the message will be automatically acknowledged,
042 * otherwise, it will not be acknowledged. According
043 * to JMS specification, the acknowledged mode must
044 * be ignored for transacted sessions. This is currently
045 * not implemented, i.e. transacted sessions behave like
046 * sessions with acknowledge mode AUTO_ACKNOWLEDGE.
047 * Messages are acknowledged even if the transaction is
048 * rolled back. However, the framework keeps track if a
049 * transaction is committed or rolled back, so you can test
050 * this and rely on the container for the rest.
051 * You can set a <code>MessageListener</code> directly to
052 * the session. This is an application server internal feature
053 * and not meant for application use in JMS.
054 * This mock session dispatches any message of any
055 * known <code>Queue</code> and <code>Topic</code> to the
056 * distinguished <code>MessageListener</code>, if such
057 * a <code>MessageListener</code> is registered.
058 */
059 public class MockSession implements Session
060 {
061 private MockConnection connection;
062 private QueueTransmissionManager queueTransManager;
063 private TopicTransmissionManager topicTransManager;
064 private GenericTransmissionManager genericTransManager;
065 private TransmissionManagerWrapper transManager;
066 private MessageManager messageManager;
067 private MessageListener messageListener;
068 private List tempQueues;
069 private List tempTopics;
070 private boolean transacted;
071 private int acknowledgeMode;
072 private int numberCommits;
073 private int numberRollbacks;
074 private boolean recovered;
075 private boolean closed;
076
077 public MockSession(MockConnection connection, boolean transacted, int acknowledgeMode)
078 {
079 this.connection = connection;
080 this.transacted = transacted;
081 this.acknowledgeMode = acknowledgeMode;
082 queueTransManager = new QueueTransmissionManager(connection, this);
083 topicTransManager = new TopicTransmissionManager(connection, this);
084 genericTransManager = new GenericTransmissionManager(connection, this);
085 transManager = new TransmissionManagerWrapper(queueTransManager, topicTransManager, genericTransManager);
086 messageManager = new MessageManager();
087 tempQueues = new ArrayList();
088 tempTopics = new ArrayList();
089 messageListener = null;
090 numberCommits = 0;
091 numberRollbacks = 0;
092 recovered = false;
093 closed = false;
094 }
095
096 /**
097 * Returns the {@link com.mockrunner.jms.QueueTransmissionManager}.
098 * @return the {@link com.mockrunner.jms.QueueTransmissionManager}
099 */
100 public QueueTransmissionManager getQueueTransmissionManager()
101 {
102 return queueTransManager;
103 }
104
105 /**
106 * Returns the {@link com.mockrunner.jms.TopicTransmissionManager}.
107 * @return the {@link com.mockrunner.jms.TopicTransmissionManager}
108 */
109 public TopicTransmissionManager getTopicTransmissionManager()
110 {
111 return topicTransManager;
112 }
113
114 /**
115 * Returns the {@link com.mockrunner.jms.GenericTransmissionManager}.
116 * @return the {@link com.mockrunner.jms.GenericTransmissionManager}
117 */
118 public GenericTransmissionManager getGenericTransmissionManager()
119 {
120 return genericTransManager;
121 }
122
123 /**
124 * @deprecated use {@link #getTransmissionManagerWrapper}
125 */
126 public TransmissionManagerWrapper getTransmissionManager()
127 {
128 return getTransmissionManagerWrapper();
129 }
130
131 /**
132 * Returns the {@link com.mockrunner.jms.TransmissionManagerWrapper}.
133 * @return the {@link com.mockrunner.jms.TransmissionManagerWrapper}
134 */
135 public TransmissionManagerWrapper getTransmissionManagerWrapper()
136 {
137 return transManager;
138 }
139
140 /**
141 * Returns the {@link MessageManager} for this session.
142 * @return the {@link MessageManager}
143 */
144 public MessageManager getMessageManager()
145 {
146 return messageManager;
147 }
148
149 /**
150 * Returns the list of temporary queues.
151 * @return the <code>TemporaryQueue</code> list
152 */
153 public List getTemporaryQueueList()
154 {
155 return Collections.unmodifiableList(tempQueues);
156 }
157
158 /**
159 * Returns a <code>TemporaryQueue</code> by its index. The
160 * index represent the number of the queue. Returns <code>null</code>
161 * if no such <code>TemporaryQueue</code> is present.
162 * @param index the index
163 * @return the <code>TemporaryQueue</code>
164 */
165 public MockTemporaryQueue getTemporaryQueue(int index)
166 {
167 if(tempQueues.size() <= index || index < 0) return null;
168 return (MockTemporaryQueue)tempQueues.get(index);
169 }
170
171 /**
172 * Returns the list of temporary topics.
173 * @return the <code>TemporaryTopic</code> list
174 */
175 public List getTemporaryTopicList()
176 {
177 return Collections.unmodifiableList(tempTopics);
178 }
179
180 /**
181 * Returns a <code>TemporaryTopic</code> by its index. The
182 * index represent the number of the topic. Returns <code>null</code>
183 * if no such <code>TemporaryTopic</code> is present.
184 * @param index the index
185 * @return the <code>TemporaryTopic</code>
186 */
187 public MockTemporaryTopic getTemporaryTopic(int index)
188 {
189 if(tempTopics.size() <= index || index < 0) return null;
190 return (MockTemporaryTopic)tempTopics.get(index);
191 }
192
193 /**
194 * Returns if this session was closed.
195 * @return <code>true</code> if this session is closed
196 */
197 public boolean isClosed()
198 {
199 return closed;
200 }
201
202 /**
203 * Returns if this session was recovered.
204 * @return <code>true</code> if this session was recovered
205 */
206 public boolean isRecovered()
207 {
208 return recovered;
209 }
210
211 /**
212 * Returns if the current transaction was committed.
213 * @return <code>true</code> if the transaction was committed
214 */
215 public boolean isCommitted()
216 {
217 return (numberCommits > 0);
218 }
219
220 /**
221 * Returns the number of commits.
222 * @return the number of commits
223 */
224 public int getNumberCommits()
225 {
226 return numberCommits;
227 }
228
229 /**
230 * Returns if the current transaction was rolled back.
231 * @return <code>true</code> if the transaction was rolled back
232 */
233 public boolean isRolledBack()
234 {
235 return (numberRollbacks > 0);
236 }
237
238 /**
239 * Returns the number of rollbacks.
240 * @return the number of rollbacks
241 */
242 public int getNumberRollbacks()
243 {
244 return numberRollbacks;
245 }
246
247 /**
248 * Returns if messages should be automatically acknowledged,
249 * i.e. if the acknowledge mode is not <code>CLIENT_ACKNOWLEDGE</code>.
250 * @return <code>true</code> if messages are automatically acknowledged
251 */
252 public boolean isAutoAcknowledge()
253 {
254 return acknowledgeMode != CLIENT_ACKNOWLEDGE;
255 }
256
257 /**
258 * Note: Returns <code>0</code> if the session is transacted.
259 * This method does not exist in JMS 1.0.2. In JMS 1.1 it
260 * should return <code>Session.SESSION_TRANSACTED</code>
261 * which is specified as <code>0</code>. In order to avoid
262 * different versions for JMS 1.0.2 and 1.1
263 * (<code>Session.SESSION_TRANSACTED</code> does not
264 * exist in 1.0.2) this method returns hardcoded <code>0</code>,
265 * if the session is transacted.
266 * @return the acknowledge mode
267 */
268 public int getAcknowledgeMode() throws JMSException
269 {
270 if(getTransacted()) return 0;
271 return acknowledgeMode;
272 }
273
274 public boolean getTransacted() throws JMSException
275 {
276 connection.throwJMSException();
277 return transacted;
278 }
279
280 public BytesMessage createBytesMessage() throws JMSException
281 {
282 connection.throwJMSException();
283 return getMessageManager().createBytesMessage();
284 }
285
286 public MapMessage createMapMessage() throws JMSException
287 {
288 connection.throwJMSException();
289 return getMessageManager().createMapMessage();
290 }
291
292 public Message createMessage() throws JMSException
293 {
294 connection.throwJMSException();
295 return getMessageManager().createMessage();
296 }
297
298 public ObjectMessage createObjectMessage() throws JMSException
299 {
300 connection.throwJMSException();
301 return createObjectMessage(null);
302 }
303
304 public ObjectMessage createObjectMessage(Serializable object) throws JMSException
305 {
306 connection.throwJMSException();
307 return getMessageManager().createObjectMessage(object);
308 }
309
310 public StreamMessage createStreamMessage() throws JMSException
311 {
312 connection.throwJMSException();
313 return getMessageManager().createStreamMessage();
314 }
315
316 public TextMessage createTextMessage() throws JMSException
317 {
318 connection.throwJMSException();
319 return createTextMessage(null);
320 }
321
322 public TextMessage createTextMessage(String text) throws JMSException
323 {
324 connection.throwJMSException();
325 return getMessageManager().createTextMessage(text);
326 }
327
328 public MessageListener getMessageListener() throws JMSException
329 {
330 connection.throwJMSException();
331 return messageListener;
332 }
333
334 public void setMessageListener(MessageListener messageListener) throws JMSException
335 {
336 connection.throwJMSException();
337 this.messageListener = messageListener;
338 }
339
340 public void run()
341 {
342
343 }
344
345 public void commit() throws JMSException
346 {
347 connection.throwJMSException();
348 numberCommits++;
349 }
350
351 public void rollback() throws JMSException
352 {
353 connection.throwJMSException();
354 recover();
355 numberRollbacks++;
356 }
357
358 public void close() throws JMSException
359 {
360 connection.throwJMSException();
361 if(getTransacted() && !isCommitted())
362 {
363 rollback();
364 }
365 getQueueTransmissionManager().closeAll();
366 getTopicTransmissionManager().closeAll();
367 getGenericTransmissionManager().closeAll();
368 closed = true;
369 }
370
371 public void recover() throws JMSException
372 {
373 connection.throwJMSException();
374 recovered = true;
375 }
376
377 public void unsubscribe(String name) throws JMSException
378 {
379 getConnection().throwJMSException();
380 topicTransManager.removeTopicDurableSubscriber(name);
381 }
382
383 public Queue createQueue(String name) throws JMSException
384 {
385 getConnection().throwJMSException();
386 MockQueue queue = ((MockConnection)getConnection()).getDestinationManager().getQueue(name);
387 if(null == queue)
388 {
389 throw new JMSException("Queue with name " + name + " not found");
390 }
391 addSessionToQueue(queue);
392 return queue;
393 }
394
395 public TemporaryQueue createTemporaryQueue() throws JMSException
396 {
397 getConnection().throwJMSException();
398 MockTemporaryQueue queue = new MockTemporaryQueue();
399 tempQueues.add(queue);
400 addSessionToQueue(queue);
401 return queue;
402 }
403
404 public Topic createTopic(String name) throws JMSException
405 {
406 getConnection().throwJMSException();
407 MockTopic topic = ((MockConnection)getConnection()).getDestinationManager().getTopic(name);
408 if(null == topic)
409 {
410 throw new JMSException("Topic with name " + name + " not found");
411 }
412 addSessionToTopic(topic);
413 return topic;
414 }
415
416 public TemporaryTopic createTemporaryTopic() throws JMSException
417 {
418 getConnection().throwJMSException();
419 MockTemporaryTopic topic = new MockTemporaryTopic();
420 tempTopics.add(topic);
421 addSessionToTopic(topic);
422 return topic;
423 }
424
425 public MessageConsumer createConsumer(Destination destination) throws JMSException
426 {
427 getConnection().throwJMSException();
428 return createConsumer(destination, null);
429 }
430
431 public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException
432 {
433 getConnection().throwJMSException();
434 return createConsumer(destination, messageSelector, false);
435 }
436
437 public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean noLocal) throws JMSException
438 {
439 if(null == destination)
440 {
441 throw new IllegalArgumentException("destination must not be null");
442 }
443 getConnection().throwJMSException();
444 if(destination instanceof MockQueue)
445 {
446 addSessionToQueue((Queue)destination);
447 return getQueueTransmissionManager().createQueueReceiver((MockQueue)destination, messageSelector);
448 }
449 else if(destination instanceof MockTopic)
450 {
451 addSessionToTopic((Topic)destination);
452 return getTopicTransmissionManager().createTopicSubscriber((MockTopic)destination, messageSelector, noLocal);
453 }
454 else
455 {
456 throw new InvalidDestinationException("destination must be an instance of MockQueue or MockTopic");
457 }
458 }
459
460 public MessageProducer createProducer(Destination destination) throws JMSException
461 {
462 getConnection().throwJMSException();
463 if(null == destination)
464 {
465 return createProducerForNullDestination();
466 }
467 if(destination instanceof MockQueue)
468 {
469 addSessionToQueue((Queue)destination);
470 return getQueueTransmissionManager().createQueueSender((MockQueue)destination);
471 }
472 else if(destination instanceof MockTopic)
473 {
474 addSessionToTopic((Topic)destination);
475 return getTopicTransmissionManager().createTopicPublisher((MockTopic)destination);
476 }
477 else
478 {
479 throw new InvalidDestinationException("destination must be an instance of MockQueue or MockTopic");
480 }
481 }
482
483 public QueueBrowser createBrowser(Queue queue) throws JMSException
484 {
485 getConnection().throwJMSException();
486 return createBrowser(queue, null);
487 }
488
489 public QueueBrowser createBrowser(Queue queue, String messageSelector) throws JMSException
490 {
491 getConnection().throwJMSException();
492 if(!(queue instanceof MockQueue))
493 {
494 throw new InvalidDestinationException("queue must be an instance of MockQueue");
495 }
496 addSessionToQueue(queue);
497 return queueTransManager.createQueueBrowser((MockQueue)queue, messageSelector);
498 }
499
500 public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException
501 {
502 getConnection().throwJMSException();
503 return createDurableSubscriber(topic, name, null, false);
504 }
505
506 public TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException
507 {
508 getConnection().throwJMSException();
509 if(!(topic instanceof MockTopic))
510 {
511 throw new InvalidDestinationException("topic must be an instance of MockTopic");
512 }
513 addSessionToTopic(topic);
514 return topicTransManager.createDurableTopicSubscriber((MockTopic)topic, name, messageSelector, noLocal);
515 }
516
517 protected MockConnection getConnection()
518 {
519 return connection;
520 }
521
522 public void addSessionToQueue(Queue queue)
523 {
524 if(queue instanceof MockQueue)
525 {
526 ((MockQueue)queue).addSession(this);
527 }
528 }
529
530 public void addSessionToTopic(Topic topic)
531 {
532 if(topic instanceof MockTopic)
533 {
534 ((MockTopic)topic).addSession(this);
535 }
536 }
537
538 protected MessageProducer createProducerForNullDestination()
539 {
540 return getGenericTransmissionManager().createMessageProducer();
541 }
542 }