1 /***
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright
7 * statements and notices. Redistributions must also contain a
8 * copy of this document.
9 *
10 * 2. Redistributions in binary form must reproduce the
11 * above copyright notice, this list of conditions and the
12 * following disclaimer in the documentation and/or other
13 * materials provided with the distribution.
14 *
15 * 3. The name "Exolab" must not be used to endorse or promote
16 * products derived from this Software without prior written
17 * permission of Exoffice Technologies. For written permission,
18 * please contact info@exolab.org.
19 *
20 * 4. Products derived from this Software may not be called "Exolab"
21 * nor may "Exolab" appear in their names without prior written
22 * permission of Exoffice Technologies. Exolab is a registered
23 * trademark of Exoffice Technologies.
24 *
25 * 5. Due credit should be given to the Exolab Project
26 * (http://www.exolab.org/).
27 *
28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Copyright 2000-2004 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: JmsSession.java,v 1.59 2004/01/21 04:08:13 tanderson Exp $
44 */
45 package org.exolab.jms.client;
46
47 import java.io.Serializable;
48 import java.util.Enumeration;
49 import java.util.Hashtable;
50 import java.util.Vector;
51
52 import javax.jms.BytesMessage;
53 import javax.jms.IllegalStateException;
54 import javax.jms.JMSException;
55 import javax.jms.MapMessage;
56 import javax.jms.Message;
57 import javax.jms.MessageListener;
58 import javax.jms.ObjectMessage;
59 import javax.jms.Session;
60 import javax.jms.StreamMessage;
61 import javax.jms.TextMessage;
62
63 import org.apache.commons.logging.Log;
64 import org.apache.commons.logging.LogFactory;
65
66 import org.exolab.jms.message.BytesMessageImpl;
67 import org.exolab.jms.message.MapMessageImpl;
68 import org.exolab.jms.message.MessageConverter;
69 import org.exolab.jms.message.MessageConverterFactory;
70 import org.exolab.jms.message.MessageImpl;
71 import org.exolab.jms.message.MessageSessionIfc;
72 import org.exolab.jms.message.ObjectMessageImpl;
73 import org.exolab.jms.message.StreamMessageImpl;
74 import org.exolab.jms.message.TextMessageImpl;
75
76
77 /***
78 * This class implements a Session interface and supports a single threaded
79 * context. A session supports multiple consumers and producers but only within
80 * the context of a single thread.
81 *
82 * @version $Revision: 1.59 $ $Date: 2004/01/21 04:08:13 $
83 * @author <a href="mailto:jima@exoffice.com">Jim Alateras</a>
84 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
85 */
86 abstract class JmsSession
87 implements Session, JmsMessageListener, MessageSessionIfc {
88
89 /***
90 * If true, indicates that the session has been closed
91 */
92 private volatile boolean _closed = false;
93
94 /***
95 * If true, indicates that the session is in the process of being closed
96 */
97 private volatile boolean _closing = false;
98
99 /***
100 * This flag determines whether message delivery is enabled or disabled.
101 * Message delivery if disabled if the enclosing connection is stopped.
102 */
103 private volatile boolean _stopped = true;
104
105 /***
106 * If true, indicates that the session has been stopped. When started,
107 * messages may be sent
108 */
109 private volatile boolean _started = false;
110
111 /***
112 * A transacted session is bounded by successive commit. If this variable
113 * set to true then this session is transacted. This implies that the
114 * session is always in a transaction and transactions are demarcated by
115 * commit or rollback.
116 */
117 private final boolean _transacted;
118
119 /***
120 * Indicates whether the consumer or the client will
121 * acknowledge any messages it receives. Ignored if the session is
122 * transacted. Legal values are
123 * <code>Session.AUTO_ACKNOWLEDGE</code>,
124 * <code>Session.CLIENT_ACKNOWLEDGE</code> and
125 * <code>Session.DUPS_OK_ACKNOWLEDGE</code>.
126 */
127 private final int _ackMode;
128
129 /***
130 * This is the owner of the session. It also maintains a remote stub to
131 * the server which it can use for its remote work.
132 */
133 private JmsConnection _connection;
134
135 /***
136 * Maintains the a map of JmsMessageConsumer.getClientId() ->
137 * JmsMessageConsumer objects
138 */
139 private Hashtable _consumers = new Hashtable();
140
141 /***
142 * Maintains a list of producers for the session
143 */
144 private Vector _producers = new Vector();
145
146 /***
147 * Maintain a collection of acked messages for this transacted
148 * session. These messages are only sent to the server on commit.
149 */
150 private Vector _messagesToSend = new Vector();
151
152 /***
153 * The identifier of the session
154 */
155 private final String _sessionId;
156
157 /***
158 * Maintain a copy of the stub that connects this machine to the remote
159 * server.
160 */
161 private JmsSessionStubIfc _stub = null;
162
163 /***
164 * This is the session's session listener which is used to receive all
165 * messages associated with all consumers registered with this session.
166 * Even if consumers have registered listeners messages for those consumers
167 * will go to the session's message listener instead.
168 */
169 private MessageListener _listener = null;
170
171 /***
172 * The consumer Id seed to allocate to new consumers
173 */
174 private long _consumerIdSeed = 0;
175
176 /***
177 * Tracks the number of messages sent by this session
178 */
179 private long _publishCount;
180
181 /***
182 * The message cache holds all messages for the session, allocated by
183 * a JmsConnectionConsumer.
184 */
185 private Vector _messageCache = new Vector();
186
187 /***
188 * Monitor used to block consumers, if the session has been
189 * stopped, or no messages are available
190 */
191 private final Object _receiveLock = new Object();
192
193 /***
194 * The logger
195 */
196 private static final Log _log = LogFactory.getLog(JmsSession.class);
197
198
199 /***
200 * Construct a new <code>JmsSession</code>
201 *
202 * @param connection the owner of the session
203 * @param transacted if <code>true</code>, the session is transacted.
204 * @param ackMode indicates whether the consumer or the client will
205 * acknowledge any messages it receives. This parameter will be ignored if
206 * the session is transacted. Legal values are
207 * <code>Session.AUTO_ACKNOWLEDGE</code>,
208 * <code>Session.CLIENT_ACKNOWLEDGE</code> and
209 * <code>Session.DUPS_OK_ACKNOWLEDGE</code>.
210 * @throws JMSException if the session cannot be created
211 */
212 public JmsSession(JmsConnection connection, boolean transacted,
213 int ackMode) throws JMSException {
214
215 if (connection == null) {
216 throw new IllegalArgumentException(
217 "Argument 'connection' is null");
218 }
219
220 _connection = connection;
221 _transacted = transacted;
222 _ackMode = ackMode;
223
224 // construct the remote stub
225 _stub = connection.getJmsConnectionStub().createSession(
226 _ackMode, transacted);
227 _sessionId = _stub.getSessionId();
228
229 // set up this instance to be a message listener
230 _stub.setMessageListener(this);
231
232 // now we need to check whether we should start the session
233 if (!connection.isStopped()) {
234 start();
235 }
236 }
237
238 /***
239 * Create a <code>BytesMessage</code>
240 *
241 * @return a new <code>BytesMessage</code>
242 * @throws JMSException if the message can't be created
243 */
244 public BytesMessage createBytesMessage() throws JMSException {
245 ensureOpen();
246 return new BytesMessageImpl();
247 }
248
249 /***
250 * Create a <code>MapMessage</code>
251 *
252 * @return a new <code>MapMessage</code>
253 * @throws JMSException if the message can't be created
254 */
255 public MapMessage createMapMessage() throws JMSException {
256 ensureOpen();
257 return new MapMessageImpl();
258 }
259
260 /***
261 * Create a <code>Message</code>
262 *
263 * @return a new <code>Message</code>
264 * @throws JMSException if the message can't be created
265 */
266 public Message createMessage() throws JMSException {
267 ensureOpen();
268 return new MessageImpl();
269 }
270
271 /***
272 * Create an <code>ObjectMessage</code>
273 *
274 * @return a new <code>ObjectMessage</code>
275 * @throws JMSException if the message can't be created
276 */
277 public ObjectMessage createObjectMessage() throws JMSException {
278 ensureOpen();
279 return new ObjectMessageImpl();
280 }
281
282 /***
283 * Create an <code>ObjectMessage</code>
284 *
285 * @param object the object to use to initialise the message
286 * @return a new <code>ObjectMessage</code>
287 * @throws JMSException if the message can't be created
288 */
289 public ObjectMessage createObjectMessage(Serializable object)
290 throws JMSException {
291 ensureOpen();
292 ObjectMessageImpl result = new ObjectMessageImpl();
293 result.setObject(object);
294 return result;
295 }
296
297 /***
298 * Create a <code>StreamMessage</code>
299 *
300 * @return a new <code>StreamMessage</code>
301 * @throws JMSException if the message can't be created
302 */
303 public StreamMessage createStreamMessage() throws JMSException {
304 ensureOpen();
305 return new StreamMessageImpl();
306 }
307
308 /***
309 * Create a <code>TextMessage</code>
310 *
311 * @return a new <code>TextMessage</code>
312 * @throws JMSException if the message can't be created
313 */
314 public TextMessage createTextMessage() throws JMSException {
315 ensureOpen();
316 return new TextMessageImpl();
317 }
318
319 /***
320 * Create a <code>TextMessage</code>
321 *
322 * @param text the text to use to initialise the message
323 * @return a new <code>TextMessage</code>
324 * @throws JMSException if the message can't be created
325 */
326 public TextMessage createTextMessage(String text) throws JMSException {
327 ensureOpen();
328 TextMessageImpl result = new TextMessageImpl();
329 result.setText(text);
330 return result;
331 }
332
333 /***
334 * Determines if the session is transacted
335 *
336 * @return <code>true</code> if the session is transacted
337 * @throws JMSException if the session is closed
338 */
339 public boolean getTransacted() throws JMSException {
340 ensureOpen();
341 return _transacted;
342 }
343
344 /***
345 * Commit all messages done in this transaction
346 *
347 * @throws JMSException if the transaction cannot be committed
348 */
349 public synchronized void commit() throws JMSException {
350 ensureOpen();
351 ensureTransactional();
352
353 // send all the cached messages to the server
354 getJmsSessionStub().sendMessages(_messagesToSend);
355 _publishCount += _messagesToSend.size();
356 _messagesToSend.clear();
357
358 // commit the session
359 getJmsSessionStub().commit();
360 }
361
362 /***
363 * Rollback any messages done in this transaction
364 *
365 * @throws JMSException if the transaction cannot be rolled back
366 */
367 public synchronized void rollback() throws JMSException {
368 ensureOpen();
369 ensureTransactional();
370
371 // clear all the cached messages
372 _messagesToSend.clear();
373
374 // rollback the session
375 getJmsSessionStub().rollback();
376 }
377
378 /***
379 * Close the session. This call will block until a receive or message
380 * listener in progress has completed. A blocked message consumer receive
381 * call returns <code>null</code> when this session is closed.
382 *
383 * @throws JMSException if the session can't be closed
384 */
385 public synchronized void close() throws JMSException {
386 if (!_closed) {
387 _closing = true;
388
389 // signal the stub that we are preparing to close the
390 // connection.
391 getJmsSessionStub().beforeClose();
392
393 // must stop first before we close
394 stop();
395
396 // wake up any blocking consumers
397 notifyConsumers();
398
399 // go through all the producer and call close on them
400 // respectively
401 Enumeration producers = getProducers();
402 while (producers.hasMoreElements()) {
403 JmsMessageProducer producer =
404 (JmsMessageProducer) producers.nextElement();
405 producer.close();
406 }
407
408 // go through all the consumer and call close on them
409 // respectively
410 Enumeration consumers = getConsumers();
411 while (consumers.hasMoreElements()) {
412 JmsMessageConsumer consumer =
413 (JmsMessageConsumer) consumers.nextElement();
414 consumer.close();
415 }
416
417 // deregister this with the connection
418 _connection.removeSession(this);
419 _connection = null;
420
421 // clear any cached messages or acks
422 _messagesToSend.clear();
423
424 // issue a close to the remote session. This will release any
425 // allocated remote resources
426 getJmsSessionStub().close();
427 _stub = null;
428
429 // update the session state
430 _closed = true;
431 _closing = false;
432 }
433 }
434
435 /***
436 * Stop message delivery in this session, and restart sending messages with
437 * the oldest unacknowledged message
438 *
439 * @throws JMSException if the session can't be recovered
440 */
441 public synchronized void recover() throws JMSException {
442 ensureOpen();
443 if (!_transacted) {
444 // let the server handle the recovery
445 getJmsSessionStub().recover();
446 } else {
447 throw new IllegalStateException(
448 "Cannot recover from a transacted session");
449 }
450 }
451
452 /***
453 * Returns the message listener associated with the session
454 *
455 * @return the message listener associated with the session, or
456 * <code>null</code> if no listener is registered
457 * @throws JMSException if the session is closed
458 */
459 public MessageListener getMessageListener() throws JMSException {
460 ensureOpen();
461 return _listener;
462 }
463
464 /***
465 * Sets the session's message listener.
466 *
467 * @param listener the session's message listener
468 * @throws JMSException if the session is closed
469 */
470 public void setMessageListener(MessageListener listener)
471 throws JMSException {
472 ensureOpen();
473 _listener = listener;
474 }
475
476 /***
477 * Iterates through the list of messages added by an
478 * {@link JmsConnectionConsumer}, sending them to the registered listener
479 */
480 public void run() {
481 try {
482 while (!_messageCache.isEmpty()) {
483 Message message = (Message) _messageCache.remove(0);
484 _listener.onMessage(message);
485 }
486 } catch (Exception exception) {
487 _log.error("Error in the Session.run()", exception);
488 } finally {
489 // Clear message cache
490 _messageCache.clear();
491 }
492 }
493
494 /***
495 * Set the message listener for a particular consumer.
496 * <p>
497 * If a listener is already registered for the consumer, it will be
498 * automatically overwritten
499 *
500 * @param listener the message listener
501 * @throws JMSException if the listener can't be set
502 */
503 public void setMessageListener(JmsMessageConsumer listener)
504 throws JMSException {
505 ensureOpen();
506 enableAsynchronousDelivery(listener.getClientId(),
507 listener.getLastMessageDelivered(), true);
508 }
509
510 /***
511 * Remove a message listener
512 *
513 * @param listener the message listener to remove
514 * @throws JMSException if the listener can't be removed
515 */
516 public void removeMessageListener(JmsMessageConsumer listener)
517 throws JMSException {
518
519 ensureOpen();
520 enableAsynchronousDelivery(listener.getClientId(),
521 listener.getLastMessageDelivered(), false);
522 }
523
524 /***
525 * This will start message delivery to this session. If message delivery
526 * has already started then this is a no-op.
527 *
528 * @throws JMSException if message delivery can't be started
529 */
530 public void start() throws JMSException {
531 ensureOpen();
532 if (_stopped) {
533 getJmsSessionStub().startMessageDelivery();
534 _stopped = false;
535
536 // wake up any blocking consumers
537 notifyConsumers();
538 }
539 }
540
541 /***
542 * This will stop message delivery to this session. If message delivery
543 * has already stoped then this is a no-op.
544 *
545 * @throws JMSException if message delivery can't be stopped
546 */
547 public void stop() throws JMSException {
548 ensureOpen();
549 if (!_stopped) {
550 getJmsSessionStub().stopMessageDelivery();
551 _stopped = true;
552
553 // wake up any blocking consumers
554 notifyConsumers();
555 }
556 }
557
558 /***
559 * Acknowledge the specified message. This is only applicable for
560 * CLIENT_ACKNOWLEDGE sessions. For other session types, the request
561 * is ignored.
562 * <p>
563 * Acking a message automatically acks all those that have come
564 * before it.
565 *
566 * @param message the message to acknowledge
567 * @throws JMSException if the message can't be acknowledged
568 */
569 public void acknowledgeMessage(Message message) throws JMSException {
570 ensureOpen();
571 if (_ackMode == Session.CLIENT_ACKNOWLEDGE) {
572 MessageImpl impl = (MessageImpl) message;
573 getJmsSessionStub().acknowledgeMessage(impl.getClientId(),
574 impl.getAckMessageID());
575 }
576 }
577
578 /***
579 * Enable or disable asynchronous message delivery for the specified
580 * client.
581 *
582 * @param clientId - the client identity
583 * @param id - the last message delivered asynchronously
584 * @param enable - <code>true</code> to enable; <code>false</code> to
585 * disable
586 * @throws JMSException if message delivery cannot be enabled or disabled
587 */
588 public void enableAsynchronousDelivery(long clientId, String id,
589 boolean enable)
590 throws JMSException {
591
592 ensureOpen();
593 getJmsSessionStub().enableAsynchronousDelivery(clientId, id, enable);
594 }
595
596 /***
597 * Asynchronously deliver a message to a <code>MessageConsumer</code>
598 *
599 * @param message the message to deliver
600 */
601 public void onMessage(Message message) {
602 if (message != null) {
603 MessageImpl impl = (MessageImpl) message;
604 impl.setJMSXRcvTimestamp(System.currentTimeMillis());
605
606 // dispatch the message;
607 execute(message);
608 }
609 }
610
611 /***
612 * Asynchronously deliver a set of message to a
613 * <code>MessageConsumer</code>
614 *
615 * @param messages the messages to deliver
616 */
617 public void onMessages(Vector messages) {
618 while (messages.size() > 0) {
619 onMessage((Message) messages.remove(0));
620 }
621 }
622
623 /***
624 * Inform the session that there is a message available
625 * for the message consumer with the specified identity
626 *
627 * @param clientId the identity of the client
628 */
629 public void onMessageAvailable(long clientId) {
630 // wake up any blocking consumers
631 notifyConsumers();
632 }
633
634 /***
635 * This is the called to process messages asynchronously delivered by the
636 * server. The session is then responsible for delivering it to the
637 * appropriate registered consumer. If it cannot resolve the consumer then
638 * it must log an exception
639 * <p>
640 * If the session has a registered listener then all messages will be
641 * delivered to the session's listener instead of the individual consumer
642 * message listeners.
643 *
644 * @param object received message
645 */
646 public synchronized void execute(Object object) {
647 // if the session is closed then drop the object
648 if (_closed) {
649 _log.error("Received a message for a closed session");
650 return;
651 }
652
653 MessageImpl message = (MessageImpl) object;
654 long clientId = message.getClientId();
655 JmsMessageConsumer consumer =
656 (JmsMessageConsumer) _consumers.get(new Long(clientId));
657
658 // tag the session that received this message
659 message.setSession(this);
660 if (consumer != null) {
661 // if a listener is defined for the session then send all the
662 // messages to that listener regardless if any consumers are
663 // have registered listeners...bit confusing but this is what
664 // I believe it should do
665 if (_listener != null) {
666 _listener.onMessage(message);
667 } else {
668 // send it to the appropriate consumer
669 consumer.onMessage(message);
670 }
671 } else {
672 // consumer no longer active...so drop the message
673 _log.error("Received a message for an inactive consumer");
674 }
675 }
676
677 /***
678 * Returns the session identifier
679 *
680 * @return the session identifier
681 */
682 public String getSessionId() {
683 return _sessionId;
684 }
685
686 /***
687 * Return the acknowledgement mode for the session
688 *
689 * @return the acknowledgement mode for the session
690 */
691 public int getAckMode() {
692 return _ackMode;
693 }
694
695 /***
696 * Fetch the next message for this client. If the session's ackMode is
697 * client acknowledge then set the session for the message, othwerwise
698 * ack the message before returning it.
699 *
700 * @param clientId the consumer identififer.
701 * @param wait the maximum time to wait for a message, in milliseconds.
702 * If <code>-1</code>, don't wait, if <code>0</code> wait indefinitely,
703 * otherwise wait the specified time.
704 * @return the received message, or <code>null</code>, if no message is
705 * available
706 * @throws JMSException if an error occurs retrieving the message
707 */
708 public Message retrieveMessage(long clientId, long wait)
709 throws JMSException {
710
711 ensureOpen();
712
713 boolean breakOnNextRead = false;
714 long start = System.currentTimeMillis();
715 long end = start + wait;
716 MessageImpl message = null;
717 while (true) {
718 synchronized (_receiveLock) {
719 if (_closing || _closed) {
720 // session is in the process of closing, or has been
721 // closed. Need to return null.
722 break;
723 } else if (_stopped) {
724 // connection has been stopped. No message can be returned,
725 // but receives continue to time out
726 } else {
727 // connection is started. Messages may be returned.
728 message = (MessageImpl) getJmsSessionStub().receiveMessage(
729 clientId, wait);
730 }
731 if (message != null) {
732 message.setSession(this);
733 break;
734 } else {
735 // if we have instructed to break, then exit the loop.
736 if (breakOnNextRead) {
737 break;
738 }
739
740 // no message was received. Block for the specified time
741 // until one of the following occurs:
742 // . a message is received
743 // . the receive times out
744 // . the session is closed
745 if (wait >= 0) {
746 try {
747 if (wait > 0) {
748 // wait for a specific period of time
749 _receiveLock.wait(wait);
750 long current = System.currentTimeMillis();
751 if (current >= end) {
752 breakOnNextRead = true;
753 } else {
754 // update the time to wait. If the value
755 // is zero then break on the next read
756 wait = end - current;
757 if (wait == 0) {
758 breakOnNextRead = true;
759 }
760 }
761 } else {
762 // wait indefinitely
763 _receiveLock.wait();
764 }
765 } catch (InterruptedException ignore) {
766 // no-op
767 }
768 } else {
769 // exit the loop since the client is performing a non
770 // blocking read
771 break;
772 }
773 }
774 }
775 }
776
777 return message;
778 }
779
780 /***
781 * Fetch up to count messages from the endpoint. This should only
782 * be called via a {@link JmsQueueBrowser}.
783 *
784 * @param clientId scoped to the session
785 * @param count the max messages to retrieve.
786 * @return the set of retrieve messages
787 * @throws JMSException if messages can't be retrieved
788 */
789 public synchronized Vector retrieveMessages(long clientId, int count)
790 throws JMSException {
791 ensureOpen();
792 return getJmsSessionStub().receiveMessages(clientId, count);
793 }
794
795 /***
796 * Release local resources used by this session object
797 *
798 * @throws JMSException - if there is a problem completing this request
799 */
800 public void destroy() throws JMSException {
801 if (!_closed) {
802 _closing = true;
803
804 // wake up any blocking consumers
805 notifyConsumers();
806
807 // go through all the producer and call close on them
808 // respectively
809 Enumeration producers = getProducers();
810 while (producers.hasMoreElements()) {
811 JmsMessageProducer producer =
812 (JmsMessageProducer) producers.nextElement();
813 producer.destroy();
814 }
815
816 // go through all the consumer and call close on them
817 // respectively
818 Enumeration consumers = getConsumers();
819 while (consumers.hasMoreElements()) {
820 JmsMessageConsumer consumer =
821 (JmsMessageConsumer) consumers.nextElement();
822 consumer.destroy();
823 }
824
825 // deregister this with the connection
826 _connection.removeSession(this);
827 _connection = null;
828
829 // clear any cached messages or acks
830 _messagesToSend.clear();
831
832 // simply release the reference to the sever session
833 _stub = null;
834
835 // update the session state
836 _closed = true;
837 _closing = false;
838 }
839 }
840
841 /***
842 * Send the specified message to the server.
843 *
844 * @param message the message to send
845 * @throws JMSException if the message can't be sent
846 */
847 protected synchronized void sendMessage(Message message)
848 throws JMSException {
849
850 if (_transacted) {
851 // if the session is transacted then cache the message locally.
852 // and wait for a commit or a rollback
853 if (message instanceof MessageImpl) {
854 try {
855 message = (Message) ((MessageImpl) message).clone();
856 } catch (CloneNotSupportedException error) {
857 throw new JMSException(error.getMessage());
858 }
859 } else {
860 message = convert(message);
861 }
862 _messagesToSend.addElement(message);
863 } else {
864 if (!(message instanceof MessageImpl)) {
865 message = convert(message);
866 }
867 getJmsSessionStub().sendMessage(message);
868 _publishCount++;
869 }
870 }
871
872 /***
873 * Return an instance of the remote stub. This is set during object
874 * creation time
875 *
876 * @return the remote stub
877 */
878 protected JmsSessionStubIfc getJmsSessionStub() {
879 return _stub;
880 }
881
882 /***
883 * Return a reference to the connection that created this session
884 *
885 * @return the owning connection
886 */
887 protected JmsConnection getConnection() {
888 return _connection;
889 }
890
891 /***
892 * This method checks the destination. If the destination is not temporary
893 * then return true. If it is a temporary destination and it is owned by
894 * this session's connection then it returns true. If it is a tmeporary
895 * destination and it is owned by another connection then it returns false
896 *
897 * @param destination the destination to check
898 * @return <code>true</code> if the destination is valid
899 */
900 protected boolean checkForValidTemporaryDestination(
901 JmsDestination destination) {
902 boolean result = false;
903
904 if (destination.isTemporaryDestination()) {
905 JmsTemporaryDestination temp =
906 (JmsTemporaryDestination) destination;
907
908 // check that this temp destination is owned by the session's
909 // connection.
910 if (temp.validForConnection(getConnection())) {
911 result = true;
912 }
913 } else {
914 result = true;
915 }
916
917 return result;
918 }
919
920 /***
921 * Returns a list of registered producers for the session
922 *
923 * @return an enumeration of the producers managed by the session
924 */
925 protected Enumeration getProducers() {
926 return _producers.elements();
927 }
928
929 /***
930 * Returns a list of registered consumers for the session
931 *
932 * @return an enumeration of the consumers managed by the session
933 */
934 protected Enumeration getConsumers() {
935 return _consumers.elements();
936 }
937
938 /***
939 * Returns the next seed value to be allocated to a new consumer
940 *
941 * @return a unique identifier for a consumer for this session
942 */
943 protected long getNextConsumerId() {
944 return ++_consumerIdSeed;
945 }
946
947 /***
948 * Add a consumer to the list of consumers managed by this session
949 *
950 * @param consumer the consumer to add
951 */
952 protected void addConsumer(JmsMessageConsumer consumer) {
953 _consumers.put(new Long(consumer.getClientId()), consumer);
954 }
955
956 /***
957 * Remove the consumer with the specified id from the list of managed
958 * consumers
959 *
960 * @param consumer the consumer to remove
961 */
962 protected void removeConsumer(JmsMessageConsumer consumer) {
963 _consumers.remove(new Long(consumer.getClientId()));
964 }
965
966 /***
967 * Add a producer to the list of producers managed by this session
968 *
969 * @param producer the producer to add
970 */
971 protected void addProducer(JmsMessageProducer producer) {
972 _producers.addElement(producer);
973 }
974
975 /***
976 * Remove the producer from the list of managed producers
977 *
978 * @param producer the producer to remove
979 */
980 protected void removeProducer(JmsMessageProducer producer) {
981 _producers.remove(producer);
982 }
983
984 /***
985 * Check if the session is closed
986 *
987 * @return <code>true</code> if the session is closed
988 */
989 protected final boolean isClosed() {
990 return _closed;
991 }
992
993 /***
994 * Add a message to the message cache. This message will be processed
995 * when the run() method is called.
996 *
997 * @param message the message to add.
998 */
999 protected void addMessage(Message message) {
1000 _messageCache.addElement(message);
1001 }
1002
1003 /***
1004 * Verifies that the session isn't closed
1005 *
1006 * @throws IllegalStateException if the session is closed
1007 */
1008 protected void ensureOpen() throws IllegalStateException {
1009 if (_closed) {
1010 throw new IllegalStateException(
1011 "Cannot perform operation - session has been closed");
1012 }
1013 }
1014
1015 /***
1016 * Verifies that the session is transactional
1017 *
1018 * @throws IllegalStateException if the session isn't transactional
1019 */
1020 private void ensureTransactional() throws IllegalStateException {
1021 if (!_transacted) {
1022 throw new IllegalStateException(
1023 "Cannot perform operatiorn - session is not transactional");
1024 }
1025 }
1026
1027 /***
1028 * Notifies any blocking synchronous consumers
1029 */
1030 private void notifyConsumers() {
1031 synchronized (_receiveLock) {
1032 _receiveLock.notifyAll();
1033 }
1034 }
1035
1036 /***
1037 * Convert a message to its corresponding OpenJMS implementation
1038 *
1039 * @param message the message to convert
1040 * @return the OpenJMS implementation of the message
1041 * @throws JMSException for any error
1042 */
1043 private Message convert(Message message) throws JMSException {
1044 MessageConverter converter =
1045 MessageConverterFactory.create(message);
1046 return converter.convert(message);
1047 }
1048
1049 }
1050
This page was automatically generated by Maven