001: /*
002: * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.jmx.snmp.agent;
027:
028: // java imports
029: //
030: import java.io.Serializable;
031: import java.util.Hashtable;
032: import java.util.Enumeration;
033: import java.util.Vector;
034:
035: // jmx imports
036: //
037: import com.sun.jmx.snmp.SnmpOid;
038: import com.sun.jmx.snmp.SnmpValue;
039: import com.sun.jmx.snmp.SnmpVarBind;
040: import com.sun.jmx.snmp.SnmpStatusException;
041:
042: // SNMP Runtime imports
043: //
044: import com.sun.jmx.snmp.agent.SnmpMibOid;
045: import com.sun.jmx.snmp.agent.SnmpMibNode;
046:
047: /**
048: * Represents a node in an SNMP MIB which corresponds to a group.
049: * This class allows subnodes to be registered below a group, providing
050: * support for nested groups. The subnodes are registered at run time
051: * when registering the nested groups in the global MIB OID tree.
052: * <P>
053: * This class is used by the class generated by <CODE>mibgen</CODE>.
054: * You should not need to use this class directly.
055: *
056: * <p><b>This API is a Sun Microsystems internal API and is subject
057: * to change without notice.</b></p>
058: */
059:
060: public abstract class SnmpMibGroup extends SnmpMibOid implements
061: Serializable {
062:
063: // We will register the OID arcs leading to subgroups in this hashtable.
064: // So for each arc in varList, if the arc is also in subgroups, it leads
065: // to a subgroup, if it is not in subgroup, it leads either to a table
066: // or to a variable.
067: protected Hashtable<Long, Long> subgroups = null;
068:
069: /**
070: * Tells whether the given arc identifies a table in this group.
071: *
072: * @param arc An OID arc.
073: *
074: * @return <CODE>true</CODE> if `arc' leads to a table.
075: */
076: public abstract boolean isTable(long arc);
077:
078: /**
079: * Tells whether the given arc identifies a variable (scalar object) in
080: * this group.
081: *
082: * @param arc An OID arc.
083: *
084: * @return <CODE>true</CODE> if `arc' leads to a variable.
085: */
086: public abstract boolean isVariable(long arc);
087:
088: /**
089: * Tells whether the given arc identifies a readable scalar object in
090: * this group.
091: *
092: * @param arc An OID arc.
093: *
094: * @return <CODE>true</CODE> if `arc' leads to a readable variable.
095: */
096: public abstract boolean isReadable(long arc);
097:
098: /**
099: * Gets the table identified by the given `arc'.
100: *
101: * @param arc An OID arc.
102: *
103: * @return The <CODE>SnmpMibTable</CODE> identified by `arc', or
104: * <CODE>null</CODE> if `arc' does not identify any table.
105: */
106: public abstract SnmpMibTable getTable(long arc);
107:
108: /**
109: * Checks whether the given OID arc identifies a variable (scalar
110: * object).
111: *
112: * @exception If the given `arc' does not identify any variable in this
113: * group, throws an SnmpStatusException.
114: */
115: public void validateVarId(long arc, Object userData)
116: throws SnmpStatusException {
117: if (isVariable(arc) == false)
118: throw noSuchObjectException;
119: }
120:
121: // -------------------------------------------------------------------
122: // We use a hashtable (subgroup) in order to determine whether an
123: // OID arc leads to a subgroup. This implementation can be changed if
124: // needed...
125: // For instance, the subclass could provide a generated isNestedArc()
126: // method in which the subgroup OID arcs would be hardcoded.
127: // However, the generic approach was prefered because at this time
128: // groups and subgroups are dynamically registered in the MIB.
129: //
130: /**
131: * Tell whether the given OID arc identifies a sub-tree
132: * leading to a nested SNMP sub-group. This method is used internally.
133: * You shouldn't need to call it directly.
134: *
135: * @param arc An OID arc.
136: *
137: * @return <CODE>true</CODE> if the given OID arc identifies a subtree
138: * leading to a nested SNMP sub-group.
139: *
140: */
141: public boolean isNestedArc(long arc) {
142: if (subgroups == null)
143: return false;
144: Object obj = subgroups.get(new Long(arc));
145: // if the arc is registered in the hashtable,
146: // it leads to a subgroup.
147: return (obj != null);
148: }
149:
150: /**
151: * Generic handling of the <CODE>get</CODE> operation.
152: * <p>The actual implementation of this method will be generated
153: * by mibgen. Usually, this implementation only delegates the
154: * job to some other provided runtime class, which knows how to
155: * access the MBean. The current toolkit thus provides two
156: * implementations:
157: * <ul><li>The standard implementation will directly access the
158: * MBean through a java reference,</li>
159: * <li>The generic implementation will access the MBean through
160: * the MBean server.</li>
161: * </ul>
162: * <p>Both implementations rely upon specific - and distinct, set of
163: * mibgen generated methods.
164: * <p> You can override this method if you need to implement some
165: * specific policies for minimizing the accesses made to some remote
166: * underlying resources.
167: * <p>
168: *
169: * @param req The sub-request that must be handled by this node.
170: *
171: * @param depth The depth reached in the OID tree.
172: *
173: * @exception SnmpStatusException An error occurred while accessing
174: * the MIB node.
175: */
176: abstract public void get(SnmpMibSubRequest req, int depth)
177: throws SnmpStatusException;
178:
179: /**
180: * Generic handling of the <CODE>set</CODE> operation.
181: * <p>The actual implementation of this method will be generated
182: * by mibgen. Usually, this implementation only delegates the
183: * job to some other provided runtime class, which knows how to
184: * access the MBean. The current toolkit thus provides two
185: * implementations:
186: * <ul><li>The standard implementation will directly access the
187: * MBean through a java reference,</li>
188: * <li>The generic implementation will access the MBean through
189: * the MBean server.</li>
190: * </ul>
191: * <p>Both implementations rely upon specific - and distinct, set of
192: * mibgen generated methods.
193: * <p> You can override this method if you need to implement some
194: * specific policies for minimizing the accesses made to some remote
195: * underlying resources.
196: * <p>
197: *
198: * @param req The sub-request that must be handled by this node.
199: *
200: * @param depth The depth reached in the OID tree.
201: *
202: * @exception SnmpStatusException An error occurred while accessing
203: * the MIB node.
204: */
205: abstract public void set(SnmpMibSubRequest req, int depth)
206: throws SnmpStatusException;
207:
208: /**
209: * Generic handling of the <CODE>check</CODE> operation.
210: *
211: * <p>The actual implementation of this method will be generated
212: * by mibgen. Usually, this implementation only delegates the
213: * job to some other provided runtime class, which knows how to
214: * access the MBean. The current toolkit thus provides two
215: * implementations:
216: * <ul><li>The standard implementation will directly access the
217: * MBean through a java reference,</li>
218: * <li>The generic implementation will access the MBean through
219: * the MBean server.</li>
220: * </ul>
221: * <p>Both implementations rely upon specific - and distinct, set of
222: * mibgen generated methods.
223: * <p> You can override this method if you need to implement some
224: * specific policies for minimizing the accesses made to some remote
225: * underlying resources, or if you need to implement some consistency
226: * checks between the different values provided in the varbind list.
227: * <p>
228: *
229: * @param req The sub-request that must be handled by this node.
230: *
231: * @param depth The depth reached in the OID tree.
232: *
233: * @exception SnmpStatusException An error occurred while accessing
234: * the MIB node.
235: */
236: abstract public void check(SnmpMibSubRequest req, int depth)
237: throws SnmpStatusException;
238:
239: // --------------------------------------------------------------------
240: // If we reach this node, we are below the root OID, so we just
241: // return.
242: // --------------------------------------------------------------------
243: public void getRootOid(Vector result) {
244: return;
245: }
246:
247: // -------------------------------------------------------------------
248: // PACKAGE METHODS
249: // -------------------------------------------------------------------
250:
251: // -------------------------------------------------------------------
252: // This method can also be overriden in a subclass to provide a
253: // different implementation of the isNestedArc() method.
254: // => if isNestedArc() is hardcoded, then registerSubArc() becomes
255: // useless and can become empty.
256: /**
257: * Register an OID arc that identifies a sub-tree
258: * leading to a nested SNMP sub-group. This method is used internally.
259: * You shouldn't ever call it directly.
260: *
261: * @param arc An OID arc.
262: *
263: */
264: void registerNestedArc(long arc) {
265: Long obj = new Long(arc);
266: if (subgroups == null)
267: subgroups = new Hashtable<Long, Long>();
268: // registers the arc in the hashtable.
269: subgroups.put(obj, obj);
270: }
271:
272: // -------------------------------------------------------------------
273: // The SnmpMibOid algorithm relies on the fact that for every arc
274: // registered in varList, there is a corresponding node at the same
275: // position in children.
276: // So the trick is to register a null node in children for each variable
277: // in varList, so that the real subgroup nodes can be inserted at the
278: // correct location.
279: // registerObject() should be called for each scalar object and each
280: // table arc by the generated subclass.
281: /**
282: * Register an OID arc that identifies a scalar object or a table.
283: * This method is used internally. You shouldn't ever call it directly.
284: *
285: * @param arc An OID arc.
286: *
287: */
288: protected void registerObject(long arc)
289: throws IllegalAccessException {
290:
291: // this will register the variable in both varList and children
292: // The node registered in children will be null, so that the parent
293: // algorithm will behave as if no node were registered. This is a
294: // trick that makes the parent algorithm behave as if only subgroups
295: // were registered in varList and children.
296: long[] oid = new long[1];
297: oid[0] = arc;
298: super .registerNode(oid, 0, null);
299: }
300:
301: // -------------------------------------------------------------------
302: // registerNode() will be called at runtime when nested groups are
303: // registered in the MIB. So we do know that this method will only
304: // be called to register nested-groups.
305: // We trap registerNode() in order to call registerSubArc()
306: /**
307: * Register a child node of this node in the OID tree.
308: * This method is used internally. You shouldn't ever call it directly.
309: *
310: * @param oid The oid of the node being registered.
311: * @param cursor The position reached in the oid.
312: * @param node The node being registered.
313: *
314: */
315: void registerNode(long[] oid, int cursor, SnmpMibNode node)
316: throws IllegalAccessException {
317: super .registerNode(oid, cursor, node);
318: if (cursor < 0)
319: return;
320: if (cursor >= oid.length)
321: return;
322: // if we get here, then it means we are registering a subgroup.
323: // We will thus register the sub arc in the subgroups hashtable.
324: registerNestedArc(oid[cursor]);
325: }
326:
327: // -------------------------------------------------------------------
328: // see comments in SnmpMibNode
329: // -------------------------------------------------------------------
330: void findHandlingNode(SnmpVarBind varbind, long[] oid, int depth,
331: SnmpRequestTree handlers) throws SnmpStatusException {
332:
333: int length = oid.length;
334: SnmpMibNode node = null;
335:
336: if (handlers == null)
337: throw new SnmpStatusException(
338: SnmpStatusException.snmpRspGenErr);
339:
340: final Object data = handlers.getUserData();
341:
342: if (depth >= length) {
343: // Nothing is left... the oid is not valid
344: throw new SnmpStatusException(SnmpStatusException.noAccess);
345: }
346:
347: long arc = oid[depth];
348:
349: if (isNestedArc(arc)) {
350: // This arc leads to a subgroup: delegates the search to the
351: // method defined in SnmpMibOid
352: super .findHandlingNode(varbind, oid, depth, handlers);
353: return;
354: } else if (isTable(arc)) {
355: // This arc leads to a table: forward the search to the table.
356:
357: // Gets the table
358: SnmpMibTable table = getTable(arc);
359:
360: // Forward the search to the table
361: table.findHandlingNode(varbind, oid, depth + 1, handlers);
362:
363: } else {
364: // If it's not a variable, throws an exception
365: validateVarId(arc, data);
366:
367: // The trailing .0 is missing in the OID
368: if (depth + 2 > length)
369: throw noSuchInstanceException;
370:
371: // There are too many arcs left in the OID (there should remain
372: // a single trailing .0)
373: if (depth + 2 < length)
374: throw noSuchInstanceException;
375:
376: // The last trailing arc is not .0
377: if (oid[depth + 1] != 0L)
378: throw noSuchInstanceException;
379:
380: // It's one of our variable, register this node.
381: handlers.add(this , depth, varbind);
382: }
383: }
384:
385: // -------------------------------------------------------------------
386: // See comments in SnmpMibNode.
387: // -------------------------------------------------------------------
388: long[] findNextHandlingNode(SnmpVarBind varbind, long[] oid,
389: int pos, int depth, SnmpRequestTree handlers,
390: AcmChecker checker) throws SnmpStatusException {
391:
392: int length = oid.length;
393: SnmpMibNode node = null;
394:
395: if (handlers == null)
396: // This should be considered as a genErr, but we do not want to
397: // abort the whole request, so we're going to throw
398: // a noSuchObject...
399: //
400: throw noSuchObjectException;
401:
402: final Object data = handlers.getUserData();
403: final int pduVersion = handlers.getRequestPduVersion();
404:
405: // The generic case where the end of the OID has been reached is
406: // handled in the superclass
407: // XXX Revisit: this works but it is somewhat convoluted. Just setting
408: // arc to -1 would work too.
409: if (pos >= length)
410: return super .findNextHandlingNode(varbind, oid, pos, depth,
411: handlers, checker);
412:
413: // Ok, we've got the arc.
414: long arc = oid[pos];
415:
416: long[] result = null;
417:
418: // We have a recursive logic. Should we have a loop instead?
419: try {
420:
421: if (isTable(arc)) {
422: // If the arc identifies a table, then we need to forward
423: // the search to the table.
424:
425: // Gets the table identified by `arc'
426: SnmpMibTable table = getTable(arc);
427:
428: // Forward to the table
429: checker.add(depth, arc);
430: try {
431: result = table.findNextHandlingNode(varbind, oid,
432: pos + 1, depth + 1, handlers, checker);
433: } catch (SnmpStatusException ex) {
434: throw noSuchObjectException;
435: } finally {
436: checker.remove(depth);
437: }
438: // Build up the leaf OID
439: result[depth] = arc;
440: return result;
441: } else if (isReadable(arc)) {
442: // If the arc identifies a readable variable, then two cases:
443:
444: if (pos == (length - 1)) {
445: // The end of the OID is reached, so we return the leaf
446: // corresponding to the variable identified by `arc'
447:
448: // Build up the OID
449: // result = new SnmpOid(0);
450: // result.insert((int)arc);
451: result = new long[depth + 2];
452: result[depth + 1] = 0L;
453: result[depth] = arc;
454:
455: checker.add(depth, result, depth, 2);
456: try {
457: checker.checkCurrentOid();
458: } catch (SnmpStatusException e) {
459: throw noSuchObjectException;
460: } finally {
461: checker.remove(depth, 2);
462: }
463:
464: // Registers this node
465: handlers.add(this , depth, varbind);
466: return result;
467: }
468:
469: // The end of the OID is not yet reached, so we must return
470: // the next leaf following the variable identified by `arc'.
471: // We cannot return the variable because whatever follows in
472: // the OID will be greater or equals to 0, and 0 identifies
473: // the variable itself - so we have indeed to return the
474: // next object.
475: // So we do nothing, because this case is handled at the
476: // end of the if ... else if ... else ... block.
477:
478: } else if (isNestedArc(arc)) {
479: // Now if the arc leads to a subgroup, we delegate the
480: // search to the child, just as done in SnmpMibNode.
481: //
482:
483: // get the child ( = nested arc node).
484: //
485: final SnmpMibNode child = getChild(arc);
486:
487: if (child != null) {
488: checker.add(depth, arc);
489: try {
490: result = child.findNextHandlingNode(varbind,
491: oid, pos + 1, depth + 1, handlers,
492: checker);
493: result[depth] = arc;
494: return result;
495: } finally {
496: checker.remove(depth);
497: }
498: }
499: }
500:
501: // The oid is not valid, we will throw an exception in order
502: // to try with the next valid identifier...
503: //
504: throw noSuchObjectException;
505:
506: } catch (SnmpStatusException e) {
507: // We didn't find anything at the given arc, so we're going
508: // to try with the next valid arc
509: //
510: long[] newOid = new long[1];
511: newOid[0] = getNextVarId(arc, data, pduVersion);
512: return findNextHandlingNode(varbind, newOid, 0, depth,
513: handlers, checker);
514: }
515: }
516:
517: }
|