1 /*
   2  * Copyright (c) 1997, 2014, 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 
  27 package com.sun.jmx.snmp.agent;
  28 
  29 
  30 
  31 // java imports
  32 //
  33 import java.io.Serializable;
  34 import java.util.Vector;
  35 import java.util.Hashtable;
  36 import java.util.Enumeration;
  37 
  38 // jmx imports
  39 //
  40 import com.sun.jmx.snmp.SnmpOid;
  41 import com.sun.jmx.snmp.SnmpValue;
  42 import com.sun.jmx.snmp.SnmpVarBind;
  43 import com.sun.jmx.snmp.SnmpDefinitions;
  44 import com.sun.jmx.snmp.SnmpStatusException;
  45 
  46 /**
  47  * The <CODE>SnmpMibNode</CODE> class represents a node in an SNMP MIB.
  48  * <P>
  49  * This class is used internally and by the class generated by
  50  * <CODE>mibgen</CODE>.
  51  * You should not need to use this class directly.
  52  *
  53  * <p><b>This API is a Sun Microsystems internal API  and is subject
  54  * to change without notice.</b></p>
  55  */
  56 @SuppressWarnings("serial") // JDK implementation class
  57 public abstract class SnmpMibNode implements Serializable {
  58 
  59     // ---------------------------------------------------------------------
  60     // PUBLIC METHODS
  61     //----------------------------------------------------------------------
  62 
  63     /**
  64      * Get the next OID arc corresponding to a readable scalar variable,
  65      * a branch leading to a subgroub, or a table.
  66      *
  67      * @param id Id we start from looking for the next.
  68      * @param userData A contextual object containing user-data.
  69      *        This object is allocated through the <code>
  70      *        {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  71      *        for each incoming SNMP request.
  72      *
  73      * @return The next id in this group.
  74      *
  75      * @exception SnmpStatusException If no id is found after the given id.
  76      */
  77     public long getNextVarId(long id, Object userData)
  78         throws SnmpStatusException {
  79         return getNextIdentifier(varList,id);
  80     }
  81 
  82     /**
  83      * Get the next OID arc corresponding to a readable scalar variable,
  84      * a branch leading to a subgroub, or a table, possibly skipping over
  85      * those arcs that must not or cannot be returned.
  86      *
  87      * Calls {@link #getNextVarId(long,java.lang.Object)} until
  88      * {@link #skipVariable(long,java.lang.Object,int)} returns false.
  89      *
  90      * @param id Id we start from looking for the next.
  91      * @param userData A contextual object containing user-data.
  92      *        This object is allocated through the <code>
  93      *        {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
  94      *        for each incoming SNMP request.
  95      * @param pduVersion Protocol version of the original request PDU.
  96      *
  97      * @return The next id in this group which can be returned using
  98      *         the given PDU's protocol version.
  99      *
 100      * @exception SnmpStatusException If no id is found after the given id.
 101      */
 102     public long getNextVarId(long id, Object userData, int pduVersion)
 103         throws SnmpStatusException {
 104         long varid=id;
 105         do {
 106             varid = getNextVarId(varid,userData);
 107         } while (skipVariable(varid,userData,pduVersion));
 108 
 109         return varid;
 110     }
 111 
 112     /**
 113      * Hook for subclasses.
 114      * The default implementation of this method is to always return
 115      * false. Subclasses should redefine this method so that it returns
 116      * true when:
 117      * <ul><li>the variable is a leaf that is not instantiated,</li>
 118      * <li>or the variable is a leaf whose type cannot be returned by that
 119      *     version of the protocol (e.g. an Counter64 with SNMPv1).</li>
 120      * </ul>
 121      *
 122      * @param id Id we start from looking for the next.
 123      * @param userData A contextual object containing user-data.
 124      *        This object is allocated through the <code>
 125      *        {@link com.sun.jmx.snmp.agent.SnmpUserDataFactory}</code>
 126      *        for each incoming SNMP request.
 127      * @param pduVersion Protocol version of the original request PDU.
 128      *
 129      * @return true if the variable must be skipped by the get-next
 130      *         algorithm.
 131      */
 132     protected boolean skipVariable(long id, Object userData, int pduVersion) {
 133         return false;
 134     }
 135 
 136     /**
 137      * Find the node which handles a varbind, and register it in the
 138      * SnmpRequestTree. This method is a pure internal method. You should
 139      * never try to call it directly.
 140      *
 141      * @param varbind  The varbind to be handled
 142      *
 143      * @param oid      The OID array extracted from the varbind
 144      *
 145      * @param depth    The depth reached in the OID at this step of the
 146      *                 processing.
 147      *
 148      * @param handlers The Hashtable in which the varbind will be registered
 149      *                 with its handling node. This hashtable contains
 150      *                 <CODE>SnmpRequestTree.Handler</CODE> items.
 151      *
 152      * @exception SnmpStatusException No handling node was found.
 153      **/
 154     void findHandlingNode(SnmpVarBind varbind,
 155                           long[] oid, int depth,
 156                           SnmpRequestTree handlers)
 157         throws SnmpStatusException {
 158         throw new SnmpStatusException(SnmpStatusException.noSuchObject);
 159     }
 160 
 161     /**
 162      * Find the node which handles the leaf that immediately follows the
 163      * given varbind OID, and register the it in the SnmpRequestTree.
 164      * This method is a pure internal method. You should never try to call
 165      * it directly.
 166      *
 167      * @param varbind  The varbind to be handled
 168      *
 169      * @param oid      The OID array extracted from the varbind
 170      *
 171      * @param depth    The depth reached in the OID at this step of the
 172      *                 processing.
 173      *
 174      * @param handlers The Hashtable in which the varbind will be registered
 175      *                 with its handling node. This hashtable contains
 176      *                 SnmpRequestTree.Handler items.
 177      *
 178      * @return The SnmpOid of the next leaf.
 179      *
 180      * @exception SnmpStatusException No handling node was found.
 181      **/
 182     long[] findNextHandlingNode(SnmpVarBind varbind,
 183                                  long[] oid, int pos, int depth,
 184                                  SnmpRequestTree handlers, AcmChecker checker)
 185         throws SnmpStatusException {
 186         throw new SnmpStatusException(SnmpStatusException.noSuchObject);
 187     }
 188 
 189     /**
 190      * Generic handling of the <CODE>get</CODE> operation.
 191      *
 192      * <p> You can override this method if you need to implement some
 193      * specific policies for minimizing the accesses made to some remote
 194      * underlying resources.
 195      * <p>
 196      *
 197      * @param req   The sub-request that must be handled by this node.
 198      *
 199      * @param depth The depth reached in the OID tree.
 200      *
 201      * @exception SnmpStatusException An error occurred while accessing
 202      *  the MIB node.
 203      */
 204     public abstract void get(SnmpMibSubRequest req, int depth)
 205         throws SnmpStatusException;
 206 
 207     /**
 208      * Generic handling of the <CODE>set</CODE> operation.
 209      * <p> You can override this method if you need to implement some
 210      * specific policies for minimizing the accesses made to some remote
 211      * underlying resources.
 212      * <p>
 213      *
 214      * @param req   The sub-request that must be handled by this node.
 215      *
 216      * @param depth The depth reached in the OID tree.
 217      *
 218      * @exception SnmpStatusException An error occurred while accessing
 219      *  the MIB node.
 220      */
 221     public abstract void set(SnmpMibSubRequest req, int depth)
 222         throws SnmpStatusException;
 223 
 224     /**
 225      * Generic handling of the <CODE>check</CODE> operation.
 226      * <p> You can override this method if you need to implement some
 227      * specific policies for minimizing the accesses made to some remote
 228      * underlying resources, or if you need to implement some consistency
 229      * checks between the different values provided in the varbind list.
 230      * <p>
 231      *
 232      * @param req   The sub-request that must be handled by this node.
 233      *
 234      * @param depth The depth reached in the OID tree.
 235      *
 236      * @exception SnmpStatusException An error occurred while accessing
 237      *  the MIB node.
 238      */
 239     public abstract void check(SnmpMibSubRequest req, int depth)
 240         throws SnmpStatusException;
 241 
 242     /**
 243      * Sorts the specified integer array.
 244      *
 245      * @param array An integer array.
 246      */
 247     static public void sort(int array[]) {
 248         QuickSort(array, 0, array.length - 1);
 249     }
 250 
 251     /**
 252      * Computes the root OID of the MIB.
 253      */
 254     public void getRootOid(Vector<Integer> result) {
 255         return;
 256     }
 257 
 258     //----------------------------------------------------------------------
 259     // PACKAGE METHODS
 260     //----------------------------------------------------------------------
 261 
 262     /**
 263      * This is a generic version of C.A.R Hoare's Quick Sort
 264      * algorithm.  This will handle arrays that are already
 265      * sorted, and arrays with duplicate keys.
 266      *
 267      * If you think of a one dimensional array as going from
 268      * the lowest index on the left to the highest index on the right
 269      * then the parameters to this function are lowest index or
 270      * left and highest index or right.  The first time you call
 271      * this function it will be with the parameters 0, a.length - 1.
 272      *
 273      * @param a An integer array.
 274      * @param lo0 Left boundary of array partition.
 275      * @param hi0 Right boundary of array partition.
 276      */
 277     static void QuickSort(int a[], int lo0, int hi0) {
 278         int lo = lo0;
 279         int hi = hi0;
 280         int mid;
 281 
 282         if ( hi0 > lo0) {
 283 
 284             /* Arbitrarily establishing partition element as the midpoint of
 285              * the array.
 286              */
 287             mid = a[ ( lo0 + hi0 ) / 2 ];
 288 
 289             // loop through the array until indices cross
 290             while( lo <= hi ) {
 291                 /* find the first element that is greater than or equal to
 292                  * the partition element starting from the left Index.
 293                  */
 294                 while( ( lo < hi0 )  && ( a[lo] < mid ))
 295                     ++lo;
 296 
 297                 /* find an element that is smaller than or equal to
 298                  * the partition element starting from the right Index.
 299                  */
 300                 while( ( hi > lo0 ) && ( a[hi] > mid ))
 301                     --hi;
 302 
 303                 // if the indexes have not crossed, swap
 304                 if( lo <= hi ) {
 305                     swap(a, lo, hi);
 306                     ++lo;
 307                     --hi;
 308                 }
 309             }
 310 
 311             /* If the right index has not reached the left side of array
 312              * must now sort the left partition.
 313              */
 314             if( lo0 < hi )
 315                 QuickSort( a, lo0, hi );
 316 
 317             /* If the left index has not reached the right side of array
 318              * must now sort the right partition.
 319              */
 320             if( lo < hi0 )
 321                 QuickSort( a, lo, hi0 );
 322 
 323         }
 324     }
 325 
 326     //----------------------------------------------------------------------
 327     // PROTECTED METHODS
 328     //----------------------------------------------------------------------
 329 
 330     /**
 331      * This will give the first element greater than <CODE>value</CODE>
 332      * in a sorted array.
 333      * If there is no element of the array greater than <CODE>value</CODE>,
 334      * the method will throw a <CODE>SnmpStatusException</CODE>.
 335      *
 336      * @param table A sorted integer array.
 337      *
 338      * @param value The greatest value.
 339      *
 340      * @exception SnmpStatusException If there is no element greater than
 341      *     <CODE>value</CODE>.
 342      */
 343     final static protected int getNextIdentifier(int table[], long value)
 344         throws SnmpStatusException {
 345 
 346         final int[] a = table;
 347         final int val= (int) value;
 348 
 349         if (a == null) {
 350             throw new SnmpStatusException(SnmpStatusException.noSuchObject);
 351         }
 352 
 353         int low= 0;
 354         int max= a.length;
 355         int curr= low + (max-low)/2;
 356         int elmt= 0;
 357 
 358         // Basic check
 359         //
 360         if (max < 1) {
 361             throw new SnmpStatusException(SnmpStatusException.noSuchObject);
 362         }
 363 
 364         if (a[max-1] <= val) {
 365             throw new SnmpStatusException(SnmpStatusException.noSuchObject);
 366         }
 367 
 368         while (low <= max) {
 369             elmt= a[curr];
 370             if (val == elmt) {
 371                 // We ned to get the next index ...
 372                 //
 373                 curr++;
 374                 return a[curr];
 375             }
 376             if (elmt < val) {
 377                 low= curr +1;
 378             } else {
 379                 max= curr -1;
 380             }
 381             curr= low + (max-low)/2;
 382         }
 383         return a[curr];
 384     }
 385 
 386 
 387     //----------------------------------------------------------------------
 388     // PRIVATE METHODS
 389     //----------------------------------------------------------------------
 390 
 391     final static private void swap(int a[], int i, int j) {
 392         int T;
 393         T = a[i];
 394         a[i] = a[j];
 395         a[j] = T;
 396     }
 397 
 398     //----------------------------------------------------------------------
 399     // PROTECTED VARIABLES
 400     //----------------------------------------------------------------------
 401 
 402     /**
 403      * Contains the list of variable identifiers.
 404      */
 405     protected int[] varList;
 406 }