232 lines · 7.9 KB · Java
RawDownload
/* * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jmx.remote.internal; import java.io.IOException; import com.sun.jmx.remote.util.ClassLogger; public abstract class ServerCommunicatorAdmin {    public ServerCommunicatorAdmin(long timeout) {        if (logger.traceOn()) {            logger.trace("Constructor",                         "Creates a new ServerCommunicatorAdmin object "+                         "with the timeout "+timeout);        }         this.timeout = timeout;         timestamp = 0;        if (timeout < Long.MAX_VALUE) {            Runnable timeoutTask = new Timeout();            final Thread t = new Thread(timeoutTask);            t.setName("JMX server connection timeout " + t.getId());            // If you change this name you will need to change a unit test            // (NoServerTimeoutTest)            t.setDaemon(true);            t.start();        }    }     /**     * Tells that a new request message is received.     * A caller of this method should always call the method     * <code>rspOutgoing</code> to inform that a response is sent out     * for the received request.     * @return the value of the termination flag:     * <ul><code>true</code> if the connection is already being terminated,     * <br><code>false</code> otherwise.</ul>     */    public boolean reqIncoming() {        if (logger.traceOn()) {            logger.trace("reqIncoming", "Receive a new request.");        }         synchronized(lock) {            if (terminated) {                logger.warning("reqIncoming",                               "The server has decided to close " +                               "this client connection.");            }            ++currentJobs;             return terminated;        }    }     /**     * Tells that a response is sent out for a received request.     * @return the value of the termination flag:     * <ul><code>true</code> if the connection is already being terminated,     * <br><code>false</code> otherwise.</ul>     */    public boolean rspOutgoing() {        if (logger.traceOn()) {            logger.trace("reqIncoming", "Finish a request.");        }         synchronized(lock) {            if (--currentJobs == 0) {                timestamp = System.currentTimeMillis();                logtime("Admin: Timestamp=",timestamp);                // tells the adminor to restart waiting with timeout                lock.notify();            }            return terminated;        }    }     /**     * Called by this class to tell an implementation to do stop.     */    protected abstract void doStop();     /**     * Terminates this object.     * Called only by outside, so do not need to call doStop     */    public void terminate() {        if (logger.traceOn()) {            logger.trace("terminate",                         "terminate the ServerCommunicatorAdmin object.");        }         synchronized(lock) {            if (terminated) {                return;            }             terminated = true;             // tell Timeout to terminate            lock.notify();        }    } // --------------------------------------------------------------// private classes// --------------------------------------------------------------    private class Timeout implements Runnable {        public void run() {            boolean stopping = false;             synchronized(lock) {                if (timestamp == 0) timestamp = System.currentTimeMillis();                logtime("Admin: timeout=",timeout);                logtime("Admin: Timestamp=",timestamp);                 while(!terminated) {                    try {                        // wait until there is no more job                        while(!terminated && currentJobs != 0) {                            if (logger.traceOn()) {                                logger.trace("Timeout-run",                                             "Waiting without timeout.");                            }                             lock.wait();                        }                         if (terminated) return;                         final long remaining =                            timeout - (System.currentTimeMillis() - timestamp);                         logtime("Admin: remaining timeout=",remaining);                         if (remaining > 0) {                             if (logger.traceOn()) {                                logger.trace("Timeout-run",                                             "Waiting with timeout: "+                                             remaining + " ms remaining");                            }                             lock.wait(remaining);                        }                         if (currentJobs > 0) continue;                         final long elapsed =                            System.currentTimeMillis() - timestamp;                        logtime("Admin: elapsed=",elapsed);                         if (!terminated && elapsed > timeout) {                            if (logger.traceOn()) {                                logger.trace("Timeout-run",                                             "timeout elapsed");                            }                            logtime("Admin: timeout elapsed! "+                                    elapsed+">",timeout);                                // stopping                            terminated = true;                             stopping = true;                            break;                        }                    } catch (InterruptedException ire) {                        logger.warning("Timeout-run","Unexpected Exception: "+                                       ire);                        logger.debug("Timeout-run",ire);                        return;                    }                }            }             if (stopping) {                if (logger.traceOn()) {                    logger.trace("Timeout-run", "Call the doStop.");                }                 doStop();            }        }    }     private void logtime(String desc,long time) {        timelogger.trace("synchro",desc+time);    } // --------------------------------------------------------------// private variables// --------------------------------------------------------------    private long    timestamp;     private final int[] lock = new int[0];    private int currentJobs = 0;     private long timeout;     // state issue    private boolean terminated = false;     private static final ClassLogger logger =        new ClassLogger("javax.management.remote.misc",                        "ServerCommunicatorAdmin");    private static final ClassLogger timelogger =        new ClassLogger("javax.management.remote.timeout",                        "ServerCommunicatorAdmin");}