blob: a6635aad8bd4f298bec3a4d2c2227caa8640a8c8 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.jmx.remote.internal;
27
28import java.io.IOException;
29import java.io.InterruptedIOException;
30
31import com.sun.jmx.remote.util.ClassLogger;
32import com.sun.jmx.remote.util.EnvHelp;
33
34public abstract class ClientCommunicatorAdmin {
35 public ClientCommunicatorAdmin(long period) {
36 this.period = period;
37
38 if (period > 0) {
39 checker = new Checker();
40
41 Thread t = new Thread(checker);
42 t.setDaemon(true);
43 t.start();
44 } else
45 checker = null;
46 }
47
48 /**
49 * Called by a client to inform of getting an IOException.
50 */
51 public void gotIOException (IOException ioe) throws IOException {
52 restart(ioe);
53 }
54
55 /**
56 * Called by this class to check a client connection.
57 */
58 protected abstract void checkConnection() throws IOException;
59
60 /**
61 * Tells a client to re-start again.
62 */
63 protected abstract void doStart() throws IOException;
64
65 /**
66 * Tells a client to stop because failing to call checkConnection.
67 */
68 protected abstract void doStop();
69
70 /**
71 * Terminates this object.
72 */
73 public void terminate() {
74 synchronized(lock) {
75 if (state == TERMINATED) {
76 return;
77 }
78
79 state = TERMINATED;
80
81 lock.notifyAll();
82
83 if (checker != null)
84 checker.stop();
85 }
86 }
87
88 private void restart(IOException ioe) throws IOException {
89 // check state
90 synchronized(lock) {
91 if (state == TERMINATED) {
92 throw new IOException("The client has been closed.");
93 } else if (state == FAILED) { // already failed to re-start by another thread
94 throw ioe;
95 } else if (state == RE_CONNECTING) {
96 // restart process has been called by another thread
97 // we need to wait
98 while(state == RE_CONNECTING) {
99 try {
100 lock.wait();
101 } catch (InterruptedException ire) {
102 // be asked to give up
103 InterruptedIOException iioe = new InterruptedIOException(ire.toString());
104 EnvHelp.initCause(iioe, ire);
105
106 throw iioe;
107 }
108 }
109
110 if (state == TERMINATED) {
111 throw new IOException("The client has been closed.");
112 } else if (state != CONNECTED) {
113 // restarted is failed by another thread
114 throw ioe;
115 }
116 } else {
117 state = RE_CONNECTING;
118 lock.notifyAll();
119 }
120 }
121
122 // re-starting
123 try {
124 doStart();
125 synchronized(lock) {
126 if (state == TERMINATED) {
127 throw new IOException("The client has been closed.");
128 }
129
130 state = CONNECTED;
131
132 lock.notifyAll();
133 }
134
135 return;
136 } catch (Exception e) {
137 logger.warning("restart", "Failed to restart: " + e);
138 logger.debug("restart",e);
139
140 synchronized(lock) {
141 if (state == TERMINATED) {
142 throw new IOException("The client has been closed.");
143 }
144
145 state = FAILED;
146
147 lock.notifyAll();
148 }
149
150 try {
151 doStop();
152 } catch (Exception eee) {
153 // OK.
154 // We know there is a problem.
155 }
156
157 terminate();
158
159 throw ioe;
160 }
161 }
162
163// --------------------------------------------------------------
164// private varaibles
165// --------------------------------------------------------------
166 private class Checker implements Runnable {
167 public void run() {
168 myThread = Thread.currentThread();
169
170 while (state != TERMINATED && !myThread.isInterrupted()) {
171 try {
172 Thread.sleep(period);
173 } catch (InterruptedException ire) {
174 // OK.
175 // We will check the state at the following steps
176 }
177
178 if (state == TERMINATED || myThread.isInterrupted()) {
179 break;
180 }
181
182 try {
183 checkConnection();
184 } catch (Exception e) {
185 synchronized(lock) {
186 if (state == TERMINATED || myThread.isInterrupted()) {
187 break;
188 }
189 }
190
191 e = (Exception)EnvHelp.getCause(e);
192
193 if (e instanceof IOException &&
194 !(e instanceof InterruptedIOException)) {
195 try {
196 restart((IOException)e);
197 } catch (Exception ee) {
198 logger.warning("Checker-run",
199 "Failed to check connection: "+ e);
200 logger.warning("Checker-run", "stopping");
201 logger.debug("Checker-run",e);
202
203 break;
204 }
205 } else {
206 logger.warning("Checker-run",
207 "Failed to check the connection: " + e);
208 logger.debug("Checker-run",e);
209
210 // XXX stop checking?
211
212 break;
213 }
214 }
215 }
216
217 if (logger.traceOn()) {
218 logger.trace("Checker-run", "Finished.");
219 }
220 }
221
222 private void stop() {
223 if (myThread != null && myThread != Thread.currentThread()) {
224 myThread.interrupt();
225 }
226 }
227
228 private Thread myThread;
229 }
230
231// --------------------------------------------------------------
232// private variables
233// --------------------------------------------------------------
234 private final Checker checker;
235 private long period;
236
237 // state
238 private final static int CONNECTED = 0;
239 private final static int RE_CONNECTING = 1;
240 private final static int FAILED = 2;
241 private final static int TERMINATED = 3;
242
243 private int state = CONNECTED;
244
245 private final int[] lock = new int[0];
246
247 private static final ClassLogger logger =
248 new ClassLogger("javax.management.remote.misc",
249 "ClientCommunicatorAdmin");
250}