/*
*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
// Copyright (c) 1995-96 by Cisco Systems, Inc.
package com.sun.jmx.snmp.daemon;
import java.util.logging.Level;
import java.util.Vector;
import java.io.Serializable;
// import debug stuff
//
import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER;
/**
* This class implements a server queue manager.
* This class is for internal use.
*/
final class SnmpQManager implements Serializable {
private static final long serialVersionUID = 2163709017015248264L;
// VARIABLES
//----------
private SendQ newq ;
private WaitQ waitq ;
private ThreadGroup queueThreadGroup = null ;
private Thread requestQThread = null ;
private Thread timerQThread = null ;
// CONSTRUCTORS
//-------------
SnmpQManager() {
newq = new SendQ(20, 5) ;
waitq = new WaitQ(20, 5) ;
queueThreadGroup = new ThreadGroup("Qmanager Thread Group") ;
// TIME BOMB HERE
startQThreads() ;
}
public void startQThreads() {
if (timerQThread == null || timerQThread.isAlive() == false) {
timerQThread = new SnmpTimerServer(queueThreadGroup, this) ;
}
if (requestQThread == null || requestQThread.isAlive() == false) {
requestQThread = new SnmpSendServer(queueThreadGroup, this) ;
}
}
public void stopQThreads() {
((SnmpTimerServer)timerQThread).isBeingDestroyed = true;
waitq.isBeingDestroyed = true;
((SnmpSendServer)requestQThread).isBeingDestroyed = true;
newq.isBeingDestroyed = true;
if (timerQThread != null && timerQThread.isAlive() == true) {
((SnmpTimerServer)timerQThread).stopTimerServer();
}
waitq = null;
timerQThread = null;
if (requestQThread != null && requestQThread.isAlive() == true) {
((SnmpSendServer)requestQThread).stopSendServer();
}
newq = null;
requestQThread = null;
}
public void addRequest(SnmpInformRequest reqc) {
newq.addRequest(reqc) ;
return ;
}
public void addWaiting(SnmpInformRequest reqc) {
waitq.addWaiting(reqc) ;
return ;
}
public Vector getAllOutstandingRequest(long range) {
return newq.getAllOutstandingRequest(range) ;
}
public SnmpInformRequest getTimeoutRequests() {
return waitq.getTimeoutRequests() ;
}
public void removeRequest(SnmpInformRequest reqc) {
newq.removeElement(reqc) ;
waitq.removeElement(reqc) ;
}
public SnmpInformRequest removeRequest(long reqid) {
SnmpInformRequest reqc = null ;
if ((reqc = newq.removeRequest(reqid)) == null)
reqc = waitq.removeRequest(reqid) ;
return reqc ;
}
}
/**
* This vector manages the inform requests to be sent to the manager.
*/
@SuppressWarnings("serial") // no serialVersionUID but never serialized
class SendQ extends Vector<SnmpInformRequest> {
SendQ(int initialCapacity, int capacityIncr) {
super(initialCapacity , capacityIncr) ;
}
private synchronized void notifyClients() {
this.notifyAll() ;
}
public synchronized void addRequest(SnmpInformRequest req) {
long nextPoll = req.getAbsNextPollTime() ;
int i ;
for (i = size() ; i > 0 ; i--) {
if (nextPoll < getRequestAt(i-1).getAbsNextPollTime())
break ;
}
if (i == size()) {
addElement(req) ;
notifyClients() ;
} else
insertElementAt(req, i) ;
return ;
}
public synchronized boolean waitUntilReady() {
while (true) {
if (isBeingDestroyed == true)
return false;
long tmp = 0 ;
if (isEmpty() == false) {
long currTime = System.currentTimeMillis() ;
SnmpInformRequest req = lastElement() ;
tmp = req.getAbsNextPollTime() - currTime ;
if (tmp <= 0) {
return true ;
}
}
waitOnThisQueue(tmp) ;
}
}
public synchronized Vector getAllOutstandingRequest(long margin) {
int i ;
Vector<SnmpInformRequest> outreq = new Vector<SnmpInformRequest>();
while (true) {
if (waitUntilReady() == true) {
long refTime = System.currentTimeMillis() + margin ;
for (i = size() ; i > 0 ; i--) {
SnmpInformRequest req = getRequestAt(i-1) ;
if (req.getAbsNextPollTime() > refTime)
break ;
outreq.addElement(req) ;
}
if (! outreq.isEmpty()) {
elementCount -= outreq.size() ;
return outreq ;
}
}
else
return null;
}
}
public synchronized void waitOnThisQueue(long time) {
if (time == 0 && !isEmpty()) {
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpQManager.class.getName(),
"waitOnThisQueue", "[" + Thread.currentThread().toString() + "]:" +
"Fatal BUG :: Blocking on newq permenantly. But size = " + size());
}
}
try {
this.wait(time) ;
} catch (InterruptedException e) {
}
}
public SnmpInformRequest getRequestAt(int idx) {
return elementAt(idx) ;
}
public synchronized SnmpInformRequest removeRequest(long reqid) {
int max= size() ;
for (int i = 0 ; i < max ; i++) {
SnmpInformRequest reqc = getRequestAt(i) ;
if (reqid == reqc.getRequestId()) {
removeElementAt(i) ;
return reqc ;
}
}
return null ;
}
// This boolean is used to stop handling requests while the corresponding SnmpQManager
// is being destroyed.
//
boolean isBeingDestroyed = false;
}
/**
* This vector manages the inform requests to be retried to the manager.
*/
@SuppressWarnings("serial") // no serialVersionUID, but never serialized
class WaitQ extends Vector<SnmpInformRequest> {
WaitQ(int initialCapacity, int capacityIncr) {
super(initialCapacity , capacityIncr) ;
}
public synchronized void addWaiting(SnmpInformRequest req) {
long waitTime = req.getAbsMaxTimeToWait() ;
int i ;
for (i = size() ; i > 0 ; i--) {
if (waitTime < getRequestAt(i-1).getAbsMaxTimeToWait())
break ;
}
if (i == size()) {
addElement(req) ;
notifyClients() ;
} else
insertElementAt(req, i) ;
return ;
}
public synchronized boolean waitUntilReady() {
while (true) {
if (isBeingDestroyed == true)
return false;
long tmp = 0 ;
if (isEmpty() == false) {
long currTime = System.currentTimeMillis() ;
SnmpInformRequest req = lastElement() ;
tmp = req.getAbsMaxTimeToWait() - currTime ;
if (tmp <= 0) {
return true ;
}
}
waitOnThisQueue(tmp) ;
}
}
public synchronized SnmpInformRequest getTimeoutRequests() {
if (waitUntilReady() == true) {
SnmpInformRequest req = lastElement() ;
elementCount-- ;
return req ;
}
else {
return null;
}
}
private synchronized void notifyClients() {
this.notifyAll() ;
}
public synchronized void waitOnThisQueue(long time) {
if (time == 0 && !isEmpty()) {
if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpQManager.class.getName(),
"waitOnThisQueue", "[" + Thread.currentThread().toString() + "]:" +
"Fatal BUG :: Blocking on waitq permenantly. But size = " + size());
}
}
try {
this.wait(time) ;
} catch (InterruptedException e) {
}
}
public SnmpInformRequest getRequestAt(int idx) {
return elementAt(idx) ;
}
public synchronized SnmpInformRequest removeRequest(long reqid) {
int max= size();
for (int i = 0 ; i < max ; i++) {
SnmpInformRequest reqc = getRequestAt(i) ;
if (reqid == reqc.getRequestId()) {
removeElementAt(i) ;
return reqc ;
}
}
return null ;
}
// This boolean is used to stop handling requests while the corresponding SnmpQManager
// is being destroyed.
//
boolean isBeingDestroyed = false;
}