/*
 * 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 CommunicatorServer and inherit this behavior. Connectors or adaptors that do not fit into this model do not extend CommunicatorServer.

A CommunicatorServer is an active object, it listens for client requests and processes them in its own thread. When necessary, a CommunicatorServer creates other threads to process multiple requests concurrently.

A CommunicatorServer object can be stopped by calling the stop method. When it is stopped, the CommunicatorServer no longer listens to client requests and no longer holds any thread or communication resources. It can be started again by calling the start method.

A CommunicatorServer has a State attribute which reflects its activity.

CommunicatorServer State
stopped OFFLINE
starting STARTING
running ONLINE
stopping STOPPING

The STARTING state marks the transition from OFFLINE to ONLINE.

The STOPPING state marks the transition from ONLINE to OFFLINE. This occurs when the CommunicatorServer is finishing or interrupting active requests.

When a CommunicatorServer is unregistered from the MBeanServer, it is stopped automatically.

When the value of the State attribute changes the CommunicatorServer sends a AttributeChangeNotification to the registered listeners, if any.

This API is a Sun Microsystems internal API and is subject to change without notice.

/** * 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 ONLINE state.
/** * Represents an <CODE>ONLINE</CODE> state. */
public static final int ONLINE = 0 ;
Represents an OFFLINE state.
/** * Represents an <CODE>OFFLINE</CODE> state. */
public static final int OFFLINE = 1 ;
Represents a STOPPING state.
/** * Represents a <CODE>STOPPING</CODE> state. */
public static final int STOPPING = 2 ;
Represents a STARTING state.
/** * 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.
/** * 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.
/** * The state of the connector server. */
transient volatile int state = OFFLINE ;
The object name of the connector server.
@serial
/** * 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
/** * 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
/** * The host name used by this CommunicatorServer. * @serial */
String host = null ;
The port number used by this CommunicatorServer.
@serial
/** * 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 CommunicatorServer.
Params:
  • connectorType – Indicates the connector type. Possible values are: SNMP_TYPE.
Throws:
  • java.lang.IllegalArgumentException – This connector type is not correct.
/** * 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 CommunicatorServer.

Has no effect if this CommunicatorServer is ONLINE or STOPPING.

Params:
  • timeout – Time in ms to wait for the connector to start. If timeout is positive, wait for at most the specified time. An infinite timeout can be specified by passing a timeout value equals Long.MAX_VALUE. 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.
Throws:
/** * 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 CommunicatorServer.

Has no effect if this CommunicatorServer is ONLINE or STOPPING.

/** * 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 CommunicatorServer.

Has no effect if this CommunicatorServer is OFFLINE or STOPPING.

/** * 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 CommunicatorServer is active.
Returns:True if connector is ONLINE; false otherwise.
/** * 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); } }

Waits until either the State attribute of this MBean equals the specified wantedState parameter, or the specified timeOut has elapsed. The method waitState returns with a boolean value indicating whether the specified wantedState parameter equals the value of this MBean's State attribute at the time the method terminates.

Two special cases for the timeOut parameter value are:

  • if timeOut is negative then waitState returns immediately (i.e. does not wait at all),
  • if timeOut equals zero then waitState waits untill the value of this MBean's State attribute is the same as the wantedState parameter (i.e. will wait indefinitely if this condition is never met).
Params:
  • wantedState – The value of this MBean's State attribute to wait for. wantedState can be one of:
    • CommunicatorServer.OFFLINE,
    • CommunicatorServer.ONLINE,
    • CommunicatorServer.STARTING,
    • CommunicatorServer.STOPPING.
  • timeOut – The maximum time to wait for, in milliseconds, if positive. Infinite time out if 0, or no waiting at all if negative.
Returns:true if the value of this MBean's State attribute is the same as the wantedState parameter; false otherwise.
/** * <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; } }

Waits until the communicator is started or timeout expires.

Params:
  • timeout – Time in ms to wait for the connector to start. If timeout is positive, wait for at most the specified time. An infinite timeout can be specified by passing a timeout value equals Long.MAX_VALUE. 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.
Throws:
/** * <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. * */
private void waitForStart(long timeout) throws CommunicationException, InterruptedException { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "waitForStart", "Timeout=" + timeout + " ; current state = " + getStateString()); } final long startTime = System.currentTimeMillis(); synchronized (stateLock) { while (state == STARTING) { // Time elapsed since startTime... // final long elapsed = System.currentTimeMillis() - startTime; // wait for timeout - elapsed. // A timeout of Long.MAX_VALUE is equivalent to something // like 292271023 years - which is pretty close to // forever as far as we are concerned ;-) // final long remainingTime = timeout-elapsed; // If remainingTime is negative, the timeout has elapsed. // if (remainingTime < 0) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "waitForStart", "timeout < 0, return without wait"); } throw new InterruptedException("Timeout expired"); } // We're going to wait until someone notifies on the // the stateLock object, or until the timeout expires, // or until the thread is interrupted. // try { stateLock.wait(remainingTime); } catch (InterruptedException e) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "waitForStart", "wait interrupted"); } // If we are now ONLINE, then no need to rethrow the // exception... we're simply going to exit the while // loop. Otherwise, throw the InterruptedException. // if (state != ONLINE) throw e; } } // We're no longer in STARTING state // if (state == ONLINE) { // OK, we're started, everything went fine, just return // if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "waitForStart", "started"); } return; } else if (startException instanceof CommunicationException) { // There was some exception during the starting phase. // Cast and throw... // throw (CommunicationException)startException; } else if (startException instanceof InterruptedException) { // There was some exception during the starting phase. // Cast and throw... // throw (InterruptedException)startException; } else if (startException != null) { // There was some exception during the starting phase. // Wrap and throw... // throw new CommunicationException(startException, "Failed to start: "+ startException); } else { // We're not ONLINE, and there's no exception... // Something went wrong but we don't know what... // throw new CommunicationException("Failed to start: state is "+ getStringForState(state)); } } }
Gets the state of this CommunicatorServer as an integer.
Returns:ONLINE, OFFLINE, STARTING or STOPPING.
/** * Gets the state of this <CODE>CommunicatorServer</CODE> as an integer. * * @return <CODE>ONLINE</CODE>, <CODE>OFFLINE</CODE>, * <CODE>STARTING</CODE> or <CODE>STOPPING</CODE>. */
public int getState() { synchronized (stateLock) { return state ; } }
Gets the state of this CommunicatorServer as a string.
Returns:One of the strings "ONLINE", "OFFLINE", "STARTING" or "STOPPING".
/** * Gets the state of this <CODE>CommunicatorServer</CODE> as a string. * * @return One of the strings "ONLINE", "OFFLINE", "STARTING" or * "STOPPING". */
public String getStateString() { return getStringForState(state) ; }
Gets the host name used by this CommunicatorServer.
Returns:The host name used by this CommunicatorServer.
/** * Gets the host name used by this <CODE>CommunicatorServer</CODE>. * * @return The host name used by this <CODE>CommunicatorServer</CODE>. */
public String getHost() { try { host = InetAddress.getLocalHost().getHostName(); } catch (Exception e) { host = "Unknown host"; } return host ; }
Gets the port number used by this CommunicatorServer.
Returns:The port number used by this CommunicatorServer.
/** * Gets the port number used by this <CODE>CommunicatorServer</CODE>. * * @return The port number used by this <CODE>CommunicatorServer</CODE>. */
public int getPort() { synchronized (stateLock) { return port ; } }
Sets the port number used by this CommunicatorServer.
Params:
  • port – The port number used by this CommunicatorServer.
Throws:
/** * Sets the port number used by this <CODE>CommunicatorServer</CODE>. * * @param port The port number used by this * <CODE>CommunicatorServer</CODE>. * * @exception java.lang.IllegalStateException This method has been invoked * while the communicator was ONLINE or STARTING. */
public void setPort(int port) throws java.lang.IllegalStateException { synchronized (stateLock) { if ((state == ONLINE) || (state == STARTING)) throw new IllegalStateException("Stop server before " + "carrying out this operation"); this.port = port; dbgTag = makeDebugTag(); } }
Gets the protocol being used by this CommunicatorServer.
Returns:The protocol as a string.
/** * Gets the protocol being used by this <CODE>CommunicatorServer</CODE>. * @return The protocol as a string. */
public abstract String getProtocol() ;
Gets the number of clients that have been processed by this CommunicatorServer since its creation.
Returns:The number of clients handled by this CommunicatorServer since its creation. This counter is not reset by the stop method.
/** * Gets the number of clients that have been processed by this * <CODE>CommunicatorServer</CODE> since its creation. * * @return The number of clients handled by this * <CODE>CommunicatorServer</CODE> * since its creation. This counter is not reset by the * <CODE>stop</CODE> method. */
int getServedClientCount() { return servedClientCount ; }
Gets the number of clients currently being processed by this CommunicatorServer.
Returns:The number of clients currently being processed by this CommunicatorServer.
/** * Gets the number of clients currently being processed by this * <CODE>CommunicatorServer</CODE>. * * @return The number of clients currently being processed by this * <CODE>CommunicatorServer</CODE>. */
int getActiveClientCount() { int result = clientHandlerVector.size() ; return result ; }
Gets the maximum number of clients that this CommunicatorServer can process concurrently.
Returns:The maximum number of clients that this CommunicatorServer can process concurrently.
/** * Gets the maximum number of clients that this * <CODE>CommunicatorServer</CODE> can process concurrently. * * @return The maximum number of clients that this * <CODE>CommunicatorServer</CODE> can * process concurrently. */
int getMaxActiveClientCount() { return maxActiveClientCount ; }
Sets the maximum number of clients this CommunicatorServer can process concurrently.
Params:
  • c – The number of clients.
Throws:
/** * Sets the maximum number of clients this * <CODE>CommunicatorServer</CODE> can process concurrently. * * @param c The number of clients. * * @exception java.lang.IllegalStateException This method has been invoked * while the communicator was ONLINE or STARTING. */
void setMaxActiveClientCount(int c) throws java.lang.IllegalStateException { synchronized (stateLock) { if ((state == ONLINE) || (state == STARTING)) { throw new IllegalStateException( "Stop server before carrying out this operation"); } maxActiveClientCount = c ; } }
For SNMP Runtime internal use only.
/** * For SNMP Runtime internal use only. */
void notifyClientHandlerCreated(ClientHandler h) { clientHandlerVector.addElement(h) ; }
For SNMP Runtime internal use only.
/** * For SNMP Runtime internal use only. */
synchronized void notifyClientHandlerDeleted(ClientHandler h) { clientHandlerVector.removeElement(h); notifyAll(); }
The number of times the communicator server will attempt to bind before giving up.
/** * The number of times the communicator server will attempt * to bind before giving up. **/
protected int getBindTries() { return 50; }
The delay, in ms, during which the communicator server will sleep before attempting to bind again.
/** * The delay, in ms, during which the communicator server will sleep before * attempting to bind again. **/
protected long getBindSleepTime() { return 100; }
For SNMP Runtime internal use only.

The run method executed by this connector's main thread.

/** * For SNMP Runtime internal use only. * <p> * The <CODE>run</CODE> method executed by this connector's main thread. */
public void run() { // Fix jaw.00667.B // It seems that the init of "i" and "success" // need to be done outside the "try" clause... // A bug in Java 2 production release ? // int i = 0; boolean success = false; // ---------------------- // Bind // ---------------------- try { // Fix for bug 4352451: "java.net.BindException: Address in use". // final int bindRetries = getBindTries(); final long sleepTime = getBindSleepTime(); while (i < bindRetries && !success) { try { // Try socket connection. // doBind(); success = true; } catch (CommunicationException ce) { i++; try { Thread.sleep(sleepTime); } catch (InterruptedException ie) { throw ie; } } } // Retry last time to get correct exception. // if (!success) { // Try socket connection. // doBind(); } } catch(Exception x) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "run", "Got unexpected exception", x); } synchronized(stateLock) { startException = x; changeState(OFFLINE); } if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "run","State is OFFLINE"); } doError(x); return; } try { // ---------------------- // State change // ---------------------- changeState(ONLINE) ; if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "run","State is ONLINE"); } // ---------------------- // Main loop // ---------------------- while (!stopRequested) { servedClientCount++; doReceive() ; waitIfTooManyClients() ; doProcess() ; } if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "run","Stop has been requested"); } } catch(InterruptedException x) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "run","Interrupt caught"); } changeState(STOPPING); } catch(Exception x) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "run","Got unexpected exception", x); } changeState(STOPPING); } finally { synchronized (stateLock) { interrupted = true; Thread.currentThread().interrupted(); } // ---------------------- // unBind // ---------------------- try { doUnbind() ; waitClientTermination() ; changeState(OFFLINE); if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "run","State is OFFLINE"); } } catch(Exception x) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "run","Got unexpected exception", x); } changeState(OFFLINE); } } } /** */ protected abstract void doError(Exception e) throws CommunicationException; // // To be defined by the subclass. // // Each method below is called by run() and must be subclassed. // If the method sends an exception (Communication or Interrupt), this // will end up the run() method and switch the connector offline. // // If it is a CommunicationException, run() will call // Debug.printException(). // // All these methods should propagate the InterruptedException to inform // run() that the connector must be switch OFFLINE. // // // // doBind() should do all what is needed before calling doReceive(). // If doBind() throws an exception, doUnbind() is not to be called // and run() ends up. // /** */ protected abstract void doBind() throws CommunicationException, InterruptedException ;
doReceive() should block until a client is available. If this method throws an exception, doProcess() is not called but doUnbind() is called then run() stops.
/** * <CODE>doReceive()</CODE> should block until a client is available. * If this method throws an exception, <CODE>doProcess()</CODE> is not * called but <CODE>doUnbind()</CODE> is called then <CODE>run()</CODE> * stops. */
protected abstract void doReceive() throws CommunicationException, InterruptedException ;
doProcess() is called after doReceive(): it should process the requests of the incoming client. If it throws an exception, doUnbind() is called and run() stops.
/** * <CODE>doProcess()</CODE> is called after <CODE>doReceive()</CODE>: * it should process the requests of the incoming client. * If it throws an exception, <CODE>doUnbind()</CODE> is called and * <CODE>run()</CODE> stops. */
protected abstract void doProcess() throws CommunicationException, InterruptedException ;
doUnbind() is called whenever the connector goes OFFLINE, except if doBind() has thrown an exception.
/** * <CODE>doUnbind()</CODE> is called whenever the connector goes * <CODE>OFFLINE</CODE>, except if <CODE>doBind()</CODE> has thrown an * exception. */
protected abstract void doUnbind() throws CommunicationException, InterruptedException ;
Get the MBeanServer object to which incoming requests are sent. This is either the MBean server in which this connector is registered, or an MBeanServerForwarder leading to that server.
/** * Get the <code>MBeanServer</code> object to which incoming requests are * sent. This is either the MBean server in which this connector is * registered, or an <code>MBeanServerForwarder</code> leading to that * server. */
public synchronized MBeanServer getMBeanServer() { return topMBS; }
Set the MBeanServer object to which incoming requests are sent. This must be either the MBean server in which this connector is registered, or an MBeanServerForwarder leading to that server. An MBeanServerForwarder mbsf leads to an MBean server mbs if mbsf.getMBeanServer() is either mbs or an MBeanServerForwarder leading to mbs.
Throws:
  • IllegalArgumentException – if newMBS is neither the MBean server in which this connector is registered nor an MBeanServerForwarder leading to that server.
  • IllegalStateException – This method has been invoked while the communicator was ONLINE or STARTING.
/** * Set the <code>MBeanServer</code> object to which incoming * requests are sent. This must be either the MBean server in * which this connector is registered, or an * <code>MBeanServerForwarder</code> leading to that server. An * <code>MBeanServerForwarder</code> <code>mbsf</code> leads to an * MBean server <code>mbs</code> if * <code>mbsf.getMBeanServer()</code> is either <code>mbs</code> * or an <code>MBeanServerForwarder</code> leading to * <code>mbs</code>. * * @exception IllegalArgumentException if <code>newMBS</code> is neither * the MBean server in which this connector is registered nor an * <code>MBeanServerForwarder</code> leading to that server. * * @exception IllegalStateException This method has been invoked * while the communicator was ONLINE or STARTING. */
public synchronized void setMBeanServer(MBeanServer newMBS) throws IllegalArgumentException, IllegalStateException { synchronized (stateLock) { if (state == ONLINE || state == STARTING) throw new IllegalStateException("Stop server before " + "carrying out this operation"); } final String error = "MBeanServer argument must be MBean server where this " + "server is registered, or an MBeanServerForwarder " + "leading to that server"; Vector<MBeanServer> seenMBS = new Vector<MBeanServer>(); for (MBeanServer mbs = newMBS; mbs != bottomMBS; mbs = ((MBeanServerForwarder) mbs).getMBeanServer()) { if (!(mbs instanceof MBeanServerForwarder)) throw new IllegalArgumentException(error); if (seenMBS.contains(mbs)) throw new IllegalArgumentException("MBeanServerForwarder " + "loop"); seenMBS.addElement(mbs); } topMBS = newMBS; } // // To be called by the subclass if needed //
For internal use only.
/** * For internal use only. */
ObjectName getObjectName() { return objectName ; }
For internal use only.
/** * For internal use only. */
void changeState(int newState) { int oldState; synchronized (stateLock) { if (state == newState) return; oldState = state; state = newState; stateLock.notifyAll(); } sendStateChangeNotification(oldState, newState); }
Returns the string used in debug traces.
/** * Returns the string used in debug traces. */
String makeDebugTag() { return "CommunicatorServer["+ getProtocol() + ":" + getPort() + "]" ; }
Returns the string used to name the connector thread.
/** * Returns the string used to name the connector thread. */
String makeThreadName() { String result ; if (objectName == null) result = "CommunicatorServer" ; else result = objectName.toString() ; return result ; }
This method blocks if there are too many active clients. Call to wait() is terminated when a client handler thread calls notifyClientHandlerDeleted(this) ;
/** * This method blocks if there are too many active clients. * Call to <CODE>wait()</CODE> is terminated when a client handler * thread calls <CODE>notifyClientHandlerDeleted(this)</CODE> ; */
private synchronized void waitIfTooManyClients() throws InterruptedException { while (getActiveClientCount() >= maxActiveClientCount) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "waitIfTooManyClients","Waiting for a client to terminate"); } wait(); } }
This method blocks until there is no more active client.
/** * This method blocks until there is no more active client. */
private void waitClientTermination() { int s = clientHandlerVector.size() ; if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { if (s >= 1) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "waitClientTermination","waiting for " + s + " clients to terminate"); } } // The ClientHandler will remove themselves from the // clientHandlerVector at the end of their run() method, by // calling notifyClientHandlerDeleted(). // Since the clientHandlerVector is modified by the ClientHandler // threads we must avoid using Enumeration or Iterator to loop // over this array. We must also take care of NoSuchElementException // which could be thrown if the last ClientHandler removes itself // between the call to clientHandlerVector.isEmpty() and the call // to clientHandlerVector.firstElement(). // What we *MUST NOT DO* is locking the clientHandlerVector, because // this would most probably cause a deadlock. // while (! clientHandlerVector.isEmpty()) { try { clientHandlerVector.firstElement().join(); } catch (NoSuchElementException x) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "waitClientTermination","No elements left", x); } } } if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { if (s >= 1) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "waitClientTermination","Ok, let's go..."); } } }
Call interrupt() on each pending client.
/** * Call <CODE>interrupt()</CODE> on each pending client. */
private void terminateAllClient() { final int s = clientHandlerVector.size() ; if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { if (s >= 1) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "terminateAllClient","Interrupting " + s + " clients"); } } // The ClientHandler will remove themselves from the // clientHandlerVector at the end of their run() method, by // calling notifyClientHandlerDeleted(). // Since the clientHandlerVector is modified by the ClientHandler // threads we must avoid using Enumeration or Iterator to loop // over this array. // We cannot use the same logic here than in waitClientTermination() // because there is no guarantee that calling interrupt() on the // ClientHandler will actually terminate the ClientHandler. // Since we do not want to wait for the actual ClientHandler // termination, we cannot simply loop over the array until it is // empty (this might result in calling interrupt() endlessly on // the same client handler. So what we do is simply take a snapshot // copy of the vector and loop over the copy. // What we *MUST NOT DO* is locking the clientHandlerVector, because // this would most probably cause a deadlock. // final ClientHandler[] handlers = clientHandlerVector.toArray(new ClientHandler[0]); for (ClientHandler h : handlers) { try { h.interrupt() ; } catch (Exception x) { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINER)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINER, dbgTag, "terminateAllClient", "Failed to interrupt pending request. " + "Ignore the exception.", x); } } } }
Controls the way the CommunicatorServer service is deserialized.
/** * Controls the way the CommunicatorServer service is deserialized. */
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { // Call the default deserialization of the object. // stream.defaultReadObject(); // Call the specific initialization for the CommunicatorServer service. // This is for transient structures to be initialized to specific // default values. // stateLock = new Object(); state = OFFLINE; stopRequested = false; servedClientCount = 0; clientHandlerVector = new Vector<ClientHandler>(); fatherThread = Thread.currentThread(); mainThread = null; notifCount = 0; notifInfos = null; notifBroadcaster = new NotificationBroadcasterSupport(); dbgTag = makeDebugTag(); } // // NotificationBroadcaster //
Adds a listener for the notifications emitted by this CommunicatorServer. There is only one type of notifications sent by the CommunicatorServer: they are AttributeChangeNotification, sent when the State attribute of this CommunicatorServer changes.
Params:
  • listener – The listener object which will handle the emitted notifications.
  • filter – The filter object. If filter is null, no filtering will be performed before handling notifications.
  • handback – An object which will be sent back unchanged to the listener when a notification is emitted.
Throws:
/** * Adds a listener for the notifications emitted by this * CommunicatorServer. * There is only one type of notifications sent by the CommunicatorServer: * they are <tt>{@link javax.management.AttributeChangeNotification}</tt>, * sent when the <tt>State</tt> attribute of this CommunicatorServer * changes. * * @param listener The listener object which will handle the emitted * notifications. * @param filter The filter object. If filter is null, no filtering * will be performed before handling notifications. * @param handback An object which will be sent back unchanged to the * listener when a notification is emitted. * * @exception IllegalArgumentException Listener parameter is null. */
public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws java.lang.IllegalArgumentException { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "addNotificationListener","Adding listener "+ listener + " with filter "+ filter + " and handback "+ handback); } notifBroadcaster.addNotificationListener(listener, filter, handback); }
Removes the specified listener from this CommunicatorServer. Note that if the listener has been registered with different handback objects or notification filters, all entries corresponding to the listener will be removed.
Params:
  • listener – The listener object to be removed.
Throws:
/** * Removes the specified listener from this CommunicatorServer. * Note that if the listener has been registered with different * handback objects or notification filters, all entries corresponding * to the listener will be removed. * * @param listener The listener object to be removed. * * @exception ListenerNotFoundException The listener is not registered. */
public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "removeNotificationListener","Removing listener "+ listener); } notifBroadcaster.removeNotificationListener(listener); }
Returns an array of MBeanNotificationInfo objects describing the notification types sent by this CommunicatorServer. There is only one type of notifications sent by the CommunicatorServer: it is AttributeChangeNotification, sent when the State attribute of this CommunicatorServer changes.
/** * Returns an array of MBeanNotificationInfo objects describing * the notification types sent by this CommunicatorServer. * There is only one type of notifications sent by the CommunicatorServer: * it is <tt>{@link javax.management.AttributeChangeNotification}</tt>, * sent when the <tt>State</tt> attribute of this CommunicatorServer * changes. */
public MBeanNotificationInfo[] getNotificationInfo() { // Initialize notifInfos on first call to getNotificationInfo() // if (notifInfos == null) { notifInfos = new MBeanNotificationInfo[1]; String[] notifTypes = { AttributeChangeNotification.ATTRIBUTE_CHANGE}; notifInfos[0] = new MBeanNotificationInfo( notifTypes, AttributeChangeNotification.class.getName(), "Sent to notify that the value of the State attribute "+ "of this CommunicatorServer instance has changed."); } return notifInfos; } /** * */ private void sendStateChangeNotification(int oldState, int newState) { String oldStateString = getStringForState(oldState); String newStateString = getStringForState(newState); String message = new StringBuffer().append(dbgTag) .append(" The value of attribute State has changed from ") .append(oldState).append(" (").append(oldStateString) .append(") to ").append(newState).append(" (") .append(newStateString).append(").").toString(); notifCount++; AttributeChangeNotification notif = new AttributeChangeNotification(this, // source notifCount, // sequence number System.currentTimeMillis(), // time stamp message, // message "State", // attribute name "int", // attribute type new Integer(oldState), // old value new Integer(newState) ); // new value if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) { SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag, "sendStateChangeNotification","Sending AttributeChangeNotification #" + notifCount + " with message: "+ message); } notifBroadcaster.sendNotification(notif); } /** * */ private static String getStringForState(int s) { switch (s) { case ONLINE: return "ONLINE"; case STARTING: return "STARTING"; case OFFLINE: return "OFFLINE"; case STOPPING: return "STOPPING"; default: return "UNDEFINED"; } } // // MBeanRegistration //
Preregister method of connector.
Params:
  • server – The MBeanServer in which the MBean will be registered.
  • name – The object name of the MBean.
Throws:
  • langException – This exception should be caught by the MBeanServer and re-thrown as an MBeanRegistrationException.
Returns: The name of the MBean registered.
/** * Preregister method of connector. * *@param server The <CODE>MBeanServer</CODE> in which the MBean will * be registered. *@param name The object name of the MBean. * *@return The name of the MBean registered. * *@exception java.langException This exception should be caught by * the <CODE>MBeanServer</CODE> and re-thrown * as an <CODE>MBeanRegistrationException</CODE>. */
public ObjectName preRegister(MBeanServer server, ObjectName name) throws java.lang.Exception { objectName = name; synchronized (this) { if (bottomMBS != null) { throw new IllegalArgumentException("connector already " + "registered in an MBean " + "server"); } topMBS = bottomMBS = server; } dbgTag = makeDebugTag(); return name; }
Params:
  • registrationDone – Indicates whether or not the MBean has been successfully registered in the MBeanServer. The value false means that the registration phase has failed.
/** * *@param registrationDone Indicates whether or not the MBean has been * successfully registered in the <CODE>MBeanServer</CODE>. * The value false means that the registration phase has failed. */
public void postRegister(Boolean registrationDone) { if (!registrationDone.booleanValue()) { synchronized (this) { topMBS = bottomMBS = null; } } }
Stop the connector.
Throws:
  • langException – This exception should be caught by the MBeanServer and re-thrown as an MBeanRegistrationException.
/** * Stop the connector. * * @exception java.langException This exception should be caught by * the <CODE>MBeanServer</CODE> and re-thrown * as an <CODE>MBeanRegistrationException</CODE>. */
public void preDeregister() throws java.lang.Exception { synchronized (this) { topMBS = bottomMBS = null; } objectName = null ; final int cstate = getState(); if ((cstate == ONLINE) || ( cstate == STARTING)) { stop() ; } }
Do nothing.
/** * Do nothing. */
public void postDeregister(){ }
Load a class using the default loader repository
/** * Load a class using the default loader repository **/
Class loadClass(String className) throws ClassNotFoundException { try { return Class.forName(className); } catch (ClassNotFoundException e) { final ClassLoaderRepository clr = MBeanServerFactory.getClassLoaderRepository(bottomMBS); if (clr == null) throw new ClassNotFoundException(className); return clr.loadClass(className); } } }