1. /*
  2. * @(#)file SnmpMibTable.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 4.57
  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.Date;
  16. import java.util.Vector;
  17. import java.util.Enumeration;
  18. // jmx imports
  19. //
  20. import javax.management.Notification;
  21. import javax.management.ObjectName;
  22. import javax.management.NotificationFilter;
  23. import javax.management.NotificationListener;
  24. import javax.management.NotificationBroadcaster;
  25. import javax.management.MBeanNotificationInfo;
  26. import javax.management.ListenerNotFoundException;
  27. import com.sun.jmx.snmp.SnmpOid;
  28. import com.sun.jmx.snmp.SnmpValue;
  29. import com.sun.jmx.snmp.SnmpInt;
  30. import com.sun.jmx.snmp.SnmpVarBind;
  31. import com.sun.jmx.snmp.SnmpStatusException;
  32. import com.sun.jmx.snmp.EnumRowStatus;
  33. import com.sun.jmx.trace.Trace;
  34. /**
  35. * This class is the base class for SNMP table metadata.
  36. * <p>
  37. * Its responsibility is to manage a sorted array of OID indexes
  38. * according to the SNMP indexing scheme over the "real" table.
  39. * Each object of this class can be bound to an
  40. * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} to which it will
  41. * forward remote entry creation requests, and invoke callbacks
  42. * when an entry has been successfully added to / removed from
  43. * the OID index array.
  44. * </p>
  45. *
  46. * <p>
  47. * For each table defined in the MIB, mibgen will generate a specific
  48. * class called Table<i>TableName</i> that will implement the
  49. * SnmpTableEntryFactory interface, and a corresponding
  50. * <i>TableName</i>Meta class that will extend this class. <br>
  51. * The Table<i>TableName</i> class corresponds to the MBean view of the
  52. * table while the <i>TableName</i>Meta class corresponds to the
  53. * MIB metadata view of the same table.
  54. * </p>
  55. *
  56. * <p>
  57. * Objects of this class are instantiated by the generated
  58. * whole MIB class extending {@link com.sun.jmx.snmp.agent.SnmpMib}
  59. * You should never need to instantiate this class directly.
  60. * </p>
  61. *
  62. * <p><b>This API is a Sun Microsystems internal API and is subject
  63. * to change without notice.</b></p>
  64. * @see com.sun.jmx.snmp.agent.SnmpMib
  65. * @see com.sun.jmx.snmp.agent.SnmpMibEntry
  66. * @see com.sun.jmx.snmp.agent.SnmpTableEntryFactory
  67. * @see com.sun.jmx.snmp.agent.SnmpTableSupport
  68. *
  69. * @version 4.57 01/22/04
  70. * @author Sun Microsystems, Inc
  71. */
  72. public abstract class SnmpMibTable extends SnmpMibNode
  73. implements NotificationBroadcaster, Serializable {
  74. /**
  75. * Create a new <CODE>SnmpMibTable</CODE> metadata node.
  76. *
  77. * <p>
  78. * @param mib The SNMP MIB to which the metadata will be linked.
  79. */
  80. public SnmpMibTable(SnmpMib mib) {
  81. this.theMib= mib;
  82. setCreationEnabled(false);
  83. }
  84. // -------------------------------------------------------------------
  85. // PUBLIC METHODS
  86. // -------------------------------------------------------------------
  87. /**
  88. * This method is invoked when the creation of a new entry is requested
  89. * by a remote SNMP manager.
  90. * <br>By default, remote entry creation is disabled - and this method
  91. * will not be called. You can dynamically switch the entry creation
  92. * policy by calling <code>setCreationEnabled(true)</code> and <code>
  93. * setCreationEnabled(false)</code> on this object.
  94. * <p><b><i>
  95. * This method is called internally by the SNMP runtime and you
  96. * should never need to call it directly. </b></i>However you might want
  97. * to extend it in order to implement your own specific application
  98. * behaviour, should the default behaviour not be at your convenience.
  99. * </p>
  100. * <p>
  101. * @param req The SNMP subrequest requesting this creation
  102. * @param rowOid The OID indexing the conceptual row (entry) for which
  103. * the creation was requested.
  104. * @param depth The position of the columnar object arc in the OIDs
  105. * from the varbind list.
  106. *
  107. * @exception SnmpStatusException if the entry cannot be created.
  108. */
  109. public abstract void createNewEntry(SnmpMibSubRequest req, SnmpOid rowOid,
  110. int depth)
  111. throws SnmpStatusException;
  112. /**
  113. * Tell whether the specific version of this metadata generated
  114. * by <code>mibgen</code> requires entries to be registered with
  115. * the MBeanServer. In this case an ObjectName will have to be
  116. * passed to addEntry() in order for the table to behave correctly
  117. * (case of the generic metadata).
  118. * <p>
  119. * If that version of the metadata does not require entry to be
  120. * registered, then passing an ObjectName becomes optional (null
  121. * can be passed instead).
  122. *
  123. * @return <code>true</code> if registration is required by this
  124. * version of the metadata.
  125. */
  126. public abstract boolean isRegistrationRequired();
  127. /**
  128. * Tell whether a new entry should be created when a SET operation
  129. * is received for an entry that does not exist yet.
  130. *
  131. * @return true if a new entry must be created, false otherwise.<br>
  132. * [default: returns <CODE>false</CODE>]
  133. **/
  134. public boolean isCreationEnabled() {
  135. return creationEnabled;
  136. }
  137. /**
  138. * This method lets you dynamically switch the creation policy.
  139. *
  140. * <p>
  141. * @param remoteCreationFlag Tells whether remote entry creation must
  142. * be enabled or disabled.
  143. * <ul><li>
  144. * <CODE>setCreationEnabled(true)</CODE> will enable remote entry
  145. * creation via SET operations.</li>
  146. * <li>
  147. * <CODE>setCreationEnabled(false)</CODE> will disable remote entry
  148. * creation via SET operations.</li>
  149. * <p> By default remote entry creation via SET operation is disabled.
  150. * </p>
  151. * </ul>
  152. **/
  153. public void setCreationEnabled(boolean remoteCreationFlag) {
  154. creationEnabled = remoteCreationFlag;
  155. }
  156. /**
  157. * Return <code>true</code> if the conceptual row contains a columnar
  158. * object used to control creation/deletion of rows in this table.
  159. * <p>
  160. * This columnar object can be either a variable with RowStatus
  161. * syntax as defined by RFC 2579, or a plain variable whose
  162. * semantics is table specific.
  163. * <p>
  164. * By default, this function returns <code>false</code>, and it is
  165. * assumed that the table has no such control variable.<br>
  166. * When <code>mibgen</code> is used over SMIv2 MIBs, it will generate
  167. * an <code>hasRowStatus()</code> method returning <code>true</code>
  168. * for each table containing an object with RowStatus syntax.
  169. * <p>
  170. * When this method returns <code>false</code> the default mechanism
  171. * for remote entry creation is used.
  172. * Otherwise, creation/deletion is performed as specified
  173. * by the control variable (see getRowAction() for more details).
  174. * <p>
  175. * This method is called internally when a SET request involving
  176. * this table is processed.
  177. * <p>
  178. * If you need to implement a control variable which do not use
  179. * the RowStatus convention as defined by RFC 2579, you should
  180. * subclass the generated table metadata class in order to redefine
  181. * this method and make it returns <code>true</code>.<br>
  182. * You will then have to redefine the isRowStatus(), mapRowStatus(),
  183. * isRowReady(), and setRowStatus() methods to suit your specific
  184. * implementation.
  185. * <p>
  186. * @return <li><code>true</code> if this table contains a control
  187. * variable (eg: a variable with RFC 2579 RowStatus syntax),
  188. * </li>
  189. * <li><code>false</code> if this table does not contain
  190. * any control variable.</li>
  191. *
  192. **/
  193. public boolean hasRowStatus() {
  194. return false;
  195. }
  196. // ---------------------------------------------------------------------
  197. //
  198. // Implements the method defined in SnmpMibNode.
  199. //
  200. // ---------------------------------------------------------------------
  201. /**
  202. * Generic handling of the <CODE>get</CODE> operation.
  203. * <p> The default implementation of this method is to
  204. * <ul>
  205. * <li> check whether the entry exists, and if not register an
  206. * exception for each varbind in the list.
  207. * <li> call the generated
  208. * <CODE>get(req,oid,depth+1)</CODE> method. </li>
  209. * </ul>
  210. * <p>
  211. * <pre>
  212. * public void get(SnmpMibSubRequest req, int depth)
  213. * throws SnmpStatusException {
  214. * boolean isnew = req.isNewEntry();
  215. *
  216. * // if the entry does not exists, then registers an error for
  217. * // each varbind involved (nb: this should not happen, since
  218. * // the error should already have been detected earlier)
  219. * //
  220. * if (isnew) {
  221. * SnmpVarBind var = null;
  222. * for (Enumeration e= req.getElements(); e.hasMoreElements();) {
  223. * var = (SnmpVarBind) e.nextElement();
  224. * req.registerGetException(var,noSuchNameException);
  225. * }
  226. * }
  227. *
  228. * final SnmpOid oid = req.getEntryOid();
  229. * get(req,oid,depth+1);
  230. * }
  231. * </pre>
  232. * <p> You should not need to override this method in any cases, because
  233. * it will eventually call
  234. * <CODE>get(SnmpMibSubRequest req, int depth)</CODE> on the generated
  235. * derivative of <CODE>SnmpMibEntry</CODE>. If you need to implement
  236. * specific policies for minimizing the accesses made to some remote
  237. * underlying resources, or if you need to implement some consistency
  238. * checks between the different values provided in the varbind list,
  239. * you should then rather override
  240. * <CODE>get(SnmpMibSubRequest req, int depth)</CODE> on the generated
  241. * derivative of <CODE>SnmpMibEntry</CODE>.
  242. * <p>
  243. *
  244. */
  245. public void get(SnmpMibSubRequest req, int depth)
  246. throws SnmpStatusException {
  247. final boolean isnew = req.isNewEntry();
  248. final SnmpMibSubRequest r = req;
  249. // if the entry does not exists, then registers an error for
  250. // each varbind involved (nb: should not happen, the error
  251. // should have been registered earlier)
  252. if (isnew) {
  253. SnmpVarBind var = null;
  254. for (Enumeration e= r.getElements(); e.hasMoreElements();) {
  255. var = (SnmpVarBind) e.nextElement();
  256. r.registerGetException(var,noSuchInstanceException);
  257. }
  258. }
  259. final SnmpOid oid = r.getEntryOid();
  260. // SnmpIndex index = buildSnmpIndex(oid.longValue(false), 0);
  261. // get(req,index,depth+1);
  262. //
  263. get(req,oid,depth+1);
  264. }
  265. // ---------------------------------------------------------------------
  266. //
  267. // Implements the method defined in SnmpMibNode.
  268. //
  269. // ---------------------------------------------------------------------
  270. /**
  271. * Generic handling of the <CODE>check</CODE> operation.
  272. * <p> The default implementation of this method is to
  273. * <ul>
  274. * <li> check whether a new entry must be created, and if remote
  275. * creation of entries is enabled, create it. </li>
  276. * <li> call the generated
  277. * <CODE>check(req,oid,depth+1)</CODE> method. </li>
  278. * </ul>
  279. * <p>
  280. * <pre>
  281. * public void check(SnmpMibSubRequest req, int depth)
  282. * throws SnmpStatusException {
  283. * final SnmpOid oid = req.getEntryOid();
  284. * final int action = getRowAction(req,oid,depth+1);
  285. *
  286. * beginRowAction(req,oid,depth+1,action);
  287. * check(req,oid,depth+1);
  288. * }
  289. * </pre>
  290. * <p> You should not need to override this method in any cases, because
  291. * it will eventually call
  292. * <CODE>check(SnmpMibSubRequest req, int depth)</CODE> on the generated
  293. * derivative of <CODE>SnmpMibEntry</CODE>. If you need to implement
  294. * specific policies for minimizing the accesses made to some remote
  295. * underlying resources, or if you need to implement some consistency
  296. * checks between the different values provided in the varbind list,
  297. * you should then rather override
  298. * <CODE>check(SnmpMibSubRequest req, int depth)</CODE> on the generated
  299. * derivative of <CODE>SnmpMibEntry</CODE>.
  300. * <p>
  301. *
  302. */
  303. public void check(SnmpMibSubRequest req, int depth)
  304. throws SnmpStatusException {
  305. final SnmpOid oid = req.getEntryOid();
  306. final int action = getRowAction(req,oid,depth+1);
  307. final boolean dbg = isDebugOn();
  308. if (dbg) debug("check","Calling beginRowAction");
  309. beginRowAction(req,oid,depth+1,action);
  310. if (dbg) debug("check","Calling check for " + req.getSize() +
  311. " varbinds.");
  312. check(req,oid,depth+1);
  313. if (dbg) debug("check","check finished");
  314. }
  315. // ---------------------------------------------------------------------
  316. //
  317. // Implements the method defined in SnmpMibNode.
  318. //
  319. // ---------------------------------------------------------------------
  320. /**
  321. * Generic handling of the <CODE>set</CODE> operation.
  322. * <p> The default implementation of this method is to
  323. * call the generated
  324. * <CODE>set(req,oid,depth+1)</CODE> method.
  325. * <p>
  326. * <pre>
  327. * public void set(SnmpMibSubRequest req, int depth)
  328. * throws SnmpStatusException {
  329. * final SnmpOid oid = req.getEntryOid();
  330. * final int action = getRowAction(req,oid,depth+1);
  331. *
  332. * set(req,oid,depth+1);
  333. * endRowAction(req,oid,depth+1,action);
  334. * }
  335. * </pre>
  336. * <p> You should not need to override this method in any cases, because
  337. * it will eventually call
  338. * <CODE>set(SnmpMibSubRequest req, int depth)</CODE> on the generated
  339. * derivative of <CODE>SnmpMibEntry</CODE>. If you need to implement
  340. * specific policies for minimizing the accesses made to some remote
  341. * underlying resources, or if you need to implement some consistency
  342. * checks between the different values provided in the varbind list,
  343. * you should then rather override
  344. * <CODE>set(SnmpMibSubRequest req, int depth)</CODE> on the generated
  345. * derivative of <CODE>SnmpMibEntry</CODE>.
  346. * <p>
  347. *
  348. */
  349. public void set(SnmpMibSubRequest req, int depth)
  350. throws SnmpStatusException {
  351. final boolean dbg = isDebugOn();
  352. if (dbg) debug("set","Entering set.");
  353. final SnmpOid oid = req.getEntryOid();
  354. final int action = getRowAction(req,oid,depth+1);
  355. if (dbg) debug("set","Calling set for " + req.getSize() +
  356. "varbinds.");
  357. set(req,oid,depth+1);
  358. if (dbg) debug("set","Calling endRowAction");
  359. endRowAction(req,oid,depth+1,action);
  360. if (dbg) debug("set","RowAction finished");
  361. }
  362. /**
  363. * Add a new entry in this <CODE>SnmpMibTable</CODE>.
  364. * Also triggers the addEntryCB() callback of the
  365. * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
  366. * if this node is bound to a factory.
  367. *
  368. * This method assumes that the given entry will not be registered.
  369. * If the entry is going to be registered, or if ObjectName's are
  370. * required, then
  371. * {@link com.sun.jmx.snmp.agent.SnmpMibTable#addEntry(SnmpOid,
  372. * ObjectName, Object)} should be prefered.
  373. * <br> This function is mainly provided for backward compatibility.
  374. *
  375. * <p>
  376. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  377. * row to be added.
  378. * @param entry The entry to add.
  379. *
  380. * @exception SnmpStatusException The entry couldn't be added
  381. * at the position identified by the given
  382. * <code>rowOid</code>, or this version of the metadata
  383. * requires ObjectName's.
  384. */
  385. // public void addEntry(SnmpIndex index, Object entry)
  386. public void addEntry(SnmpOid rowOid, Object entry)
  387. throws SnmpStatusException {
  388. addEntry(rowOid, null, entry);
  389. }
  390. /**
  391. * Add a new entry in this <CODE>SnmpMibTable</CODE>.
  392. * Also triggers the addEntryCB() callback of the
  393. * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
  394. * if this node is bound to a factory.
  395. *
  396. * <p>
  397. * @param oid The <CODE>SnmpOid</CODE> identifying the table
  398. * row to be added.
  399. *
  400. * @param name The ObjectName with which this entry is registered.
  401. * This parameter can be omitted if isRegistrationRequired()
  402. * return false.
  403. *
  404. * @param entry The entry to add.
  405. *
  406. * @exception SnmpStatusException The entry couldn't be added
  407. * at the position identified by the given
  408. * <code>rowOid</code>, or if this version of the metadata
  409. * requires ObjectName's, and the given name is null.
  410. */
  411. // protected synchronized void addEntry(SnmpIndex index, ObjectName name,
  412. // Object entry)
  413. public synchronized void addEntry(SnmpOid oid, ObjectName name,
  414. Object entry)
  415. throws SnmpStatusException {
  416. if (isRegistrationRequired() == true && name == null)
  417. throw new SnmpStatusException(SnmpStatusException.badValue);
  418. if (size == 0) {
  419. // indexes.addElement(index);
  420. // XX oids.addElement(oid);
  421. insertOid(0,oid);
  422. if (entries != null)
  423. entries.addElement(entry);
  424. if (entrynames != null)
  425. entrynames.addElement(name);
  426. size++;
  427. // triggers callbacks on the entry factory
  428. //
  429. if (factory != null) {
  430. try {
  431. factory.addEntryCb(0,oid,name,entry,this);
  432. } catch (SnmpStatusException x) {
  433. removeOid(0);
  434. if (entries != null)
  435. entries.removeElementAt(0);
  436. if (entrynames != null)
  437. entrynames.removeElementAt(0);
  438. throw x;
  439. }
  440. }
  441. // sends the notifications
  442. //
  443. sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_ADDED,
  444. (new Date()).getTime(), entry, name);
  445. return;
  446. }
  447. // Get the insertion position ...
  448. //
  449. int pos= 0;
  450. // bug jaw.00356.B : use oid rather than index to get the
  451. // insertion point.
  452. //
  453. pos= getInsertionPoint(oid,true);
  454. if (pos == size) {
  455. // Add a new element in the vectors ...
  456. //
  457. // indexes.addElement(index);
  458. // XX oids.addElement(oid);
  459. insertOid(tablecount,oid);
  460. if (entries != null)
  461. entries.addElement(entry);
  462. if (entrynames != null)
  463. entrynames.addElement(name);
  464. size++;
  465. } else {
  466. // Insert new element ...
  467. //
  468. try {
  469. // indexes.insertElementAt(index, pos);
  470. // XX oids.insertElementAt(oid, pos);
  471. insertOid(pos,oid);
  472. if (entries != null)
  473. entries.insertElementAt(entry, pos);
  474. if (entrynames != null)
  475. entrynames.insertElementAt(name,pos);
  476. size++;
  477. } catch(ArrayIndexOutOfBoundsException e) {
  478. }
  479. }
  480. // triggers callbacks on the entry factory
  481. //
  482. if (factory != null) {
  483. try {
  484. factory.addEntryCb(pos,oid,name,entry,this);
  485. } catch (SnmpStatusException x) {
  486. removeOid(pos);
  487. if (entries != null)
  488. entries.removeElementAt(pos);
  489. if (entrynames != null)
  490. entrynames.removeElementAt(pos);
  491. throw x;
  492. }
  493. }
  494. // sends the notifications
  495. //
  496. sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_ADDED,
  497. (new Date()).getTime(), entry, name);
  498. }
  499. /**
  500. * Remove the specified entry from the table.
  501. * Also triggers the removeEntryCB() callback of the
  502. * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
  503. * if this node is bound to a factory.
  504. *
  505. * <p>
  506. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  507. * row to remove.
  508. *
  509. * @param entry The entry to be removed. This parameter is not used
  510. * internally, it is simply passed along to the
  511. * removeEntryCB() callback.
  512. *
  513. * @exception SnmpStatusException if the specified entry couldn't
  514. * be removed (if the given <code>rowOid</code> is not
  515. * valid for instance).
  516. */
  517. public synchronized void removeEntry(SnmpOid rowOid, Object entry)
  518. throws SnmpStatusException {
  519. int pos = findObject(rowOid);
  520. if (pos == -1)
  521. return;
  522. removeEntry(pos,entry);
  523. }
  524. /**
  525. * Remove the specified entry from the table.
  526. * Also triggers the removeEntryCB() callback of the
  527. * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
  528. * if this node is bound to a factory.
  529. *
  530. * <p>
  531. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  532. * row to remove.
  533. *
  534. * @exception SnmpStatusException if the specified entry couldn't
  535. * be removed (if the given <code>rowOid</code> is not
  536. * valid for instance).
  537. */
  538. public void removeEntry(SnmpOid rowOid)
  539. throws SnmpStatusException {
  540. int pos = findObject(rowOid);
  541. if (pos == -1)
  542. return;
  543. removeEntry(pos,null);
  544. }
  545. /**
  546. * Remove the specified entry from the table.
  547. * Also triggers the removeEntryCB() callback of the
  548. * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} interface
  549. * if this node is bound to a factory.
  550. *
  551. * <p>
  552. * @param pos The position of the entry in the table.
  553. *
  554. * @param entry The entry to be removed. This parameter is not used
  555. * internally, it is simply passed along to the
  556. * removeEntryCB() callback.
  557. *
  558. * @exception SnmpStatusException if the specified entry couldn't
  559. * be removed.
  560. */
  561. public synchronized void removeEntry(int pos, Object entry)
  562. throws SnmpStatusException {
  563. if (pos == -1)
  564. return;
  565. if (pos >= size) return;
  566. Object obj = entry;
  567. if (entries != null && entries.size() > pos) {
  568. obj = entries.elementAt(pos);
  569. entries.removeElementAt(pos);
  570. }
  571. ObjectName name = null;
  572. if (entrynames != null && entrynames.size() > pos) {
  573. name = (ObjectName) entrynames.elementAt(pos);
  574. entrynames.removeElementAt(pos);
  575. }
  576. final SnmpOid rowOid = tableoids[pos];
  577. removeOid(pos);
  578. size --;
  579. if (obj == null) obj = entry;
  580. if (factory != null)
  581. factory.removeEntryCb(pos,rowOid,name,obj,this);
  582. sendNotification(SnmpTableEntryNotification.SNMP_ENTRY_REMOVED,
  583. (new Date()).getTime(), obj, name);
  584. }
  585. /**
  586. * Get the entry corresponding to the specified rowOid.
  587. *
  588. * <p>
  589. * @param rowOid The <CODE>SnmpOid</CODE> identifying the
  590. * row to be retrieved.
  591. *
  592. * @return The entry.
  593. *
  594. * @exception SnmpStatusException There is no entry with the specified
  595. * <code>rowOid</code> in the table.
  596. */
  597. public synchronized Object getEntry(SnmpOid rowOid)
  598. throws SnmpStatusException {
  599. int pos= findObject(rowOid);
  600. if (pos == -1)
  601. throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
  602. return entries.elementAt(pos);
  603. }
  604. /**
  605. * Get the ObjectName of the entry corresponding to the
  606. * specified rowOid.
  607. * The result of this method is only meaningful if
  608. * isRegistrationRequired() yields true.
  609. *
  610. * <p>
  611. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  612. * row whose ObjectName we want to retrieve.
  613. *
  614. * @return The object name of the entry.
  615. *
  616. * @exception SnmpStatusException There is no entry with the specified
  617. * <code>rowOid</code> in the table.
  618. */
  619. public synchronized ObjectName getEntryName(SnmpOid rowOid)
  620. throws SnmpStatusException {
  621. int pos = findObject(rowOid);
  622. if (entrynames == null) return null;
  623. if (pos == -1 || pos >= entrynames.size())
  624. throw new SnmpStatusException(SnmpStatusException.noSuchInstance);
  625. return (ObjectName) entrynames.elementAt(pos);
  626. }
  627. /**
  628. * Return the entries stored in this table <CODE>SnmpMibTable</CODE>.
  629. * <p>
  630. * If the subclass generated by mibgen uses the generic way to access
  631. * the entries (i.e. if it goes through the MBeanServer) then some of
  632. * the entries may be <code>null</code>. It all depends whether a non
  633. * <code>null</code> entry was passed to addEntry().<br>
  634. * Otherwise, if it uses the standard way (access the entry directly
  635. * through their standard MBean interface) this array will contain all
  636. * the entries.
  637. * <p>
  638. * @return The entries array.
  639. */
  640. public Object[] getBasicEntries() {
  641. Object[] array= new Object[size];
  642. entries.copyInto(array);
  643. return array;
  644. }
  645. /**
  646. * Get the size of the table.
  647. *
  648. * @return The number of entries currently registered in this table.
  649. */
  650. public int getSize() {
  651. return size;
  652. }
  653. // EVENT STUFF
  654. //------------
  655. /**
  656. * Enable to add an SNMP entry listener to this
  657. * <CODE>SnmpMibTable</CODE>.
  658. *
  659. * <p>
  660. * @param listener The listener object which will handle the
  661. * notifications emitted by the registered MBean.
  662. *
  663. * @param filter The filter object. If filter is null, no filtering
  664. * will be performed before handling notifications.
  665. *
  666. * @param handback The context to be sent to the listener when a
  667. * notification is emitted.
  668. *
  669. * @exception IllegalArgumentException Listener parameter is null.
  670. */
  671. public synchronized void
  672. addNotificationListener(NotificationListener listener,
  673. NotificationFilter filter, Object handback) {
  674. // Check listener
  675. //
  676. if (listener == null) {
  677. throw new java.lang.IllegalArgumentException
  678. ("Listener can't be null") ;
  679. }
  680. // looking for listener in handbackTable
  681. //
  682. java.util.Vector handbackList =
  683. (java.util.Vector) handbackTable.get(listener) ;
  684. java.util.Vector filterList =
  685. (java.util.Vector) filterTable.get(listener) ;
  686. if ( handbackList == null ) {
  687. handbackList = new java.util.Vector() ;
  688. filterList = new java.util.Vector() ;
  689. handbackTable.put(listener, handbackList) ;
  690. filterTable.put(listener, filterList) ;
  691. }
  692. // Add the handback and the filter
  693. //
  694. handbackList.addElement(handback) ;
  695. filterList.addElement(filter) ;
  696. }
  697. /**
  698. * Enable to remove an SNMP entry listener from this
  699. * <CODE>SnmpMibTable</CODE>.
  700. *
  701. * @param listener The listener object which will handle the
  702. * notifications emitted by the registered MBean.
  703. * This method will remove all the information related to this
  704. * listener.
  705. *
  706. * @exception ListenerNotFoundException The listener is not registered
  707. * in the MBean.
  708. */
  709. public synchronized void
  710. removeNotificationListener(NotificationListener listener)
  711. throws ListenerNotFoundException {
  712. // looking for listener in handbackTable
  713. //
  714. java.util.Vector handbackList =
  715. (java.util.Vector) handbackTable.get(listener) ;
  716. java.util.Vector filterList =
  717. (java.util.Vector) filterTable.get(listener) ;
  718. if ( handbackList == null ) {
  719. throw new ListenerNotFoundException("listener");
  720. }
  721. // If handback is null, remove the listener entry
  722. //
  723. handbackTable.remove(listener) ;
  724. filterTable.remove(listener) ;
  725. }
  726. /**
  727. * Return a <CODE>NotificationInfo</CODE> object containing the
  728. * notification class and the notification type sent by the
  729. * <CODE>SnmpMibTable</CODE>.
  730. */
  731. public MBeanNotificationInfo[] getNotificationInfo() {
  732. String[] types = {SnmpTableEntryNotification.SNMP_ENTRY_ADDED,
  733. SnmpTableEntryNotification.SNMP_ENTRY_REMOVED};
  734. MBeanNotificationInfo[] notifsInfo = {
  735. new MBeanNotificationInfo
  736. (types, "com.sun.jmx.snmp.agent.SnmpTableEntryNotification",
  737. "Notifications sent by the SnmpMibTable")
  738. };
  739. return notifsInfo;
  740. }
  741. /**
  742. * Register the factory through which table entries should
  743. * be created when remote entry creation is enabled.
  744. *
  745. * <p>
  746. * @param factory The
  747. * {@link com.sun.jmx.snmp.agent.SnmpTableEntryFactory} through
  748. * which entries will be created when a remote SNMP manager
  749. * request the creation of a new entry via an SNMP SET request.
  750. */
  751. public void registerEntryFactory(SnmpTableEntryFactory factory) {
  752. this.factory = factory;
  753. }
  754. // ----------------------------------------------------------------------
  755. // PROTECTED METHODS - RowStatus
  756. // ----------------------------------------------------------------------
  757. /**
  758. * Return true if the columnar object identified by <code>var</code>
  759. * is used to control the addition/deletion of rows in this table.
  760. *
  761. * <p>
  762. * By default, this method assumes that there is no control variable
  763. * and always return <code>false</code>
  764. * <p>
  765. * If this table was defined using SMIv2, and if it contains a
  766. * control variable with RowStatus syntax, <code>mibgen</code>
  767. * will generate a non default implementation for this method
  768. * that will identify the RowStatus control variable.
  769. * <p>
  770. * You will have to redefine this method if you need to implement
  771. * control variables that do not conform to RFC 2579 RowStatus
  772. * TEXTUAL-CONVENTION.
  773. * <p>
  774. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  775. * row involved in the operation.
  776. *
  777. * @param var The OID arc identifying the involved columnar object.
  778. *
  779. * @param userData A contextual object containing user-data.
  780. * This object is allocated through the <code>
  781. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  782. * for each incoming SNMP request.
  783. *
  784. **/
  785. protected boolean isRowStatus(SnmpOid rowOid, long var,
  786. Object userData) {
  787. return false;
  788. }
  789. /**
  790. * Return the RowStatus code value specified in this request.
  791. * <p>
  792. * The RowStatus code value should be one of the values defined
  793. * by {@link com.sun.jmx.snmp.EnumRowStatus}. These codes correspond
  794. * to RowStatus codes as defined in RFC 2579, plus the <i>unspecified</i>
  795. * value which is SNMP Runtime specific.
  796. * <p>
  797. *
  798. * @param req The sub-request that must be handled by this node.
  799. *
  800. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  801. * row involved in the operation.
  802. *
  803. * @param depth The depth reached in the OID tree.
  804. *
  805. * @return The RowStatus code specified in this request, if any:
  806. * <ul>
  807. * <li>If the specified row does not exist and this table do
  808. * not use any variable to control creation/deletion of
  809. * rows, then default creation mechanism is assumed and
  810. * <i>createAndGo</i> is returned</li>
  811. * <li>Otherwise, if the row exists and this table do not use any
  812. * variable to control creation/deletion of rows,
  813. * <i>unspecified</i> is returned.</li>
  814. * <li>Otherwise, if the request does not contain the control variable,
  815. * <i>unspecified</i> is returned.</li>
  816. * <li>Otherwise, mapRowStatus() is called to extract the RowStatus
  817. * code from the SnmpVarBind that contains the control variable.</li>
  818. * </ul>
  819. *
  820. * @exception SnmpStatusException if the value of the control variable
  821. * could not be mapped to a RowStatus code.
  822. *
  823. * @see com.sun.jmx.snmp.EnumRowStatus
  824. **/
  825. protected int getRowAction(SnmpMibSubRequest req, SnmpOid rowOid,
  826. int depth)
  827. throws SnmpStatusException {
  828. final boolean isnew = req.isNewEntry();
  829. final SnmpVarBind vb = req.getRowStatusVarBind();
  830. if (vb == null) {
  831. if (isnew && ! hasRowStatus())
  832. return EnumRowStatus.createAndGo;
  833. else return EnumRowStatus.unspecified;
  834. }
  835. try {
  836. return mapRowStatus(rowOid, vb, req.getUserData());
  837. } catch( SnmpStatusException x) {
  838. checkRowStatusFail(req, x.getStatus());
  839. }
  840. return EnumRowStatus.unspecified;
  841. }
  842. /**
  843. * Map the value of the <code>vbstatus</code> varbind to the
  844. * corresponding RowStatus code defined in
  845. * {@link com.sun.jmx.snmp.EnumRowStatus}.
  846. * These codes correspond to RowStatus codes as defined in RFC 2579,
  847. * plus the <i>unspecified</i> value which is SNMP Runtime specific.
  848. * <p>
  849. * By default, this method assumes that the control variable is
  850. * an Integer, and it simply returns its value without further
  851. * analysis.
  852. * <p>
  853. * If this table was defined using SMIv2, and if it contains a
  854. * control variable with RowStatus syntax, <code>mibgen</code>
  855. * will generate a non default implementation for this method.
  856. * <p>
  857. * You will have to redefine this method if you need to implement
  858. * control variables that do not conform to RFC 2579 RowStatus
  859. * TEXTUAL-CONVENTION.
  860. *
  861. * <p>
  862. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  863. * row involved in the operation.
  864. *
  865. * @param vbstatus The SnmpVarBind containing the value of the control
  866. * variable, as identified by the isRowStatus() method.
  867. *
  868. * @param userData A contextual object containing user-data.
  869. * This object is allocated through the <code>
  870. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  871. * for each incoming SNMP request.
  872. *
  873. * @return The RowStatus code mapped from the value contained
  874. * in <code>vbstatus</code>.
  875. *
  876. * @exception SnmpStatusException if the value of the control variable
  877. * could not be mapped to a RowStatus code.
  878. *
  879. * @see com.sun.jmx.snmp.EnumRowStatus
  880. **/
  881. protected int mapRowStatus(SnmpOid rowOid, SnmpVarBind vbstatus,
  882. Object userData)
  883. throws SnmpStatusException {
  884. final SnmpValue rsvalue = vbstatus.value;
  885. if (rsvalue instanceof SnmpInt)
  886. return ((SnmpInt)rsvalue).intValue();
  887. else
  888. throw new SnmpStatusException(
  889. SnmpStatusException.snmpRspInconsistentValue);
  890. }
  891. /**
  892. * Set the control variable to the specified <code>newStatus</code>
  893. * value.
  894. *
  895. * <p>
  896. * This method maps the given <code>newStatus</code> to the appropriate
  897. * value for the control variable, then sets the control variable in
  898. * the entry identified by <code>rowOid</code>. It returns the new
  899. * value of the control variable.
  900. * <p>
  901. * By default, it is assumed that there is no control variable so this
  902. * method does nothing and simply returns <code>null</code>.
  903. * <p>
  904. * If this table was defined using SMIv2, and if it contains a
  905. * control variable with RowStatus syntax, <code>mibgen</code>
  906. * will generate a non default implementation for this method.
  907. * <p>
  908. * You will have to redefine this method if you need to implement
  909. * control variables that do not conform to RFC 2579 RowStatus
  910. * TEXTUAL-CONVENTION.
  911. *
  912. * <p>
  913. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  914. * row involved in the operation.
  915. *
  916. * @param newStatus The new status for the row: one of the
  917. * RowStatus code defined in
  918. * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes
  919. * correspond to RowStatus codes as defined in RFC 2579,
  920. * plus the <i>unspecified</i> value which is SNMP Runtime specific.
  921. *
  922. * @param userData A contextual object containing user-data.
  923. * This object is allocated through the <code>
  924. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  925. * for each incoming SNMP request.
  926. *
  927. * @return The new value of the control variable (usually
  928. * <code>new SnmpInt(newStatus)</code>) or <code>null</code>
  929. * if the table do not have any control variable.
  930. *
  931. * @exception SnmpStatusException If the given <code>newStatus</code>
  932. * could not be set on the specified entry, or if the
  933. * given <code>newStatus</code> is not valid.
  934. *
  935. * @see com.sun.jmx.snmp.EnumRowStatus
  936. **/
  937. protected SnmpValue setRowStatus(SnmpOid rowOid, int newStatus,
  938. Object userData)
  939. throws SnmpStatusException {
  940. return null;
  941. }
  942. /**
  943. * Tell whether the specified row is ready and can be put in the
  944. * <i>notInService</i> state.
  945. * <p>
  946. * This method is called only once, after all the varbind have been
  947. * set on a new entry for which <i>createAndWait</i> was specified.
  948. * <p>
  949. * If the entry is not yet ready, this method should return false.
  950. * It will then be the responsibility of the entry to switch its
  951. * own state to <i>notInService</i> when it becomes ready.
  952. * No further call to <code>isRowReady()</code> will be made.
  953. * <p>
  954. * By default, this method always return true. <br>
  955. * <code>mibgen</code> will not generate any specific implementation
  956. * for this method - meaning that by default, a row created using
  957. * <i>createAndWait</i> will always be placed in <i>notInService</i>
  958. * state at the end of the request.
  959. * <p>
  960. * If this table was defined using SMIv2, and if it contains a
  961. * control variable with RowStatus syntax, <code>mibgen</code>
  962. * will generate an implementation for this method that will
  963. * delegate the work to the metadata class modelling the conceptual
  964. * row, so that you can override the default behaviour by subclassing
  965. * that metadata class.
  966. * <p>
  967. * You will have to redefine this method if this default mechanism
  968. * does not suit your needs.
  969. *
  970. * <p>
  971. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  972. * row involved in the operation.
  973. *
  974. * @param userData A contextual object containing user-data.
  975. * This object is allocated through the <code>
  976. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  977. * for each incoming SNMP request.
  978. *
  979. * @return <code>true</code> if the row can be placed in
  980. * <i>notInService</i> state.
  981. *
  982. * @exception SnmpStatusException An error occured while trying
  983. * to retrieve the row status, and the operation should
  984. * be aborted.
  985. *
  986. * @see com.sun.jmx.snmp.EnumRowStatus
  987. **/
  988. protected boolean isRowReady(SnmpOid rowOid, Object userData)
  989. throws SnmpStatusException {
  990. return true;
  991. }
  992. /**
  993. * Check whether the control variable of the given row can be
  994. * switched to the new specified <code>newStatus</code>.
  995. * <p>
  996. * This method is called during the <i>check</i> phase of a SET
  997. * request when the control variable specifies <i>active</i> or
  998. * <i>notInService</i>.
  999. * <p>
  1000. * By default it is assumed that nothing prevents putting the
  1001. * row in the requested state, and this method does nothing.
  1002. * It is simply provided as a hook so that specific checks can
  1003. * be implemented.
  1004. * <p>
  1005. * Note that if the actual row deletion fails afterward, the
  1006. * atomicity of the request is no longer guaranteed.
  1007. *
  1008. * <p>
  1009. * @param req The sub-request that must be handled by this node.
  1010. *
  1011. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  1012. * row involved in the operation.
  1013. *
  1014. * @param depth The depth reached in the OID tree.
  1015. *
  1016. * @param newStatus The new status for the row: one of the
  1017. * RowStatus code defined in
  1018. * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes
  1019. * correspond to RowStatus codes as defined in RFC 2579,
  1020. * plus the <i>unspecified</i> value which is SNMP Runtime specific.
  1021. *
  1022. * @exception SnmpStatusException if switching to this new state
  1023. * would fail.
  1024. *
  1025. **/
  1026. protected void checkRowStatusChange(SnmpMibSubRequest req,
  1027. SnmpOid rowOid, int depth,
  1028. int newStatus)
  1029. throws SnmpStatusException {
  1030. }
  1031. /**
  1032. * Check whether the specified row can be removed from the table.
  1033. * <p>
  1034. * This method is called during the <i>check</i> phase of a SET
  1035. * request when the control variable specifies <i>destroy</i>
  1036. * <p>
  1037. * By default it is assumed that nothing prevents row deletion
  1038. * and this method does nothing. It is simply provided as a hook
  1039. * so that specific checks can be implemented.
  1040. * <p>
  1041. * Note that if the actual row deletion fails afterward, the
  1042. * atomicity of the request is no longer guaranteed.
  1043. *
  1044. * <p>
  1045. * @param req The sub-request that must be handled by this node.
  1046. *
  1047. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  1048. * row involved in the operation.
  1049. *
  1050. * @param depth The depth reached in the OID tree.
  1051. *
  1052. * @exception SnmpStatusException if the row deletion must be
  1053. * rejected.
  1054. **/
  1055. protected void checkRemoveTableRow(SnmpMibSubRequest req, SnmpOid rowOid,
  1056. int depth)
  1057. throws SnmpStatusException {
  1058. }
  1059. /**
  1060. * Remove a table row upon a remote manager request.
  1061. *
  1062. * This method is called internally when <code>getRowAction()</code>
  1063. * yields <i>destroy</i> - i.e.: it is only called when a remote
  1064. * manager requests the removal of a table row.<br>
  1065. * You should never need to call this function directly.
  1066. * <p>
  1067. * By default, this method simply calls <code>removeEntry(rowOid)
  1068. * </code>.
  1069. * <p>
  1070. * You can redefine this method if you need to implement some
  1071. * specific behaviour when a remote row deletion is invoked.
  1072. * <p>
  1073. * Note that specific checks should not be implemented in this
  1074. * method, but rather in <code>checkRemoveTableRow()</code>.
  1075. * If <code>checkRemoveTableRow()</code> succeeds and this method
  1076. * fails afterward, the atomicity of the original SET request can no
  1077. * longer be guaranteed.
  1078. * <p>
  1079. *
  1080. * @param req The sub-request that must be handled by this node.
  1081. *
  1082. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  1083. * row involved in the operation.
  1084. *
  1085. * @param depth The depth reached in the OID tree.
  1086. *
  1087. * @exception SnmpStatusException if the actual row deletion fails.
  1088. * This should not happen since it would break the
  1089. * atomicity of the SET request. Specific checks should
  1090. * be implemented in <code>checkRemoveTableRow()</code>
  1091. * if needed. If the entry does not exists, no exception
  1092. * is generated and the method simply returns.
  1093. *
  1094. **/
  1095. protected void removeTableRow(SnmpMibSubRequest req, SnmpOid rowOid,
  1096. int depth)
  1097. throws SnmpStatusException {
  1098. removeEntry(rowOid);
  1099. }
  1100. /**
  1101. * This method takes care of initial RowStatus handling during the
  1102. * check() phase of a SET request.
  1103. *
  1104. * In particular it will:
  1105. * <ul><li>check that the given <code>rowAction</code> returned by
  1106. * <code>getRowAction()</code> is valid.</li>
  1107. * <li>Then depending on the <code>rowAction</code> specified it will:
  1108. * <ul><li>either call <code>createNewEntry()</code> (<code>
  1109. * rowAction = <i>createAndGo</i> or <i>createAndWait</i>
  1110. * </code>),</li>
  1111. * <li>or call <code>checkRemoveTableRow()</code> (<code>
  1112. * rowAction = <i>destroy</i></code>),</li>
  1113. * <li>or call <code>checkRowStatusChange()</code> (<code>
  1114. * rowAction = <i>active</i> or <i>notInService</i></code>),</li>
  1115. * <li>or generate a SnmpStatusException if the passed <code>
  1116. * rowAction</code> is not correct.</li>
  1117. * </ul></li></ul>
  1118. * <p>
  1119. * In principle, you should not need to redefine this method.
  1120. * <p>
  1121. * <code>beginRowAction()</code> is called during the check phase
  1122. * of a SET request, before actual checking on the varbind list
  1123. * is performed.
  1124. *
  1125. * <p>
  1126. * @param req The sub-request that must be handled by this node.
  1127. *
  1128. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  1129. * row involved in the operation.
  1130. *
  1131. * @param depth The depth reached in the OID tree.
  1132. *
  1133. * @param rowAction The requested action as returned by <code>
  1134. * getRowAction()</code>: one of the RowStatus codes defined in
  1135. * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes
  1136. * correspond to RowStatus codes as defined in RFC 2579,
  1137. * plus the <i>unspecified</i> value which is SNMP Runtime specific.
  1138. *
  1139. * @exception SnmpStatusException if the specified <code>rowAction</code>
  1140. * is not valid or cannot be executed.
  1141. * This should not happen since it would break the
  1142. * atomicity of the SET request. Specific checks should
  1143. * be implemented in <code>beginRowAction()</code> if needed.
  1144. *
  1145. * @see com.sun.jmx.snmp.EnumRowStatus
  1146. **/
  1147. protected synchronized void beginRowAction(SnmpMibSubRequest req,
  1148. SnmpOid rowOid, int depth, int rowAction)
  1149. throws SnmpStatusException {
  1150. final boolean isnew = req.isNewEntry();
  1151. final SnmpOid oid = rowOid;
  1152. final int action = rowAction;
  1153. switch (action) {
  1154. case EnumRowStatus.unspecified:
  1155. if (isnew) {
  1156. if (isDebugOn())
  1157. debug("beginRowAction","Failed to create row[" + rowOid +
  1158. "] : RowStatus = unspecified");
  1159. checkRowStatusFail(req,SnmpStatusException.snmpRspNoAccess);
  1160. }
  1161. break;
  1162. case EnumRowStatus.createAndGo:
  1163. case EnumRowStatus.createAndWait:
  1164. if (isnew) {
  1165. if (isCreationEnabled()) {
  1166. if (isDebugOn())
  1167. debug("beginRowAction","Creating row[" + rowOid +
  1168. "] : RowStatus = createAndGo | createAndWait");
  1169. createNewEntry(req,oid,depth);
  1170. } else {
  1171. if (isDebugOn())
  1172. debug("beginRowAction","Can't create row[" + rowOid +
  1173. "] : RowStatus = createAndGo | createAndWait" +
  1174. " but creation is disabled");
  1175. checkRowStatusFail(req,
  1176. SnmpStatusException.snmpRspNoAccess);
  1177. }
  1178. } else {
  1179. if (isDebugOn())
  1180. debug("beginRowAction","Can't create row[" + rowOid +
  1181. "] : RowStatus = createAndGo | createAndWait" +
  1182. " but row already exists");
  1183. checkRowStatusFail(req,
  1184. SnmpStatusException.snmpRspInconsistentValue);
  1185. }
  1186. break;
  1187. case EnumRowStatus.destroy:
  1188. if (isnew) {
  1189. if (isDebugOn())
  1190. debug("beginRowAction","Warning: can't destroy row[" +
  1191. rowOid + "] : RowStatus = destroy" +
  1192. " but row does not exist");
  1193. } else if (!isCreationEnabled()) {
  1194. if (isDebugOn())
  1195. debug("beginRowAction","Can't destroy row[" + rowOid +
  1196. "] : RowStatus = destroy " +
  1197. " but creation is disabled");
  1198. checkRowStatusFail(req,SnmpStatusException.snmpRspNoAccess);
  1199. }
  1200. checkRemoveTableRow(req,rowOid,depth);
  1201. break;
  1202. case EnumRowStatus.active:
  1203. case EnumRowStatus.notInService:
  1204. if (isnew) {
  1205. if (isDebugOn())
  1206. debug("beginRowAction","Can't switch state of row[" +
  1207. rowOid +
  1208. "] : specified RowStatus = active | notInService" +
  1209. " but row does not exist");
  1210. checkRowStatusFail(req,
  1211. SnmpStatusException.snmpRspInconsistentValue);
  1212. }
  1213. checkRowStatusChange(req,rowOid,depth,action);
  1214. break;
  1215. case EnumRowStatus.notReady:
  1216. default:
  1217. if (isDebugOn())
  1218. debug("beginRowAction","Invalid RowStatus value for row[" +
  1219. rowOid + "] : specified RowStatus = " + action);
  1220. checkRowStatusFail(req,
  1221. SnmpStatusException.snmpRspInconsistentValue);
  1222. }
  1223. }
  1224. /**
  1225. * This method takes care of final RowStatus handling during the
  1226. * set() phase of a SET request.
  1227. *
  1228. * In particular it will:
  1229. * <ul><li>either call <code>setRowStatus(<i>active</i>)</code>
  1230. * (<code> rowAction = <i>createAndGo</i> or <i>active</i>
  1231. * </code>),</li>
  1232. * <li>or call <code>setRowStatus(<i>notInService</i> or <i>
  1233. * notReady</i>)</code> depending on the result of <code>
  1234. * isRowReady()</i> (<code>rowAction = <i>createAndWait</i>
  1235. * </code>),</li>
  1236. * <li>or call <code>setRowStatus(<i>notInService</i>)</code>
  1237. * (<code> rowAction = <i>notInService</i></code>),
  1238. * <li>or call <code>removeTableRow()</code> (<code>
  1239. * rowAction = <i>destroy</i></code>),</li>
  1240. * <li>or generate a SnmpStatusException if the passed <code>
  1241. * rowAction</code> is not correct. This should be avoided
  1242. * since it would break SET request atomicity</li>
  1243. * </ul>
  1244. * <p>
  1245. * In principle, you should not need to redefine this method.
  1246. * <p>
  1247. * <code>endRowAction()</code> is called during the set() phase
  1248. * of a SET request, after the actual set() on the varbind list
  1249. * has been performed. The varbind containing the control variable
  1250. * is updated with the value returned by setRowStatus() (if it is
  1251. * not <code>null</code>).
  1252. *
  1253. * <p>
  1254. * @param req The sub-request that must be handled by this node.
  1255. *
  1256. * @param rowOid The <CODE>SnmpOid</CODE> identifying the table
  1257. * row involved in the operation.
  1258. *
  1259. * @param depth The depth reached in the OID tree.
  1260. *
  1261. * @param rowAction The requested action as returned by <code>
  1262. * getRowAction()</code>: one of the RowStatus codes defined in
  1263. * {@link com.sun.jmx.snmp.EnumRowStatus}. These codes
  1264. * correspond to RowStatus codes as defined in RFC 2579,
  1265. * plus the <i>unspecified</i> value which is SNMP Runtime specific.
  1266. *
  1267. * @exception SnmpStatusException if the specified <code>rowAction</code>
  1268. * is not valid.
  1269. *
  1270. * @see com.sun.jmx.snmp.EnumRowStatus
  1271. **/
  1272. protected void endRowAction(SnmpMibSubRequest req, SnmpOid rowOid,
  1273. int depth, int rowAction)
  1274. throws SnmpStatusException {
  1275. final boolean isnew = req.isNewEntry();
  1276. final SnmpOid oid = rowOid;
  1277. final int action = rowAction;
  1278. final Object data = req.getUserData();
  1279. SnmpValue value = null;
  1280. switch (action) {
  1281. case EnumRowStatus.unspecified:
  1282. break;
  1283. case EnumRowStatus.createAndGo:
  1284. if (isDebugOn())
  1285. debug("endRowAction","Setting RowStatus to `active'" +
  1286. " for row[" + rowOid + "] : requested RowStatus = "
  1287. + "createAndGo");
  1288. value = setRowStatus(oid,EnumRowStatus.active,data);
  1289. break;
  1290. case EnumRowStatus.createAndWait:
  1291. if (isRowReady(oid,data)) {
  1292. if (isDebugOn())
  1293. debug("endRowAction",
  1294. "Setting RowStatus to `notInService'" +
  1295. " for row[" + rowOid + "] : requested RowStatus = "
  1296. + "createAndWait");
  1297. value = setRowStatus(oid,EnumRowStatus.notInService,data);
  1298. } else {
  1299. if (isDebugOn())
  1300. debug("endRowAction",
  1301. "Setting RowStatus to `notReady'" +
  1302. " for row[" + rowOid + "] : requested RowStatus = "
  1303. + "createAndWait");
  1304. value = setRowStatus(oid,EnumRowStatus.notReady,data);
  1305. }
  1306. break;
  1307. case EnumRowStatus.destroy:
  1308. if (isnew) {
  1309. if (isDebugOn())
  1310. debug("endRowAction",
  1311. "Warning: " + " requested RowStatus = destroy," +
  1312. "but row[" + rowOid + "] does not exist.");
  1313. } else {
  1314. if (isDebugOn())
  1315. debug("endRowAction",
  1316. "destroying row[" + rowOid +
  1317. "] : requested RowStatus = destroy");
  1318. }
  1319. removeTableRow(req,oid,depth);
  1320. break;
  1321. case EnumRowStatus.active:
  1322. if (isDebugOn())
  1323. debug("endRowAction",
  1324. "Setting RowStatus to `active'" +
  1325. " for row[" + rowOid + "] : requested RowStatus = "
  1326. + "active");
  1327. value = setRowStatus(oid,EnumRowStatus.active,data);
  1328. break;
  1329. case EnumRowStatus.notInService:
  1330. if (isDebugOn())
  1331. debug("endRowAction",
  1332. "Setting RowStatus to `notInService'" +
  1333. " for row[" + rowOid + "] : requested RowStatus = "
  1334. + "notInService");
  1335. value = setRowStatus(oid,EnumRowStatus.notInService,data);
  1336. break;
  1337. case EnumRowStatus.notReady:
  1338. default:
  1339. if (isDebugOn())
  1340. debug("endRowAction","Invalid RowStatus value for row[" +
  1341. rowOid + "] : specified RowStatus = " + action);
  1342. setRowStatusFail(req,
  1343. SnmpStatusException.snmpRspInconsistentValue);
  1344. }
  1345. if (value != null) {
  1346. final SnmpVarBind vb = req.getRowStatusVarBind();
  1347. if (vb != null) vb.value = value;
  1348. }
  1349. }
  1350. // -------------------------------------------------------------------
  1351. // PROTECTED METHODS - get next
  1352. // -------------------------------------------------------------------
  1353. /**
  1354. * Return the next OID arc corresponding to a readable columnar
  1355. * object in the underlying entry OBJECT-TYPE, possibly skipping over
  1356. * those objects that must not or cannot be returned.
  1357. * Calls {@link
  1358. * #getNextVarEntryId(com.sun.jmx.snmp.SnmpOid,long,java.lang.Object)},
  1359. * until
  1360. * {@link #skipEntryVariable(com.sun.jmx.snmp.SnmpOid,long,
  1361. * java.lang.Object,int)} returns false.
  1362. *
  1363. *
  1364. * @param rowOid The OID index of the row involved in the operation.
  1365. *
  1366. * @param var Id of the variable we start from, looking for the next.
  1367. *
  1368. * @param userData A contextual object containing user-data.
  1369. * This object is allocated through the <code>
  1370. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  1371. * for each incoming SNMP request.
  1372. *
  1373. * @param pduVersion Protocol version of the original request PDU.
  1374. *
  1375. * @return The next columnar object id which can be returned using
  1376. * the given PDU's protocol version.
  1377. *
  1378. * @exception SnmpStatusException If no id is found after the given id.
  1379. *
  1380. **/
  1381. protected long getNextVarEntryId(SnmpOid rowOid,
  1382. long var,
  1383. Object userData,
  1384. int pduVersion)
  1385. throws SnmpStatusException {
  1386. long varid=var;
  1387. do {
  1388. varid = getNextVarEntryId(rowOid,varid,userData);
  1389. } while (skipEntryVariable(rowOid,varid,userData,pduVersion));
  1390. return varid;
  1391. }
  1392. /**
  1393. * Hook for subclasses.
  1394. * The default implementation of this method is to always return
  1395. * false. Subclasses should redefine this method so that it returns
  1396. * true when:
  1397. * <ul><li>the variable is a leaf that is not instantiated,</li>
  1398. * <li>or the variable is a leaf whose type cannot be returned by that
  1399. * version of the protocol (e.g. an Counter64 with SNMPv1).</li>
  1400. * </ul>
  1401. *
  1402. * @param rowOid The OID index of the row involved in the operation.
  1403. *
  1404. * @param var Id of the variable we start from, looking for the next.
  1405. *
  1406. * @param userData A contextual object containing user-data.
  1407. * This object is allocated through the <code>
  1408. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  1409. * for each incoming SNMP request.
  1410. *
  1411. * @param pduVersion Protocol version of the original request PDU.
  1412. *
  1413. * @return true if the variable must be skipped by the get-next
  1414. * algorithm.
  1415. */
  1416. protected boolean skipEntryVariable(SnmpOid rowOid,
  1417. long var,
  1418. Object userData,
  1419. int pduVersion) {
  1420. return false;
  1421. }
  1422. /**
  1423. * Get the <CODE>SnmpOid</CODE> index of the row that follows
  1424. * the given <CODE>oid</CODE> in the table. The given <CODE>
  1425. * oid</CODE> does not need to be a valid row OID index.
  1426. *
  1427. * <p>
  1428. * @param oid The OID from which the search will begin.
  1429. *
  1430. * @param userData A contextual object containing user-data.
  1431. * This object is allocated through the <code>
  1432. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  1433. * for each incoming SNMP request.
  1434. *
  1435. * @return The next <CODE>SnmpOid</CODE> index.
  1436. *
  1437. * @exception SnmpStatusException There is no index following the
  1438. * specified <CODE>oid</CODE> in the table.
  1439. */
  1440. protected SnmpOid getNextOid(SnmpOid oid, Object userData)
  1441. throws SnmpStatusException {
  1442. if (size == 0)
  1443. throw noSuchInstanceException;
  1444. final SnmpOid resOid = oid;
  1445. // Just a simple check to speed up retrieval of last element ...
  1446. //
  1447. // XX SnmpOid last= (SnmpOid) oids.lastElement();
  1448. SnmpOid last= tableoids[tablecount-1];
  1449. if (last.equals(resOid)) {
  1450. // Last element of the table ...
  1451. //
  1452. throw noSuchInstanceException;
  1453. }
  1454. // First find the oid. This will allow to speed up retrieval process
  1455. // during smart discovery of table (using the getNext) as the
  1456. // management station will use the valid index returned during a
  1457. // previous getNext ...
  1458. //
  1459. // Returns the position following the position at which resOid
  1460. // is found, or the position at which resOid should be inserted.
  1461. //
  1462. final int newPos = getInsertionPoint(resOid,false);
  1463. // If the position returned is not out of bound, we will find
  1464. // the next element in the array.
  1465. //
  1466. if (newPos > -1 && newPos < size) {
  1467. try {
  1468. // XX last = (SnmpOid) oids.elementAt(newPos);
  1469. last = tableoids[newPos];
  1470. } catch(ArrayIndexOutOfBoundsException e) {
  1471. throw noSuchInstanceException;
  1472. }
  1473. } else {
  1474. // We are dealing with the last element of the table ..
  1475. //
  1476. throw noSuchInstanceException;
  1477. }
  1478. return last;
  1479. }
  1480. /**
  1481. * Return the first entry OID registered in the table.
  1482. *
  1483. * <p>
  1484. * @param userData A contextual object containing user-data.
  1485. * This object is allocated through the <code>
  1486. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  1487. * for each incoming SNMP request.
  1488. *
  1489. * @return The <CODE>SnmpOid</CODE> of the first entry in the table.
  1490. *
  1491. * @exception SnmpStatusException If the table is empty.
  1492. */
  1493. protected SnmpOid getNextOid(Object userData)
  1494. throws SnmpStatusException {
  1495. if (size == 0)
  1496. throw noSuchInstanceException;
  1497. // XX return (SnmpOid) oids.firstElement();
  1498. return tableoids[0];
  1499. }
  1500. // -------------------------------------------------------------------
  1501. // Abstract Protected Methods
  1502. // -------------------------------------------------------------------
  1503. /**
  1504. * This method is used internally and is implemented by the
  1505. * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
  1506. *
  1507. * <p> Return the next OID arc corresponding to a readable columnar
  1508. * object in the underlying entry OBJECT-TYPE.</p>
  1509. *
  1510. * <p>
  1511. * @param rowOid The OID index of the row involved in the operation.
  1512. *
  1513. * @param var Id of the variable we start from, looking for the next.
  1514. *
  1515. * @param userData A contextual object containing user-data.
  1516. * This object is allocated through the <code>
  1517. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  1518. * for each incoming SNMP request.
  1519. *
  1520. * @return The next columnar object id.
  1521. *
  1522. * @exception SnmpStatusException If no id is found after the given id.
  1523. *
  1524. **/
  1525. abstract protected long getNextVarEntryId(SnmpOid rowOid, long var,
  1526. Object userData)
  1527. throws SnmpStatusException;
  1528. /**
  1529. * This method is used internally and is implemented by the
  1530. * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
  1531. *
  1532. * <p>
  1533. * @param rowOid The OID index of the row involved in the operation.
  1534. *
  1535. * @param var The var we want to validate.
  1536. *
  1537. * @param userData A contextual object containing user-data.
  1538. * This object is allocated through the <code>
  1539. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  1540. * for each incoming SNMP request.
  1541. *
  1542. * @exception SnmpStatusException If this id is not valid.
  1543. *
  1544. */
  1545. abstract protected void validateVarEntryId(SnmpOid rowOid, long var,
  1546. Object userData)
  1547. throws SnmpStatusException;
  1548. /**
  1549. *
  1550. * This method is used internally and is implemented by the
  1551. * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
  1552. *
  1553. * <p>
  1554. * @param rowOid The OID index of the row involved in the operation.
  1555. *
  1556. * @param var The OID arc.
  1557. *
  1558. * @param userData A contextual object containing user-data.
  1559. * This object is allocated through the <code>
  1560. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  1561. * for each incoming SNMP request.
  1562. *
  1563. * @exception SnmpStatusException If this id is not valid.
  1564. *
  1565. */
  1566. abstract protected boolean isReadableEntryId(SnmpOid rowOid, long var,
  1567. Object userData)
  1568. throws SnmpStatusException;
  1569. /**
  1570. * This method is used internally and is implemented by the
  1571. * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
  1572. */
  1573. abstract protected void get(SnmpMibSubRequest req,
  1574. SnmpOid rowOid, int depth)
  1575. throws SnmpStatusException;
  1576. /**
  1577. * This method is used internally and is implemented by the
  1578. * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
  1579. */
  1580. abstract protected void check(SnmpMibSubRequest req,
  1581. SnmpOid rowOid, int depth)
  1582. throws SnmpStatusException;
  1583. /**
  1584. * This method is used internally and is implemented by the
  1585. * <CODE>SnmpMibTable</CODE> subclasses generated by <CODE>mibgen</CODE>.
  1586. */
  1587. abstract protected void set(SnmpMibSubRequest req,
  1588. SnmpOid rowOid, int depth)
  1589. throws SnmpStatusException;
  1590. // ----------------------------------------------------------------------
  1591. // PACKAGE METHODS
  1592. // ----------------------------------------------------------------------
  1593. /**
  1594. * Get the <CODE>SnmpOid</CODE> index of the row that follows the
  1595. * index extracted from the specified OID array.
  1596. * Builds the SnmpOid corresponding to the row OID and calls
  1597. * <code>getNextOid(oid,userData)</code>
  1598. *
  1599. * <p>
  1600. * @param oid The OID array.
  1601. *
  1602. * @param pos The position in the OID array at which the index starts.
  1603. *
  1604. * @param userData A contextual object containing user-data.
  1605. * This object is allocated through the <code>
  1606. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  1607. * for each incoming SNMP request.
  1608. *
  1609. * @return The next <CODE>SnmpOid</CODE>.
  1610. *
  1611. * @exception SnmpStatusException There is no index following the
  1612. * specified one in the table.
  1613. */
  1614. SnmpOid getNextOid(long[] oid, int pos, Object userData)
  1615. throws SnmpStatusException {
  1616. // Construct the sub-oid starting at pos.
  1617. // This sub-oid correspond to the oid part just after the entry
  1618. // variable oid.
  1619. //
  1620. final SnmpOid resOid = new SnmpEntryOid(oid,pos);
  1621. return getNextOid(resOid,userData);
  1622. }
  1623. // ---------------------------------------------------------------------
  1624. //
  1625. // Register an exception when checking the RowStatus variable
  1626. //
  1627. // ---------------------------------------------------------------------
  1628. final static void checkRowStatusFail(SnmpMibSubRequest req,
  1629. int errorStatus)
  1630. throws SnmpStatusException {
  1631. final SnmpVarBind statusvb = req.getRowStatusVarBind();
  1632. final SnmpStatusException x = new SnmpStatusException(errorStatus);
  1633. req.registerCheckException(statusvb,x);
  1634. }
  1635. // ---------------------------------------------------------------------
  1636. //
  1637. // Register an exception when checking the RowStatus variable
  1638. //
  1639. // ---------------------------------------------------------------------
  1640. final static void setRowStatusFail(SnmpMibSubRequest req,
  1641. int errorStatus)
  1642. throws SnmpStatusException {
  1643. final SnmpVarBind statusvb = req.getRowStatusVarBind();
  1644. final SnmpStatusException x = new SnmpStatusException(errorStatus);
  1645. req.registerSetException(statusvb,x);
  1646. }
  1647. // ---------------------------------------------------------------------
  1648. //
  1649. // Implements the method defined in SnmpMibNode.
  1650. //
  1651. // ---------------------------------------------------------------------
  1652. final synchronized void findHandlingNode(SnmpVarBind varbind,
  1653. long[] oid, int depth,
  1654. SnmpRequestTree handlers)
  1655. throws SnmpStatusException {
  1656. final int length = oid.length;
  1657. if (handlers == null)
  1658. throw new SnmpStatusException(SnmpStatusException.snmpRspGenErr);
  1659. if (depth >= length)
  1660. throw new SnmpStatusException(SnmpStatusException.noAccess);
  1661. if (oid[depth] != nodeId)
  1662. throw new SnmpStatusException(SnmpStatusException.noAccess);
  1663. if (depth+2 >= length)
  1664. throw new SnmpStatusException(SnmpStatusException.noAccess);
  1665. // Checks that the oid is valid
  1666. // validateOid(oid,depth);
  1667. // Gets the part of the OID that identifies the entry
  1668. final SnmpOid entryoid = new SnmpEntryOid(oid, depth+2);
  1669. // Finds the entry: false means that the entry does not exists
  1670. final Object data = handlers.getUserData();
  1671. final boolean hasEntry = contains(entryoid, data);
  1672. // Fails if the entry is not found and the table does not
  1673. // not support creation.
  1674. // We know that the entry does not exists if (isentry == false).
  1675. if (!hasEntry) {
  1676. if (!handlers.isCreationAllowed())
  1677. // we're not doing a set
  1678. throw noSuchInstanceException;
  1679. else if (!isCreationEnabled())
  1680. // we're doing a set but creation is disabled.
  1681. throw new
  1682. SnmpStatusException(SnmpStatusException.snmpRspNoAccess);
  1683. }
  1684. final long var = oid[depth+1];
  1685. // Validate the entry id
  1686. if (hasEntry) {
  1687. // The entry already exists - validate the id
  1688. validateVarEntryId(entryoid,var,data);
  1689. }
  1690. // Registers this node for the identified entry.
  1691. //
  1692. if (handlers.isSetRequest() && isRowStatus(entryoid,var,data))
  1693. // We only try to identify the RowStatus for SET operations
  1694. //
  1695. handlers.add(this,depth,entryoid,varbind,(!hasEntry),varbind);
  1696. else
  1697. handlers.add(this,depth,entryoid,varbind,(!hasEntry));
  1698. }
  1699. // ---------------------------------------------------------------------
  1700. //
  1701. // Implements the method defined in SnmpMibNode. The algorithm is very
  1702. // largely inspired from the original getNext() method.
  1703. //
  1704. // ---------------------------------------------------------------------
  1705. final synchronized long[] findNextHandlingNode(SnmpVarBind varbind,
  1706. long[] oid, int pos, int depth,
  1707. SnmpRequestTree handlers,
  1708. AcmChecker checker)
  1709. throws SnmpStatusException {
  1710. int length = oid.length;
  1711. if (handlers == null)
  1712. // This should be considered as a genErr, but we do not want to
  1713. // abort the whole request, so we're going to throw
  1714. // a noSuchObject...
  1715. //
  1716. throw noSuchObjectException;
  1717. final Object data = handlers.getUserData();
  1718. final int pduVersion = handlers.getRequestPduVersion();
  1719. long var= -1;
  1720. // If the querried oid contains less arcs than the OID of the
  1721. // xxxEntry object, we must return the first leaf under the
  1722. // first columnar object: the best way to do that is to reset
  1723. // the queried oid:
  1724. // oid[0] = nodeId (arc of the xxxEntry object)
  1725. // pos = 0 (points to the arc of the xxxEntry object)
  1726. // then we just have to proceed...
  1727. //
  1728. if (pos >= length) {
  1729. // this will have the side effect to set
  1730. // oid[pos] = nodeId
  1731. // and
  1732. // (pos+1) = length
  1733. // so we won't fall into the "else if" cases below -
  1734. // so using "else if" rather than "if ..." is guaranteed
  1735. // to be safe.
  1736. //
  1737. oid = new long[1];
  1738. oid[0] = nodeId;
  1739. pos = 0;
  1740. length = 1;
  1741. } else if (oid[pos] > nodeId) {
  1742. // oid[pos] is expected to be the id of the xxxEntry ...
  1743. // The id requested is greater than the id of the xxxEntry,
  1744. // so we won't find the next element in this table... (any
  1745. // element in this table will have a smaller OID)
  1746. //
  1747. throw noSuchObjectException;
  1748. } else if (oid[pos] < nodeId) {
  1749. // we must return the first leaf under the first columnar
  1750. // object, so we are back to our first case where pos was
  1751. // out of bounds... => reset the oid to contain only the
  1752. // arc of the xxxEntry object.
  1753. //
  1754. oid = new long[1];
  1755. oid[0] = nodeId;
  1756. pos = 0;
  1757. length = 0;
  1758. } else if ((pos + 1) < length) {
  1759. // The arc at the position "pos+1" is the id of the columnar
  1760. // object (ie: the id of the variable in the table entry)
  1761. //
  1762. var = oid[pos+1];
  1763. }
  1764. // Now that we've got everything right we can begin.
  1765. SnmpOid entryoid = null ;
  1766. if (pos == (length - 1)) {
  1767. // pos points to the last arc in the oid, and this arc is
  1768. // guaranteed to be the xxxEntry id (we have handled all
  1769. // the other possibilities before)
  1770. //
  1771. // We must therefore return the first leaf below the first
  1772. // columnar object in the table.
  1773. //
  1774. // Get the first index. If an exception is raised,
  1775. // then it means that the table is empty. We thus do not
  1776. // have to catch the exception - we let it propagate to
  1777. // the caller.
  1778. //
  1779. entryoid = getNextOid(data);
  1780. var = getNextVarEntryId(entryoid,var,data,pduVersion);
  1781. } else if ( pos == (length-2)) {
  1782. // In that case we have (pos+1) = (length-1), so pos
  1783. // points to the arc of the querried variable (columnar object).
  1784. // Since the requested oid stops there, it means we have
  1785. // to return the first leaf under this columnar object.
  1786. //
  1787. // So we first get the first index:
  1788. // Note: if this raises an exception, this means that the table
  1789. // is empty, so we can let the exception propagate to the caller.
  1790. //
  1791. entryoid = getNextOid(data);
  1792. // XXX revisit: not exactly perfect:
  1793. // a specific row could be empty.. But we don't know
  1794. // how to make the difference! => tradeoff holes
  1795. // in tables can't be properly supported (all rows
  1796. // must have the same holes)
  1797. //
  1798. if (skipEntryVariable(entryoid,var,data,pduVersion)) {
  1799. var = getNextVarEntryId(entryoid,var,data,pduVersion);
  1800. }
  1801. } else {
  1802. // So now there remain one last case, namely: some part of the
  1803. // index is provided by the oid...
  1804. // We build a possibly incomplete and invalid index from
  1805. // the OID.
  1806. // The piece of index provided should begin at pos+2
  1807. // oid[pos] = id of the xxxEntry object,
  1808. // oid[pos+1] = id of the columnar object,
  1809. // oid[pos+2] ... oid[length-1] = piece of index.
  1810. //
  1811. // We get the next index following the provided index.
  1812. // If this raises an exception, then it means that we have
  1813. // reached the last index in the table, and we must then
  1814. // try with the next columnar object.
  1815. //
  1816. // Bug fix 4269251
  1817. // The SnmpIndex is defined to contain a valid oid:
  1818. // this is not an SNMP requirement for the getNext request.
  1819. // So we no more use the SnmpIndex but directly the SnmpOid.
  1820. //
  1821. try {
  1822. entryoid = getNextOid(oid, pos + 2, data);
  1823. // If the variable must ne skipped, fall through...
  1824. //
  1825. // XXX revisit: not exactly perfect:
  1826. // a specific row could be empty.. But we don't know
  1827. // how to make the difference! => tradeoff holes
  1828. // in tables can't be properly supported (all rows
  1829. // must have the same holes)
  1830. //
  1831. if (skipEntryVariable(entryoid,var,data,pduVersion))
  1832. throw noSuchObjectException;
  1833. } catch(SnmpStatusException se) {
  1834. entryoid = getNextOid(data);
  1835. var = getNextVarEntryId(entryoid,var,data,pduVersion);
  1836. }
  1837. }
  1838. return findNextAccessibleOid(entryoid,
  1839. varbind,
  1840. oid,
  1841. depth,
  1842. handlers,
  1843. checker,
  1844. data,
  1845. var);
  1846. }
  1847. private long[] findNextAccessibleOid(SnmpOid entryoid,
  1848. SnmpVarBind varbind,long[] oid,
  1849. int depth, SnmpRequestTree handlers,
  1850. AcmChecker checker, Object data,
  1851. long var)
  1852. throws SnmpStatusException {
  1853. final int pduVersion = handlers.getRequestPduVersion();
  1854. // Loop on each var (column)
  1855. while(true) {
  1856. // This should not happen. If it happens, (bug, or customized
  1857. // methods returning garbage instead of raising an exception),
  1858. // it probably means that there is nothing to return anyway.
  1859. // So we throw the exception.
  1860. // => will skip to next node in the MIB tree.
  1861. //
  1862. if (entryoid == null || var == -1 ) throw noSuchObjectException;
  1863. // So here we know both the row (entryoid) and the column (var)
  1864. //
  1865. try {
  1866. // Raising an exception here will make the catch() clause
  1867. // switch to the next variable. If `var' is not readable
  1868. // for this specific entry, it is not readable for any
  1869. // other entry => skip to next column.
  1870. //
  1871. if (!isReadableEntryId(entryoid,var,data))
  1872. throw noSuchObjectException;
  1873. // Prepare the result and the ACM checker.
  1874. //
  1875. final long[] etable = entryoid.longValue(false);
  1876. final int elength = etable.length;
  1877. final long[] result = new long[depth + 2 + elength];
  1878. result[0] = -1 ; // Bug detector!
  1879. // Copy the entryOid at the end of `result'
  1880. //
  1881. java.lang.System.arraycopy(etable, 0, result,
  1882. depth+2, elength);
  1883. // Set the node Id and var Id in result.
  1884. //
  1885. result[depth] = nodeId;
  1886. result[depth+1] = var;
  1887. // Append nodeId.varId.<rowOid> to ACM checker.
  1888. //
  1889. checker.add(depth,result,depth,elength+2);
  1890. // No we're going to ACM check our OID.
  1891. try {
  1892. checker.checkCurrentOid();
  1893. // No exception thrown by checker => this is all OK!
  1894. // we have it: register the handler and return the
  1895. // result.
  1896. //
  1897. handlers.add(this,depth,entryoid,varbind,false);
  1898. return result;
  1899. } catch(SnmpStatusException e) {
  1900. // Skip to the next entry. If an exception is
  1901. // thrown, will be catch by enclosing catch
  1902. // and a skip is done to the next var.
  1903. //
  1904. entryoid = getNextOid(entryoid, data);
  1905. } finally {
  1906. // Clean the checker.
  1907. //
  1908. checker.remove(depth,elength+2);
  1909. }
  1910. } catch(SnmpStatusException e) {
  1911. // Catching an exception here means we have to skip to the
  1912. // next column.
  1913. //
  1914. // Back to the first row.
  1915. entryoid = getNextOid(data);
  1916. // Find out the next column.
  1917. //
  1918. var = getNextVarEntryId(entryoid,var,data,pduVersion);
  1919. }
  1920. // This should not happen. If it happens, (bug, or customized
  1921. // methods returning garbage instead of raising an exception),
  1922. // it probably means that there is nothing to return anyway.
  1923. // No need to continue, we throw an exception.
  1924. // => will skip to next node in the MIB tree.
  1925. //
  1926. if (entryoid == null || var == -1 )
  1927. throw noSuchObjectException;
  1928. }
  1929. }
  1930. /**
  1931. * Validate the specified OID.
  1932. *
  1933. * <p>
  1934. * @param oid The OID array.
  1935. *
  1936. * @param pos The position in the array.
  1937. *
  1938. * @exception SnmpStatusException If the validation fails.
  1939. */
  1940. final void validateOid(long[] oid, int pos) throws SnmpStatusException {
  1941. final int length= oid.length;
  1942. // Control the length of the oid
  1943. //
  1944. if (pos +2 >= length)
  1945. throw noSuchInstanceException;
  1946. // Check that the entry identifier is specified
  1947. //
  1948. if (oid[pos] != nodeId)
  1949. throw noSuchObjectException;
  1950. }
  1951. // ----------------------------------------------------------------------
  1952. // PRIVATE METHODS
  1953. // ----------------------------------------------------------------------
  1954. /**
  1955. * Enable this <CODE>SnmpMibTable</CODE> to send a notification.
  1956. *
  1957. * <p>
  1958. * @param notification The notification to send.
  1959. */
  1960. private synchronized void sendNotification(Notification notification) {
  1961. // loop on listener
  1962. //
  1963. for(java.util.Enumeration k = handbackTable.keys();
  1964. k.hasMoreElements(); ) {
  1965. NotificationListener listener =
  1966. (NotificationListener) k.nextElement();
  1967. // Get the associated handback list and the associated filter list
  1968. //
  1969. java.util.Vector handbackList =
  1970. (java.util.Vector) handbackTable.get(listener) ;
  1971. java.util.Vector filterList =
  1972. (java.util.Vector) filterTable.get(listener) ;
  1973. // loop on handback
  1974. //
  1975. java.util.Enumeration f = filterList.elements();
  1976. for(java.util.Enumeration h = handbackList.elements();
  1977. h.hasMoreElements(); ) {
  1978. Object handback = h.nextElement();
  1979. NotificationFilter filter =
  1980. (NotificationFilter)f.nextElement();
  1981. if ((filter == null) ||
  1982. ((filter != null) &&
  1983. (filter.isNotificationEnabled(notification)))) {
  1984. listener.handleNotification(notification,handback) ;
  1985. }
  1986. }
  1987. }
  1988. }
  1989. /**
  1990. * This method is used by the SnmpMibTable to create and send a table
  1991. * entry notification to all the listeners registered for this kind of
  1992. * notification.
  1993. *
  1994. * <p>
  1995. * @param type The notification type.
  1996. *
  1997. * @param timeStamp The notification emission date.
  1998. *
  1999. * @param entry The entry object.
  2000. */
  2001. private void sendNotification(String type, long timeStamp,
  2002. Object entry, ObjectName name) {
  2003. synchronized(this) {
  2004. sequenceNumber = sequenceNumber + 1;
  2005. }
  2006. SnmpTableEntryNotification notif =
  2007. new SnmpTableEntryNotification(type, this, sequenceNumber,
  2008. timeStamp, entry, name);
  2009. this.sendNotification(notif) ;
  2010. }
  2011. /**
  2012. * Return true if the entry identified by the given OID index
  2013. * is contained in this table.
  2014. * <p>
  2015. * <b>Do not call this method directly</b>.
  2016. * <p>
  2017. * This method is provided has a hook for subclasses.
  2018. * It is called when a get/set request is received in order to
  2019. * determine whether the specified entry is contained in the table.
  2020. * You may want to override this method if you need to perform e.g.
  2021. * lazy evaluation of tables (you need to update the table when a
  2022. * request is received) or if your table is virtual.
  2023. * <p>
  2024. * Note that this method is called by the Runtime from within a
  2025. * synchronized block.
  2026. *
  2027. * @param oid The index part of the OID we're looking for.
  2028. * @param userData A contextual object containing user-data.
  2029. * This object is allocated through the <code>
  2030. * {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  2031. * for each incoming SNMP request.
  2032. *
  2033. * @return <code>true</code> if the entry is found, <code>false</code>
  2034. * otherwise.
  2035. *
  2036. * @since 1.5
  2037. **/
  2038. protected boolean contains(SnmpOid oid, Object userData) {
  2039. return (findObject(oid) > -1);
  2040. }
  2041. /**
  2042. * Look for the given oid in the OID table (tableoids) and returns
  2043. * its position.
  2044. *
  2045. * <p>
  2046. * @param oid The OID we're looking for.
  2047. *
  2048. * @return The position of the OID in the table. -1 if the given
  2049. * OID was not found.
  2050. *
  2051. **/
  2052. private final int findObject(SnmpOid oid) {
  2053. int low= 0;
  2054. int max= size - 1;
  2055. SnmpOid pos;
  2056. int comp;
  2057. int curr= low + (max-low)/2;
  2058. //System.out.println("Try to retrieve: " + oid.toString());
  2059. while (low <= max) {
  2060. // XX pos = (SnmpOid) oids.elementAt(curr);
  2061. pos = tableoids[curr];
  2062. //System.out.println("Compare with" + pos.toString());
  2063. // never know ...we might find something ...
  2064. //
  2065. comp = oid.compareTo(pos);
  2066. if (comp == 0)
  2067. return curr;
  2068. if (oid.equals(pos) == true) {
  2069. return curr;
  2070. }
  2071. if (comp > 0) {
  2072. low = curr + 1;
  2073. } else {
  2074. max = curr - 1;
  2075. }
  2076. curr = low + (max-low)/2;
  2077. }
  2078. return -1;
  2079. }
  2080. /**
  2081. * Search the position at which the given oid should be inserted
  2082. * in the OID table (tableoids).
  2083. *
  2084. * <p>
  2085. * @param oid The OID we would like to insert.
  2086. *
  2087. * @return The position at which the OID should be inserted in
  2088. * the table.
  2089. *
  2090. * @exception SnmpStatusException if the OID is already present in the
  2091. * table.
  2092. *
  2093. **/
  2094. private final int getInsertionPoint(SnmpOid oid)
  2095. throws SnmpStatusException {
  2096. return getInsertionPoint(oid, true);
  2097. }
  2098. /**
  2099. * Search the position at which the given oid should be inserted
  2100. * in the OID table (tableoids).
  2101. *
  2102. * <p>
  2103. * @param oid The OID we would like to insert.
  2104. *
  2105. * @param fail Tells whether a SnmpStatusException must be generated
  2106. * if the given OID is already present in the table.
  2107. *
  2108. * @return The position at which the OID should be inserted in
  2109. * the table. When the OID is found, it returns the next
  2110. * position. Note that it is not valid to insert twice the
  2111. * same OID. This feature is only an optimization to improve
  2112. * the getNextOid() behaviour.
  2113. *
  2114. * @exception SnmpStatusException if the OID is already present in the
  2115. * table and <code>fail</code> is <code>true</code>.
  2116. *
  2117. **/
  2118. private final int getInsertionPoint(SnmpOid oid, boolean fail)
  2119. throws SnmpStatusException {
  2120. final int failStatus = SnmpStatusException.snmpRspNotWritable;
  2121. int low= 0;
  2122. int max= size - 1;
  2123. SnmpOid pos;
  2124. int comp;
  2125. int curr= low + (max-low)/2;
  2126. while (low <= max) {
  2127. // XX pos= (SnmpOid) oids.elementAt(curr);
  2128. pos= tableoids[curr];
  2129. // never know ...we might find something ...
  2130. //
  2131. comp= oid.compareTo(pos);
  2132. if (comp == 0) {
  2133. if (fail)
  2134. throw new SnmpStatusException(failStatus,curr);
  2135. else
  2136. return curr+1;
  2137. }
  2138. if (comp>0) {
  2139. low= curr +1;
  2140. } else {
  2141. max= curr -1;
  2142. }
  2143. curr= low + (max-low)/2;
  2144. }
  2145. return curr;
  2146. }
  2147. /**
  2148. * Remove the OID located at the given position.
  2149. *
  2150. * <p>
  2151. * @param pos The position at which the OID to be removed is located.
  2152. *
  2153. **/
  2154. private final void removeOid(int pos) {
  2155. if (pos >= tablecount) return;
  2156. if (pos < 0) return;
  2157. final int l1 = --tablecount-pos;
  2158. tableoids[pos] = null;
  2159. if (l1 > 0)
  2160. java.lang.System.arraycopy(tableoids,pos+1,tableoids,pos,l1);
  2161. tableoids[tablecount] = null;
  2162. }
  2163. /**
  2164. * Insert an OID at the given position.
  2165. *
  2166. * <p>
  2167. * @param oid The OID to be inserted in the table
  2168. * @param pos The position at which the OID to be added is located.
  2169. *
  2170. **/
  2171. private final void insertOid(int pos, SnmpOid oid) {
  2172. if (pos >= tablesize || tablecount == tablesize) {
  2173. // Vector must be enlarged
  2174. // Save old vector
  2175. final SnmpOid[] olde = tableoids;
  2176. // Allocate larger vectors
  2177. tablesize += Delta;
  2178. tableoids = new SnmpOid[tablesize];
  2179. // Check pos validity
  2180. if (pos > tablecount) pos = tablecount;
  2181. if (pos < 0) pos = 0;
  2182. final int l1 = pos;
  2183. final int l2 = tablecount - pos;
  2184. // Copy original vector up to `pos'
  2185. if (l1 > 0)
  2186. java.lang.System.arraycopy(olde,0,tableoids,0,l1);
  2187. // Copy original vector from `pos' to end, leaving
  2188. // an empty room at `pos' in the new vector.
  2189. if (l2 > 0)
  2190. java.lang.System.arraycopy(olde,l1,tableoids,
  2191. l1+1,l2);
  2192. } else if (pos < tablecount) {
  2193. // Vector is large enough to accomodate one additional
  2194. // entry.
  2195. //
  2196. // Shift vector, making an empty room at `pos'
  2197. java.lang.System.arraycopy(tableoids,pos,tableoids,
  2198. pos+1,tablecount-pos);
  2199. }
  2200. // Fill the gap at `pos'
  2201. tableoids[pos] = oid;
  2202. tablecount++;
  2203. }
  2204. // Returns true if debug is on
  2205. private final static boolean isDebugOn() {
  2206. return Trace.isSelected(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP);
  2207. }
  2208. // Prints a debug message
  2209. private final void debug(String func, String info) {
  2210. Trace.send(Trace.LEVEL_DEBUG, Trace.INFO_ADAPTOR_SNMP,
  2211. getClass().getName(), func, info);
  2212. }
  2213. // ----------------------------------------------------------------------
  2214. // PROTECTED VARIABLES
  2215. // ----------------------------------------------------------------------
  2216. /**
  2217. * The id of the contained entry object.
  2218. * @serial
  2219. */
  2220. protected int nodeId=1;
  2221. /**
  2222. * The MIB to which the metadata is linked.
  2223. * @serial
  2224. */
  2225. protected SnmpMib theMib;
  2226. /**
  2227. * <CODE>true</CODE> if remote creation of entries via SET operations
  2228. * is enabled.
  2229. * [default value is <CODE>false</CODE>]
  2230. * @serial
  2231. */
  2232. protected boolean creationEnabled = false;
  2233. /**
  2234. * The entry factory
  2235. */
  2236. protected SnmpTableEntryFactory factory = null;
  2237. // ----------------------------------------------------------------------
  2238. // PRIVATE VARIABLES
  2239. // ----------------------------------------------------------------------
  2240. /**
  2241. * The number of elements in the table.
  2242. * @serial
  2243. */
  2244. private int size=0;
  2245. /**
  2246. * The list of indexes.
  2247. * @serial
  2248. */
  2249. // private Vector indexes= new Vector();
  2250. /**
  2251. * The list of OIDs.
  2252. * @serial
  2253. */
  2254. // private Vector oids= new Vector();
  2255. private final static int Delta = 16;
  2256. private int tablecount = 0;
  2257. private int tablesize = Delta;
  2258. private SnmpOid tableoids[] = new SnmpOid[tablesize];
  2259. /**
  2260. * The list of entries.
  2261. * @serial
  2262. */
  2263. private final Vector entries= new Vector();
  2264. /**
  2265. * The list of object names.
  2266. * @serial
  2267. */
  2268. private final Vector entrynames= new Vector();
  2269. /**
  2270. * Callback handlers
  2271. */
  2272. // final Vector callbacks = new Vector();
  2273. /**
  2274. * Listener hastable containing the hand-back objects.
  2275. */
  2276. private java.util.Hashtable handbackTable = new java.util.Hashtable();
  2277. /**
  2278. * Listener hastable containing the filter objects.
  2279. */
  2280. private java.util.Hashtable filterTable = new java.util.Hashtable();
  2281. // PACKAGE VARIABLES
  2282. //------------------
  2283. /**
  2284. * SNMP table sequence number.
  2285. * The default value is set to 0.
  2286. */
  2287. transient long sequenceNumber = 0;
  2288. }