1375 lines · 47.9 KB · Java
RawDownload
/* * Copyright (c) 1999, 2007, 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.snmp.daemon;   // java import//import java.io.ObjectInputStream;import java.io.IOException;import java.net.InetAddress;import java.util.Enumeration;import java.util.logging.Level;import java.util.Vector;import java.util.NoSuchElementException; // jmx import//import javax.management.MBeanServer;import javax.management.MBeanRegistration;import javax.management.ObjectName;import javax.management.NotificationListener;import javax.management.NotificationFilter;import javax.management.NotificationBroadcaster;import javax.management.NotificationBroadcasterSupport;import javax.management.MBeanNotificationInfo;import javax.management.AttributeChangeNotification;import javax.management.ListenerNotFoundException;import javax.management.loading.ClassLoaderRepository;import javax.management.MBeanServerFactory; import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER; // JSR 160 import//// XXX Revisit://   used to import com.sun.jmx.snmp.MBeanServerForwarder// Now using JSR 160 instead. => this is an additional// dependency to JSR 160.//import javax.management.remote.MBeanServerForwarder; /** * Defines generic behavior for the server part of a connector or an adaptor. * Most connectors or adaptors extend <CODE>CommunicatorServer</CODE> * and inherit this behavior. Connectors or adaptors that do not fit into * this model do not extend <CODE>CommunicatorServer</CODE>. * <p> * A <CODE>CommunicatorServer</CODE> is an active object, it listens for * client requests  and processes them in its own thread. When necessary, a * <CODE>CommunicatorServer</CODE> creates other threads to process multiple * requests concurrently. * <p> * A <CODE>CommunicatorServer</CODE> object can be stopped by calling the * <CODE>stop</CODE> method. When it is stopped, the * <CODE>CommunicatorServer</CODE> no longer listens to client requests and * no longer holds any thread or communication resources. * It can be started again by calling the <CODE>start</CODE> method. * <p> * A <CODE>CommunicatorServer</CODE> has a <CODE>State</CODE> attribute * which reflects its  activity. * <p> * <TABLE> * <TR><TH>CommunicatorServer</TH>      <TH>State</TH></TR> * <TR><TD><CODE>stopped</CODE></TD>    <TD><CODE>OFFLINE</CODE></TD></TR> * <TR><TD><CODE>starting</CODE></TD>    <TD><CODE>STARTING</CODE></TD></TR> * <TR><TD><CODE>running</CODE></TD>     <TD><CODE>ONLINE</CODE></TD></TR> * <TR><TD><CODE>stopping</CODE></TD>     <TD><CODE>STOPPING</CODE></TD></TR> * </TABLE> * <p> * The <CODE>STARTING</CODE> state marks the transition * from <CODE>OFFLINE</CODE> to <CODE>ONLINE</CODE>. * <p> * The <CODE>STOPPING</CODE> state marks the transition from * <CODE>ONLINE</CODE> to <CODE>OFFLINE</CODE>. This occurs when the * <CODE>CommunicatorServer</CODE> is finishing or interrupting active * requests. * <p> * When a <CODE>CommunicatorServer</CODE> is unregistered from the MBeanServer, * it is stopped automatically. * <p> * When the value of the <CODE>State</CODE> attribute changes the * <CODE>CommunicatorServer</CODE> sends a * <tt>{@link javax.management.AttributeChangeNotification}</tt> to the * registered listeners, if any. * * <p><b>This API is a Sun Microsystems internal API  and is subject * to change without notice.</b></p> */ public abstract class CommunicatorServer    implements Runnable, MBeanRegistration, NotificationBroadcaster,               CommunicatorServerMBean {     //    // States of a CommunicatorServer    //     /**     * Represents an <CODE>ONLINE</CODE> state.     */    public static final int ONLINE = 0 ;     /**     * Represents an <CODE>OFFLINE</CODE> state.     */    public static final int OFFLINE = 1 ;     /**     * Represents a <CODE>STOPPING</CODE> state.     */    public static final int STOPPING = 2 ;     /**     * Represents a <CODE>STARTING</CODE> state.     */    public static final int STARTING = 3 ;     //    // Types of connectors.    //     /**     * Indicates that it is an RMI connector type.     */    //public static final int RMI_TYPE = 1 ;     /**     * Indicates that it is an HTTP connector type.     */    //public static final int HTTP_TYPE = 2 ;     /**     * Indicates that it is an HTML connector type.     */    //public static final int HTML_TYPE = 3 ;     /**     * Indicates that it is an SNMP connector type.     */    public static final int SNMP_TYPE = 4 ;     /**     * Indicates that it is an HTTPS connector type.     */    //public static final int HTTPS_TYPE = 5 ;     //    // Package variables    //     /**     * The state of the connector server.     */     transient volatile int state = OFFLINE ;     /**     * The object name of the connector server.     * @serial     */    ObjectName objectName ;     MBeanServer topMBS;    MBeanServer bottomMBS;     /**     */    transient String dbgTag = null ;     /**     * The maximum number of clients that the CommunicatorServer can     * process concurrently.     * @serial     */    int maxActiveClientCount = 1 ;     /**     */    transient int servedClientCount = 0 ;     /**     * The host name used by this CommunicatorServer.     * @serial     */    String host = null ;     /**     * The port number used by this CommunicatorServer.     * @serial     */    int port = -1 ;      //    // Private fields    //     /* This object controls access to the "state" and "interrupted" variables.       If held at the same time as the lock on "this", the "this" lock must       be taken first.  */    private transient Object stateLock = new Object();     private transient Vector<ClientHandler>            clientHandlerVector = new Vector<ClientHandler>() ;     private transient Thread fatherThread = Thread.currentThread() ;    private transient Thread mainThread = null ;     private volatile boolean stopRequested = false ;    private boolean interrupted = false;    private transient Exception startException = null;     // Notifs count, broadcaster and info    private transient long notifCount = 0;    private transient NotificationBroadcasterSupport notifBroadcaster =        new NotificationBroadcasterSupport();    private transient MBeanNotificationInfo[] notifInfos = null;      /**     * Instantiates a <CODE>CommunicatorServer</CODE>.     *     * @param connectorType Indicates the connector type. Possible values are:     * SNMP_TYPE.     *     * @exception <CODE>java.lang.IllegalArgumentException</CODE>     *            This connector type is not correct.     */    public CommunicatorServer(int connectorType)        throws IllegalArgumentException {        switch (connectorType) {        case SNMP_TYPE :            //No op. int Type deciding debugging removed.            break;        default:            throw new IllegalArgumentException("Invalid connector Type") ;        }        dbgTag = makeDebugTag() ;    }     protected Thread createMainThread() {        return new Thread (this, makeThreadName());    }     /**     * Starts this <CODE>CommunicatorServer</CODE>.     * <p>     * Has no effect if this <CODE>CommunicatorServer</CODE> is     * <CODE>ONLINE</CODE> or <CODE>STOPPING</CODE>.     * @param timeout Time in ms to wait for the connector to start.     *        If <code>timeout</code> is positive, wait for at most     *        the specified time. An infinite timeout can be specified     *        by passing a <code>timeout</code> value equals     *        <code>Long.MAX_VALUE</code>. In that case the method     *        will wait until the connector starts or fails to start.     *        If timeout is negative or zero, returns as soon as possible     *        without waiting.     * @exception CommunicationException if the connectors fails to start.     * @exception InterruptedException if the thread is interrupted or the     *            timeout expires.     */    public void start(long timeout)        throws CommunicationException, InterruptedException {        boolean start;         synchronized (stateLock) {            if (state == STOPPING) {                // Fix for bug 4352451:                //     "java.net.BindException: Address in use".                waitState(OFFLINE, 60000);            }            start = (state == OFFLINE);            if (start) {                changeState(STARTING);                stopRequested = false;                interrupted = false;                startException = null;            }        }         if (!start) {            if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {                SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                    "start","Connector is not OFFLINE");            }            return;        }         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {            SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                "start","--> Start connector ");        }         mainThread = createMainThread();         mainThread.start() ;         if (timeout > 0) waitForStart(timeout);    }     /**     * Starts this <CODE>CommunicatorServer</CODE>.     * <p>     * Has no effect if this <CODE>CommunicatorServer</CODE> is     * <CODE>ONLINE</CODE> or <CODE>STOPPING</CODE>.     */    public void start() {        try {            start(0);        } catch (InterruptedException x) {            // cannot happen because of `0'            if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {                SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                    "start","interrupted", x);            }        }    }     /**     * Stops this <CODE>CommunicatorServer</CODE>.     * <p>     * Has no effect if this <CODE>CommunicatorServer</CODE> is     * <CODE>OFFLINE</CODE> or  <CODE>STOPPING</CODE>.     */    public void stop() {        synchronized (stateLock) {            if (state == OFFLINE || state == STOPPING) {                if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {                    SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                        "stop","Connector is not ONLINE");                }                return;            }            changeState(STOPPING);            //            // Stop the connector thread            //            if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {                SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                    "stop","Interrupt main thread");            }            stopRequested = true ;            if (!interrupted) {                interrupted = true;                mainThread.interrupt();            }        }         //        // Call terminate on each active client handler        //        if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {            SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                "stop","terminateAllClient");        }        terminateAllClient() ;         // ----------------------        // changeState        // ----------------------        synchronized (stateLock) {            if (state == STARTING)                changeState(OFFLINE);        }    }     /**     * Tests whether the <CODE>CommunicatorServer</CODE> is active.     *     * @return True if connector is <CODE>ONLINE</CODE>; false otherwise.     */    public boolean isActive() {        synchronized (stateLock) {            return (state == ONLINE);        }    }     /**     * <p>Waits until either the State attribute of this MBean equals the     * specified <VAR>wantedState</VAR> parameter,     * or the specified  <VAR>timeOut</VAR> has elapsed.     * The method <CODE>waitState</CODE> returns with a boolean value     * indicating whether the specified <VAR>wantedState</VAR> parameter     * equals the value of this MBean's State attribute at the time the method     * terminates.</p>     *     * <p>Two special cases for the <VAR>timeOut</VAR> parameter value are:</p>     * <UL><LI> if <VAR>timeOut</VAR> is negative then <CODE>waitState</CODE>     *     returns immediately (i.e. does not wait at all),</LI>     * <LI> if <VAR>timeOut</VAR> equals zero then <CODE>waitState</CODE>     *     waits untill the value of this MBean's State attribute     *     is the same as the <VAR>wantedState</VAR> parameter (i.e. will wait     *     indefinitely if this condition is never met).</LI></UL>     *     * @param wantedState The value of this MBean's State attribute to wait     *        for. <VAR>wantedState</VAR> can be one of:     * <ul>     * <li><CODE>CommunicatorServer.OFFLINE</CODE>,</li>     * <li><CODE>CommunicatorServer.ONLINE</CODE>,</li>     * <li><CODE>CommunicatorServer.STARTING</CODE>,</li>     * <li><CODE>CommunicatorServer.STOPPING</CODE>.</li>     * </ul>     * @param timeOut The maximum time to wait for, in milliseconds,     *        if positive.     * Infinite time out if 0, or no waiting at all if negative.     *     * @return true if the value of this MBean's State attribute is the     *      same as the <VAR>wantedState</VAR> parameter; false otherwise.     */    public boolean waitState(int wantedState, long timeOut) {        if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {            SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                "waitState", wantedState + "(0on,1off,2st) TO=" + timeOut +                  " ; current state = " + getStateString());        }         long endTime = 0;        if (timeOut > 0)            endTime = System.currentTimeMillis() + timeOut;         synchronized (stateLock) {            while (state != wantedState) {                if (timeOut < 0) {                    if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {                        SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                            "waitState", "timeOut < 0, return without wait");                    }                    return false;                } else {                    try {                        if (timeOut > 0) {                            long toWait = endTime - System.currentTimeMillis();                            if (toWait <= 0) {                                if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {                                    SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                                        "waitState", "timed out");                                }                                return false;                            }                            stateLock.wait(toWait);                        } else {  // timeOut == 0                            stateLock.wait();                        }                    } catch (InterruptedException e) {                        if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {                            SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                                "waitState", "wait interrupted");                        }                        return (state == wantedState);                    }                }            }            if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) {                SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag,                    "waitState","returning in desired state");            }            return true;        }    }     /**     * <p>Waits until the communicator is started or timeout expires.     *     * @param timeout Time in ms to wait for the connector to start.     *        If <code>timeout</code> is positive, wait for at most     *        the specified time. An infinite timeout can be specified     *        by passing a <code>timeout</code> value equals     *        <code>Long.MAX_VALUE</code>. In that case the method     *        will wait until the connector starts or fails to start.     *        If timeout is negative or zero, returns as soon as possible     *        without waiting.     *     * @exception CommunicationException if the connectors fails to start.     * @exception InterruptedException if the thread is interrupted or the     *            timeout expires.     *

Lines 1–500 of 1375.