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-2003 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: RmiJmsConnectionStub.java,v 1.20 2003/08/07 13:32:54 tanderson Exp $
44 *
45 * Date Author Changes
46 * 04/12/2000 jima Created
47 */
48 package org.exolab.jms.client.rmi;
49
50 import java.rmi.ConnectException;
51 import java.rmi.RemoteException;
52
53 import javax.jms.JMSException;
54
55 import org.apache.commons.logging.Log;
56 import org.apache.commons.logging.LogFactory;
57
58 import org.exolab.jms.client.JmsConnectionStubIfc;
59 import org.exolab.jms.client.JmsErrorCodes;
60 import org.exolab.jms.client.JmsSessionStubIfc;
61 import org.exolab.jms.server.rmi.RemoteJmsServerConnectionIfc;
62 import org.exolab.jms.server.rmi.RemoteJmsServerSessionIfc;
63
64
65 /***
66 * This class is repsonsible for returning a reference to a remote JMS
67 * connection. If it cannot access get a remote connection then the constructor
68 * will fail with a JMSException
69 *
70 * @version $Revision: 1.20 $ $Date: 2003/08/07 13:32:54 $
71 * @author <a href="mailto:jima@exoffice.com">Jim Alateras</a>
72 */
73 public class RmiJmsConnectionStub
74 implements JmsConnectionStubIfc {
75
76 /***
77 * This is a reference to the remote connection stub that is constructed
78 * during object initialisation.
79 */
80 protected volatile RemoteJmsServerConnectionIfc _delegate = null;
81
82 /***
83 * This is a reference to the server stub that created this connection
84 */
85 protected RmiJmsServerStub _owner = null;
86
87 /***
88 * Cache a reference to the pinging thread. This thread is used to
89 * determine whether the server is still active
90 */
91 private PingThread _pinger = null;
92
93 /***
94 * System property to override the max retries for failed rmi requests.
95 * The default is 10
96 */
97 public final String MAX_RETRY_PROP = "org.exolab.jms.rmi.retryCount";
98
99 /***
100 * System property, which specifies the interval between successive
101 * retries.
102 * The value is specified in milliseconds and defaults to 100ms
103 */
104 public final String RETRY_INTERVAL_PROP =
105 "org.exolab.jms.rmi.retryInterval";
106
107 /***
108 * The logger
109 */
110 private static final Log _log =
111 LogFactory.getLog(RmiJmsConnectionStub.class);
112
113
114 /***
115 * Instantiate an instance of this class with the specified remote object.
116 * This object is a delegate for all other requests. If a null connection
117 * is specified then throw a JMSException exception
118 *
119 * @param RemoteJmsServerConnectionIfc
120 * @param pingInterval interval between client pings
121 * @param server the server creating the connection
122 * @throws JMSException
123 */
124 public RmiJmsConnectionStub(RemoteJmsServerConnectionIfc connection,
125 int pingInterval, RmiJmsServerStub server)
126 throws JMSException {
127
128 if (connection != null) {
129 _owner = server;
130 _delegate = connection;
131
132 // this is used to determine whether or not the server is
133 // active
134 if (pingInterval > 0) {
135 (_pinger = new PingThread(pingInterval)).start();
136 }
137 } else {
138 throw new JMSException("Cannot instantiate with a null " +
139 "connection");
140 }
141 }
142
143 // implementation of JmsConnectionStubIfc.createSession
144 public JmsSessionStubIfc createSession(int ackMode, boolean transacted)
145 throws JMSException {
146 RmiJmsSessionStub stub = null;
147 try {
148 RemoteJmsServerSessionIfc session = _delegate.createSession(
149 ackMode, transacted);
150 stub = new RmiJmsSessionStub(session);
151 session.setMessageListener(stub);
152
153 } catch (RemoteException exception) {
154 // rethrow as a JMSException
155 throw new JMSException("Failed to createSession " + exception);
156 }
157
158 return stub;
159 }
160
161 // implementation of JmsConnectionStubIfc.close
162 public void close() throws JMSException {
163 // stop the pinging thread
164 if (_pinger != null) {
165 _pinger.close();
166 }
167
168 // close the delegate
169 try {
170 _delegate.close();
171 _delegate = null;
172 } catch (RemoteException exception) {
173 // rethrow as a JMSException
174 throw new JMSException("Failed to close " + exception);
175 }
176 }
177
178 // implementation of JmsConnectionStubIfc.getConnectionId
179 public String getConnectionId() throws JMSException {
180 try {
181 return _delegate.getConnectionId();
182 } catch (RemoteException exception) {
183 // rethrow as a JMSException
184 throw new JMSException("Failed to getConnectionId " + exception);
185 }
186 }
187
188 // implementation of JmsConnectionStubIfc.destroy
189 public void destroy() {
190 if (_pinger != null) {
191 _pinger.close();
192 }
193 _delegate = null;
194 _owner = null;
195 }
196
197 /***
198 * This thread is used to send ping requests to the server. The server uses
199 * these requests to determine whether a client has disconnected.
200 * The frequency of these requests is determined by the server.
201 */
202 private class PingThread extends Thread {
203
204 /***
205 * Maintains the interval at which ping requests are generated to the
206 * server. The value is in seconds
207 */
208 private int _interval;
209
210 /***
211 * The maximum no. of times to retry failed pings
212 */
213 private int _retries;
214
215 /***
216 * The interval between retrying failed pings
217 */
218 private int _retryInterval;
219
220 /***
221 * Determines if the thread should stop
222 */
223 private volatile boolean _stop = false;
224
225
226 /***
227 * Instantiate a daemon thread that will be used to periodically send
228 * ping requests to the server at the specified interval
229 *
230 * @param interval the interval between ping requests in seconds
231 */
232 PingThread(int interval) {
233 _interval = interval;
234 setName("PingThread-" + Math.abs(hashCode()));
235 setDaemon(true);
236
237 _retries = getProperty(MAX_RETRY_PROP, 10, 1);
238 _retryInterval = getProperty(RETRY_INTERVAL_PROP, 100, 100);
239 }
240
241 /***
242 * This will run forever generating ping requests to the clients
243 */
244 public void run() {
245 while (!_stop) {
246 if (ping()) {
247 // sleep for the specified interval
248 try {
249 Thread.currentThread().sleep(_interval * 1000);
250 } catch (InterruptedException ignore) {
251 }
252 } else {
253 // the server is no longer available so notify the
254 // client
255 try {
256 JMSException error = new JMSException(
257 "Connection to server terminated",
258 JmsErrorCodes.CONNECTION_TO_SERVER_DROPPED);
259 _log.warn("Server is not responding. "
260 + "Generating onException",
261 error);
262 _owner.getExceptionListener().onException(error);
263 } catch (Throwable ignore) {
264 }
265 break;
266 }
267 }
268 }
269
270 public void close() {
271 _stop = true;
272 try {
273 interrupt();
274 } catch (SecurityException ignore) {
275 }
276 }
277
278 private boolean ping() {
279 boolean successful = false;
280
281 // send the ping request. We need to wrap this up in a
282 // retry loop to cater for a ConnectException that happens
283 // when the server is busy or out of resources.
284 RemoteJmsServerConnectionIfc delegate = _delegate;
285 if (delegate != null) {
286 int count = 0;
287 while ((count < _retries) && !successful && !_stop) {
288 try {
289 delegate.ping();
290 successful = true;
291 } catch (RemoteException exception) {
292 _log.warn("Failed to ping openjms server. "
293 + "Retry count=" + count, exception);
294 if ((exception.detail instanceof ConnectException) &&
295 (count < _retries - 1)) {
296 // underlying exception is connection
297 // related...let's retry the request after sleeping
298 try {
299 Thread.sleep(_retryInterval);
300 } catch (InterruptedException ignore) {
301 }
302 }
303 } catch (Throwable exception) {
304 // print the exception but continue
305 _log.warn("Exception pinging server", exception);
306 }
307 ++count;
308 }
309 }
310 return successful;
311 }
312
313 private int getProperty(String name, int defaultValue, int minimum) {
314 int result = defaultValue;
315 String value = null;
316 try {
317 value = System.getProperty(name);
318 } catch (SecurityException ignore) {
319 }
320
321 if (value != null) {
322 try {
323 result = Integer.parseInt(value);
324 if (result <= minimum) {
325 result = minimum;
326 }
327 } catch (NumberFormatException ignore) {
328 // keep the default
329 }
330 }
331 return result;
332 }
333
334 } //-- PingThread
335
336 } //-- RmiJmsConnectionStub
This page was automatically generated by Maven