Methods Summary |
---|
public void | addNotificationListener(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.
if (isDebugOn()) {
debug("addNotificationListener","Adding listener "+ listener +
" with filter "+ filter + " and handback "+ handback);
}
notifBroadcaster.addNotificationListener(listener, filter, handback);
|
void | changeState(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.Thread | createMainThread()
return new Thread (this, makeThreadName());
|
void | debug(java.lang.String clz, java.lang.String func, java.lang.String info)
Trace.send(Trace.LEVEL_DEBUG, infoType, clz, func, info);
|
void | debug(java.lang.String clz, java.lang.String func, java.lang.Throwable exception)
Trace.send(Trace.LEVEL_DEBUG, infoType, clz, func, exception);
|
void | debug(java.lang.String func, java.lang.String info)
debug(dbgTag, func, info);
|
void | debug(java.lang.String func, java.lang.Throwable exception)
debug(dbgTag, func, exception);
|
protected abstract void | doBind()
|
protected abstract void | doError(java.lang.Exception e)
|
protected abstract void | doProcess()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 void | doReceive()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 void | doUnbind()doUnbind() is called whenever the connector goes
OFFLINE , except if doBind() has thrown an
exception.
|
int | getActiveClientCount()Gets the number of clients currently being processed by this
CommunicatorServer .
int result = clientHandlerVector.size() ;
return result ;
|
protected long | getBindSleepTime()The delay, in ms, during which the communicator server will sleep before
attempting to bind again.
return 100;
|
protected int | getBindTries()The number of times the communicator server will attempt
to bind before giving up.
return 50;
|
public java.lang.String | getHost()Gets the host name used by this CommunicatorServer .
try {
host = InetAddress.getLocalHost().getHostName();
} catch (Exception e) {
host = "Unknown host";
}
return host ;
|
public synchronized javax.management.MBeanServer | getMBeanServer()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;
|
int | getMaxActiveClientCount()Gets 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.ObjectName | getObjectName()For internal use only.
return objectName ;
|
public int | getPort()Gets the port number used by this CommunicatorServer .
synchronized (stateLock) {
return port ;
}
|
public abstract java.lang.String | getProtocol()Gets the protocol being used by this CommunicatorServer .
|
int | getServedClientCount()Gets the number of clients that have been processed by this
CommunicatorServer since its creation.
return servedClientCount ;
|
public int | getState()Gets the state of this CommunicatorServer as an integer.
synchronized (stateLock) {
return state ;
}
|
public java.lang.String | getStateString()Gets the state of this CommunicatorServer as a string.
return getStringForState(state) ;
|
private static java.lang.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";
}
|
public boolean | isActive()Tests whether the CommunicatorServer is active.
synchronized (stateLock) {
return (state == ONLINE);
}
|
boolean | isDebugOn()
return Trace.isSelected(Trace.LEVEL_DEBUG, infoType);
|
boolean | isTraceOn()
return Trace.isSelected(Trace.LEVEL_TRACE, infoType);
|
java.lang.Class | loadClass(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.String | makeDebugTag()Returns the string used in debug traces.
return "CommunicatorServer["+ getProtocol() + ":" + getPort() + "]" ;
|
java.lang.String | makeThreadName()Returns the string used to name the connector thread.
String result ;
if (objectName == null)
result = "CommunicatorServer" ;
else
result = objectName.toString() ;
return result ;
|
void | notifyClientHandlerCreated(ClientHandler h)For SNMP Runtime internal use only.
clientHandlerVector.addElement(h) ;
|
synchronized void | notifyClientHandlerDeleted(ClientHandler h)For SNMP Runtime internal use only.
clientHandlerVector.removeElement(h);
notifyAll();
|
public void | postDeregister()Do nothing.
|
public void | postRegister(java.lang.Boolean registrationDone)
if (!registrationDone.booleanValue()) {
synchronized (this) {
topMBS = bottomMBS = null;
}
}
|
public void | preDeregister()Stop the connector.
synchronized (this) {
topMBS = bottomMBS = null;
}
objectName = null ;
final int cstate = getState();
if ((cstate == ONLINE) || ( cstate == STARTING)) {
stop() ;
}
|
public javax.management.ObjectName | preRegister(javax.management.MBeanServer server, javax.management.ObjectName name)Preregister method of connector.
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 void | readObject(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 void | removeNotificationListener(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.
if (isDebugOn()) {
debug("removeNotificationListener","Removing listener "+ listener);
}
notifBroadcaster.removeNotificationListener(listener);
|
public void | run()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 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 (isDebugOn()) {
debug("sendStateChangeNotification",
"Sending AttributeChangeNotification #"+ notifCount +
" with message: "+ message);
}
notifBroadcaster.sendNotification(notif);
|
public synchronized void | setMBeanServer(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 .
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;
|
void | setMaxActiveClientCount(int c)Sets the maximum number of clients this
CommunicatorServer can process concurrently.
synchronized (stateLock) {
if ((state == ONLINE) || (state == STARTING)) {
throw new IllegalStateException(
"Stop server before carrying out this operation");
}
maxActiveClientCount = c ;
}
|
public void | setPort(int port)Sets the port number used by this CommunicatorServer .
synchronized (stateLock) {
if ((state == ONLINE) || (state == STARTING))
throw new IllegalStateException("Stop server before " +
"carrying out this operation");
this.port = port;
dbgTag = makeDebugTag();
}
|
public void | start(long timeout)Starts this CommunicatorServer .
Has no effect if this CommunicatorServer is
ONLINE or STOPPING .
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 void | start()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 void | stop()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 void | terminateAllClient()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");
}
}
|
void | trace(java.lang.String clz, java.lang.String func, java.lang.String info)
Trace.send(Trace.LEVEL_TRACE, infoType, clz, func, info);
|
void | trace(java.lang.String func, java.lang.String info)
trace(dbgTag, func, info);
|
private void | waitClientTermination()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 void | waitForStart(long timeout)Waits until the communicator is started or 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 void | waitIfTooManyClients()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 boolean | waitState(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).
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;
}
|