blob: 25f9b6b79480d9360e2bef5660b7f9ff48310998 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2004 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;
29
30import com.sun.jmx.remote.util.ClassLogger;
31
32public abstract class ServerCommunicatorAdmin {
33 public ServerCommunicatorAdmin(long timeout) {
34 if (logger.traceOn()) {
35 logger.trace("Constructor",
36 "Creates a new ServerCommunicatorAdmin object "+
37 "with the timeout "+timeout);
38 }
39
40 this.timeout = timeout;
41
42 timestamp = 0;
43 if (timeout < Long.MAX_VALUE) {
44 Runnable timeoutTask = new Timeout();
45 final Thread t = new Thread(timeoutTask);
46 t.setName("JMX server connection timeout " + t.getId());
47 // If you change this name you will need to change a unit test
48 // (NoServerTimeoutTest)
49 t.setDaemon(true);
50 t.start();
51 }
52 }
53
54 /**
55 * Tells that a new request message is received.
56 * A caller of this method should always call the method
57 * <code>rspOutgoing</code> to inform that a response is sent out
58 * for the received request.
59 * @return the value of the termination flag:
60 * <ul><code>true</code> if the connection is already being terminated,
61 * <br><code>false</code> otherwise.</ul>
62 */
63 public boolean reqIncoming() {
64 if (logger.traceOn()) {
65 logger.trace("reqIncoming", "Receive a new request.");
66 }
67
68 synchronized(lock) {
69 if (terminated) {
70 logger.warning("reqIncoming",
71 "The server has decided to close " +
72 "this client connection.");
73 }
74 ++currentJobs;
75
76 return terminated;
77 }
78 }
79
80 /**
81 * Tells that a response is sent out for a received request.
82 * @return the value of the termination flag:
83 * <ul><code>true</code> if the connection is already being terminated,
84 * <br><code>false</code> otherwise.</ul>
85 */
86 public boolean rspOutgoing() {
87 if (logger.traceOn()) {
88 logger.trace("reqIncoming", "Finish a request.");
89 }
90
91 synchronized(lock) {
92 if (--currentJobs == 0) {
93 timestamp = System.currentTimeMillis();
94 logtime("Admin: Timestamp=",timestamp);
95 // tells the adminor to restart waiting with timeout
96 lock.notify();
97 }
98 return terminated;
99 }
100 }
101
102 /**
103 * Called by this class to tell an implementation to do stop.
104 */
105 protected abstract void doStop();
106
107 /**
108 * Terminates this object.
109 * Called only by outside, so do not need to call doStop
110 */
111 public void terminate() {
112 if (logger.traceOn()) {
113 logger.trace("terminate",
114 "terminate the ServerCommunicatorAdmin object.");
115 }
116
117 synchronized(lock) {
118 if (terminated) {
119 return;
120 }
121
122 terminated = true;
123
124 // tell Timeout to terminate
125 lock.notify();
126 }
127 }
128
129// --------------------------------------------------------------
130// private classes
131// --------------------------------------------------------------
132 private class Timeout implements Runnable {
133 public void run() {
134 boolean stopping = false;
135
136 synchronized(lock) {
137 if (timestamp == 0) timestamp = System.currentTimeMillis();
138 logtime("Admin: timeout=",timeout);
139 logtime("Admin: Timestamp=",timestamp);
140
141 while(!terminated) {
142 try {
143 // wait until there is no more job
144 while(!terminated && currentJobs != 0) {
145 if (logger.traceOn()) {
146 logger.trace("Timeout-run",
147 "Waiting without timeout.");
148 }
149
150 lock.wait();
151 }
152
153 if (terminated) return;
154
155 final long remaining =
156 timeout - (System.currentTimeMillis() - timestamp);
157
158 logtime("Admin: remaining timeout=",remaining);
159
160 if (remaining > 0) {
161
162 if (logger.traceOn()) {
163 logger.trace("Timeout-run",
164 "Waiting with timeout: "+
165 remaining + " ms remaining");
166 }
167
168 lock.wait(remaining);
169 }
170
171 if (currentJobs > 0) continue;
172
173 final long elapsed =
174 System.currentTimeMillis() - timestamp;
175 logtime("Admin: elapsed=",elapsed);
176
177 if (!terminated && elapsed > timeout) {
178 if (logger.traceOn()) {
179 logger.trace("Timeout-run",
180 "timeout elapsed");
181 }
182 logtime("Admin: timeout elapsed! "+
183 elapsed+">",timeout);
184 // stopping
185 terminated = true;
186
187 stopping = true;
188 break;
189 }
190 } catch (InterruptedException ire) {
191 logger.warning("Timeout-run","Unexpected Exception: "+
192 ire);
193 logger.debug("Timeout-run",ire);
194 return;
195 }
196 }
197 }
198
199 if (stopping) {
200 if (logger.traceOn()) {
201 logger.trace("Timeout-run", "Call the doStop.");
202 }
203
204 doStop();
205 }
206 }
207 }
208
209 private void logtime(String desc,long time) {
210 timelogger.trace("synchro",desc+time);
211 }
212
213// --------------------------------------------------------------
214// private variables
215// --------------------------------------------------------------
216 private long timestamp;
217
218 private final int[] lock = new int[0];
219 private int currentJobs = 0;
220
221 private long timeout;
222
223 // state issue
224 private boolean terminated = false;
225
226 private static final ClassLogger logger =
227 new ClassLogger("javax.management.remote.misc",
228 "ServerCommunicatorAdmin");
229 private static final ClassLogger timelogger =
230 new ClassLogger("javax.management.remote.timeout",
231 "ServerCommunicatorAdmin");
232}