1. /*
  2. * @(#)file SnmpMibOid.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 4.21
  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. */
  11. package com.sun.jmx.snmp.agent;
  12. // java imports
  13. //
  14. import java.io.Serializable;
  15. import java.util.Vector;
  16. import java.util.Enumeration;
  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. /**
  24. * Represents a node in an SNMP MIB which is neither a group nor a variable.
  25. * This class defines a list of sub-nodes and the methods that allow to
  26. * manipulate the sub-nodes.
  27. * <P>
  28. * This class is used internally and by the class generated by
  29. * <CODE>mibgen</CODE>.
  30. * You should not need to use this class directly.
  31. *
  32. * <p><b>This API is a Sun Microsystems internal API and is subject
  33. * to change without notice.</b></p>
  34. * @version 4.21 02/25/04
  35. * @author Sun Microsystems, Inc
  36. */
  37. public class SnmpMibOid extends SnmpMibNode implements Serializable {
  38. /**
  39. * Default constructor.
  40. */
  41. public SnmpMibOid() {
  42. }
  43. // PUBLIC METHODS
  44. //---------------
  45. /**
  46. * Generic handling of the <CODE>get</CODE> operation.
  47. *
  48. * <p> This method should be overridden in subclasses.
  49. * <p>
  50. *
  51. * @param req The sub-request that must be handled by this node.
  52. *
  53. * @param depth The depth reached in the OID tree.
  54. *
  55. * @exception SnmpStatusException The default implementation (if not
  56. * overridden) is to generate a SnmpStatusException.
  57. */
  58. public void get(SnmpMibSubRequest req, int depth)
  59. throws SnmpStatusException {
  60. for (Enumeration e= req.getElements(); e.hasMoreElements();) {
  61. SnmpVarBind var= (SnmpVarBind) e.nextElement();
  62. SnmpStatusException x =
  63. new SnmpStatusException(SnmpStatusException.noSuchObject);
  64. req.registerGetException(var,x);
  65. }
  66. }
  67. /**
  68. * Generic handling of the <CODE>set</CODE> operation.
  69. *
  70. * <p> This method should be overridden in subclasses.
  71. * <p>
  72. *
  73. * @param req The sub-request that must be handled by this node.
  74. *
  75. * @param depth The depth reached in the OID tree.
  76. *
  77. * @exception SnmpStatusException The default implementation (if not
  78. * overridden) is to generate a SnmpStatusException.
  79. */
  80. public void set(SnmpMibSubRequest req, int depth)
  81. throws SnmpStatusException {
  82. for (Enumeration e= req.getElements(); e.hasMoreElements();) {
  83. SnmpVarBind var= (SnmpVarBind) e.nextElement();
  84. SnmpStatusException x =
  85. new SnmpStatusException(SnmpStatusException.noAccess);
  86. req.registerSetException(var,x);
  87. }
  88. }
  89. /**
  90. * Generic handling of the <CODE>check</CODE> operation.
  91. *
  92. * <p> This method should be overridden in subclasses.
  93. * <p>
  94. *
  95. * @param req The sub-request that must be handled by this node.
  96. *
  97. * @param depth The depth reached in the OID tree.
  98. *
  99. * @exception SnmpStatusException The default implementation (if not
  100. * overriden) is to generate a SnmpStatusException.
  101. */
  102. public void check(SnmpMibSubRequest req, int depth)
  103. throws SnmpStatusException {
  104. for (Enumeration e= req.getElements(); e.hasMoreElements();) {
  105. SnmpVarBind var= (SnmpVarBind) e.nextElement();
  106. SnmpStatusException x =
  107. new SnmpStatusException(SnmpStatusException.noAccess);
  108. req.registerCheckException(var,x);
  109. }
  110. }
  111. // ---------------------------------------------------------------------
  112. //
  113. // Implements the method defined in SnmpMibNode.
  114. //
  115. // ---------------------------------------------------------------------
  116. //
  117. void findHandlingNode(SnmpVarBind varbind,
  118. long[] oid, int depth,
  119. SnmpRequestTree handlers)
  120. throws SnmpStatusException {
  121. final int length = oid.length;
  122. SnmpMibNode node = null;
  123. if (handlers == null)
  124. throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
  125. if (depth > length) {
  126. // Nothing is left... the oid is not valid
  127. throw noSuchObjectException;
  128. } else if (depth == length) {
  129. // The oid is not complete...
  130. throw noSuchInstanceException;
  131. } else {
  132. // Some children variable or subobject is being querried
  133. // getChild() will raise an exception if no child is found.
  134. //
  135. final SnmpMibNode child= getChild(oid[depth]);
  136. // XXXX zzzz : what about null children?
  137. // (variables for nested groups)
  138. // if child==null, then we're dealing with a variable or
  139. // a table: we register this node.
  140. // This behaviour should be overriden in subclasses,
  141. // in particular in group meta classes: the group
  142. // meta classes that hold tables should take care
  143. // of forwarding this call to all the tables involved.
  144. //
  145. if (child == null)
  146. handlers.add(this,depth,varbind);
  147. else
  148. child.findHandlingNode(varbind,oid,depth+1,handlers);
  149. }
  150. }
  151. // ---------------------------------------------------------------------
  152. //
  153. // Implements the method defined in SnmpMibNode.
  154. //
  155. // ---------------------------------------------------------------------
  156. //
  157. long[] findNextHandlingNode(SnmpVarBind varbind,
  158. long[] oid, int pos, int depth,
  159. SnmpRequestTree handlers,
  160. AcmChecker checker)
  161. throws SnmpStatusException {
  162. final int length = oid.length;
  163. SnmpMibNode node = null;
  164. long[] result = null;
  165. if (handlers == null)
  166. // This should be considered as a genErr, but we do not want to
  167. // abort the whole request, so we're going to throw
  168. // a noSuchObject...
  169. //
  170. throw noSuchObjectException;
  171. final Object data = handlers.getUserData();
  172. final int pduVersion = handlers.getRequestPduVersion();
  173. if (pos >= length) {
  174. long[] newOid= new long[1];
  175. newOid[0]= getNextVarId(-1,data,pduVersion);
  176. result = findNextHandlingNode(varbind,newOid,0,depth,handlers,
  177. checker);
  178. return result;
  179. }
  180. // search the element specified in the oid
  181. //
  182. long[] newOid= new long[1];
  183. long index= oid[pos];
  184. while (true) {
  185. try {
  186. final SnmpMibNode child = getChild(index);
  187. // SnmpOid result = null;
  188. if (child == null) {
  189. // shouldn't happen
  190. throw noSuchObjectException;
  191. // validateVarId(index);
  192. // handlers.add(this,varbind,depth);
  193. // result = new SnmpOid(0);
  194. } else {
  195. checker.add(depth, index);
  196. try {
  197. result = child.findNextHandlingNode(varbind,oid,pos+1,
  198. depth+1,handlers,
  199. checker);
  200. } finally {
  201. checker.remove(depth);
  202. }
  203. }
  204. // Build up the leaf OID
  205. result[depth] = index;
  206. return result;
  207. } catch(SnmpStatusException e) {
  208. // If there is no such element go one level up ...
  209. //
  210. index= getNextVarId(index,data,pduVersion);
  211. // There is no need to carry the original oid ...
  212. newOid[0]=index;
  213. pos= 1;
  214. oid=newOid;
  215. }
  216. }
  217. }
  218. /**
  219. * Computes the root OID of the MIB.
  220. */
  221. public void getRootOid(Vector result) {
  222. // If a node has several children, let assume that we are one step to
  223. // far in order to get the MIB root.
  224. //
  225. if (nbChildren != 1)
  226. return;
  227. result.addElement(new Integer(varList[0]));
  228. // Now query our child.
  229. //
  230. ((SnmpMibNode)children.firstElement()).getRootOid(result);
  231. }
  232. /**
  233. * Registers a specific node in the tree.
  234. */
  235. public void registerNode(String oidString ,SnmpMibNode node)
  236. throws IllegalAccessException {
  237. SnmpOid oid= new SnmpOid(oidString);
  238. registerNode(oid.longValue(), 0, node);
  239. }
  240. // PROTECTED METHODS
  241. //------------------
  242. /**
  243. * Registers a specific node in the tree.
  244. */
  245. void registerNode(long[] oid, int cursor ,SnmpMibNode node)
  246. throws IllegalAccessException {
  247. if (cursor >= oid.length)
  248. throw new IllegalAccessException();
  249. // Check if the node is already defined
  250. //
  251. long var= oid[cursor];
  252. //System.out.println("entering registration for val="
  253. // + String.valueOf(var) + " position= " + cursor);
  254. int pos = retrieveIndex(var);
  255. if (pos == nbChildren) {
  256. nbChildren++;
  257. varList= new int[nbChildren];
  258. varList[0]= (int) var;
  259. pos =0;
  260. if ( (cursor + 1) == oid.length) {
  261. // That 's the end of the trip.
  262. // Do not forward the registration
  263. //System.out.println("End of trip for val="
  264. // + String.valueOf(var) + " position= " + cursor);
  265. children.insertElementAt(node,pos);
  266. return;
  267. }
  268. //System.out.println("Create node for val="
  269. // + String.valueOf(var) + " position= " + cursor);
  270. SnmpMibOid child= new SnmpMibOid();
  271. children.insertElementAt(child, pos);
  272. child.registerNode(oid, cursor + 1, node);
  273. return;
  274. }
  275. if (pos == -1) {
  276. // The node is not yet registered
  277. //
  278. int[] tmp= new int[nbChildren + 1];
  279. tmp[nbChildren]= (int) var;
  280. System.arraycopy(varList, 0, tmp, 0, nbChildren);
  281. varList= tmp;
  282. nbChildren++;
  283. SnmpMibNode.sort(varList);
  284. int newPos = retrieveIndex(var);
  285. varList[newPos]= (int) var;
  286. if ( (cursor + 1) == oid.length) {
  287. // That 's the end of the trip.
  288. // Do not forward the registration
  289. //System.out.println("End of trip for val="
  290. // + String.valueOf(var) + " position= " + cursor);
  291. children.insertElementAt(node, newPos);
  292. return;
  293. }
  294. SnmpMibOid child= new SnmpMibOid();
  295. // System.out.println("Create node for val=" +
  296. // String.valueOf(var) + " position= " + cursor);
  297. children.insertElementAt(child, newPos);
  298. child.registerNode(oid, cursor + 1, node);
  299. return;
  300. }
  301. else {
  302. // The node is already registered
  303. //
  304. SnmpMibNode child= (SnmpMibNode) children.elementAt(pos);
  305. if ( (cursor + 1) == oid.length ) {
  306. //System.out.println("Node already registered val=" +
  307. // String.valueOf(var) + " position= " + cursor);
  308. if (child == node) return;
  309. if (child != null && node != null) {
  310. // Now we're going to patch the tree the following way:
  311. // if a subgroup has been registered before its father,
  312. // we're going to replace the father OID node with
  313. // the actual group-node and export the children from
  314. // the temporary OID node to the actual group node.
  315. //
  316. if (node instanceof SnmpMibGroup) {
  317. // `node' is a group => replace `child' with `node'
  318. // export the child's subtree to `node'.
  319. //
  320. ((SnmpMibOid)child).exportChildren((SnmpMibOid)node);
  321. children.setElementAt(node,pos);
  322. return;
  323. } else if ((node instanceof SnmpMibOid) &&
  324. (child instanceof SnmpMibGroup)) {
  325. // `node' is a temporary node, and `child' is a
  326. // group => keep child and export the node's
  327. // subtree to `child'.
  328. //
  329. ((SnmpMibOid)node).exportChildren((SnmpMibOid)child);
  330. return;
  331. } else if (node instanceof SnmpMibOid) {
  332. // `node' and `child' are both temporary OID nodes
  333. // => replace `child' with `node' and export child's
  334. // subtree to `node'.
  335. //
  336. ((SnmpMibOid)child).exportChildren((SnmpMibOid)node);
  337. children.setElementAt(node,pos);
  338. return;
  339. }
  340. }
  341. children.setElementAt(node,pos);
  342. return;
  343. } else {
  344. if (child == null)
  345. throw new IllegalAccessException();
  346. ((SnmpMibOid)child).registerNode(oid, cursor + 1, node);
  347. }
  348. }
  349. }
  350. /**
  351. * Export this node's children to a brother node that will replace
  352. * this node in the OID tree.
  353. * This method is a patch that fixes the problem of registering
  354. * a subnode before its father node.
  355. *
  356. **/
  357. void exportChildren(SnmpMibOid brother)
  358. throws IllegalAccessException {
  359. if (brother == null) return;
  360. final long[] oid = new long[1];
  361. for (int i=0; i<nbChildren; i++) {
  362. final SnmpMibNode child = (SnmpMibNode)children.elementAt(i);
  363. if (child == null) continue;
  364. oid[0] = varList[i];
  365. brother.registerNode(oid,0,child);
  366. }
  367. }
  368. // PRIVATE METHODS
  369. //----------------
  370. SnmpMibNode getChild(long id) throws SnmpStatusException {
  371. // first we need to retrieve the identifier in the list of children
  372. //
  373. final int pos= getInsertAt(id);
  374. if (pos >= nbChildren)
  375. throw noSuchObjectException;
  376. if (varList[pos] != (int) id)
  377. throw noSuchObjectException;
  378. // Access the node
  379. //
  380. SnmpMibNode child = null;
  381. try {
  382. child = (SnmpMibNode) children.elementAtNonSync(pos);
  383. } catch(ArrayIndexOutOfBoundsException e) {
  384. throw noSuchObjectException;
  385. }
  386. if (child == null)
  387. throw noSuchInstanceException;
  388. return child;
  389. }
  390. private int retrieveIndex(long val) {
  391. int low= 0;
  392. int cursor= (int) val;
  393. if (varList == null || varList.length < 1)
  394. return nbChildren;
  395. int max= varList.length -1 ;
  396. int curr= low + (max-low)/2;
  397. int elmt= 0;
  398. while (low <= max) {
  399. elmt= varList[curr];
  400. if (cursor == elmt) {
  401. // We need to get the next index ...
  402. //
  403. return curr;
  404. }
  405. if (elmt < cursor) {
  406. low= curr +1;
  407. } else {
  408. max= curr -1;
  409. }
  410. curr= low + (max-low)/2;
  411. }
  412. return -1;
  413. }
  414. private int getInsertAt(long val) {
  415. int low= 0;
  416. final int index= (int) val;
  417. if (varList == null)
  418. return -1;
  419. int max= varList.length -1 ;
  420. int elmt=0;
  421. //final int[] v = varList;
  422. //if (index > a[max])
  423. //return max +1;
  424. int curr= low + (max-low)/2;
  425. while (low <= max) {
  426. elmt= varList[curr];
  427. // never know ...we might find something ...
  428. //
  429. if (index == elmt)
  430. return curr;
  431. if (elmt < index) {
  432. low= curr +1;
  433. } else {
  434. max= curr -1;
  435. }
  436. curr= low + (max-low)/2;
  437. }
  438. return curr;
  439. }
  440. // PRIVATE VARIABLES
  441. //------------------
  442. /**
  443. * Contains the list of sub nodes.
  444. */
  445. private NonSyncVector children= new NonSyncVector(1);
  446. /**
  447. * The number of sub nodes.
  448. */
  449. private int nbChildren= 0;
  450. // All the methods of the Vector class are synchronized.
  451. // Synchronization is a very expensive operation. In our case it is
  452. // not always required...
  453. //
  454. class NonSyncVector extends Vector {
  455. public NonSyncVector(int size) {
  456. super(size);
  457. }
  458. final void addNonSyncElement(Object obj) {
  459. ensureCapacity(elementCount + 1);
  460. elementData[elementCount++] = obj;
  461. }
  462. final Object elementAtNonSync(int index) {
  463. return elementData[index];
  464. }
  465. }
  466. }