/* * * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ // Copyright (c) 1995-96 by Cisco Systems, Inc. package com.sun.jmx.snmp; // java imports // import java.util.StringTokenizer; import java.util.NoSuchElementException; // sun imports import sun.misc.JavaAWTAccess; import sun.misc.SharedSecrets; /** * Represents an SNMP Object Identifier (OID). * * <p><b>This API is a Sun Microsystems internal API and is subject * to change without notice.</b></p> */ public class SnmpOid extends SnmpValue { // CONSTRUCTORS //------------- /** * Constructs a new <CODE>SnmpOid</CODE> with no components. */ public SnmpOid() { components = new long[15] ; componentCount = 0 ; } /** * Constructs a new <CODE>SnmpOid</CODE> from the specified component array. * @param oidComponents The initialization component array. */ public SnmpOid(long[] oidComponents) { components = oidComponents.clone() ; componentCount = components.length ; } /** * Constructs a new <CODE>SnmpOid</CODE> containing one component with the * specified value. * @param id The initialization component value. */ public SnmpOid(long id) { components = new long[1] ; components[0] = id ; componentCount = components.length ; } /** * Constructs a new <CODE>SnmpOid</CODE> containing four components * with the specified values. * @param id1 The first component value. * @param id2 The second component values. * @param id3 The third component values. * @param id4 The fourth component values. */ public SnmpOid(long id1, long id2, long id3, long id4) { components = new long[4] ; components[0] = id1 ; components[1] = id2 ; components[2] = id3 ; components[3] = id4 ; componentCount = components.length ; } /** * Constructs a new <CODE>SnmpOid</CODE> from a dot-formatted <CODE>String</CODE> or a MIB variable * name. It generates an exception if the variable name cannot be resolved, or * if the dot-formatted <CODE>String</CODE> has an invalid subidentifier. * This constructor helps build an OID object with a <CODE>String</CODE> like .1.2.3.4 or 1.2.3.4 * or <CODE>ifInOctets</CODE> or <CODE>ifInOctets</CODE>.0. * @param s <CODE>String</CODE> or MIB variable of the form .1.2.3 or 1.2.3 or <CODE>ifInOctets</CODE>. * @exception IllegalArgumentException The subidentifier is neither a numeric <CODE>String</CODE> * nor a <CODE>String</CODE> of the MIB database. */ public SnmpOid(String s) throws IllegalArgumentException { String dotString = s ; if (s.startsWith(".") == false) { try { dotString = resolveVarName(s); } catch(SnmpStatusException e) { throw new IllegalArgumentException(e.getMessage()); } } StringTokenizer st = new StringTokenizer(dotString, ".", false) ; componentCount= st.countTokens(); // Now extract the ids // if (componentCount == 0) { components = new long[15] ; } else { components = new long[componentCount] ; try { for (int i = 0 ; i < componentCount ; i++) { try { components[i] = Long.parseLong(st.nextToken()) ; } catch(NoSuchElementException e) {} } } catch(NumberFormatException e) { throw new IllegalArgumentException(s) ; } } } // PUBLIC METHODS //--------------- /** * Gets the number of components in this OID. * @return The number of components. */ public int getLength() { return componentCount ; } /** * Returns a copy of the components array of this <CODE>SnmpOid</CODE>. * @return The copy of the components array. */ public long[] longValue() { long[] result = new long[componentCount] ; System.arraycopy(components,0,result,0,componentCount); return result ; } /** * Returns the components array of this <CODE>SnmpOid</CODE>. * If <code>duplicate</code> is true, a copy is returned. * Otherwise, a reference to the internal array is returned, * in which case the caller <b>shall not</b> modify this array. * This method is provided to optimize processing in those cases * where the caller needs only to read the components array. * * @param duplicate Indicates whether a copy or a reference must * be returned: * <li><code>true</code> if a copy must be returned,</li> * <li><code>false</code> if a reference on the internal data * can be returned.</li> * @return A copy of (or a reference on) the components array. */ public final long[] longValue(boolean duplicate) { if (duplicate) return longValue(); if (componentCount == components.length) return components ; components = longValue(); componentCount = components.length; return components ; } /** * Returns the value of the OID arc found at the requested position * in the <CODE>components</CODE> array. The first element is at * position <code>0</code>. * * @param pos The position at which the OID arc should be peeked. * * @return The OID arc found at the requested position. * * @exception SnmpStatusException No OID arc was found at the requested * position. */ public final long getOidArc(int pos) throws SnmpStatusException { try { return components[pos]; } catch(Exception e) { throw new SnmpStatusException(SnmpStatusException.noAccess); } } /** * Converts the OID value to its <CODE>Long</CODE> form. * @return The <CODE>Long</CODE> representation of the value. */ public Long toLong() { if (componentCount != 1) { throw new IllegalArgumentException() ; } return new Long(components[0]) ; } /** * Converts the OID value to its <CODE>Integer</CODE> form. * @return The <CODE>Integer</CODE> representation of the value. */ public Integer toInteger() { if ((componentCount != 1) || (components[0] > Integer.MAX_VALUE)) { throw new IllegalArgumentException() ; } return new Integer((int)components[0]) ; } /** * Converts the OID value to its <CODE>String</CODE> form. * @return The <CODE>String</CODE> representation of the value. */ public String toString() { String result = "" ; if (componentCount >= 1) { for (int i = 0 ; i < componentCount - 1 ; i++) { result = result + components[i] + "." ; } result = result + components[componentCount - 1] ; } return result ; } /** * Converts the OID value to its <CODE>Boolean</CODE> form. * @return The <CODE>Boolean</CODE> representation of the value. */ public Boolean toBoolean() { if ((componentCount != 1) && (components[0] != 1) && (components[0] != 2)) { throw new IllegalArgumentException() ; } return Boolean.valueOf(components[0] == 1) ; } /** * Converts the OID value to its array of <CODE>Bytes</CODE> form. * @return The array of <CODE>Bytes</CODE> representation of the value. */ public Byte[] toByte() { Byte[] result = new Byte[componentCount] ; for (int i =0 ; i < componentCount ; i++) { if (components[0] > 255) { throw new IllegalArgumentException() ; } result[i] = new Byte((byte)components[i]) ; } return result ; } /** * Converts the OID value to its <CODE>SnmpOid</CODE> form. * @return The OID representation of the value. */ public SnmpOid toOid() { long[] ids = new long[componentCount] ; for (int i = 0 ; i < componentCount ; i++) { ids[i] = components[i] ; } return new SnmpOid(ids) ; } /** * Extracts the OID from an index OID and returns its * value converted as an <CODE>SnmpOid</CODE>. * @param index The index array. * @param start The position in the index array. * @return The OID representing the OID value. * @exception SnmpStatusException There is no OID value * available at the start position. */ public static SnmpOid toOid(long[] index, int start) throws SnmpStatusException { try { if (index[start] > Integer.MAX_VALUE) { throw new SnmpStatusException(SnmpStatusException.noSuchName) ; } int idCount = (int)index[start++] ; long[] ids = new long[idCount] ; for (int i = 0 ; i < idCount ; i++) { ids[i] = index[start + i] ; } return new SnmpOid(ids) ; } catch(IndexOutOfBoundsException e) { throw new SnmpStatusException(SnmpStatusException.noSuchName) ; } } /** * Scans an index OID, skips the OID value and returns the position * of the next value. * @param index The index array. * @param start The position in the index array. * @return The position of the next value. * @exception SnmpStatusException There is no OID value * available at the start position. */ public static int nextOid(long[] index, int start) throws SnmpStatusException { try { if (index[start] > Integer.MAX_VALUE) { throw new SnmpStatusException(SnmpStatusException.noSuchName) ; } int idCount = (int)index[start++] ; start += idCount ; if (start <= index.length) { return start ; } else { throw new SnmpStatusException(SnmpStatusException.noSuchName) ; } } catch(IndexOutOfBoundsException e) { throw new SnmpStatusException(SnmpStatusException.noSuchName) ; } } /** * Appends an <CODE>SnmpOid</CODE> representing an <CODE>SnmpOid</CODE> to another OID. * @param source An OID representing an <CODE>SnmpOid</CODE> value. * @param dest Where source should be appended. */ public static void appendToOid(SnmpOid source, SnmpOid dest) { dest.append(source.getLength()) ; dest.append(source) ; } /** * Performs a clone action. This provides a workaround for the * <CODE>SnmpValue</CODE> interface. * @return The SnmpValue clone. */ final synchronized public SnmpValue duplicate() { return (SnmpValue)clone() ; } /** * Clones the <CODE>SnmpOid</CODE> object, making a copy of its data. * @return The object clone. */ public Object clone() { try { SnmpOid obj = (SnmpOid)super.clone() ; obj.components = new long[this.componentCount] ; System.arraycopy(this.components, 0, obj.components, 0, this.componentCount) ; return obj ; } catch (CloneNotSupportedException e) { throw new InternalError() ; // should never happen. VM bug. } } /** * Inserts a subid at the beginning of this <CODE>SnmpOid</CODE>. * @param id The long subid to insert. */ public void insert(long id) { enlargeIfNeeded(1) ; for (int i = componentCount - 1 ; i >= 0 ; i--) { components[i + 1] = components[i] ; } components[0] = id ; componentCount++ ; } /** * Inserts a subid at the beginning of this <CODE>SnmpOid</CODE>. * @param id The integer subid to insert. */ public void insert(int id) { insert((long)id) ; } /** * Appends the specified <CODE>SnmpOid</CODE> to the end of this <CODE>SnmpOid</CODE>. * @param oid The OID to append. */ public void append(SnmpOid oid) { enlargeIfNeeded(oid.componentCount) ; for (int i = 0 ; i < oid.componentCount ; i++) { components[componentCount + i] = oid.components[i] ; } componentCount += oid.componentCount ; } /** * Appends the specified long to the end of this <CODE>SnmpOid</CODE>. * @param id The long to append. */ public void append(long id) { enlargeIfNeeded(1) ; components[componentCount] = id ; componentCount++ ; } /** * Adds the specified dot-formatted OID <CODE>String</CODE> to the end of this <CODE>SnmpOid</CODE>. * The subidentifiers can be expressed as a dot-formatted <CODE>String</CODE> or a * MIB variable name. * @param s Variable name of the form .1.2.3 or 1.2.3 or * <CODE>ifInOctets</CODE>. * @exception SnmpStatusException An error occurred while accessing a MIB node. */ public void addToOid(String s) throws SnmpStatusException { SnmpOid suffix= new SnmpOid(s); this.append(suffix); } /** * Adds the specified array of longs to the end of this <CODE>SnmpOid</CODE>. * @param oid An array of longs. * @exception SnmpStatusException An error occurred while accessing a MIB node. */ public void addToOid(long []oid) throws SnmpStatusException { SnmpOid suffix= new SnmpOid(oid); this.append(suffix); } /** * Checks the validity of the OID. * @return <CODE>true</CODE> if the OID is valid, <CODE>false</CODE> otherwise. */ public boolean isValid() { return ((componentCount >= 2) && ((0 <= components[0]) && (components[0] < 3)) && ((0 <= components[1]) && (components[1] < 40))) ; } /** * Checks whether the specified <CODE>Object</CODE> is equal to this <CODE>SnmpOid</CODE>. * @param o The <CODE>Object</CODE> to be compared. * @return <CODE>true</CODE> if <CODE>o</CODE> is an <CODE>SnmpOid</CODE> instance and equal to this, <CODE>false</CODE> otherwise. */ public boolean equals(Object o) { boolean result = false ; if (o instanceof SnmpOid) { SnmpOid oid = (SnmpOid)o ; if (oid.componentCount == componentCount) { int i = 0 ; long[] objoid = oid.components; while ((i < componentCount) && (components[i] == objoid[i])) i++ ; result = (i == componentCount) ; } } return result ; } /** * The hashCode is computed from the OID components. * @return a hashCode for this SnmpOid. **/ public int hashCode() { long acc=0; for (int i=0;i<componentCount;i++) { acc = acc*31+components[i]; } return (int)acc; } /** * Compares two OIDs lexicographically. * @param other The OID to be compared. * @return * The value 0 if the parameter <CODE>other</CODE> is equal to this <CODE>SnmpOid</CODE>. * A value smaller than 0 if this <CODE>SnmpOid</CODE> is lexicographically smaller than <CODE>other</CODE>. * A value larger than 0 if this <CODE>SnmpOid</CODE> is lexicographically larger than <CODE>other</CODE>. */ public int compareTo(SnmpOid other) { int result = 0 ; int i = 0 ; int cmplen = Math.min(componentCount, other.componentCount) ; long[] otheroid = other.components; for (i = 0; i < cmplen; i++) { if (components[i] != otheroid[i]) { break ; } } if ((i == componentCount) && (i == other.componentCount)) { result = 0 ; } else if (i == componentCount) { result = -1 ; } else if (i == other.componentCount) { result = 1 ; } else { result = (components[i] < otheroid[i]) ? -1 : 1 ; } return result ; } /** * Resolves a MIB variable <CODE>String</CODE> with the MIB database. * @param s The variable name to resolve. * @exception SnmpStatusException If the variable is not found in the MIB database. */ public String resolveVarName(String s) throws SnmpStatusException { int index = s.indexOf('.') ; // First handle the case where oid is expressed as 1.2.3.4 // try { return handleLong(s, index); } catch(NumberFormatException e) {} SnmpOidTable table = getSnmpOidTable(); // if we are here, it means we have something to resolve.. // if (table == null) throw new SnmpStatusException(SnmpStatusException.noSuchName); // Ok assume there is a variable name to resolve ... // if (index <= 0) { SnmpOidRecord rec = table.resolveVarName(s); return rec.getOid(); } else { SnmpOidRecord rec = table.resolveVarName(s.substring(0, index)); return (rec.getOid()+ s.substring(index)); } } /** * Returns a textual description of the type object. * @return ASN.1 textual description. */ public String getTypeName() { return name ; } /** * Returns the MIB table used for resolving MIB variable names. * @return The MIB table. */ public static SnmpOidTable getSnmpOidTable() { JavaAWTAccess awtAccess = SharedSecrets.getJavaAWTAccess(); if (awtAccess == null) { return meta; } else { return (SnmpOidTable) awtAccess.get(SnmpOidTable.class); } } /** * Sets the MIB table to use for resolving MIB variable names. * If no mib table is available, the class will not be able to resolve * names contained in the Object Identifier. * @param db The MIB table to use. */ public static void setSnmpOidTable(SnmpOidTable db) { JavaAWTAccess awtAccess = SharedSecrets.getJavaAWTAccess(); if (awtAccess == null) { meta = db; } else { if (db == null) { awtAccess.remove(SnmpOidTable.class); } else { awtAccess.put(SnmpOidTable.class, db); } } } /** * Converts an OID index converted string back to a DisplayString * **/ public String toOctetString() { return new String(tobyte()) ; } // PRIVATE METHODS //------------------ /** * convert the components array into a byte array **/ private byte[] tobyte() { byte[] result = new byte[componentCount] ; for (int i =0 ; i < componentCount ; i++) { if (components[0] > 255) { throw new IllegalArgumentException() ; } result[i] = (byte)components[i] ; } return result ; } /** * Checks if there is enough space in the components * array to insert n new subids. If not, it increases the size of * the array. * In fact it reallocates a new array and copy the old one into the new one. * @param n The number of subids to insert. */ private void enlargeIfNeeded(int n) { int neededSize = components.length ; while (componentCount + n > neededSize) { neededSize = neededSize * 2 ; } if (neededSize > components.length) { long[] newComponents = new long[neededSize] ; for (int i = 0 ; i < components.length ; i++) { newComponents[i] = components[i] ; } components = newComponents ; } } // PRIVATE METHODS //---------------- private String handleLong(String oid, int index) throws NumberFormatException, SnmpStatusException { String str; if (index >0) { str= oid.substring(0, index); } else { str= oid ; } // just parse the element. // Long.parseLong(str); return oid; } // VARIABLES //---------- /** * The components' array. * @serial */ protected long components[] = null ; /** * The length of the components' array. * @serial */ protected int componentCount = 0 ; /** * The name of the type. */ final static String name = "Object Identifier"; /** * Reference to a mib table. If no mib table is available, * the class will not be able to resolve names contained in the Object Identifier. */ private static SnmpOidTable meta= null; /** * Ensure serialization compatibility with version 4.1 FCS * */ static final long serialVersionUID = 8956237235607885096L; }