252 lines · 7.8 KB · Java
RawDownload
/* * Copyright (c) 2003, 2008, 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 java.io.InterruptedIOException; import com.sun.jmx.remote.util.ClassLogger;import com.sun.jmx.remote.util.EnvHelp; public abstract class ClientCommunicatorAdmin {    private static volatile long threadNo = 1;     public ClientCommunicatorAdmin(long period) {        this.period = period;         if (period > 0) {            checker = new Checker();             Thread t = new Thread(checker, "JMX client heartbeat " + ++threadNo);            t.setDaemon(true);            t.start();        } else            checker = null;    }     /**     * Called by a client to inform of getting an IOException.     */    public void gotIOException (IOException ioe) throws IOException {        restart(ioe);    }     /**     * Called by this class to check a client connection.     */    protected abstract void checkConnection() throws IOException;     /**     * Tells a client to re-start again.     */    protected abstract void doStart() throws IOException;     /**     * Tells a client to stop because failing to call checkConnection.     */    protected abstract void doStop();     /**     * Terminates this object.     */    public void terminate() {        synchronized(lock) {            if (state == TERMINATED) {                return;            }             state = TERMINATED;             lock.notifyAll();             if (checker != null)                checker.stop();        }    }     private void restart(IOException ioe) throws IOException {        // check state        synchronized(lock) {            if (state == TERMINATED) {                throw new IOException("The client has been closed.");            } else if (state == FAILED) { // already failed to re-start by another thread                throw ioe;            } else if (state == RE_CONNECTING) {                // restart process has been called by another thread                // we need to wait                while(state == RE_CONNECTING) {                    try {                        lock.wait();                    } catch (InterruptedException ire) {                        // be asked to give up                        InterruptedIOException iioe = new InterruptedIOException(ire.toString());                        EnvHelp.initCause(iioe, ire);                         throw iioe;                    }                }                 if (state == TERMINATED) {                    throw new IOException("The client has been closed.");                } else if (state != CONNECTED) {                    // restarted is failed by another thread                    throw ioe;                }            } else {                state = RE_CONNECTING;                lock.notifyAll();            }        }         // re-starting        try {            doStart();            synchronized(lock) {                if (state == TERMINATED) {                    throw new IOException("The client has been closed.");                }                 state = CONNECTED;                 lock.notifyAll();            }             return;        } catch (Exception e) {            logger.warning("restart", "Failed to restart: " + e);            logger.debug("restart",e);             synchronized(lock) {                if (state == TERMINATED) {                    throw new IOException("The client has been closed.");                }                 state = FAILED;                 lock.notifyAll();            }             try {                doStop();            } catch (Exception eee) {                // OK.                // We know there is a problem.            }             terminate();             throw ioe;        }    } // --------------------------------------------------------------// private varaibles// --------------------------------------------------------------    private class Checker implements Runnable {        public void run() {            myThread = Thread.currentThread();             while (state != TERMINATED && !myThread.isInterrupted()) {                try {                    Thread.sleep(period);                } catch (InterruptedException ire) {                    // OK.                    // We will check the state at the following steps                }                 if (state == TERMINATED || myThread.isInterrupted()) {                    break;                }                 try {                    checkConnection();                } catch (Exception e) {                    synchronized(lock) {                        if (state == TERMINATED || myThread.isInterrupted()) {                            break;                        }                    }                     e = (Exception)EnvHelp.getCause(e);                     if (e instanceof IOException &&                        !(e instanceof InterruptedIOException)) {                        try {                            restart((IOException)e);                        } catch (Exception ee) {                            logger.warning("Checker-run",                                           "Failed to check connection: "+ e);                            logger.warning("Checker-run", "stopping");                            logger.debug("Checker-run",e);                             break;                        }                    } else {                        logger.warning("Checker-run",                                     "Failed to check the connection: " + e);                        logger.debug("Checker-run",e);                         // XXX stop checking?                         break;                    }                }            }             if (logger.traceOn()) {                logger.trace("Checker-run", "Finished.");            }        }         private void stop() {            if (myThread != null && myThread != Thread.currentThread()) {                myThread.interrupt();            }        }         private Thread myThread;    } // --------------------------------------------------------------// private variables// --------------------------------------------------------------    private final Checker checker;    private long period;     // state    private final static int CONNECTED = 0;    private final static int RE_CONNECTING = 1;    private final static int FAILED = 2;    private final static int TERMINATED = 3;     private int state = CONNECTED;     private final int[] lock = new int[0];     private static final ClassLogger logger =        new ClassLogger("javax.management.remote.misc",                        "ClientCommunicatorAdmin");}