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