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 import sun.misc.ManagedLocalsThread; 31 32 public 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 ManagedLocalsThread(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 }