1. /*
  2. * @(#)file SnmpMibGroup.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 1.24
  5. * @(#)date 04/09/15
  6. *
  7. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  8. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  9. */
  10. package com.sun.jmx.snmp.agent;
  11. // java imports
  12. //
  13. import java.io.Serializable;
  14. import java.util.Hashtable;
  15. import java.util.Enumeration;
  16. import java.util.Vector;
  17. // jmx imports
  18. //
  19. import com.sun.jmx.snmp.SnmpOid;
  20. import com.sun.jmx.snmp.SnmpValue;
  21. import com.sun.jmx.snmp.SnmpVarBind;
  22. import com.sun.jmx.snmp.SnmpStatusException;
  23. // SNMP Runtime imports
  24. //
  25. import com.sun.jmx.snmp.agent.SnmpMibOid;
  26. import com.sun.jmx.snmp.agent.SnmpMibNode;
  27. /**
  28. * Represents a node in an SNMP MIB which corresponds to a group.
  29. * This class allows subnodes to be registered below a group, providing
  30. * support for nested groups. The subnodes are registered at run time
  31. * when registering the nested groups in the global MIB OID tree.
  32. * <P>
  33. * This class is used by the class generated by <CODE>mibgen</CODE>.
  34. * You should not need to use this class directly.
  35. *
  36. * <p><b>This API is a Sun Microsystems internal API and is subject
  37. * to change without notice.</b></p>
  38. * @version 4.3 10/29/99
  39. * @author Sun Microsystems, Inc
  40. */
  41. public abstract class SnmpMibGroup extends SnmpMibOid
  42. implements Serializable {
  43. // We will register the OID arcs leading to subgroups in this hashtable.
  44. // So for each arc in varList, if the arc is also in subgroups, it leads
  45. // to a subgroup, if it is not in subgroup, it leads either to a table
  46. // or to a variable.
  47. protected Hashtable subgroups = null;
  48. /**
  49. * Tells whether the given arc identifies a table in this group.
  50. *
  51. * @param arc An OID arc.
  52. *
  53. * @return <CODE>true</CODE> if `arc' leads to a table.
  54. */
  55. public abstract boolean isTable(long arc);
  56. /**
  57. * Tells whether the given arc identifies a variable (scalar object) in
  58. * this group.
  59. *
  60. * @param arc An OID arc.
  61. *
  62. * @return <CODE>true</CODE> if `arc' leads to a variable.
  63. */
  64. public abstract boolean isVariable(long arc);
  65. /**
  66. * Tells whether the given arc identifies a readable scalar object in
  67. * this group.
  68. *
  69. * @param arc An OID arc.
  70. *
  71. * @return <CODE>true</CODE> if `arc' leads to a readable variable.
  72. */
  73. public abstract boolean isReadable(long arc);
  74. /**
  75. * Gets the table identified by the given `arc'.
  76. *
  77. * @param arc An OID arc.
  78. *
  79. * @return The <CODE>SnmpMibTable</CODE> identified by `arc', or
  80. * <CODE>null</CODE> if `arc' does not identify any table.
  81. */
  82. public abstract SnmpMibTable getTable(long arc);
  83. /**
  84. * Checks whether the given OID arc identifies a variable (scalar
  85. * object).
  86. *
  87. * @exception If the given `arc' does not identify any variable in this
  88. * group, throws an SnmpStatusException.
  89. */
  90. public void validateVarId(long arc, Object userData)
  91. throws SnmpStatusException {
  92. if (isVariable(arc) == false)
  93. throw noSuchObjectException;
  94. }
  95. // -------------------------------------------------------------------
  96. // We use a hashtable (subgroup) in order to determine whether an
  97. // OID arc leads to a subgroup. This implementation can be changed if
  98. // needed...
  99. // For instance, the subclass could provide a generated isNestedArc()
  100. // method in which the subgroup OID arcs would be hardcoded.
  101. // However, the generic approach was prefered because at this time
  102. // groups and subgroups are dynamically registered in the MIB.
  103. //
  104. /**
  105. * Tell whether the given OID arc identifies a sub-tree
  106. * leading to a nested SNMP sub-group. This method is used internally.
  107. * You shouldn't need to call it directly.
  108. *
  109. * @param arc An OID arc.
  110. *
  111. * @return <CODE>true</CODE> if the given OID arc identifies a subtree
  112. * leading to a nested SNMP sub-group.
  113. *
  114. */
  115. public boolean isNestedArc(long arc) {
  116. if (subgroups == null) return false;
  117. Object obj = subgroups.get(new Long(arc));
  118. // if the arc is registered in the hashtable,
  119. // it leads to a subgroup.
  120. return (obj != null);
  121. }
  122. /**
  123. * Generic handling of the <CODE>get</CODE> operation.
  124. * <p>The actual implementation of this method will be generated
  125. * by mibgen. Usually, this implementation only delegates the
  126. * job to some other provided runtime class, which knows how to
  127. * access the MBean. The current toolkit thus provides two
  128. * implementations:
  129. * <ul><li>The standard implementation will directly access the
  130. * MBean through a java reference,</li>
  131. * <li>The generic implementation will access the MBean through
  132. * the MBean server.</li>
  133. * </ul>
  134. * <p>Both implementations rely upon specific - and distinct, set of
  135. * mibgen generated methods.
  136. * <p> You can override this method if you need to implement some
  137. * specific policies for minimizing the accesses made to some remote
  138. * underlying resources.
  139. * <p>
  140. *
  141. * @param req The sub-request that must be handled by this node.
  142. *
  143. * @param depth The depth reached in the OID tree.
  144. *
  145. * @exception SnmpStatusException An error occurred while accessing
  146. * the MIB node.
  147. */
  148. abstract public void get(SnmpMibSubRequest req, int depth)
  149. throws SnmpStatusException;
  150. /**
  151. * Generic handling of the <CODE>set</CODE> operation.
  152. * <p>The actual implementation of this method will be generated
  153. * by mibgen. Usually, this implementation only delegates the
  154. * job to some other provided runtime class, which knows how to
  155. * access the MBean. The current toolkit thus provides two
  156. * implementations:
  157. * <ul><li>The standard implementation will directly access the
  158. * MBean through a java reference,</li>
  159. * <li>The generic implementation will access the MBean through
  160. * the MBean server.</li>
  161. * </ul>
  162. * <p>Both implementations rely upon specific - and distinct, set of
  163. * mibgen generated methods.
  164. * <p> You can override this method if you need to implement some
  165. * specific policies for minimizing the accesses made to some remote
  166. * underlying resources.
  167. * <p>
  168. *
  169. * @param req The sub-request that must be handled by this node.
  170. *
  171. * @param depth The depth reached in the OID tree.
  172. *
  173. * @exception SnmpStatusException An error occurred while accessing
  174. * the MIB node.
  175. */
  176. abstract public void set(SnmpMibSubRequest req, int depth)
  177. throws SnmpStatusException;
  178. /**
  179. * Generic handling of the <CODE>check</CODE> operation.
  180. *
  181. * <p>The actual implementation of this method will be generated
  182. * by mibgen. Usually, this implementation only delegates the
  183. * job to some other provided runtime class, which knows how to
  184. * access the MBean. The current toolkit thus provides two
  185. * implementations:
  186. * <ul><li>The standard implementation will directly access the
  187. * MBean through a java reference,</li>
  188. * <li>The generic implementation will access the MBean through
  189. * the MBean server.</li>
  190. * </ul>
  191. * <p>Both implementations rely upon specific - and distinct, set of
  192. * mibgen generated methods.
  193. * <p> You can override this method if you need to implement some
  194. * specific policies for minimizing the accesses made to some remote
  195. * underlying resources, or if you need to implement some consistency
  196. * checks between the different values provided in the varbind list.
  197. * <p>
  198. *
  199. * @param req The sub-request that must be handled by this node.
  200. *
  201. * @param depth The depth reached in the OID tree.
  202. *
  203. * @exception SnmpStatusException An error occurred while accessing
  204. * the MIB node.
  205. */
  206. abstract public void check(SnmpMibSubRequest req, int depth)
  207. throws SnmpStatusException;
  208. // --------------------------------------------------------------------
  209. // If we reach this node, we are below the root OID, so we just
  210. // return.
  211. // --------------------------------------------------------------------
  212. public void getRootOid(Vector result) {
  213. return;
  214. }
  215. // -------------------------------------------------------------------
  216. // PACKAGE METHODS
  217. // -------------------------------------------------------------------
  218. // -------------------------------------------------------------------
  219. // This method can also be overriden in a subclass to provide a
  220. // different implementation of the isNestedArc() method.
  221. // => if isNestedArc() is hardcoded, then registerSubArc() becomes
  222. // useless and can become empty.
  223. /**
  224. * Register an OID arc that identifies a sub-tree
  225. * leading to a nested SNMP sub-group. This method is used internally.
  226. * You shouldn't ever call it directly.
  227. *
  228. * @param arc An OID arc.
  229. *
  230. */
  231. void registerNestedArc(long arc) {
  232. Long obj = new Long(arc);
  233. if (subgroups == null) subgroups = new Hashtable();
  234. // registers the arc in the hashtable.
  235. subgroups.put(obj,obj);
  236. }
  237. // -------------------------------------------------------------------
  238. // The SnmpMibOid algorithm relies on the fact that for every arc
  239. // registered in varList, there is a corresponding node at the same
  240. // position in children.
  241. // So the trick is to register a null node in children for each variable
  242. // in varList, so that the real subgroup nodes can be inserted at the
  243. // correct location.
  244. // registerObject() should be called for each scalar object and each
  245. // table arc by the generated subclass.
  246. /**
  247. * Register an OID arc that identifies a scalar object or a table.
  248. * This method is used internally. You shouldn't ever call it directly.
  249. *
  250. * @param arc An OID arc.
  251. *
  252. */
  253. protected void registerObject(long arc)
  254. throws IllegalAccessException {
  255. // this will register the variable in both varList and children
  256. // The node registered in children will be null, so that the parent
  257. // algorithm will behave as if no node were registered. This is a
  258. // trick that makes the parent algorithm behave as if only subgroups
  259. // were registered in varList and children.
  260. long[] oid = new long[1];
  261. oid[0] = arc;
  262. super.registerNode(oid,0,null);
  263. }
  264. // -------------------------------------------------------------------
  265. // registerNode() will be called at runtime when nested groups are
  266. // registered in the MIB. So we do know that this method will only
  267. // be called to register nested-groups.
  268. // We trap registerNode() in order to call registerSubArc()
  269. /**
  270. * Register a child node of this node in the OID tree.
  271. * This method is used internally. You shouldn't ever call it directly.
  272. *
  273. * @param oid The oid of the node being registered.
  274. * @param cursor The position reached in the oid.
  275. * @param node The node being registered.
  276. *
  277. */
  278. void registerNode(long[] oid, int cursor ,SnmpMibNode node)
  279. throws IllegalAccessException {
  280. super.registerNode(oid,cursor,node);
  281. if (cursor < 0) return;
  282. if (cursor >= oid.length) return;
  283. // if we get here, then it means we are registering a subgroup.
  284. // We will thus register the sub arc in the subgroups hashtable.
  285. registerNestedArc(oid[cursor]);
  286. }
  287. // -------------------------------------------------------------------
  288. // see comments in SnmpMibNode
  289. // -------------------------------------------------------------------
  290. void findHandlingNode(SnmpVarBind varbind,
  291. long[] oid, int depth,
  292. SnmpRequestTree handlers)
  293. throws SnmpStatusException {
  294. int length = oid.length;
  295. SnmpMibNode node = null;
  296. if (handlers == null)
  297. throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
  298. final Object data = handlers.getUserData();
  299. if (depth >= length) {
  300. // Nothing is left... the oid is not valid
  301. throw new SnmpStatusException(SnmpStatusException.noAccess);
  302. }
  303. long arc = oid[depth];
  304. if (isNestedArc(arc)) {
  305. // This arc leads to a subgroup: delegates the search to the
  306. // method defined in SnmpMibOid
  307. super.findHandlingNode(varbind,oid,depth,handlers);
  308. return;
  309. } else if (isTable(arc)) {
  310. // This arc leads to a table: forward the search to the table.
  311. // Gets the table
  312. SnmpMibTable table = getTable(arc);
  313. // Forward the search to the table
  314. table.findHandlingNode(varbind,oid,depth+1,handlers);
  315. } else {
  316. // If it's not a variable, throws an exception
  317. validateVarId(arc, data);
  318. // The trailing .0 is missing in the OID
  319. if (depth+2 > length)
  320. throw noSuchInstanceException;
  321. // There are too many arcs left in the OID (there should remain
  322. // a single trailing .0)
  323. if (depth+2 < length)
  324. throw noSuchInstanceException;
  325. // The last trailing arc is not .0
  326. if (oid[depth+1] != 0L)
  327. throw noSuchInstanceException;
  328. // It's one of our variable, register this node.
  329. handlers.add(this,depth,varbind);
  330. }
  331. }
  332. // -------------------------------------------------------------------
  333. // See comments in SnmpMibNode.
  334. // -------------------------------------------------------------------
  335. long[] findNextHandlingNode(SnmpVarBind varbind,
  336. long[] oid, int pos, int depth,
  337. SnmpRequestTree handlers, AcmChecker checker)
  338. throws SnmpStatusException {
  339. int length = oid.length;
  340. SnmpMibNode node = null;
  341. if (handlers == null)
  342. // This should be considered as a genErr, but we do not want to
  343. // abort the whole request, so we're going to throw
  344. // a noSuchObject...
  345. //
  346. throw noSuchObjectException;
  347. final Object data = handlers.getUserData();
  348. final int pduVersion = handlers.getRequestPduVersion();
  349. // The generic case where the end of the OID has been reached is
  350. // handled in the superclass
  351. // XXX Revisit: this works but it is somewhat convoluted. Just setting
  352. // arc to -1 would work too.
  353. if (pos >= length)
  354. return super.findNextHandlingNode(varbind,oid,pos,depth,
  355. handlers, checker);
  356. // Ok, we've got the arc.
  357. long arc = oid[pos];
  358. long[] result = null;
  359. // We have a recursive logic. Should we have a loop instead?
  360. try {
  361. if (isTable(arc)) {
  362. // If the arc identifies a table, then we need to forward
  363. // the search to the table.
  364. // Gets the table identified by `arc'
  365. SnmpMibTable table = getTable(arc);
  366. // Forward to the table
  367. checker.add(depth, arc);
  368. try {
  369. result = table.findNextHandlingNode(varbind,oid,pos+1,
  370. depth+1,handlers,
  371. checker);
  372. }catch(SnmpStatusException ex) {
  373. throw noSuchObjectException;
  374. } finally {
  375. checker.remove(depth);
  376. }
  377. // Build up the leaf OID
  378. result[depth] = arc;
  379. return result;
  380. } else if (isReadable(arc)) {
  381. // If the arc identifies a readable variable, then two cases:
  382. if (pos == (length - 1)) {
  383. // The end of the OID is reached, so we return the leaf
  384. // corresponding to the variable identified by `arc'
  385. // Build up the OID
  386. // result = new SnmpOid(0);
  387. // result.insert((int)arc);
  388. result = new long[depth+2];
  389. result[depth+1] = 0L;
  390. result[depth] = arc;
  391. checker.add(depth, result, depth, 2);
  392. try {
  393. checker.checkCurrentOid();
  394. } catch(SnmpStatusException e) {
  395. throw noSuchObjectException;
  396. } finally {
  397. checker.remove(depth,2);
  398. }
  399. // Registers this node
  400. handlers.add(this,depth,varbind);
  401. return result;
  402. }
  403. // The end of the OID is not yet reached, so we must return
  404. // the next leaf following the variable identified by `arc'.
  405. // We cannot return the variable because whatever follows in
  406. // the OID will be greater or equals to 0, and 0 identifies
  407. // the variable itself - so we have indeed to return the
  408. // next object.
  409. // So we do nothing, because this case is handled at the
  410. // end of the if ... else if ... else ... block.
  411. } else if (isNestedArc(arc)) {
  412. // Now if the arc leads to a subgroup, we delegate the
  413. // search to the child, just as done in SnmpMibNode.
  414. //
  415. // get the child ( = nested arc node).
  416. //
  417. final SnmpMibNode child = getChild(arc);
  418. if (child != null) {
  419. checker.add(depth, arc);
  420. try {
  421. result = child.findNextHandlingNode(varbind,oid,pos+1,
  422. depth+1,handlers,
  423. checker);
  424. result[depth] = arc;
  425. return result;
  426. } finally {
  427. checker.remove(depth);
  428. }
  429. }
  430. }
  431. // The oid is not valid, we will throw an exception in order
  432. // to try with the next valid identifier...
  433. //
  434. throw noSuchObjectException;
  435. } catch (SnmpStatusException e) {
  436. // We didn't find anything at the given arc, so we're going
  437. // to try with the next valid arc
  438. //
  439. long[] newOid = new long[1];
  440. newOid[0] = getNextVarId(arc,data,pduVersion);
  441. return findNextHandlingNode(varbind,newOid,0,depth,
  442. handlers,checker);
  443. }
  444. }
  445. }