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 }