|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package com.sun.jmx.snmp.agent; |
|
|
|
// java imports |
|
|
|
import java.io.Serializable; |
|
import java.util.Hashtable; |
|
import java.util.Vector; |
|
|
|
// jmx imports |
|
|
|
import com.sun.jmx.snmp.SnmpVarBind; |
|
import com.sun.jmx.snmp.SnmpStatusException; |
|
|
|
|
|
/** |
|
* Represents a node in an SNMP MIB which corresponds to a group. |
|
* This class allows subnodes to be registered below a group, providing |
|
* support for nested groups. The subnodes are registered at run time |
|
* when registering the nested groups in the global MIB OID tree. |
|
* <P> |
|
* This class is used by the class generated by <CODE>mibgen</CODE>. |
|
* You should not need to use this class directly. |
|
* |
|
* <p><b>This API is a Sun Microsystems internal API and is subject |
|
* to change without notice.</b></p> |
|
*/ |
|
|
|
public abstract class SnmpMibGroup extends SnmpMibOid |
|
implements Serializable { |
|
|
|
// We will register the OID arcs leading to subgroups in this hashtable. |
|
// So for each arc in varList, if the arc is also in subgroups, it leads |
|
// to a subgroup, if it is not in subgroup, it leads either to a table |
|
|
|
protected Hashtable<Long, Long> subgroups = null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract boolean isTable(long arc); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract boolean isVariable(long arc); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract boolean isReadable(long arc); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract SnmpMibTable getTable(long arc); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void validateVarId(long arc, Object userData) |
|
throws SnmpStatusException { |
|
if (isVariable(arc) == false) { |
|
throw new SnmpStatusException(SnmpStatusException.noSuchObject); |
|
} |
|
} |
|
|
|
|
|
// ------------------------------------------------------------------- |
|
// We use a hashtable (subgroup) in order to determine whether an |
|
// OID arc leads to a subgroup. This implementation can be changed if |
|
// needed... |
|
// For instance, the subclass could provide a generated isNestedArc() |
|
// method in which the subgroup OID arcs would be hardcoded. |
|
// However, the generic approach was preferred because at this time |
|
// groups and subgroups are dynamically registered in the MIB. |
|
// |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public boolean isNestedArc(long arc) { |
|
if (subgroups == null) return false; |
|
Object obj = subgroups.get(new Long(arc)); |
|
// if the arc is registered in the hashtable, |
|
|
|
return (obj != null); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
abstract public void get(SnmpMibSubRequest req, int depth) |
|
throws SnmpStatusException; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
abstract public void set(SnmpMibSubRequest req, int depth) |
|
throws SnmpStatusException; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
abstract public void check(SnmpMibSubRequest req, int depth) |
|
throws SnmpStatusException; |
|
|
|
// -------------------------------------------------------------------- |
|
// If we reach this node, we are below the root OID, so we just |
|
// return. |
|
|
|
@Override |
|
public void getRootOid(Vector<Integer> result) { |
|
} |
|
|
|
// ------------------------------------------------------------------- |
|
// PACKAGE METHODS |
|
// ------------------------------------------------------------------- |
|
|
|
// ------------------------------------------------------------------- |
|
// This method can also be overriden in a subclass to provide a |
|
// different implementation of the isNestedArc() method. |
|
// => if isNestedArc() is hardcoded, then registerSubArc() becomes |
|
// useless and can become empty. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
void registerNestedArc(long arc) { |
|
Long obj = new Long(arc); |
|
if (subgroups == null) subgroups = new Hashtable<>(); |
|
|
|
subgroups.put(obj,obj); |
|
} |
|
|
|
// ------------------------------------------------------------------- |
|
// The SnmpMibOid algorithm relies on the fact that for every arc |
|
// registered in varList, there is a corresponding node at the same |
|
// position in children. |
|
// So the trick is to register a null node in children for each variable |
|
// in varList, so that the real subgroup nodes can be inserted at the |
|
// correct location. |
|
// registerObject() should be called for each scalar object and each |
|
// table arc by the generated subclass. |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected void registerObject(long arc) |
|
throws IllegalAccessException { |
|
|
|
// this will register the variable in both varList and children |
|
// The node registered in children will be null, so that the parent |
|
// algorithm will behave as if no node were registered. This is a |
|
// trick that makes the parent algorithm behave as if only subgroups |
|
|
|
long[] oid = new long[1]; |
|
oid[0] = arc; |
|
super.registerNode(oid,0,null); |
|
} |
|
|
|
// ------------------------------------------------------------------- |
|
// registerNode() will be called at runtime when nested groups are |
|
// registered in the MIB. So we do know that this method will only |
|
// be called to register nested-groups. |
|
// We trap registerNode() in order to call registerSubArc() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Override |
|
void registerNode(long[] oid, int cursor ,SnmpMibNode node) |
|
throws IllegalAccessException { |
|
super.registerNode(oid,cursor,node); |
|
if (cursor < 0) return; |
|
if (cursor >= oid.length) return; |
|
// if we get here, then it means we are registering a subgroup. |
|
|
|
registerNestedArc(oid[cursor]); |
|
} |
|
|
|
// ------------------------------------------------------------------- |
|
// see comments in SnmpMibNode |
|
|
|
@Override |
|
void findHandlingNode(SnmpVarBind varbind, |
|
long[] oid, int depth, |
|
SnmpRequestTree handlers) |
|
throws SnmpStatusException { |
|
|
|
int length = oid.length; |
|
|
|
if (handlers == null) |
|
throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr); |
|
|
|
final Object data = handlers.getUserData(); |
|
|
|
if (depth >= length) { |
|
|
|
throw new SnmpStatusException(SnmpStatusException.noAccess); |
|
} |
|
|
|
long arc = oid[depth]; |
|
|
|
if (isNestedArc(arc)) { |
|
// This arc leads to a subgroup: delegates the search to the |
|
|
|
super.findHandlingNode(varbind,oid,depth,handlers); |
|
} else if (isTable(arc)) { |
|
// This arc leads to a table: forward the search to the table. |
|
|
|
|
|
SnmpMibTable table = getTable(arc); |
|
|
|
|
|
table.findHandlingNode(varbind,oid,depth+1,handlers); |
|
|
|
} else { |
|
|
|
validateVarId(arc, data); |
|
|
|
|
|
if (depth+2 > length) { |
|
throw new SnmpStatusException(SnmpStatusException.noSuchInstance); |
|
} |
|
|
|
// There are too many arcs left in the OID (there should remain |
|
|
|
if (depth+2 < length) { |
|
throw new SnmpStatusException(SnmpStatusException.noSuchInstance); |
|
} |
|
|
|
|
|
if (oid[depth+1] != 0L) { |
|
throw new SnmpStatusException(SnmpStatusException.noSuchInstance); |
|
} |
|
|
|
|
|
handlers.add(this,depth,varbind); |
|
} |
|
} |
|
|
|
// ------------------------------------------------------------------- |
|
// See comments in SnmpMibNode. |
|
|
|
@Override |
|
long[] findNextHandlingNode(SnmpVarBind varbind, |
|
long[] oid, int pos, int depth, |
|
SnmpRequestTree handlers, AcmChecker checker) |
|
throws SnmpStatusException { |
|
|
|
int length = oid.length; |
|
SnmpMibNode node = null; |
|
|
|
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 new SnmpStatusException(SnmpStatusException.noSuchObject); |
|
} |
|
|
|
final Object data = handlers.getUserData(); |
|
final int pduVersion = handlers.getRequestPduVersion(); |
|
|
|
|
|
// The generic case where the end of the OID has been reached is |
|
// handled in the superclass |
|
// XXX Revisit: this works but it is somewhat convoluted. Just setting |
|
|
|
if (pos >= length) |
|
return super.findNextHandlingNode(varbind,oid,pos,depth, |
|
handlers, checker); |
|
|
|
|
|
long arc = oid[pos]; |
|
|
|
long[] result = null; |
|
|
|
|
|
try { |
|
|
|
if (isTable(arc)) { |
|
// If the arc identifies a table, then we need to forward |
|
// the search to the table. |
|
|
|
|
|
SnmpMibTable table = getTable(arc); |
|
|
|
|
|
checker.add(depth, arc); |
|
try { |
|
result = table.findNextHandlingNode(varbind,oid,pos+1, |
|
depth+1,handlers, |
|
checker); |
|
}catch(SnmpStatusException ex) { |
|
throw new SnmpStatusException(SnmpStatusException.noSuchObject); |
|
} finally { |
|
checker.remove(depth); |
|
} |
|
|
|
result[depth] = arc; |
|
return result; |
|
} else if (isReadable(arc)) { |
|
// If the arc identifies a readable variable, then two cases: |
|
|
|
if (pos == (length - 1)) { |
|
// The end of the OID is reached, so we return the leaf |
|
// corresponding to the variable identified by `arc' |
|
|
|
// Build up the OID |
|
// result = new SnmpOid(0); |
|
|
|
result = new long[depth+2]; |
|
result[depth+1] = 0L; |
|
result[depth] = arc; |
|
|
|
checker.add(depth, result, depth, 2); |
|
try { |
|
checker.checkCurrentOid(); |
|
} catch(SnmpStatusException e) { |
|
throw new SnmpStatusException(SnmpStatusException.noSuchObject); |
|
} finally { |
|
checker.remove(depth,2); |
|
} |
|
|
|
|
|
handlers.add(this,depth,varbind); |
|
return result; |
|
} |
|
|
|
// The end of the OID is not yet reached, so we must return |
|
// the next leaf following the variable identified by `arc'. |
|
// We cannot return the variable because whatever follows in |
|
// the OID will be greater or equals to 0, and 0 identifies |
|
// the variable itself - so we have indeed to return the |
|
// next object. |
|
// So we do nothing, because this case is handled at the |
|
// end of the if ... else if ... else ... block. |
|
|
|
} else if (isNestedArc(arc)) { |
|
// Now if the arc leads to a subgroup, we delegate the |
|
// search to the child, just as done in SnmpMibNode. |
|
// |
|
|
|
// get the child ( = nested arc node). |
|
|
|
final SnmpMibNode child = getChild(arc); |
|
|
|
if (child != null) { |
|
checker.add(depth, arc); |
|
try { |
|
result = child.findNextHandlingNode(varbind,oid,pos+1, |
|
depth+1,handlers, |
|
checker); |
|
result[depth] = arc; |
|
return result; |
|
} finally { |
|
checker.remove(depth); |
|
} |
|
} |
|
} |
|
|
|
// The oid is not valid, we will throw an exception in order |
|
// to try with the next valid identifier... |
|
|
|
throw new SnmpStatusException(SnmpStatusException.noSuchObject); |
|
|
|
} catch (SnmpStatusException e) { |
|
// We didn't find anything at the given arc, so we're going |
|
// to try with the next valid arc |
|
|
|
long[] newOid = new long[1]; |
|
newOid[0] = getNextVarId(arc,data,pduVersion); |
|
return findNextHandlingNode(varbind,newOid,0,depth, |
|
handlers,checker); |
|
} |
|
} |
|
|
|
} |