SnmpMibTablepublic abstract class SnmpMibTable extends SnmpMibNode implements Serializable, NotificationBroadcasterThis class is the base class for SNMP table metadata.
Its responsibility is to manage a sorted array of OID indexes
according to the SNMP indexing scheme over the "real" table.
Each object of this class can be bound to an
{@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} to which it will
forward remote entry creation requests, and invoke callbacks
when an entry has been successfully added to / removed from
the OID index array.
For each table defined in the MIB, mibgen will generate a specific
class called TableTableName that will implement the
SnmpTableEntryFactory interface, and a corresponding
TableNameMeta class that will extend this class.
The TableTableName class corresponds to the MBean view of the
table while the TableNameMeta class corresponds to the
MIB metadata view of the same table.
Objects of this class are instantiated by the generated
whole MIB class extending {@link com.sun.jmx.snmp.agent.SnmpMib}
You should never need to instantiate this class directly.
This API is a Sun Microsystems internal API and is subject
to change without notice. |
Fields Summary |
---|
protected int | nodeIdThe id of the contained entry object. | protected SnmpMib | theMibThe MIB to which the metadata is linked. | protected boolean | creationEnabledtrue if remote creation of entries via SET operations
is enabled.
[default value is false ] | protected SnmpTableEntryFactory | factoryThe entry factory | private int | sizeThe number of elements in the table. | private static final int | DeltaThe list of OIDs. | private int | tablecount | private int | tablesize | private com.sun.jmx.snmp.SnmpOid[] | tableoids | private final Vector | entriesThe list of entries. | private final Vector | entrynamesThe list of object names. | private Hashtable | handbackTableListener hastable containing the hand-back objects. | private Hashtable | filterTableListener hastable containing the filter objects. | transient long | sequenceNumberSNMP table sequence number.
The default value is set to 0. |
Constructors Summary |
---|
public SnmpMibTable(SnmpMib mib)Create a new SnmpMibTable metadata node.
this.theMib= mib;
setCreationEnabled(false);
|
Methods Summary |
---|
public void | addEntry(com.sun.jmx.snmp.SnmpOid rowOid, java.lang.Object entry)Add a new entry in this SnmpMibTable .
Also triggers the addEntryCB() callback of the
{@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
if this node is bound to a factory.
This method assumes that the given entry will not be registered.
If the entry is going to be registered, or if ObjectName's are
required, then
{@link com.sun.jmx.snmp.agent.SnmpMibTable#addEntry(SnmpOid,
ObjectName, Object)} should be prefered.
This function is mainly provided for backward compatibility.
addEntry(rowOid, null, entry);
| public synchronized void | addEntry(com.sun.jmx.snmp.SnmpOid oid, javax.management.ObjectName name, java.lang.Object entry)Add a new entry in this SnmpMibTable .
Also triggers the addEntryCB() callback of the
{@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
if this node is bound to a factory.
if (isRegistrationRequired() == true && name == null)
throw new SnmpStatusException(SnmpStatusException.badValue);
if (size == 0) {
// indexes.addElement(index);
// XX oids.addElement(oid);
insertOid(0,oid);
if (entries != null)
entries.addElement(entry);
if (entrynames != null)
entrynames.addElement(name);
size++;
// triggers callbacks on the entry factory
//
if (factory != null) {
try {
factory.addEntryCb(0,oid,name,entry,this);
} catch (SnmpStatusException x) {
removeOid(0);
if (entries != null)
entries.removeElementAt(0);
if (entrynames != null)
entrynames.removeElementAt(0);
throw x;
}
}
// sends the notifications
//
sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_ADDED,
(new Date()).getTime(), entry, name);
return;
}
// Get the insertion position ...
//
int pos= 0;
// bug jaw.00356.B : use oid rather than index to get the
// insertion point.
//
pos= getInsertionPoint(oid,true);
if (pos == size) {
// Add a new element in the vectors ...
//
// indexes.addElement(index);
// XX oids.addElement(oid);
insertOid(tablecount,oid);
if (entries != null)
entries.addElement(entry);
if (entrynames != null)
entrynames.addElement(name);
size++;
} else {
// Insert new element ...
//
try {
// indexes.insertElementAt(index, pos);
// XX oids.insertElementAt(oid, pos);
insertOid(pos,oid);
if (entries != null)
entries.insertElementAt(entry, pos);
if (entrynames != null)
entrynames.insertElementAt(name,pos);
size++;
} catch(ArrayIndexOutOfBoundsException e) {
}
}
// triggers callbacks on the entry factory
//
if (factory != null) {
try {
factory.addEntryCb(pos,oid,name,entry,this);
} catch (SnmpStatusException x) {
removeOid(pos);
if (entries != null)
entries.removeElementAt(pos);
if (entrynames != null)
entrynames.removeElementAt(pos);
throw x;
}
}
// sends the notifications
//
sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_ADDED,
(new Date()).getTime(), entry, name);
| public synchronized void | addNotificationListener(javax.management.NotificationListener listener, javax.management.NotificationFilter filter, java.lang.Object handback)Enable to add an SNMP entry listener to this
SnmpMibTable .
// Check listener
//
if (listener == null) {
throw new java.lang.IllegalArgumentException
("Listener can't be null") ;
}
// looking for listener in handbackTable
//
java.util.Vector handbackList =
(java.util.Vector) handbackTable.get(listener) ;
java.util.Vector filterList =
(java.util.Vector) filterTable.get(listener) ;
if ( handbackList == null ) {
handbackList = new java.util.Vector() ;
filterList = new java.util.Vector() ;
handbackTable.put(listener, handbackList) ;
filterTable.put(listener, filterList) ;
}
// Add the handback and the filter
//
handbackList.addElement(handback) ;
filterList.addElement(filter) ;
| protected synchronized void | beginRowAction(SnmpMibSubRequest req, com.sun.jmx.snmp.SnmpOid rowOid, int depth, int rowAction)This method takes care of initial RowStatus handling during the
check() phase of a SET request.
In particular it will:
- check that the given
rowAction returned by
getRowAction() is valid.
- Then depending on the
rowAction specified it will:
- either call
createNewEntry() (
rowAction = createAndGo or createAndWait
),
- or call
checkRemoveTableRow() (
rowAction = destroy ),
- or call
checkRowStatusChange() (
rowAction = active or notInService ),
- or generate a SnmpStatusException if the passed
rowAction is not correct.
In principle, you should not need to redefine this method.
beginRowAction() is called during the check phase
of a SET request, before actual checking on the varbind list
is performed.
final boolean isnew = req.isNewEntry();
final SnmpOid oid = rowOid;
final int action = rowAction;
switch (action) {
case EnumRowStatus.unspecified:
if (isnew) {
if (isDebugOn())
debug("beginRowAction","Failed to create row[" + rowOid +
"] : RowStatus = unspecified");
checkRowStatusFail(req,SnmpStatusException.snmpRspNoAccess);
}
break;
case EnumRowStatus.createAndGo:
case EnumRowStatus.createAndWait:
if (isnew) {
if (isCreationEnabled()) {
if (isDebugOn())
debug("beginRowAction","Creating row[" + rowOid +
"] : RowStatus = createAndGo | createAndWait");
createNewEntry(req,oid,depth);
} else {
if (isDebugOn())
debug("beginRowAction","Can't create row[" + rowOid +
"] : RowStatus = createAndGo | createAndWait" +
" but creation is disabled");
checkRowStatusFail(req,
SnmpStatusException.snmpRspNoAccess);
}
} else {
if (isDebugOn())
debug("beginRowAction","Can't create row[" + rowOid +
"] : RowStatus = createAndGo | createAndWait" +
" but row already exists");
checkRowStatusFail(req,
SnmpStatusException.snmpRspInconsistentValue);
}
break;
case EnumRowStatus.destroy:
if (isnew) {
if (isDebugOn())
debug("beginRowAction","Warning: can't destroy row[" +
rowOid + "] : RowStatus = destroy" +
" but row does not exist");
} else if (!isCreationEnabled()) {
if (isDebugOn())
debug("beginRowAction","Can't destroy row[" + rowOid +
"] : RowStatus = destroy " +
" but creation is disabled");
checkRowStatusFail(req,SnmpStatusException.snmpRspNoAccess);
}
checkRemoveTableRow(req,rowOid,depth);
break;
case EnumRowStatus.active:
case EnumRowStatus.notInService:
if (isnew) {
if (isDebugOn())
debug("beginRowAction","Can't switch state of row[" +
rowOid +
"] : specified RowStatus = active | notInService" +
" but row does not exist");
checkRowStatusFail(req,
SnmpStatusException.snmpRspInconsistentValue);
}
checkRowStatusChange(req,rowOid,depth,action);
break;
case EnumRowStatus.notReady:
default:
if (isDebugOn())
debug("beginRowAction","Invalid RowStatus value for row[" +
rowOid + "] : specified RowStatus = " + action);
checkRowStatusFail(req,
SnmpStatusException.snmpRspInconsistentValue);
}
| protected abstract void | check(SnmpMibSubRequest req, com.sun.jmx.snmp.SnmpOid rowOid, int depth)This method is used internally and is implemented by the
SnmpMibTable subclasses generated by mibgen .
| public void | check(SnmpMibSubRequest req, int depth)Generic handling of the check operation.
The default implementation of this method is to
- check whether a new entry must be created, and if remote
creation of entries is enabled, create it.
- call the generated
check(req,oid,depth+1) method.
public void check(SnmpMibSubRequest req, int depth)
throws SnmpStatusException {
final SnmpOid oid = req.getEntryOid();
final int action = getRowAction(req,oid,depth+1);
beginRowAction(req,oid,depth+1,action);
check(req,oid,depth+1);
}
You should not need to override this method in any cases, because
it will eventually call
check(SnmpMibSubRequest req, int depth) on the generated
derivative of SnmpMibEntry . If you need to implement
specific policies for minimizing the accesses made to some remote
underlying resources, or if you need to implement some consistency
checks between the different values provided in the varbind list,
you should then rather override
check(SnmpMibSubRequest req, int depth) on the generated
derivative of SnmpMibEntry .
final SnmpOid oid = req.getEntryOid();
final int action = getRowAction(req,oid,depth+1);
final boolean dbg = isDebugOn();
if (dbg) debug("check","Calling beginRowAction");
beginRowAction(req,oid,depth+1,action);
if (dbg) debug("check","Calling check for " + req.getSize() +
" varbinds.");
check(req,oid,depth+1);
if (dbg) debug("check","check finished");
| protected void | checkRemoveTableRow(SnmpMibSubRequest req, com.sun.jmx.snmp.SnmpOid rowOid, int depth)Check whether the specified row can be removed from the table.
This method is called during the check phase of a SET
request when the control variable specifies destroy
By default it is assumed that nothing prevents row deletion
and this method does nothing. It is simply provided as a hook
so that specific checks can be implemented.
Note that if the actual row deletion fails afterward, the
atomicity of the request is no longer guaranteed.
| protected void | checkRowStatusChange(SnmpMibSubRequest req, com.sun.jmx.snmp.SnmpOid rowOid, int depth, int newStatus)Check whether the control variable of the given row can be
switched to the new specified newStatus .
This method is called during the check phase of a SET
request when the control variable specifies active or
notInService.
By default it is assumed that nothing prevents putting the
row in the requested state, and this method does nothing.
It is simply provided as a hook so that specific checks can
be implemented.
Note that if the actual row deletion fails afterward, the
atomicity of the request is no longer guaranteed.
| static final void | checkRowStatusFail(SnmpMibSubRequest req, int errorStatus)
final SnmpVarBind statusvb = req.getRowStatusVarBind();
final SnmpStatusException x = new SnmpStatusException(errorStatus);
req.registerCheckException(statusvb,x);
| protected boolean | contains(com.sun.jmx.snmp.SnmpOid oid, java.lang.Object userData)Return true if the entry identified by the given OID index
is contained in this table.
Do not call this method directly.
This method is provided has a hook for subclasses.
It is called when a get/set request is received in order to
determine whether the specified entry is contained in the table.
You may want to override this method if you need to perform e.g.
lazy evaluation of tables (you need to update the table when a
request is received) or if your table is virtual.
Note that this method is called by the Runtime from within a
synchronized block.
return (findObject(oid) > -1);
| public abstract void | createNewEntry(SnmpMibSubRequest req, com.sun.jmx.snmp.SnmpOid rowOid, int depth)This method is invoked when the creation of a new entry is requested
by a remote SNMP manager.
By default, remote entry creation is disabled - and this method
will not be called. You can dynamically switch the entry creation
policy by calling setCreationEnabled(true) and
setCreationEnabled(false) on this object.
This method is called internally by the SNMP runtime and you
should never need to call it directly. However you might want
to extend it in order to implement your own specific application
behaviour, should the default behaviour not be at your convenience.
| private final void | debug(java.lang.String func, java.lang.String info)
Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP,
getClass().getName(), func, info);
| protected void | endRowAction(SnmpMibSubRequest req, com.sun.jmx.snmp.SnmpOid rowOid, int depth, int rowAction)This method takes care of final RowStatus handling during the
set() phase of a SET request.
In particular it will:
- either call
setRowStatus(active)
( rowAction = createAndGo or active
),
- or call
setRowStatus(notInService or
notReady) depending on the result of
isRowReady() (rowAction = createAndWait
),
- or call
setRowStatus(notInService)
( rowAction = notInService ),
- or call
removeTableRow() (
rowAction = destroy ),
- or generate a SnmpStatusException if the passed
rowAction is not correct. This should be avoided
since it would break SET request atomicity
In principle, you should not need to redefine this method.
endRowAction() is called during the set() phase
of a SET request, after the actual set() on the varbind list
has been performed. The varbind containing the control variable
is updated with the value returned by setRowStatus() (if it is
not null ).
final boolean isnew = req.isNewEntry();
final SnmpOid oid = rowOid;
final int action = rowAction;
final Object data = req.getUserData();
SnmpValue value = null;
switch (action) {
case EnumRowStatus.unspecified:
break;
case EnumRowStatus.createAndGo:
if (isDebugOn())
debug("endRowAction","Setting RowStatus to `active'" +
" for row[" + rowOid + "] : requested RowStatus = "
+ "createAndGo");
value = setRowStatus(oid,EnumRowStatus.active,data);
break;
case EnumRowStatus.createAndWait:
if (isRowReady(oid,data)) {
if (isDebugOn())
debug("endRowAction",
"Setting RowStatus to `notInService'" +
" for row[" + rowOid + "] : requested RowStatus = "
+ "createAndWait");
value = setRowStatus(oid,EnumRowStatus.notInService,data);
} else {
if (isDebugOn())
debug("endRowAction",
"Setting RowStatus to `notReady'" +
" for row[" + rowOid + "] : requested RowStatus = "
+ "createAndWait");
value = setRowStatus(oid,EnumRowStatus.notReady,data);
}
break;
case EnumRowStatus.destroy:
if (isnew) {
if (isDebugOn())
debug("endRowAction",
"Warning: " + " requested RowStatus = destroy," +
"but row[" + rowOid + "] does not exist.");
} else {
if (isDebugOn())
debug("endRowAction",
"destroying row[" + rowOid +
"] : requested RowStatus = destroy");
}
removeTableRow(req,oid,depth);
break;
case EnumRowStatus.active:
if (isDebugOn())
debug("endRowAction",
"Setting RowStatus to `active'" +
" for row[" + rowOid + "] : requested RowStatus = "
+ "active");
value = setRowStatus(oid,EnumRowStatus.active,data);
break;
case EnumRowStatus.notInService:
if (isDebugOn())
debug("endRowAction",
"Setting RowStatus to `notInService'" +
" for row[" + rowOid + "] : requested RowStatus = "
+ "notInService");
value = setRowStatus(oid,EnumRowStatus.notInService,data);
break;
case EnumRowStatus.notReady:
default:
if (isDebugOn())
debug("endRowAction","Invalid RowStatus value for row[" +
rowOid + "] : specified RowStatus = " + action);
setRowStatusFail(req,
SnmpStatusException.snmpRspInconsistentValue);
}
if (value != null) {
final SnmpVarBind vb = req.getRowStatusVarBind();
if (vb != null) vb.value = value;
}
| final synchronized void | findHandlingNode(com.sun.jmx.snmp.SnmpVarBind varbind, long[] oid, int depth, SnmpRequestTree handlers)
final int length = oid.length;
if (handlers == null)
throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
if (depth >= length)
throw new SnmpStatusException(SnmpStatusException.noAccess);
if (oid[depth] != nodeId)
throw new SnmpStatusException(SnmpStatusException.noAccess);
if (depth+2 >= length)
throw new SnmpStatusException(SnmpStatusException.noAccess);
// Checks that the oid is valid
// validateOid(oid,depth);
// Gets the part of the OID that identifies the entry
final SnmpOid entryoid = new SnmpEntryOid(oid, depth+2);
// Finds the entry: false means that the entry does not exists
final Object data = handlers.getUserData();
final boolean hasEntry = contains(entryoid, data);
// Fails if the entry is not found and the table does not
// not support creation.
// We know that the entry does not exists if (isentry == false).
if (!hasEntry) {
if (!handlers.isCreationAllowed())
// we're not doing a set
throw noSuchInstanceException;
else if (!isCreationEnabled())
// we're doing a set but creation is disabled.
throw new
SnmpStatusException(SnmpStatusException.snmpRspNoAccess);
}
final long var = oid[depth+1];
// Validate the entry id
if (hasEntry) {
// The entry already exists - validate the id
validateVarEntryId(entryoid,var,data);
}
// Registers this node for the identified entry.
//
if (handlers.isSetRequest() && isRowStatus(entryoid,var,data))
// We only try to identify the RowStatus for SET operations
//
handlers.add(this,depth,entryoid,varbind,(!hasEntry),varbind);
else
handlers.add(this,depth,entryoid,varbind,(!hasEntry));
| private long[] | findNextAccessibleOid(com.sun.jmx.snmp.SnmpOid entryoid, com.sun.jmx.snmp.SnmpVarBind varbind, long[] oid, int depth, SnmpRequestTree handlers, AcmChecker checker, java.lang.Object data, long var)
final int pduVersion = handlers.getRequestPduVersion();
// Loop on each var (column)
while(true) {
// This should not happen. If it happens, (bug, or customized
// methods returning garbage instead of raising an exception),
// it probably means that there is nothing to return anyway.
// So we throw the exception.
// => will skip to next node in the MIB tree.
//
if (entryoid == null || var == -1 ) throw noSuchObjectException;
// So here we know both the row (entryoid) and the column (var)
//
try {
// Raising an exception here will make the catch() clause
// switch to the next variable. If `var' is not readable
// for this specific entry, it is not readable for any
// other entry => skip to next column.
//
if (!isReadableEntryId(entryoid,var,data))
throw noSuchObjectException;
// Prepare the result and the ACM checker.
//
final long[] etable = entryoid.longValue(false);
final int elength = etable.length;
final long[] result = new long[depth + 2 + elength];
result[0] = -1 ; // Bug detector!
// Copy the entryOid at the end of `result'
//
java.lang.System.arraycopy(etable, 0, result,
depth+2, elength);
// Set the node Id and var Id in result.
//
result[depth] = nodeId;
result[depth+1] = var;
// Append nodeId.varId.<rowOid> to ACM checker.
//
checker.add(depth,result,depth,elength+2);
// No we're going to ACM check our OID.
try {
checker.checkCurrentOid();
// No exception thrown by checker => this is all OK!
// we have it: register the handler and return the
// result.
//
handlers.add(this,depth,entryoid,varbind,false);
return result;
} catch(SnmpStatusException e) {
// Skip to the next entry. If an exception is
// thrown, will be catch by enclosing catch
// and a skip is done to the next var.
//
entryoid = getNextOid(entryoid, data);
} finally {
// Clean the checker.
//
checker.remove(depth,elength+2);
}
} catch(SnmpStatusException e) {
// Catching an exception here means we have to skip to the
// next column.
//
// Back to the first row.
entryoid = getNextOid(data);
// Find out the next column.
//
var = getNextVarEntryId(entryoid,var,data,pduVersion);
}
// This should not happen. If it happens, (bug, or customized
// methods returning garbage instead of raising an exception),
// it probably means that there is nothing to return anyway.
// No need to continue, we throw an exception.
// => will skip to next node in the MIB tree.
//
if (entryoid == null || var == -1 )
throw noSuchObjectException;
}
| final synchronized long[] | findNextHandlingNode(com.sun.jmx.snmp.SnmpVarBind varbind, long[] oid, int pos, int depth, SnmpRequestTree handlers, AcmChecker checker)
int length = oid.length;
if (handlers == null)
// This should be considered as a genErr, but we do not want to
// abort the whole request, so we're going to throw
// a noSuchObject...
//
throw noSuchObjectException;
final Object data = handlers.getUserData();
final int pduVersion = handlers.getRequestPduVersion();
long var= -1;
// If the querried oid contains less arcs than the OID of the
// xxxEntry object, we must return the first leaf under the
// first columnar object: the best way to do that is to reset
// the queried oid:
// oid[0] = nodeId (arc of the xxxEntry object)
// pos = 0 (points to the arc of the xxxEntry object)
// then we just have to proceed...
//
if (pos >= length) {
// this will have the side effect to set
// oid[pos] = nodeId
// and
// (pos+1) = length
// so we won't fall into the "else if" cases below -
// so using "else if" rather than "if ..." is guaranteed
// to be safe.
//
oid = new long[1];
oid[0] = nodeId;
pos = 0;
length = 1;
} else if (oid[pos] > nodeId) {
// oid[pos] is expected to be the id of the xxxEntry ...
// The id requested is greater than the id of the xxxEntry,
// so we won't find the next element in this table... (any
// element in this table will have a smaller OID)
//
throw noSuchObjectException;
} else if (oid[pos] < nodeId) {
// we must return the first leaf under the first columnar
// object, so we are back to our first case where pos was
// out of bounds... => reset the oid to contain only the
// arc of the xxxEntry object.
//
oid = new long[1];
oid[0] = nodeId;
pos = 0;
length = 0;
} else if ((pos + 1) < length) {
// The arc at the position "pos+1" is the id of the columnar
// object (ie: the id of the variable in the table entry)
//
var = oid[pos+1];
}
// Now that we've got everything right we can begin.
SnmpOid entryoid = null ;
if (pos == (length - 1)) {
// pos points to the last arc in the oid, and this arc is
// guaranteed to be the xxxEntry id (we have handled all
// the other possibilities before)
//
// We must therefore return the first leaf below the first
// columnar object in the table.
//
// Get the first index. If an exception is raised,
// then it means that the table is empty. We thus do not
// have to catch the exception - we let it propagate to
// the caller.
//
entryoid = getNextOid(data);
var = getNextVarEntryId(entryoid,var,data,pduVersion);
} else if ( pos == (length-2)) {
// In that case we have (pos+1) = (length-1), so pos
// points to the arc of the querried variable (columnar object).
// Since the requested oid stops there, it means we have
// to return the first leaf under this columnar object.
//
// So we first get the first index:
// Note: if this raises an exception, this means that the table
// is empty, so we can let the exception propagate to the caller.
//
entryoid = getNextOid(data);
// XXX revisit: not exactly perfect:
// a specific row could be empty.. But we don't know
// how to make the difference! => tradeoff holes
// in tables can't be properly supported (all rows
// must have the same holes)
//
if (skipEntryVariable(entryoid,var,data,pduVersion)) {
var = getNextVarEntryId(entryoid,var,data,pduVersion);
}
} else {
// So now there remain one last case, namely: some part of the
// index is provided by the oid...
// We build a possibly incomplete and invalid index from
// the OID.
// The piece of index provided should begin at pos+2
// oid[pos] = id of the xxxEntry object,
// oid[pos+1] = id of the columnar object,
// oid[pos+2] ... oid[length-1] = piece of index.
//
// We get the next index following the provided index.
// If this raises an exception, then it means that we have
// reached the last index in the table, and we must then
// try with the next columnar object.
//
// Bug fix 4269251
// The SnmpIndex is defined to contain a valid oid:
// this is not an SNMP requirement for the getNext request.
// So we no more use the SnmpIndex but directly the SnmpOid.
//
try {
entryoid = getNextOid(oid, pos + 2, data);
// If the variable must ne skipped, fall through...
//
// XXX revisit: not exactly perfect:
// a specific row could be empty.. But we don't know
// how to make the difference! => tradeoff holes
// in tables can't be properly supported (all rows
// must have the same holes)
//
if (skipEntryVariable(entryoid,var,data,pduVersion))
throw noSuchObjectException;
} catch(SnmpStatusException se) {
entryoid = getNextOid(data);
var = getNextVarEntryId(entryoid,var,data,pduVersion);
}
}
return findNextAccessibleOid(entryoid,
varbind,
oid,
depth,
handlers,
checker,
data,
var);
| private final int | findObject(com.sun.jmx.snmp.SnmpOid oid)Look for the given oid in the OID table (tableoids) and returns
its position.
int low= 0;
int max= size - 1;
SnmpOid pos;
int comp;
int curr= low + (max-low)/2;
//System.out.println("Try to retrieve: " + oid.toString());
while (low <= max) {
// XX pos = (SnmpOid) oids.elementAt(curr);
pos = tableoids[curr];
//System.out.println("Compare with" + pos.toString());
// never know ...we might find something ...
//
comp = oid.compareTo(pos);
if (comp == 0)
return curr;
if (oid.equals(pos) == true) {
return curr;
}
if (comp > 0) {
low = curr + 1;
} else {
max = curr - 1;
}
curr = low + (max-low)/2;
}
return -1;
| protected abstract void | get(SnmpMibSubRequest req, com.sun.jmx.snmp.SnmpOid rowOid, int depth)This method is used internally and is implemented by the
SnmpMibTable subclasses generated by mibgen .
| public void | get(SnmpMibSubRequest req, int depth)Generic handling of the get operation.
The default implementation of this method is to
- check whether the entry exists, and if not register an
exception for each varbind in the list.
- call the generated
get(req,oid,depth+1) method.
public void get(SnmpMibSubRequest req, int depth)
throws SnmpStatusException {
boolean isnew = req.isNewEntry();
// if the entry does not exists, then registers an error for
// each varbind involved (nb: this should not happen, since
// the error should already have been detected earlier)
//
if (isnew) {
SnmpVarBind var = null;
for (Enumeration e= req.getElements(); e.hasMoreElements();) {
var = (SnmpVarBind) e.nextElement();
req.registerGetException(var,noSuchNameException);
}
}
final SnmpOid oid = req.getEntryOid();
get(req,oid,depth+1);
}
You should not need to override this method in any cases, because
it will eventually call
get(SnmpMibSubRequest req, int depth) on the generated
derivative of SnmpMibEntry . If you need to implement
specific policies for minimizing the accesses made to some remote
underlying resources, or if you need to implement some consistency
checks between the different values provided in the varbind list,
you should then rather override
get(SnmpMibSubRequest req, int depth) on the generated
derivative of SnmpMibEntry .
final boolean isnew = req.isNewEntry();
final SnmpMibSubRequest r = req;
// if the entry does not exists, then registers an error for
// each varbind involved (nb: should not happen, the error
// should have been registered earlier)
if (isnew) {
SnmpVarBind var = null;
for (Enumeration e= r.getElements(); e.hasMoreElements();) {
var = (SnmpVarBind) e.nextElement();
r.registerGetException(var,noSuchInstanceException);
}
}
final SnmpOid oid = r.getEntryOid();
// SnmpIndex index = buildSnmpIndex(oid.longValue(false), 0);
// get(req,index,depth+1);
//
get(req,oid,depth+1);
| public java.lang.Object[] | getBasicEntries()Return the entries stored in this table SnmpMibTable .
If the subclass generated by mibgen uses the generic way to access
the entries (i.e. if it goes through the MBeanServer) then some of
the entries may be null . It all depends whether a non
null entry was passed to addEntry().
Otherwise, if it uses the standard way (access the entry directly
through their standard MBean interface) this array will contain all
the entries.
Object[] array= new Object[size];
entries.copyInto(array);
return array;
| public synchronized java.lang.Object | getEntry(com.sun.jmx.snmp.SnmpOid rowOid)Get the entry corresponding to the specified rowOid.
int pos= findObject(rowOid);
if (pos == -1)
throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
return entries.elementAt(pos);
| public synchronized javax.management.ObjectName | getEntryName(com.sun.jmx.snmp.SnmpOid rowOid)Get the ObjectName of the entry corresponding to the
specified rowOid.
The result of this method is only meaningful if
isRegistrationRequired() yields true.
int pos = findObject(rowOid);
if (entrynames == null) return null;
if (pos == -1 || pos >= entrynames.size())
throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
return (ObjectName) entrynames.elementAt(pos);
| private final int | getInsertionPoint(com.sun.jmx.snmp.SnmpOid oid)Search the position at which the given oid should be inserted
in the OID table (tableoids).
return getInsertionPoint(oid, true);
| private final int | getInsertionPoint(com.sun.jmx.snmp.SnmpOid oid, boolean fail)Search the position at which the given oid should be inserted
in the OID table (tableoids).
final int failStatus = SnmpStatusException.snmpRspNotWritable;
int low= 0;
int max= size - 1;
SnmpOid pos;
int comp;
int curr= low + (max-low)/2;
while (low <= max) {
// XX pos= (SnmpOid) oids.elementAt(curr);
pos= tableoids[curr];
// never know ...we might find something ...
//
comp= oid.compareTo(pos);
if (comp == 0) {
if (fail)
throw new SnmpStatusException(failStatus,curr);
else
return curr+1;
}
if (comp>0) {
low= curr +1;
} else {
max= curr -1;
}
curr= low + (max-low)/2;
}
return curr;
| protected com.sun.jmx.snmp.SnmpOid | getNextOid(com.sun.jmx.snmp.SnmpOid oid, java.lang.Object userData)Get the SnmpOid index of the row that follows
the given oid in the table. The given
oid does not need to be a valid row OID index.
if (size == 0)
throw noSuchInstanceException;
final SnmpOid resOid = oid;
// Just a simple check to speed up retrieval of last element ...
//
// XX SnmpOid last= (SnmpOid) oids.lastElement();
SnmpOid last= tableoids[tablecount-1];
if (last.equals(resOid)) {
// Last element of the table ...
//
throw noSuchInstanceException;
}
// First find the oid. This will allow to speed up retrieval process
// during smart discovery of table (using the getNext) as the
// management station will use the valid index returned during a
// previous getNext ...
//
// Returns the position following the position at which resOid
// is found, or the position at which resOid should be inserted.
//
final int newPos = getInsertionPoint(resOid,false);
// If the position returned is not out of bound, we will find
// the next element in the array.
//
if (newPos > -1 && newPos < size) {
try {
// XX last = (SnmpOid) oids.elementAt(newPos);
last = tableoids[newPos];
} catch(ArrayIndexOutOfBoundsException e) {
throw noSuchInstanceException;
}
} else {
// We are dealing with the last element of the table ..
//
throw noSuchInstanceException;
}
return last;
| protected com.sun.jmx.snmp.SnmpOid | getNextOid(java.lang.Object userData)Return the first entry OID registered in the table.
if (size == 0)
throw noSuchInstanceException;
// XX return (SnmpOid) oids.firstElement();
return tableoids[0];
| com.sun.jmx.snmp.SnmpOid | getNextOid(long[] oid, int pos, java.lang.Object userData)Get the SnmpOid index of the row that follows the
index extracted from the specified OID array.
Builds the SnmpOid corresponding to the row OID and calls
getNextOid(oid,userData) ;
// Construct the sub-oid starting at pos.
// This sub-oid correspond to the oid part just after the entry
// variable oid.
//
final SnmpOid resOid = new SnmpEntryOid(oid,pos);
return getNextOid(resOid,userData);
| protected long | getNextVarEntryId(com.sun.jmx.snmp.SnmpOid rowOid, long var, java.lang.Object userData, int pduVersion)Return the next OID arc corresponding to a readable columnar
object in the underlying entry OBJECT-TYPE, possibly skipping over
those objects that must not or cannot be returned.
Calls {@link
#getNextVarEntryId(com.sun.jmx.snmp.SnmpOid,long,java.lang.Object)},
until
{@link #skipEntryVariable(com.sun.jmx.snmp.SnmpOid,long,
java.lang.Object,int)} returns false.
long varid=var;
do {
varid = getNextVarEntryId(rowOid,varid,userData);
} while (skipEntryVariable(rowOid,varid,userData,pduVersion));
return varid;
| protected abstract long | getNextVarEntryId(com.sun.jmx.snmp.SnmpOid rowOid, long var, java.lang.Object userData)This method is used internally and is implemented by the
SnmpMibTable subclasses generated by mibgen .
Return the next OID arc corresponding to a readable columnar
object in the underlying entry OBJECT-TYPE.
| public javax.management.MBeanNotificationInfo[] | getNotificationInfo()Return a NotificationInfo object containing the
notification class and the notification type sent by the
SnmpMibTable .
String[] types = {SnmpTableEntryNotification.SNMP_ENTRY_ADDED,
SnmpTableEntryNotification.SNMP_ENTRY_REMOVED};
MBeanNotificationInfo[] notifsInfo = {
new MBeanNotificationInfo
(types, "com.sun.jmx.snmp.agent.SnmpTableEntryNotification",
"Notifications sent by the SnmpMibTable")
};
return notifsInfo;
| protected int | getRowAction(SnmpMibSubRequest req, com.sun.jmx.snmp.SnmpOid rowOid, int depth)Return the RowStatus code value specified in this request.
The RowStatus code value should be one of the values defined
by {@link com.sun.jmx.snmp.EnumRowStatus}. These codes correspond
to RowStatus codes as defined in RFC 2579, plus the unspecified
value which is SNMP Runtime specific.
final boolean isnew = req.isNewEntry();
final SnmpVarBind vb = req.getRowStatusVarBind();
if (vb == null) {
if (isnew && ! hasRowStatus())
return EnumRowStatus.createAndGo;
else return EnumRowStatus.unspecified;
}
try {
return mapRowStatus(rowOid, vb, req.getUserData());
} catch( SnmpStatusException x) {
checkRowStatusFail(req, x.getStatus());
}
return EnumRowStatus.unspecified;
| public int | getSize()Get the size of the table.
return size;
| public boolean | hasRowStatus()Return true if the conceptual row contains a columnar
object used to control creation/deletion of rows in this table.
This columnar object can be either a variable with RowStatus
syntax as defined by RFC 2579, or a plain variable whose
semantics is table specific.
By default, this function returns false , and it is
assumed that the table has no such control variable.
When mibgen is used over SMIv2 MIBs, it will generate
an hasRowStatus() method returning true
for each table containing an object with RowStatus syntax.
When this method returns false the default mechanism
for remote entry creation is used.
Otherwise, creation/deletion is performed as specified
by the control variable (see getRowAction() for more details).
This method is called internally when a SET request involving
this table is processed.
If you need to implement a control variable which do not use
the RowStatus convention as defined by RFC 2579, you should
subclass the generated table metadata class in order to redefine
this method and make it returns true .
You will then have to redefine the isRowStatus(), mapRowStatus(),
isRowReady(), and setRowStatus() methods to suit your specific
implementation.
return false;
| private final void | insertOid(int pos, com.sun.jmx.snmp.SnmpOid oid)Insert an OID at the given position.
if (pos >= tablesize || tablecount == tablesize) {
// Vector must be enlarged
// Save old vector
final SnmpOid[] olde = tableoids;
// Allocate larger vectors
tablesize += Delta;
tableoids = new SnmpOid[tablesize];
// Check pos validity
if (pos > tablecount) pos = tablecount;
if (pos < 0) pos = 0;
final int l1 = pos;
final int l2 = tablecount - pos;
// Copy original vector up to `pos'
if (l1 > 0)
java.lang.System.arraycopy(olde,0,tableoids,0,l1);
// Copy original vector from `pos' to end, leaving
// an empty room at `pos' in the new vector.
if (l2 > 0)
java.lang.System.arraycopy(olde,l1,tableoids,
l1+1,l2);
} else if (pos < tablecount) {
// Vector is large enough to accomodate one additional
// entry.
//
// Shift vector, making an empty room at `pos'
java.lang.System.arraycopy(tableoids,pos,tableoids,
pos+1,tablecount-pos);
}
// Fill the gap at `pos'
tableoids[pos] = oid;
tablecount++;
| public boolean | isCreationEnabled()Tell whether a new entry should be created when a SET operation
is received for an entry that does not exist yet.
return creationEnabled;
| private static final boolean | isDebugOn()
return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP);
| protected abstract boolean | isReadableEntryId(com.sun.jmx.snmp.SnmpOid rowOid, long var, java.lang.Object userData)This method is used internally and is implemented by the
SnmpMibTable subclasses generated by mibgen .
| public abstract boolean | isRegistrationRequired()Tell whether the specific version of this metadata generated
by mibgen requires entries to be registered with
the MBeanServer. In this case an ObjectName will have to be
passed to addEntry() in order for the table to behave correctly
(case of the generic metadata).
If that version of the metadata does not require entry to be
registered, then passing an ObjectName becomes optional (null
can be passed instead).
| protected boolean | isRowReady(com.sun.jmx.snmp.SnmpOid rowOid, java.lang.Object userData)Tell whether the specified row is ready and can be put in the
notInService state.
This method is called only once, after all the varbind have been
set on a new entry for which createAndWait was specified.
If the entry is not yet ready, this method should return false.
It will then be the responsibility of the entry to switch its
own state to notInService when it becomes ready.
No further call to isRowReady() will be made.
By default, this method always return true.
mibgen will not generate any specific implementation
for this method - meaning that by default, a row created using
createAndWait will always be placed in notInService
state at the end of the request.
If this table was defined using SMIv2, and if it contains a
control variable with RowStatus syntax, mibgen
will generate an implementation for this method that will
delegate the work to the metadata class modelling the conceptual
row, so that you can override the default behaviour by subclassing
that metadata class.
You will have to redefine this method if this default mechanism
does not suit your needs.
return true;
| protected boolean | isRowStatus(com.sun.jmx.snmp.SnmpOid rowOid, long var, java.lang.Object userData)Return true if the columnar object identified by var
is used to control the addition/deletion of rows in this table.
By default, this method assumes that there is no control variable
and always return false
If this table was defined using SMIv2, and if it contains a
control variable with RowStatus syntax, mibgen
will generate a non default implementation for this method
that will identify the RowStatus control variable.
You will have to redefine this method if you need to implement
control variables that do not conform to RFC 2579 RowStatus
TEXTUAL-CONVENTION.
return false;
| protected int | mapRowStatus(com.sun.jmx.snmp.SnmpOid rowOid, com.sun.jmx.snmp.SnmpVarBind vbstatus, java.lang.Object userData)Map the value of the vbstatus varbind to the
corresponding RowStatus code defined in
{@link com.sun.jmx.snmp.EnumRowStatus}.
These codes correspond to RowStatus codes as defined in RFC 2579,
plus the unspecified value which is SNMP Runtime specific.
By default, this method assumes that the control variable is
an Integer, and it simply returns its value without further
analysis.
If this table was defined using SMIv2, and if it contains a
control variable with RowStatus syntax, mibgen
will generate a non default implementation for this method.
You will have to redefine this method if you need to implement
control variables that do not conform to RFC 2579 RowStatus
TEXTUAL-CONVENTION.
final SnmpValue rsvalue = vbstatus.value;
if (rsvalue instanceof SnmpInt)
return ((SnmpInt)rsvalue).intValue();
else
throw new SnmpStatusException(
SnmpStatusException.snmpRspInconsistentValue);
| public void | registerEntryFactory(SnmpTableEntryFactory factory)Register the factory through which table entries should
be created when remote entry creation is enabled.
this.factory = factory;
| public synchronized void | removeEntry(com.sun.jmx.snmp.SnmpOid rowOid, java.lang.Object entry)Remove the specified entry from the table.
Also triggers the removeEntryCB() callback of the
{@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
if this node is bound to a factory.
int pos = findObject(rowOid);
if (pos == -1)
return;
removeEntry(pos,entry);
| public void | removeEntry(com.sun.jmx.snmp.SnmpOid rowOid)Remove the specified entry from the table.
Also triggers the removeEntryCB() callback of the
{@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
if this node is bound to a factory.
int pos = findObject(rowOid);
if (pos == -1)
return;
removeEntry(pos,null);
| public synchronized void | removeEntry(int pos, java.lang.Object entry)Remove the specified entry from the table.
Also triggers the removeEntryCB() callback of the
{@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
if this node is bound to a factory.
if (pos == -1)
return;
if (pos >= size) return;
Object obj = entry;
if (entries != null && entries.size() > pos) {
obj = entries.elementAt(pos);
entries.removeElementAt(pos);
}
ObjectName name = null;
if (entrynames != null && entrynames.size() > pos) {
name = (ObjectName) entrynames.elementAt(pos);
entrynames.removeElementAt(pos);
}
final SnmpOid rowOid = tableoids[pos];
removeOid(pos);
size --;
if (obj == null) obj = entry;
if (factory != null)
factory.removeEntryCb(pos,rowOid,name,obj,this);
sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_REMOVED,
(new Date()).getTime(), obj, name);
| public synchronized void | removeNotificationListener(javax.management.NotificationListener listener)Enable to remove an SNMP entry listener from this
SnmpMibTable .
// looking for listener in handbackTable
//
java.util.Vector handbackList =
(java.util.Vector) handbackTable.get(listener) ;
java.util.Vector filterList =
(java.util.Vector) filterTable.get(listener) ;
if ( handbackList == null ) {
throw new ListenerNotFoundException("listener");
}
// If handback is null, remove the listener entry
//
handbackTable.remove(listener) ;
filterTable.remove(listener) ;
| private final void | removeOid(int pos)Remove the OID located at the given position.
if (pos >= tablecount) return;
if (pos < 0) return;
final int l1 = --tablecount-pos;
tableoids[pos] = null;
if (l1 > 0)
java.lang.System.arraycopy(tableoids,pos+1,tableoids,pos,l1);
tableoids[tablecount] = null;
| protected void | removeTableRow(SnmpMibSubRequest req, com.sun.jmx.snmp.SnmpOid rowOid, int depth)Remove a table row upon a remote manager request.
This method is called internally when getRowAction()
yields destroy - i.e.: it is only called when a remote
manager requests the removal of a table row.
You should never need to call this function directly.
By default, this method simply calls removeEntry(rowOid)
.
You can redefine this method if you need to implement some
specific behaviour when a remote row deletion is invoked.
Note that specific checks should not be implemented in this
method, but rather in checkRemoveTableRow() .
If checkRemoveTableRow() succeeds and this method
fails afterward, the atomicity of the original SET request can no
longer be guaranteed.
removeEntry(rowOid);
| private synchronized void | sendNotification(javax.management.Notification notification)Enable this SnmpMibTable to send a notification.
// loop on listener
//
for(java.util.Enumeration k = handbackTable.keys();
k.hasMoreElements(); ) {
NotificationListener listener =
(NotificationListener) k.nextElement();
// Get the associated handback list and the associated filter list
//
java.util.Vector handbackList =
(java.util.Vector) handbackTable.get(listener) ;
java.util.Vector filterList =
(java.util.Vector) filterTable.get(listener) ;
// loop on handback
//
java.util.Enumeration f = filterList.elements();
for(java.util.Enumeration h = handbackList.elements();
h.hasMoreElements(); ) {
Object handback = h.nextElement();
NotificationFilter filter =
(NotificationFilter)f.nextElement();
if ((filter == null) ||
((filter != null) &&
(filter.isNotificationEnabled(notification)))) {
listener.handleNotification(notification,handback) ;
}
}
}
| private void | sendNotification(java.lang.String type, long timeStamp, java.lang.Object entry, javax.management.ObjectName name)This method is used by the SnmpMibTable to create and send a table
entry notification to all the listeners registered for this kind of
notification.
synchronized(this) {
sequenceNumber = sequenceNumber + 1;
}
SnmpTableEntryNotification notif =
new SnmpTableEntryNotification(type, this, sequenceNumber,
timeStamp, entry, name);
this.sendNotification(notif) ;
| protected abstract void | set(SnmpMibSubRequest req, com.sun.jmx.snmp.SnmpOid rowOid, int depth)This method is used internally and is implemented by the
SnmpMibTable subclasses generated by mibgen .
| public void | set(SnmpMibSubRequest req, int depth)Generic handling of the set operation.
The default implementation of this method is to
call the generated
set(req,oid,depth+1) method.
public void set(SnmpMibSubRequest req, int depth)
throws SnmpStatusException {
final SnmpOid oid = req.getEntryOid();
final int action = getRowAction(req,oid,depth+1);
set(req,oid,depth+1);
endRowAction(req,oid,depth+1,action);
}
You should not need to override this method in any cases, because
it will eventually call
set(SnmpMibSubRequest req, int depth) on the generated
derivative of SnmpMibEntry . If you need to implement
specific policies for minimizing the accesses made to some remote
underlying resources, or if you need to implement some consistency
checks between the different values provided in the varbind list,
you should then rather override
set(SnmpMibSubRequest req, int depth) on the generated
derivative of SnmpMibEntry .
final boolean dbg = isDebugOn();
if (dbg) debug("set","Entering set.");
final SnmpOid oid = req.getEntryOid();
final int action = getRowAction(req,oid,depth+1);
if (dbg) debug("set","Calling set for " + req.getSize() +
"varbinds.");
set(req,oid,depth+1);
if (dbg) debug("set","Calling endRowAction");
endRowAction(req,oid,depth+1,action);
if (dbg) debug("set","RowAction finished");
| public void | setCreationEnabled(boolean remoteCreationFlag)This method lets you dynamically switch the creation policy.
creationEnabled = remoteCreationFlag;
| protected com.sun.jmx.snmp.SnmpValue | setRowStatus(com.sun.jmx.snmp.SnmpOid rowOid, int newStatus, java.lang.Object userData)Set the control variable to the specified newStatus
value.
This method maps the given newStatus to the appropriate
value for the control variable, then sets the control variable in
the entry identified by rowOid . It returns the new
value of the control variable.
By default, it is assumed that there is no control variable so this
method does nothing and simply returns null .
If this table was defined using SMIv2, and if it contains a
control variable with RowStatus syntax, mibgen
will generate a non default implementation for this method.
You will have to redefine this method if you need to implement
control variables that do not conform to RFC 2579 RowStatus
TEXTUAL-CONVENTION.
return null;
| static final void | setRowStatusFail(SnmpMibSubRequest req, int errorStatus)
final SnmpVarBind statusvb = req.getRowStatusVarBind();
final SnmpStatusException x = new SnmpStatusException(errorStatus);
req.registerSetException(statusvb,x);
| protected boolean | skipEntryVariable(com.sun.jmx.snmp.SnmpOid rowOid, long var, java.lang.Object userData, int pduVersion)Hook for subclasses.
The default implementation of this method is to always return
false. Subclasses should redefine this method so that it returns
true when:
- the variable is a leaf that is not instantiated,
- or the variable is a leaf whose type cannot be returned by that
version of the protocol (e.g. an Counter64 with SNMPv1).
return false;
| final void | validateOid(long[] oid, int pos)Validate the specified OID.
final int length= oid.length;
// Control the length of the oid
//
if (pos +2 >= length)
throw noSuchInstanceException;
// Check that the entry identifier is specified
//
if (oid[pos] != nodeId)
throw noSuchObjectException;
| protected abstract void | validateVarEntryId(com.sun.jmx.snmp.SnmpOid rowOid, long var, java.lang.Object userData)This method is used internally and is implemented by the
SnmpMibTable subclasses generated by mibgen .
|
|