FileDocCategorySizeDatePackage
CommunicatorServer.javaAPI DocJava SE 6 API42074Tue Jun 10 00:22:08 BST 2008com.sun.jmx.snmp.daemon

CommunicatorServer

public abstract class CommunicatorServer extends Object implements Runnable, NotificationBroadcaster, CommunicatorServerMBean, MBeanRegistration
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 {@link javax.management.AttributeChangeNotification} to the registered listeners, if any.

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

version
1.60 11/17/05
author
Sun Microsystems, Inc

Fields Summary
public static final int
ONLINE
Represents an ONLINE state.
public static final int
OFFLINE
Represents an OFFLINE state.
public static final int
STOPPING
Represents a STOPPING state.
public static final int
STARTING
Represents a STARTING state.
public static final int
SNMP_TYPE
Indicates that it is an SNMP connector type.
volatile transient int
state
The state of the connector server.
ObjectName
objectName
The object name of the connector server.
MBeanServer
topMBS
MBeanServer
bottomMBS
transient String
dbgTag
int
maxActiveClientCount
The maximum number of clients that the CommunicatorServer can process concurrently.
transient int
servedClientCount
String
host
The host name used by this CommunicatorServer.
int
port
The port number used by this CommunicatorServer.
private transient Object
stateLock
private transient Vector
clientHandlerVector
private transient Thread
fatherThread
private transient Thread
mainThread
private volatile boolean
stopRequested
private boolean
interrupted
private transient Exception
startException
private transient long
notifCount
private transient NotificationBroadcasterSupport
notifBroadcaster
private transient MBeanNotificationInfo[]
notifInfos
int
infoType
Constructors Summary
public CommunicatorServer(int connectorType)
Instantiates a CommunicatorServer.

param
connectorType Indicates the connector type. Possible values are: SNMP_TYPE.
exception
java.lang.IllegalArgumentException This connector type is not correct.

    

                                            
       
	  
        switch (connectorType) {
        case SNMP_TYPE :
            infoType = Trace.INFO_ADAPTOR_SNMP ;
            break;
        default:
            throw new IllegalArgumentException("Invalid connector Type") ;
        }
        dbgTag = makeDebugTag() ;
    
Methods Summary
public voidaddNotificationListener(javax.management.NotificationListener listener, javax.management.NotificationFilter filter, java.lang.Object handback)
Adds a listener for the notifications emitted by this CommunicatorServer. There is only one type of notifications sent by the CommunicatorServer: they are {@link javax.management.AttributeChangeNotification}, sent when the State 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.


	if (isDebugOn()) {
	    debug("addNotificationListener","Adding listener "+ listener +
		  " with filter "+ filter + " and handback "+ handback);
	}
	notifBroadcaster.addNotificationListener(listener, filter, handback); 
    
voidchangeState(int newState)
For internal use only.

	int oldState;
	synchronized (stateLock) {
	    if (state == newState)
		return;
	    oldState = state;
	    state = newState;
	    stateLock.notifyAll();
	}
	sendStateChangeNotification(oldState, newState);
    
protected java.lang.ThreadcreateMainThread()

	return new Thread (this, makeThreadName());
    
voiddebug(java.lang.String clz, java.lang.String func, java.lang.String info)

        Trace.send(Trace.LEVEL_DEBUG, infoType, clz, func, info);
    
voiddebug(java.lang.String clz, java.lang.String func, java.lang.Throwable exception)

        Trace.send(Trace.LEVEL_DEBUG, infoType, clz, func, exception);
    
voiddebug(java.lang.String func, java.lang.String info)

        debug(dbgTag, func, info);
    
voiddebug(java.lang.String func, java.lang.Throwable exception)

        debug(dbgTag, func, exception);
    
protected abstract voiddoBind()

protected abstract voiddoError(java.lang.Exception e)

protected abstract voiddoProcess()
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.

protected abstract voiddoReceive()
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.

protected abstract voiddoUnbind()
doUnbind() is called whenever the connector goes OFFLINE, except if doBind() has thrown an exception.

intgetActiveClientCount()
Gets the number of clients currently being processed by this CommunicatorServer.

return
The number of clients currently being processed by this CommunicatorServer.

        int result = clientHandlerVector.size() ;
        return result ;
    
protected longgetBindSleepTime()
The delay, in ms, during which the communicator server will sleep before attempting to bind again.

	return 100;
    
protected intgetBindTries()
The number of times the communicator server will attempt to bind before giving up.

	return 50;
    
public java.lang.StringgetHost()
Gets the host name used by this CommunicatorServer.

return
The host name used by this CommunicatorServer.

        try {
            host = InetAddress.getLocalHost().getHostName();
        } catch (Exception e) {
            host = "Unknown host";
        }
        return host ;
    
public synchronized javax.management.MBeanServergetMBeanServer()
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.

        return topMBS;
    
intgetMaxActiveClientCount()
Gets the maximum number of clients that this CommunicatorServer can process concurrently.

return
The maximum number of clients that this CommunicatorServer can process concurrently.

        return maxActiveClientCount ;
    
public javax.management.MBeanNotificationInfo[]getNotificationInfo()
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 {@link javax.management.AttributeChangeNotification}, sent when the State attribute of this CommunicatorServer changes.

	
	// 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;
    
javax.management.ObjectNamegetObjectName()
For internal use only.

        return objectName ;
    
public intgetPort()
Gets the port number used by this CommunicatorServer.

return
The port number used by this CommunicatorServer.

	synchronized (stateLock) {
	    return port ;
	}
    
public abstract java.lang.StringgetProtocol()
Gets the protocol being used by this CommunicatorServer.

return
The protocol as a string.

intgetServedClientCount()
Gets the number of clients that have been processed by this CommunicatorServer since its creation.

return
The number of clients handled by this CommunicatorServer since its creation. This counter is not reset by the stop method.

        return servedClientCount ;
    
public intgetState()
Gets the state of this CommunicatorServer as an integer.

return
ONLINE, OFFLINE, STARTING or STOPPING.

	synchronized (stateLock) {
	    return state ;
	}
    
public java.lang.StringgetStateString()
Gets the state of this CommunicatorServer as a string.

return
One of the strings "ONLINE", "OFFLINE", "STARTING" or "STOPPING".

        return getStringForState(state) ;
    
private static java.lang.StringgetStringForState(int s)

        switch (s) {
        case ONLINE:   return "ONLINE";
        case STARTING: return "STARTING";
        case OFFLINE:  return "OFFLINE";
        case STOPPING: return "STOPPING";
	default:       return "UNDEFINED";
        }
    
public booleanisActive()
Tests whether the CommunicatorServer is active.

return
True if connector is ONLINE; false otherwise.

	synchronized (stateLock) {
	    return (state == ONLINE);
	}
    
booleanisDebugOn()

        return Trace.isSelected(Trace.LEVEL_DEBUG, infoType);
    
booleanisTraceOn()

        return Trace.isSelected(Trace.LEVEL_TRACE, infoType);
    
java.lang.ClassloadClass(java.lang.String className)
Load a class using the default loader repository

	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);
	}
    
java.lang.StringmakeDebugTag()
Returns the string used in debug traces.

        return "CommunicatorServer["+ getProtocol() + ":" + getPort() + "]" ;
    
java.lang.StringmakeThreadName()
Returns the string used to name the connector thread.

        String result ;

        if (objectName == null)
            result = "CommunicatorServer" ;
        else
            result = objectName.toString() ;
        
        return result ;
    
voidnotifyClientHandlerCreated(ClientHandler h)
For SNMP Runtime internal use only.

        clientHandlerVector.addElement(h) ;
    
synchronized voidnotifyClientHandlerDeleted(ClientHandler h)
For SNMP Runtime internal use only.

        clientHandlerVector.removeElement(h);
	notifyAll();
    
public voidpostDeregister()
Do nothing.

    
public voidpostRegister(java.lang.Boolean registrationDone)

param
registrationDone Indicates whether or not the MBean has been successfully registered in the MBeanServer. The value false means that the registration phase has failed.

	if (!registrationDone.booleanValue()) {
	    synchronized (this) {
		topMBS = bottomMBS = null;
	    }
	}
    
public voidpreDeregister()
Stop the connector.

exception
java.langException This exception should be caught by the MBeanServer and re-thrown as an MBeanRegistrationException.

	synchronized (this) {
	    topMBS = bottomMBS = null;
	}
        objectName = null ;
	final int cstate = getState(); 
        if ((cstate == ONLINE) || ( cstate == STARTING)) {
            stop() ;
        }
    
public javax.management.ObjectNamepreRegister(javax.management.MBeanServer server, javax.management.ObjectName name)
Preregister method of connector.

param
server The MBeanServer 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 MBeanServer and re-thrown as an MBeanRegistrationException.

        objectName = name;
	synchronized (this) {
	    if (bottomMBS != null) {
		throw new IllegalArgumentException("connector already " +
						   "registered in an MBean " +
						   "server");
	    }
	    topMBS = bottomMBS = server;
	}
        dbgTag = makeDebugTag(); 
        return name;
    
private voidreadObject(java.io.ObjectInputStream stream)
Controls the way the CommunicatorServer service is deserialized.

      
        // 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();
    
public voidremoveNotificationListener(javax.management.NotificationListener listener)
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.


	if (isDebugOn()) {
	    debug("removeNotificationListener","Removing listener "+ listener);
	}
	notifBroadcaster.removeNotificationListener(listener); 
    
public voidrun()
For SNMP Runtime internal use only.

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

        
        // 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 (isDebugOn()) {
                debug("run","Unexpected exception = "+x) ;
            }
	    synchronized(stateLock) {
		startException = x;
		changeState(OFFLINE);
	    }
            if (isTraceOn()) {
                trace("run","State is OFFLINE") ;
            }
	    doError(x);
	    return;
        }

        try {
            // ----------------------
            // State change
            // ----------------------
            changeState(ONLINE) ;
            if (isTraceOn()) {
                trace("run","State is ONLINE") ;
            }

            // ----------------------
            // Main loop
            // ----------------------
            while (!stopRequested) {
                servedClientCount++;	
                doReceive() ;
                waitIfTooManyClients() ;
                doProcess() ;
            }
            if (isTraceOn()) {
                trace("run","Stop has been requested") ;
            }

        } catch(InterruptedException x) {
            if (isTraceOn()) {
                trace("run","Interrupt caught") ;
            }
            changeState(STOPPING);
        } catch(Exception x) {
            if (isDebugOn()) {
                debug("run","Unexpected exception = "+x) ;
            }
            changeState(STOPPING);
	} finally {
	    synchronized (stateLock) {
		interrupted = true;
		Thread.currentThread().interrupted();
	    }

	    // ----------------------
	    // unBind
	    // ----------------------
	    try {
		doUnbind() ;
		waitClientTermination() ;
		changeState(OFFLINE);
		if (isTraceOn()) {
		    trace("run","State is OFFLINE") ;
		}
	    } catch(Exception x) {
		if (isDebugOn()) {
		    debug("run","Unexpected exception = "+x) ;
		}
		changeState(OFFLINE);
	    }
	    
	}
    
private voidsendStateChangeNotification(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 (isDebugOn()) {
	    debug("sendStateChangeNotification",
		  "Sending AttributeChangeNotification #"+ notifCount +
		  " with message: "+ message);	    
	}
	notifBroadcaster.sendNotification(notif);
    
public synchronized voidsetMBeanServer(javax.management.MBeanServer newMBS)
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.

exception
IllegalArgumentException if newMBS is neither the MBean server in which this connector is registered nor an MBeanServerForwarder leading to that server.
exception
IllegalStateException This method has been invoked while the communicator was ONLINE or STARTING.

	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 seenMBS = new Vector();
	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;
    
voidsetMaxActiveClientCount(int c)
Sets the maximum number of clients this CommunicatorServer 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.

	synchronized (stateLock) {
	    if ((state == ONLINE) || (state == STARTING)) {
		throw new IllegalStateException(
			  "Stop server before carrying out this operation");
	    }	    
	    maxActiveClientCount = c ;
	}
    
public voidsetPort(int port)
Sets the port number used by this CommunicatorServer.

param
port The port number used by this CommunicatorServer.
exception
java.lang.IllegalStateException This method has been invoked while the communicator was ONLINE or STARTING.

	synchronized (stateLock) {
	    if ((state == ONLINE) || (state == STARTING))
		throw new IllegalStateException("Stop server before " +
						"carrying out this operation");
	    this.port = port;
	    dbgTag = makeDebugTag();
	}
    
public voidstart(long timeout)
Starts this CommunicatorServer.

Has no effect if this CommunicatorServer is ONLINE or STOPPING.

param
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.
exception
CommunicationException if the connectors fails to start.
exception
InterruptedException if the thread is interrupted or the timeout expires.

	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 (isTraceOn())
                trace("start","Connector is not OFFLINE") ;
	    return;
	}

	if (isTraceOn())
	    trace("start","--> Start connector ") ;

	mainThread = createMainThread();

	mainThread.start() ;
	
	if (timeout > 0) waitForStart(timeout);
    
public voidstart()
Starts this CommunicatorServer.

Has no effect if this CommunicatorServer is ONLINE or STOPPING.

	try {
	    start(0);
	} catch (InterruptedException x) {
	    // can not happen because of `0'
	    trace("start","interrupted: " + x);
	}
    
public voidstop()
Stops this CommunicatorServer.

Has no effect if this CommunicatorServer is OFFLINE or STOPPING.

	synchronized (stateLock) {
	    if (state == OFFLINE || state == STOPPING) {
		if (isTraceOn())
		    trace("stop","Connector is not ONLINE") ;
		return;
	    }
	    changeState(STOPPING);
	    //
	    // Stop the connector thread
	    //
	    if (isTraceOn())
		trace("stop","Interrupt main thread") ;
	    stopRequested = true ;
	    if (!interrupted) {		    
		interrupted = true;
		mainThread.interrupt();
	    }
	}

	//
	// Call terminate on each active client handler
	//
	if (isTraceOn()) {
	    trace("stop","terminateAllClient") ;
	}
	terminateAllClient() ;
	
	// ----------------------
	// changeState
	// ----------------------
	synchronized (stateLock) {
	    if (state == STARTING)
		changeState(OFFLINE);
	}
    
private voidterminateAllClient()
Call interrupt() on each pending client.

        final int s = clientHandlerVector.size() ;
        if (isTraceOn()) {
            if (s >= 1) {
                trace("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 (isTraceOn())
                    trace("terminateAllClient",
                          "Failed to interrupt pending request: "+x+
                          " - skiping");
            }
        }
    
voidtrace(java.lang.String clz, java.lang.String func, java.lang.String info)

        Trace.send(Trace.LEVEL_TRACE, infoType, clz, func, info);
    
voidtrace(java.lang.String func, java.lang.String info)

        trace(dbgTag, func, info);
    
private voidwaitClientTermination()
This method blocks until there is no more active client.

        int s = clientHandlerVector.size() ;
        if (isTraceOn()) {        
            if (s >= 1) {
                trace("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) {
                trace("waitClientTermination","No element left: " + x);
            }
        }

        if (isTraceOn()) {  
            if (s >= 1) {
                trace("waitClientTermination","Ok, let's go...") ;
            }
        }
    
private voidwaitForStart(long timeout)

Waits until the communicator is started or timeout expires.

param
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.
exception
CommunicationException if the connectors fails to start.
exception
InterruptedException if the thread is interrupted or the timeout expires.

        if (isTraceOn())
            trace("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 (isTraceOn())
			trace("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 (isTraceOn())
			trace("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 (isTraceOn()) trace("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));
	    }
	}
    
private synchronized voidwaitIfTooManyClients()
This method blocks if there are too many active clients. Call to wait() is terminated when a client handler thread calls notifyClientHandlerDeleted(this) ;

        while (getActiveClientCount() >= maxActiveClientCount) {
            if (isTraceOn()) {
                trace("waitIfTooManyClients",
		      "Waiting for a client to terminate") ;
            }
            wait();
        }
    
public booleanwaitState(int wantedState, long timeOut)

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).

param
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.
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 wantedState parameter; false otherwise.

        if (isTraceOn())
            trace("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 (isTraceOn())
			trace("waitState", "timeOut < 0, return without wait");
		    return false;
		} else {
		    try {
			if (timeOut > 0) {
			    long toWait = endTime - System.currentTimeMillis();
			    if (toWait <= 0) {
				if (isTraceOn())
				    trace("waitState", "timed out");
				return false;
			    }
			    stateLock.wait(toWait);
			} else {  // timeOut == 0
			    stateLock.wait();
			}
		    } catch (InterruptedException e) {
			if (isTraceOn())
			    trace("waitState", "wait interrupted");
			return (state == wantedState);
		    }
		}
	    }
	    if (isTraceOn())
		trace("waitState", "returning in desired state");
	    return true;
	}