1 /*
2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.jmx.snmp.agent;
27 
28 import java.io.Serializable;
29 import java.util.Enumeration;
30 import java.util.logging.Level;
31 import java.util.Vector;
32 
33 import javax.management.ObjectName;
34 import javax.management.MBeanServer;
35 import javax.management.MalformedObjectNameException;
36 import javax.management.InstanceAlreadyExistsException;
37 import javax.management.MBeanRegistrationException;
38 import javax.management.NotCompliantMBeanException;
39 
40 import static com.sun.jmx.defaults.JmxProperties.SNMP_ADAPTOR_LOGGER;
41 import com.sun.jmx.snmp.SnmpOid;
42 import com.sun.jmx.snmp.SnmpVarBind;
43 import com.sun.jmx.snmp.SnmpDefinitions;
44 import com.sun.jmx.snmp.SnmpStatusException;
45 
46 /**
47  * Abstract class for representing an SNMP MIB.
48  * <P>
49  * When compiling a SNMP MIB, among all the classes generated by
50  * <CODE>mibgen</CODE>, there is one which extends <CODE>SnmpMib</CODE>
51  * for representing a whole MIB.
52  * <BR>The class is used by the SNMP protocol adaptor as the entry point in
53  * the MIB.
54  *
55  * <p>This generated class can be subclassed in your code in order to
56  * plug in your own specific behaviour.
57  * </p>
58  *
59  * <p><b>This API is a Sun Microsystems internal API  and is subject
60  * to change without notice.</b></p>
61  */
62 public abstract class SnmpMib extends SnmpMibAgent implements Serializable {
63 
64     /**
65      * Default constructor.
66      * Initializes the OID tree.
67      */
SnmpMib()68     public SnmpMib() {
69         root= new SnmpMibOid();
70     }
71 
72 
73     // --------------------------------------------------------------------
74     // POLYMORHIC METHODS
75     // --------------------------------------------------------------------
76 
77     /**
78      * <p>
79      * This callback should return the OID associated to the group
80      * identified by the given <code>groupName</code>.
81      * </p>
82      *
83      * <p>
84      * This method is provided as a hook to plug-in some custom
85      * specific behavior. Although doing so is discouraged you might
86      * want to subclass this method in order to store & provide more metadata
87      * information (mapping OID <-> symbolic name) within the agent,
88      * or to "change" the root of the MIB OID by prefixing the
89      * defaultOid by an application dependant OID string, for instance.
90      * </p>
91      *
92      * <p>
93      * The default implementation of this method is to return the given
94      * <code>defaultOid</code>
95      * </p>
96      *
97      * @param groupName   The java-ized name of the SNMP group.
98      * @param defaultOid  The OID defined in the MIB for that group
99      *                    (in dot notation).
100      *
101      * @return The OID of the group identified by <code>groupName</code>,
102      *         in dot-notation.
103      */
getGroupOid(String groupName, String defaultOid)104     protected String getGroupOid(String groupName, String defaultOid) {
105         return defaultOid;
106     }
107 
108     /**
109      * <p>
110      * This callback should return the ObjectName associated to the
111      * group identified by the given <code>groupName</code>.
112      * </p>
113      *
114      * <p>
115      * This method is provided as a hook to plug-in some custom
116      * specific behavior. You might want to override this method
117      * in order to provide a different object naming scheme than
118      * that proposed by default by <code>mibgen</code>.
119      * </p>
120      *
121      * <p>
122      * This method is only meaningful if the MIB is registered
123      * in the MBeanServer, otherwise, it will not be called.
124      * </p>
125      *
126      * <p>
127      * The default implementation of this method is to return an ObjectName
128      * built from the given <code>defaultName</code>.
129      * </p>
130      *
131      * @param name  The java-ized name of the SNMP group.
132      * @param oid   The OID returned by getGroupOid() - in dot notation.
133      * @param defaultName The name by default generated by <code>
134      *                    mibgen</code>
135      *
136      * @return The ObjectName of the group identified by <code>name</code>
137      */
getGroupObjectName(String name, String oid, String defaultName)138     protected ObjectName getGroupObjectName(String name, String oid,
139                                             String defaultName)
140         throws MalformedObjectNameException {
141         return new ObjectName(defaultName);
142     }
143 
144     /**
145      * <p>
146      * Register an SNMP group and its metadata node in the MIB.
147      * </p>
148      *
149      * <p>
150      * This method is provided as a hook to plug-in some custom
151      * specific behavior. You might want to override this method
152      * if you want to set special links between the MBean, its metadata
153      * node, its OID or ObjectName etc..
154      * </p>
155      *
156      * <p>
157      * If the MIB is not registered in the MBeanServer, the <code>
158      * server</code> and <code>groupObjName</code> parameters will be
159      * <code>null</code>.<br>
160      * If the given group MBean is not <code>null</code>, and if the
161      * <code>server</code> and <code>groupObjName</code> parameters are
162      * not null, then this method will also automatically register the
163      * group MBean with the given MBeanServer <code>server</code>.
164      * </p>
165      *
166      * @param groupName  The java-ized name of the SNMP group.
167      * @param groupOid   The OID as returned by getGroupOid() - in dot
168      *                   notation.
169      * @param groupObjName The ObjectName as returned by getGroupObjectName().
170      *                   This parameter may be <code>null</code> if the
171      *                   MIB is not registered in the MBeanServer.
172      * @param node       The metadata node, as returned by the metadata
173      *                   factory method for this group.
174      * @param group      The MBean for this group, as returned by the
175      *                   MBean factory method for this group.
176      * @param server     The MBeanServer in which the groups are to be
177      *                   registered. This parameter will be <code>null</code>
178      *                   if the MIB is not registered, otherwise it is a
179      *                   reference to the MBeanServer in which the MIB is
180      *                   registered.
181      *
182      */
registerGroupNode(String groupName, String groupOid, ObjectName groupObjName, SnmpMibNode node, Object group, MBeanServer server)183     protected void registerGroupNode(String groupName,   String groupOid,
184                                      ObjectName groupObjName, SnmpMibNode node,
185                                      Object group, MBeanServer server)
186         throws NotCompliantMBeanException, MBeanRegistrationException,
187         InstanceAlreadyExistsException, IllegalAccessException {
188         root.registerNode(groupOid,node);
189         if (server != null && groupObjName != null && group != null)
190             server.registerMBean(group,groupObjName);
191     }
192 
193     /**
194      * <p>
195      * Register an SNMP Table metadata node in the MIB.
196      * </p>
197      *
198      * <p>
199      * <b><i>
200      * This method is used internally and you should never need to
201      * call it directly.</i></b><br> It is used to establish the link
202      * between an SNMP table metadata node and its bean-like counterpart.
203      * <br>
204      * The group metadata nodes will create and register their
205      * underlying table metadata nodes in the MIB using this
206      * method. <br>
207      * The metadata nodes will be later retrieved from the MIB by the
208      * bean-like table objects using the getRegisterTableMeta() method.
209      * </p>
210      *
211      * @param name      The java-ized name of the SNMP table.
212      * @param table     The SNMP table metadata node - usually this
213      *                  corresponds to a <code>mibgen</code> generated
214      *                  object.
215      */
registerTableMeta(String name, SnmpMibTable table)216     public abstract void registerTableMeta(String name, SnmpMibTable table);
217 
218     /**
219      * Returns a registered SNMP Table metadata node.
220      *
221      * <p><b><i>
222      * This method is used internally and you should never need to
223      * call it directly.
224      * </i></b></p>
225      *
226      */
getRegisteredTableMeta(String name)227     public abstract SnmpMibTable getRegisteredTableMeta(String name);
228 
229     // --------------------------------------------------------------------
230     // PUBLIC METHODS
231     // --------------------------------------------------------------------
232 
233     /**
234      * Processes a <CODE>get</CODE> operation.
235      *
236      **/
237     // Implements the method defined in SnmpMibAgent. See SnmpMibAgent
238     // for java-doc
239     //
240     @Override
get(SnmpMibRequest req)241     public void get(SnmpMibRequest req) throws SnmpStatusException {
242 
243         // Builds the request tree: creation is not allowed, operation
244         // is not atomic.
245 
246         final int reqType = SnmpDefinitions.pduGetRequestPdu;
247         SnmpRequestTree handlers = getHandlers(req,false,false,reqType);
248 
249         SnmpRequestTree.Handler h = null;
250         SnmpMibNode meta = null;
251 
252         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
253             SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
254                     "get", "Processing handlers for GET... ");
255         }
256 
257         // For each sub-request stored in the request-tree, invoke the
258         // get() method.
259         for (Enumeration<SnmpRequestTree.Handler> eh=handlers.getHandlers();eh.hasMoreElements();) {
260             h = eh.nextElement();
261 
262             // Gets the Meta node. It can be either a Group Meta or a
263             // Table Meta.
264             //
265             meta = handlers.getMetaNode(h);
266 
267             // Gets the depth of the Meta node in the OID tree
268             final int depth = handlers.getOidDepth(h);
269 
270             for (Enumeration<SnmpMibSubRequest> rqs=handlers.getSubRequests(h);
271                  rqs.hasMoreElements();) {
272 
273                 // Invoke the get() operation.
274                 meta.get(rqs.nextElement(),depth);
275             }
276         }
277     }
278 
279     /**
280      * Processes a <CODE>set</CODE> operation.
281      *
282      */
283     // Implements the method defined in SnmpMibAgent. See SnmpMibAgent
284     // for java-doc
285     //
286     @Override
set(SnmpMibRequest req)287     public void set(SnmpMibRequest req) throws SnmpStatusException {
288 
289         SnmpRequestTree handlers = null;
290 
291         // Optimization: we're going to get the whole SnmpRequestTree
292         // built in the "check" method, so that we don't have to rebuild
293         // it here.
294         //
295         if (req instanceof SnmpMibRequestImpl)
296             handlers = ((SnmpMibRequestImpl)req).getRequestTree();
297 
298         // Optimization didn't work: we have to rebuild the tree.
299         //
300         // Builds the request tree: creation is not allowed, operation
301         // is atomic.
302         //
303         final int reqType = SnmpDefinitions.pduSetRequestPdu;
304         if (handlers == null) handlers = getHandlers(req,false,true,reqType);
305         handlers.switchCreationFlag(false);
306         handlers.setPduType(reqType);
307 
308         SnmpRequestTree.Handler h;
309         SnmpMibNode meta;
310 
311         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
312             SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
313                     "set", "Processing handlers for SET... ");
314         }
315 
316         // For each sub-request stored in the request-tree, invoke the
317         // get() method.
318         for (Enumeration<SnmpRequestTree.Handler> eh=handlers.getHandlers();eh.hasMoreElements();) {
319             h = eh.nextElement();
320 
321             // Gets the Meta node. It can be either a Group Meta or a
322             // Table Meta.
323             //
324             meta = handlers.getMetaNode(h);
325 
326             // Gets the depth of the Meta node in the OID tree
327             final int depth = handlers.getOidDepth(h);
328 
329             for (Enumeration<SnmpMibSubRequest> rqs=handlers.getSubRequests(h);
330                  rqs.hasMoreElements();) {
331 
332                 // Invoke the set() operation
333                 meta.set(rqs.nextElement(),depth);
334             }
335         }
336     }
337 
338     /**
339      * Checks if a <CODE>set</CODE> operation can be performed.
340      * If the operation cannot be performed, the method will raise a
341      * <CODE>SnmpStatusException</CODE>.
342      *
343      */
344     // Implements the method defined in SnmpMibAgent. See SnmpMibAgent
345     // for java-doc
346     //
347     @Override
check(SnmpMibRequest req)348     public void check(SnmpMibRequest req) throws SnmpStatusException {
349 
350         final int reqType = SnmpDefinitions.pduWalkRequest;
351         // Builds the request tree: creation is allowed, operation
352         // is atomic.
353         SnmpRequestTree handlers = getHandlers(req,true,true,reqType);
354 
355         SnmpRequestTree.Handler h;
356         SnmpMibNode meta;
357 
358         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
359             SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
360                     "check", "Processing handlers for CHECK... ");
361         }
362 
363         // For each sub-request stored in the request-tree, invoke the
364         // check() method.
365         for (Enumeration<SnmpRequestTree.Handler> eh=handlers.getHandlers();eh.hasMoreElements();) {
366             h = eh.nextElement();
367 
368             // Gets the Meta node. It can be either a Group Meta or a
369             // Table Meta.
370             //
371             meta = handlers.getMetaNode(h);
372 
373             // Gets the depth of the Meta node in the OID tree
374             final int depth = handlers.getOidDepth(h);
375 
376             for (Enumeration<SnmpMibSubRequest> rqs=handlers.getSubRequests(h);
377                  rqs.hasMoreElements();) {
378 
379                 // Invoke the check() operation
380                 meta.check(rqs.nextElement(),depth);
381             }
382         }
383 
384         // Optimization: we're going to pass the whole SnmpRequestTree
385         // to the "set" method, so that we don't have to rebuild it there.
386         //
387         if (req instanceof SnmpMibRequestImpl) {
388             ((SnmpMibRequestImpl)req).setRequestTree(handlers);
389         }
390 
391     }
392 
393     /**
394      * Processes a <CODE>getNext</CODE> operation.
395      *
396      */
397     // Implements the method defined in SnmpMibAgent. See SnmpMibAgent
398     // for java-doc
399     //
400     @Override
getNext(SnmpMibRequest req)401     public void getNext(SnmpMibRequest req) throws SnmpStatusException {
402         // Build the request tree for the operation
403         // The subrequest stored in the request tree are valid GET requests
404         SnmpRequestTree handlers = getGetNextHandlers(req);
405 
406         SnmpRequestTree.Handler h;
407         SnmpMibNode meta;
408 
409         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
410             SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
411                     "getNext", "Processing handlers for GET-NEXT... ");
412         }
413 
414         // Now invoke get() for each subrequest of the request tree.
415         for (Enumeration<SnmpRequestTree.Handler> eh=handlers.getHandlers();eh.hasMoreElements();) {
416             h = eh.nextElement();
417 
418             // Gets the Meta node. It can be either a Group Meta or a
419             // Table Meta.
420             //
421             meta = handlers.getMetaNode(h);
422 
423             // Gets the depth of the Meta node in the OID tree
424             int depth = handlers.getOidDepth(h);
425 
426             for (Enumeration<SnmpMibSubRequest> rqs=handlers.getSubRequests(h);
427                  rqs.hasMoreElements();) {
428 
429                 // Invoke the get() operation
430                 meta.get(rqs.nextElement(),depth);
431             }
432         }
433     }
434 
435 
436     /**
437      * Processes a <CODE>getBulk</CODE> operation.
438      * The method implements the <CODE>getBulk</CODE> operation by calling
439      * appropriately the <CODE>getNext</CODE> method.
440      *
441      */
442     // Implements the method defined in SnmpMibAgent. See SnmpMibAgent
443     // for java-doc
444     //
445     @Override
getBulk(SnmpMibRequest req, int nonRepeat, int maxRepeat)446     public void getBulk(SnmpMibRequest req, int nonRepeat, int maxRepeat)
447         throws SnmpStatusException {
448 
449         getBulkWithGetNext(req, nonRepeat, maxRepeat);
450     }
451 
452     /**
453      * Gets the root object identifier of the MIB.
454      * <P>In order to be accurate, the method should be called once the
455      * MIB is fully initialized (that is, after a call to <CODE>init</CODE>
456      * or <CODE>preRegister</CODE>).
457      *
458      * @return The root object identifier.
459      */
460     @Override
getRootOid()461     public long[] getRootOid() {
462 
463         if( rootOid == null) {
464             Vector<Integer> list= new Vector<>(10);
465 
466             // Ask the tree to do the job !
467             //
468             root.getRootOid(list);
469 
470             // Now format the result
471             //
472             rootOid= new long[list.size()];
473             int i=0;
474             for(Enumeration<Integer> e= list.elements(); e.hasMoreElements(); ) {
475                 Integer val= e.nextElement();
476                 rootOid[i++]= val.longValue();
477             }
478         }
479         return rootOid.clone();
480     }
481 
482     // --------------------------------------------------------------------
483     // PRIVATE METHODS
484     //---------------------------------------------------------------------
485 
486     /**
487      * This method builds the temporary request-tree that will be used to
488      * perform the SNMP request associated with the given vector of varbinds
489      * `list'.
490      *
491      * @param req The SnmpMibRequest object holding the varbind list
492      *             concerning this MIB.
493      * @param createflag Indicates whether the operation allow for creation
494      *        of new instances (ie: it is a SET).
495      * @param atomic Indicates whether the operation is atomic or not.
496      * @param type Request type (from SnmpDefinitions).
497      *
498      * @return The request-tree where the original varbind list has been
499      *         dispatched to the appropriate nodes.
500      */
getHandlers(SnmpMibRequest req, boolean createflag, boolean atomic, int type)501     private SnmpRequestTree getHandlers(SnmpMibRequest req,
502                                         boolean createflag, boolean atomic,
503                                         int type)
504         throws SnmpStatusException {
505 
506         // Build an empty request tree
507         SnmpRequestTree handlers =
508             new SnmpRequestTree(req,createflag,type);
509 
510         int index=0;
511         SnmpVarBind var;
512         final int ver= req.getVersion();
513 
514         // For each varbind in the list finds its handling node.
515         for (Enumeration<SnmpVarBind> e= req.getElements(); e.hasMoreElements(); index++) {
516 
517             var= e.nextElement();
518 
519             try {
520                 // Find the handling node for this varbind.
521                 root.findHandlingNode(var,var.oid.longValue(false),
522                                       0,handlers);
523             } catch(SnmpStatusException x) {
524 
525                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
526                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
527                             SnmpMib.class.getName(),
528                             "getHandlers",
529                             "Couldn't find a handling node for " +
530                             var.oid.toString());
531                 }
532 
533                 // If the operation is atomic (Check/Set) or the version
534                 // is V1 we must generate an exception.
535                 //
536                 if (ver == SnmpDefinitions.snmpVersionOne) {
537 
538                     if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
539                         SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
540                                 SnmpMib.class.getName(),
541                                 "getHandlers", "\tV1: Throwing exception");
542                     }
543 
544                     // The index in the exception must correspond to the
545                     // SNMP index ...
546                     //
547                     final SnmpStatusException sse =
548                         new SnmpStatusException(x, index + 1);
549                     sse.initCause(x);
550                     throw sse;
551                 } else if ((type == SnmpDefinitions.pduWalkRequest)   ||
552                            (type == SnmpDefinitions.pduSetRequestPdu)) {
553                     final int status =
554                         SnmpRequestTree.mapSetException(x.getStatus(),ver);
555 
556                     if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
557                         SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
558                                 SnmpMib.class.getName(),
559                                 "getHandlers", "\tSET: Throwing exception");
560                     }
561 
562                     final SnmpStatusException sse =
563                         new SnmpStatusException(status, index + 1);
564                     sse.initCause(x);
565                     throw sse;
566                 } else if (atomic) {
567 
568                     // Should never come here...
569                     if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
570                         SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
571                                 SnmpMib.class.getName(),
572                                 "getHandlers", "\tATOMIC: Throwing exception");
573                     }
574 
575                     final SnmpStatusException sse =
576                         new SnmpStatusException(x, index + 1);
577                     sse.initCause(x);
578                     throw sse;
579                 }
580 
581                 final int status =
582                     SnmpRequestTree.mapGetException(x.getStatus(),ver);
583 
584                 if (status == SnmpStatusException.noSuchInstance) {
585 
586                     if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
587                         SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
588                                 SnmpMib.class.getName(),
589                                 "getHandlers",
590                                 "\tGET: Registering noSuchInstance");
591                     }
592 
593                     var.value= SnmpVarBind.noSuchInstance;
594 
595                 } else if (status == SnmpStatusException.noSuchObject) {
596                     if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
597                         SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
598                                 SnmpMib.class.getName(),
599                                 "getHandlers",
600                                 "\tGET: Registering noSuchObject");
601                     }
602 
603                         var.value= SnmpVarBind.noSuchObject;
604 
605                 } else {
606 
607                     if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
608                         SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
609                                 SnmpMib.class.getName(),
610                                 "getHandlers",
611                                 "\tGET: Registering global error: " + status);
612                     }
613 
614                     final SnmpStatusException sse =
615                         new SnmpStatusException(status, index + 1);
616                     sse.initCause(x);
617                     throw sse;
618                 }
619             }
620         }
621         return handlers;
622     }
623 
624     /**
625      * This method builds the temporary request-tree that will be used to
626      * perform the SNMP GET-NEXT request associated with the given vector
627      * of varbinds `list'.
628      *
629      * @param req The SnmpMibRequest object holding the varbind list
630      *             concerning this MIB.
631      *
632      * @return The request-tree where the original varbind list has been
633      *         dispatched to the appropriate nodes, and where the original
634      *         OIDs have been replaced with the correct "next" OID.
635      */
getGetNextHandlers(SnmpMibRequest req)636     private SnmpRequestTree getGetNextHandlers(SnmpMibRequest req)
637         throws SnmpStatusException {
638 
639         // Creates an empty request tree, no entry creation is allowed (false)
640         SnmpRequestTree handlers = new
641             SnmpRequestTree(req,false,SnmpDefinitions.pduGetNextRequestPdu);
642 
643         // Sets the getNext flag: if version=V2, status exception are
644         // transformed in  endOfMibView
645         handlers.setGetNextFlag();
646 
647         if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
648             SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, SnmpMib.class.getName(),
649                     "getGetNextHandlers", "Received MIB request : " + req);
650         }
651         AcmChecker checker = new AcmChecker(req);
652         int index=0;
653         SnmpVarBind var = null;
654         final int ver= req.getVersion();
655         SnmpOid original = null;
656         // For each varbind, finds the handling node.
657         // This function has the side effect of transforming a GET-NEXT
658         // request into a valid GET request, replacing the OIDs in the
659         // original GET-NEXT request with the OID of the first leaf that
660         // follows.
661         for (Enumeration<SnmpVarBind> e= req.getElements(); e.hasMoreElements(); index++) {
662 
663             var = e.nextElement();
664             SnmpOid result;
665             try {
666                 // Find the node handling the OID that follows the varbind
667                 // OID. `result' contains this next leaf OID.
668                 //ACM loop.
669                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
670                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
671                             SnmpMib.class.getName(),
672                             "getGetNextHandlers", " Next OID of : " + var.oid);
673                 }
674                 result = new SnmpOid(root.findNextHandlingNode
675                                      (var,var.oid.longValue(false),0,
676                                       0,handlers, checker));
677 
678                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
679                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
680                             SnmpMib.class.getName(),
681                             "getGetNextHandlers", " is : " + result);
682                 }
683                 // We replace the varbind original OID with the OID of the
684                 // leaf object we have to return.
685                 var.oid = result;
686             } catch(SnmpStatusException x) {
687 
688                 // if (isDebugOn())
689                 //    debug("getGetNextHandlers",
690                 //        "Couldn't find a handling node for "
691                 //        + var.oid.toString());
692 
693                 if (ver == SnmpDefinitions.snmpVersionOne) {
694                     if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
695                         SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
696                                 SnmpMib.class.getName(),
697                                 "getGetNextHandlers",
698                                 "\tThrowing exception " + x.toString());
699                     }
700                     // The index in the exception must correspond to the
701                     // SNMP index ...
702                     //
703                     throw new SnmpStatusException(x, index + 1);
704                 }
705                 if (SNMP_ADAPTOR_LOGGER.isLoggable(Level.FINEST)) {
706                     SNMP_ADAPTOR_LOGGER.logp(Level.FINEST,
707                             SnmpMib.class.getName(),
708                             "getGetNextHandlers",
709                             "Exception : " + x.getStatus());
710                 }
711 
712                 var.setSnmpValue(SnmpVarBind.endOfMibView);
713             }
714         }
715         return handlers;
716     }
717 
718     // --------------------------------------------------------------------
719     // PROTECTED VARIABLES
720     // --------------------------------------------------------------------
721 
722     /**
723      * The top element in the Mib tree.
724      * @serial
725      */
726     protected SnmpMibOid root;
727 
728 
729     // --------------------------------------------------------------------
730     // PRIVATE VARIABLES
731     // --------------------------------------------------------------------
732 
733     /**
734      * The root object identifier of the MIB.
735      */
736     private transient long[] rootOid= null;
737 }
738