View Javadoc

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-2001,2003 (C) Exoffice Technologies Inc. All Rights Reserved.
42   *
43   * $Id: JmsServerConnection.java,v 1.16 2003/08/17 01:32:26 tanderson Exp $
44   *
45   * Date         Author  Changes
46   * 04/07/2000   jima    Created
47   */
48  package org.exolab.jms.server;
49  
50  import java.util.Enumeration;
51  import java.util.Hashtable;
52  
53  import javax.jms.JMSException;
54  
55  import org.exolab.jms.util.UUID;
56  
57  
58  /***
59   * A connection is created for every client connecting to the JmsServer. A
60   * connection supports multiple sessions.
61   *
62   * @version     $Revision: 1.16 $ $Date: 2003/08/17 01:32:26 $
63   * @author      <a href="mailto:jima@exoffice.com">Jim Alateras</a>
64   * @see         JmsServerConnectionManager
65   */
66  public class JmsServerConnection {
67  
68      /***
69       * The maximum number of consecutive failed attempts to ping the client
70       * before considering that the connection is inactive
71       */
72      private static final int MAX_PING_ATTEMPTS = 3;
73  
74      /***
75       * manage all sessions allocated through this connection.
76       */
77      private Hashtable _sessions = null;
78  
79      /***
80       * This is the client that is responsible for this connection. It should
81       * map back to a client-side entity
82       */
83      private String _clientId = null;
84  
85      /***
86       * The connection id is unique within the context of a JMS server
87       */
88      private String _connectionId = null;
89  
90      /***
91       * Indicates if message delivery has been stopped for this connection
92       */
93      private boolean _stopped = true;
94  
95      /***
96       * Store the number of consecutive failed attempts to ping the client
97       * side of the connection
98       */
99      private int _consecutiveFailedPingAttempts = 0;
100 
101 
102     /***
103      * Instantiate an instance of this class for the specified client identity.
104      * The JmsConnection object can only be instantiated by classes in the same
105      * package (i.e ConnectionManager). The ConnectionManager is responsible
106      * for allocating the client identity which is passed to the constructor
107      *
108      * @param       id              client identity
109      */
110     JmsServerConnection(String id) {
111         _clientId = id;
112         _sessions = new Hashtable(20);
113         _connectionId = UUID.next();
114         _stopped = true;
115     }
116 
117     /***
118      * Returns the client identifier
119      *
120      * @return the client identifier
121      */
122     public String getID() {
123         return _clientId;
124     }
125 
126     /***
127      * Create a sesion for the specified connection. Assign the clientId to
128      * the sessions. The created session is initially in the stopped mode.
129      * <p>
130      * The created session represents an endpoint with the JmsServer where
131      * you can create consumers. producers and destinations.
132      *
133      * @param       ackMode         the ackmode for the session
134      * @param       transacted      true if the session is transacted
135      * @return      JmsSession      created session
136      */
137     public JmsServerSession createSession(int ackMode, boolean transacted) {
138         JmsServerSession session = new JmsServerSession(this, _clientId,
139             ackMode, transacted);
140         session.setSessionId(UUID.next());
141         _sessions.put(session.getSessionId(), session);
142         if (!_stopped) {
143             session.start();
144         }
145 
146         return session;
147     }
148 
149     /***
150      * Delete the specified session. If the session does not exist then
151      * fail silently.
152      *
153      * @param       session         session to delete
154      */
155     public void deleteSession(JmsServerSession session) {
156         _sessions.remove(session.getSessionId());
157     }
158 
159     /***
160      * Return the number of sessions currently allocated to this connection.
161      *
162      * @return      int
163      */
164     public int getSessionCount() {
165         return _sessions.size();
166     }
167 
168     /***
169      * Return an enumeration of all the sessions associated with this
170      * connection
171      *
172      * @return      Enumeration
173      */
174     public Enumeration getSessions() {
175         return _sessions.elements();
176     }
177 
178     /***
179      * Start all the sessions allocated to this connection.
180      */
181     public void start() {
182         if (_stopped) {
183             Enumeration sessions = _sessions.elements();
184 
185             while (sessions.hasMoreElements()) {
186                 JmsServerSession session = (JmsServerSession)
187                     sessions.nextElement();
188                 session.start();
189             }
190             _stopped = false;
191         }
192     }
193 
194     /***
195      * Stop all the sessions allocated to this collection. Do not reemove
196      * the session
197      */
198     public void stop() {
199         if (!_stopped) {
200             Enumeration sessions = _sessions.elements();
201 
202             while (sessions.hasMoreElements()) {
203                 JmsServerSession session = (JmsServerSession)
204                     sessions.nextElement();
205                 session.stop();
206             }
207             _stopped = true;
208         }
209     }
210 
211     /***
212      * Close all the sessions allocated to this collection. This will also
213      * remove the session from the allocated list of sessions
214      */
215     public void close() {
216         Enumeration sessions = _sessions.elements();
217         try {
218             while (sessions.hasMoreElements()) {
219                 JmsServerSession session = (JmsServerSession) sessions.nextElement();
220                 session.close();
221             }
222         } catch (JMSException exception) {
223             // log the message
224         }
225 
226         // remove all the sessions
227         _sessions.clear();
228     }
229 
230     /***
231      * Retrive the JmsServerSession with the given sessionId. Return null
232      * if the session does not exist.
233      *
234      * @param sessionId The id of the required session.
235      * @return JmsServerSession The requested session if it exists.
236      *
237      */
238     public JmsServerSession getSession(String sessionId) {
239         return (JmsServerSession) _sessions.get(sessionId);
240     }
241 
242     /***
243      * Retrieve the identity of this conection. If this method does not
244      * complete successfully then throw JMSException.
245      *
246      * @return      String
247      */
248     public String getConnectionId() {
249         return _connectionId;
250     }
251 
252     /***
253      * Determine whether the endpoint is active by trying to ping the first
254      * session in the list. If there are no active sessions then assume that
255      * the connection is active...(need to probably fix this up).
256      *
257      * @return boolean true if active; false otherwise
258      */
259     boolean isClientEndpointActive() {
260         boolean active = true;
261 
262         JmsServerSession[] sessions;
263         synchronized (_sessions) {
264             // get a copy of the list of sessions to avoid
265             // ConcurrentModificationExceptions
266             sessions = (JmsServerSession[]) _sessions.values().toArray(
267                 new JmsServerSession[0]);
268         }
269         for (int i = 0; i < sessions.length; ++i) {
270             JmsServerSession session = sessions[i];
271             if (session.isClientEndpointActive()) {
272                 // if there is one active session then mark the connection
273                 // as active
274                 active = true;
275                 _consecutiveFailedPingAttempts = 0;
276                 break;
277             } else {
278                 if (++_consecutiveFailedPingAttempts > MAX_PING_ATTEMPTS) {
279                     active = false;
280                 } else {
281                     active = true;
282                 }
283             }
284         }
285 
286         return active;
287     }
288 }