1. /*
  2. * @(#)file SnmpOid.java
  3. * @(#)author Sun Microsystems, Inc.
  4. * @(#)version 4.22
  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. // Copyright (c) 1995-96 by Cisco Systems, Inc.
  12. package com.sun.jmx.snmp;
  13. // java imports
  14. //
  15. import java.util.StringTokenizer;
  16. import java.util.NoSuchElementException;
  17. /**
  18. * Represents an SNMP Object Identifier (OID).
  19. *
  20. * <p><b>This API is a Sun Microsystems internal API and is subject
  21. * to change without notice.</b></p>
  22. * @version 4.22 12/19/03
  23. * @author Sun Microsystems, Inc
  24. * @author Cisco Systems, Inc.
  25. */
  26. public class SnmpOid extends SnmpValue {
  27. // CONSTRUCTORS
  28. //-------------
  29. /**
  30. * Constructs a new <CODE>SnmpOid</CODE> with no components.
  31. */
  32. public SnmpOid() {
  33. components = new long[15] ;
  34. componentCount = 0 ;
  35. }
  36. /**
  37. * Constructs a new <CODE>SnmpOid</CODE> from the specified component array.
  38. * @param oidComponents The initialization component array.
  39. */
  40. public SnmpOid(long[] oidComponents) {
  41. components = (long[])oidComponents.clone() ;
  42. componentCount = components.length ;
  43. }
  44. /**
  45. * Constructs a new <CODE>SnmpOid</CODE> containing one component with the
  46. * specified value.
  47. * @param id The initialization component value.
  48. */
  49. public SnmpOid(long id) {
  50. components = new long[1] ;
  51. components[0] = id ;
  52. componentCount = components.length ;
  53. }
  54. /**
  55. * Constructs a new <CODE>SnmpOid</CODE> containing four components
  56. * with the specified values.
  57. * @param id1 The first component value.
  58. * @param id2 The second component values.
  59. * @param id3 The third component values.
  60. * @param id4 The fourth component values.
  61. */
  62. public SnmpOid(long id1, long id2, long id3, long id4) {
  63. components = new long[4] ;
  64. components[0] = id1 ;
  65. components[1] = id2 ;
  66. components[2] = id3 ;
  67. components[3] = id4 ;
  68. componentCount = components.length ;
  69. }
  70. /**
  71. * Constructs a new <CODE>SnmpOid</CODE> from a dot-formatted <CODE>String</CODE> or a MIB variable
  72. * name. It generates an exception if the variable name cannot be resolved, or
  73. * if the dot-formatted <CODE>String</CODE> has an invalid subidentifier.
  74. * This constructor helps build an OID object with a <CODE>String</CODE> like .1.2.3.4 or 1.2.3.4
  75. * or <CODE>ifInOctets</CODE> or <CODE>ifInOctets</CODE>.0.
  76. * @param s <CODE>String</CODE> or MIB variable of the form .1.2.3 or 1.2.3 or <CODE>ifInOctets</CODE>.
  77. * @exception IllegalArgumentException The subidentifier is neither a numeric <CODE>String</CODE>
  78. * nor a <CODE>String</CODE> of the MIB database.
  79. */
  80. public SnmpOid(String s) throws IllegalArgumentException {
  81. String dotString = s ;
  82. if (s.startsWith(".") == false) {
  83. try {
  84. dotString = resolveVarName(s);
  85. } catch(SnmpStatusException e) {
  86. throw new IllegalArgumentException(e.getMessage());
  87. }
  88. }
  89. StringTokenizer st = new StringTokenizer(dotString, ".", false) ;
  90. componentCount= st.countTokens();
  91. // Now extract the ids
  92. //
  93. if (componentCount == 0) {
  94. components = new long[15] ;
  95. } else {
  96. components = new long[componentCount] ;
  97. try {
  98. for (int i = 0 ; i < componentCount ; i++) {
  99. try {
  100. components[i] = Long.parseLong(st.nextToken()) ;
  101. }
  102. catch(NoSuchElementException e) {}
  103. }
  104. }
  105. catch(NumberFormatException e) {
  106. throw new IllegalArgumentException(s) ;
  107. }
  108. }
  109. }
  110. // PUBLIC METHODS
  111. //---------------
  112. /**
  113. * Gets the number of components in this OID.
  114. * @return The number of components.
  115. */
  116. public int getLength() {
  117. return componentCount ;
  118. }
  119. /**
  120. * Returns a copy of the components array of this <CODE>SnmpOid</CODE>.
  121. * @return The copy of the components array.
  122. */
  123. public long[] longValue() {
  124. long[] result = new long[componentCount] ;
  125. System.arraycopy(components,0,result,0,componentCount);
  126. return result ;
  127. }
  128. /**
  129. * Returns the components array of this <CODE>SnmpOid</CODE>.
  130. * If <code>duplicate</code> is true, a copy is returned.
  131. * Otherwise, a reference to the internal array is returned,
  132. * in which case the caller <b>shall not</b> modify this array.
  133. * This method is provided to optimize processing in those cases
  134. * where the caller needs only to read the components array.
  135. *
  136. * @param duplicate Indicates whether a copy or a reference must
  137. * be returned:
  138. * <li><code>true</code> if a copy must be returned,</li>
  139. * <li><code>false</code> if a reference on the internal data
  140. * can be returned.</li>
  141. * @return A copy of (or a reference on) the components array.
  142. */
  143. public final long[] longValue(boolean duplicate) {
  144. if (duplicate) return longValue();
  145. if (componentCount == components.length) return components ;
  146. components = longValue();
  147. componentCount = components.length;
  148. return components ;
  149. }
  150. /**
  151. * Returns the value of the OID arc found at the requested position
  152. * in the <CODE>components</CODE> array. The first element is at
  153. * position <code>0</code>.
  154. *
  155. * @param pos The position at which the OID arc should be peeked.
  156. *
  157. * @return The OID arc found at the requested position.
  158. *
  159. * @exception SnmpStatusException No OID arc was found at the requested
  160. * position.
  161. */
  162. public final long getOidArc(int pos) throws SnmpStatusException {
  163. try {
  164. return components[pos];
  165. } catch(Exception e) {
  166. throw new SnmpStatusException(SnmpStatusException.noAccess);
  167. }
  168. }
  169. /**
  170. * Converts the OID value to its <CODE>Long</CODE> form.
  171. * @return The <CODE>Long</CODE> representation of the value.
  172. */
  173. public Long toLong() {
  174. if (componentCount != 1) {
  175. throw new IllegalArgumentException() ;
  176. }
  177. return new Long(components[0]) ;
  178. }
  179. /**
  180. * Converts the OID value to its <CODE>Integer</CODE> form.
  181. * @return The <CODE>Integer</CODE> representation of the value.
  182. */
  183. public Integer toInteger() {
  184. if ((componentCount != 1) || (components[0] > Integer.MAX_VALUE)) {
  185. throw new IllegalArgumentException() ;
  186. }
  187. return new Integer((int)components[0]) ;
  188. }
  189. /**
  190. * Converts the OID value to its <CODE>String</CODE> form.
  191. * @return The <CODE>String</CODE> representation of the value.
  192. */
  193. public String toString() {
  194. String result = "" ;
  195. if (componentCount >= 1) {
  196. for (int i = 0 ; i < componentCount - 1 ; i++) {
  197. result = result + components[i] + "." ;
  198. }
  199. result = result + components[componentCount - 1] ;
  200. }
  201. return result ;
  202. }
  203. /**
  204. * Converts the OID value to its <CODE>Boolean</CODE> form.
  205. * @return The <CODE>Boolean</CODE> representation of the value.
  206. */
  207. public Boolean toBoolean() {
  208. if ((componentCount != 1) && (components[0] != 1) && (components[0] != 2)) {
  209. throw new IllegalArgumentException() ;
  210. }
  211. return new Boolean(components[0] == 1) ;
  212. }
  213. /**
  214. * Converts the OID value to its array of <CODE>Bytes</CODE> form.
  215. * @return The array of <CODE>Bytes</CODE> representation of the value.
  216. */
  217. public Byte[] toByte() {
  218. Byte[] result = new Byte[componentCount] ;
  219. for (int i =0 ; i < componentCount ; i++) {
  220. if (components[0] > 255) {
  221. throw new IllegalArgumentException() ;
  222. }
  223. result[i] = new Byte((byte)components[i]) ;
  224. }
  225. return result ;
  226. }
  227. /**
  228. * Converts the OID value to its <CODE>SnmpOid</CODE> form.
  229. * @return The OID representation of the value.
  230. */
  231. public SnmpOid toOid() {
  232. long[] ids = new long[componentCount] ;
  233. for (int i = 0 ; i < componentCount ; i++) {
  234. ids[i] = components[i] ;
  235. }
  236. return new SnmpOid(ids) ;
  237. }
  238. /**
  239. * Extracts the OID from an index OID and returns its
  240. * value converted as an <CODE>SnmpOid</CODE>.
  241. * @param index The index array.
  242. * @param start The position in the index array.
  243. * @return The OID representing the OID value.
  244. * @exception SnmpStatusException There is no OID value
  245. * available at the start position.
  246. */
  247. public static SnmpOid toOid(long[] index, int start) throws SnmpStatusException {
  248. try {
  249. if (index[start] > Integer.MAX_VALUE) {
  250. throw new SnmpStatusException(SnmpStatusException.noSuchName) ;
  251. }
  252. int idCount = (int)index[start++] ;
  253. long[] ids = new long[idCount] ;
  254. for (int i = 0 ; i < idCount ; i++) {
  255. ids[i] = index[start + i] ;
  256. }
  257. return new SnmpOid(ids) ;
  258. }
  259. catch(IndexOutOfBoundsException e) {
  260. throw new SnmpStatusException(SnmpStatusException.noSuchName) ;
  261. }
  262. }
  263. /**
  264. * Scans an index OID, skips the OID value and returns the position
  265. * of the next value.
  266. * @param index The index array.
  267. * @param start The position in the index array.
  268. * @return The position of the next value.
  269. * @exception SnmpStatusException There is no OID value
  270. * available at the start position.
  271. */
  272. public static int nextOid(long[] index, int start) throws SnmpStatusException {
  273. try {
  274. if (index[start] > Integer.MAX_VALUE) {
  275. throw new SnmpStatusException(SnmpStatusException.noSuchName) ;
  276. }
  277. int idCount = (int)index[start++] ;
  278. start += idCount ;
  279. if (start <= index.length) {
  280. return start ;
  281. }
  282. else {
  283. throw new SnmpStatusException(SnmpStatusException.noSuchName) ;
  284. }
  285. }
  286. catch(IndexOutOfBoundsException e) {
  287. throw new SnmpStatusException(SnmpStatusException.noSuchName) ;
  288. }
  289. }
  290. /**
  291. * Appends an <CODE>SnmpOid</CODE> representing an <CODE>SnmpOid</CODE> to another OID.
  292. * @param source An OID representing an <CODE>SnmpOid</CODE> value.
  293. * @param dest Where source should be appended.
  294. */
  295. public static void appendToOid(SnmpOid source, SnmpOid dest) {
  296. dest.append(source.getLength()) ;
  297. dest.append(source) ;
  298. }
  299. /**
  300. * Performs a clone action. This provides a workaround for the
  301. * <CODE>SnmpValue</CODE> interface.
  302. * @return The SnmpValue clone.
  303. */
  304. final synchronized public SnmpValue duplicate() {
  305. return (SnmpValue)clone() ;
  306. }
  307. /**
  308. * Clones the <CODE>SnmpOid</CODE> object, making a copy of its data.
  309. * @return The object clone.
  310. */
  311. public Object clone() {
  312. try {
  313. SnmpOid obj = (SnmpOid)super.clone() ;
  314. obj.components = new long[this.componentCount] ;
  315. System.arraycopy(this.components, 0, obj.components, 0,
  316. this.componentCount) ;
  317. return obj ;
  318. } catch (CloneNotSupportedException e) {
  319. throw new InternalError() ; // should never happen. VM bug.
  320. }
  321. }
  322. /**
  323. * Inserts a subid at the beginning of this <CODE>SnmpOid</CODE>.
  324. * @param id The long subid to insert.
  325. */
  326. public void insert(long id) {
  327. enlargeIfNeeded(1) ;
  328. for (int i = componentCount - 1 ; i >= 0 ; i--) {
  329. components[i + 1] = components[i] ;
  330. }
  331. components[0] = id ;
  332. componentCount++ ;
  333. }
  334. /**
  335. * Inserts a subid at the beginning of this <CODE>SnmpOid</CODE>.
  336. * @param id The integer subid to insert.
  337. */
  338. public void insert(int id) {
  339. insert((long)id) ;
  340. }
  341. /**
  342. * Appends the specified <CODE>SnmpOid</CODE> to the end of this <CODE>SnmpOid</CODE>.
  343. * @param oid The OID to append.
  344. */
  345. public void append(SnmpOid oid) {
  346. enlargeIfNeeded(oid.componentCount) ;
  347. for (int i = 0 ; i < oid.componentCount ; i++) {
  348. components[componentCount + i] = oid.components[i] ;
  349. }
  350. componentCount += oid.componentCount ;
  351. }
  352. /**
  353. * Appends the specified long to the end of this <CODE>SnmpOid</CODE>.
  354. * @param id The long to append.
  355. */
  356. public void append(long id) {
  357. enlargeIfNeeded(1) ;
  358. components[componentCount] = id ;
  359. componentCount++ ;
  360. }
  361. /**
  362. * Adds the specified dot-formatted OID <CODE>String</CODE> to the end of this <CODE>SnmpOid</CODE>.
  363. * The subidentifiers can be expressed as a dot-formatted <CODE>String</CODE> or a
  364. * MIB variable name.
  365. * @param s Variable name of the form .1.2.3 or 1.2.3 or
  366. * <CODE>ifInOctets</CODE>.
  367. * @exception SnmpStatusException An error occurred while accessing a MIB node.
  368. */
  369. public void addToOid(String s) throws SnmpStatusException {
  370. SnmpOid suffix= new SnmpOid(s);
  371. this.append(suffix);
  372. }
  373. /**
  374. * Adds the specified array of longs to the end of this <CODE>SnmpOid</CODE>.
  375. * @param oid An array of longs.
  376. * @exception SnmpStatusException An error occurred while accessing a MIB node.
  377. */
  378. public void addToOid(long []oid) throws SnmpStatusException {
  379. SnmpOid suffix= new SnmpOid(oid);
  380. this.append(suffix);
  381. }
  382. /**
  383. * Checks the validity of the OID.
  384. * @return <CODE>true</CODE> if the OID is valid, <CODE>false</CODE> otherwise.
  385. */
  386. public boolean isValid() {
  387. return ((componentCount >= 2) &&
  388. ((0 <= components[0]) && (components[0] < 3)) &&
  389. ((0 <= components[1]) && (components[1] < 40))) ;
  390. }
  391. /**
  392. * Checks whether the specified <CODE>Object</CODE> is equal to this <CODE>SnmpOid</CODE>.
  393. * @param o The <CODE>Object</CODE> to be compared.
  394. * @return <CODE>true</CODE> if <CODE>o</CODE> is an <CODE>SnmpOid</CODE> instance and equal to this, <CODE>false</CODE> otherwise.
  395. */
  396. public boolean equals(Object o) {
  397. boolean result = false ;
  398. if (o instanceof SnmpOid) {
  399. SnmpOid oid = (SnmpOid)o ;
  400. if (oid.componentCount == componentCount) {
  401. int i = 0 ;
  402. long[] objoid = oid.components;
  403. while ((i < componentCount) && (components[i] == objoid[i]))
  404. i++ ;
  405. result = (i == componentCount) ;
  406. }
  407. }
  408. return result ;
  409. }
  410. /**
  411. * The hashCode is computed from the OID components.
  412. * @return a hashCode for this SnmpOid.
  413. **/
  414. public int hashCode() {
  415. long acc=0;
  416. for (int i=0;i<componentCount;i++) {
  417. acc = acc*31+components[i];
  418. }
  419. return (int)acc;
  420. }
  421. /**
  422. * Compares two OIDs lexicographically.
  423. * @param other The OID to be compared.
  424. * @return
  425. * The value 0 if the parameter <CODE>other</CODE> is equal to this <CODE>SnmpOid</CODE>.
  426. * A value smaller than 0 if this <CODE>SnmpOid</CODE> is lexicographically smaller than <CODE>other</CODE>.
  427. * A value larger than 0 if this <CODE>SnmpOid</CODE> is lexicographically larger than <CODE>other</CODE>.
  428. */
  429. public int compareTo(SnmpOid other) {
  430. int result = 0 ;
  431. int i = 0 ;
  432. int cmplen = Math.min(componentCount, other.componentCount) ;
  433. long[] otheroid = other.components;
  434. for (i = 0; i < cmplen; i++) {
  435. if (components[i] != otheroid[i]) {
  436. break ;
  437. }
  438. }
  439. if ((i == componentCount) && (i == other.componentCount)) {
  440. result = 0 ;
  441. }
  442. else if (i == componentCount) {
  443. result = -1 ;
  444. }
  445. else if (i == other.componentCount) {
  446. result = 1 ;
  447. }
  448. else {
  449. result = (components[i] < otheroid[i]) ? -1 : 1 ;
  450. }
  451. return result ;
  452. }
  453. /**
  454. * Resolves a MIB variable <CODE>String</CODE> with the MIB database.
  455. * @param s The variable name to resolve.
  456. * @exception SnmpStatusException If the variable is not found in the MIB database.
  457. */
  458. public String resolveVarName(String s) throws SnmpStatusException {
  459. int index = s.indexOf('.') ;
  460. // First handle the case where oid is expressed as 1.2.3.4
  461. //
  462. try {
  463. return handleLong(s, index);
  464. } catch(NumberFormatException e) {}
  465. // if we are here, it means we have something to resolve..
  466. //
  467. if (meta == null)
  468. throw new SnmpStatusException(SnmpStatusException.noSuchName);
  469. // Ok assume there is a variable name to resolve ...
  470. //
  471. if (index <= 0) {
  472. SnmpOidRecord rec = meta.resolveVarName(s);
  473. return rec.getOid();
  474. } else {
  475. SnmpOidRecord rec = meta.resolveVarName(s.substring(0, index));
  476. return (rec.getOid()+ s.substring(index));
  477. }
  478. }
  479. /**
  480. * Returns a textual description of the type object.
  481. * @return ASN.1 textual description.
  482. */
  483. public String getTypeName() {
  484. return name ;
  485. }
  486. /**
  487. * Returns the MIB table used for resolving MIB variable names.
  488. * @return The MIB table.
  489. */
  490. public static SnmpOidTable getSnmpOidTable() {
  491. return meta;
  492. }
  493. /**
  494. * Sets the MIB table to use for resolving MIB variable names.
  495. * If no mib table is available, the class will not be able to resolve
  496. * names contained in the Object Identifier.
  497. * @param db The MIB table to use.
  498. */
  499. public static void setSnmpOidTable(SnmpOidTable db) {
  500. meta = db;
  501. }
  502. /**
  503. * Converts an OID index converted string back to a DisplayString
  504. *
  505. **/
  506. public String toOctetString() {
  507. return new String(tobyte()) ;
  508. }
  509. // PRIVATE METHODS
  510. //------------------
  511. /**
  512. * convert the components array into a byte array
  513. **/
  514. private byte[] tobyte() {
  515. byte[] result = new byte[componentCount] ;
  516. for (int i =0 ; i < componentCount ; i++) {
  517. if (components[0] > 255) {
  518. throw new IllegalArgumentException() ;
  519. }
  520. result[i] = (byte)components[i] ;
  521. }
  522. return result ;
  523. }
  524. /**
  525. * Checks if there is enough space in the components
  526. * array to insert n new subids. If not, it increases the size of
  527. * the array.
  528. * In fact it reallocates a new array and copy the old one into the new one.
  529. * @param n The number of subids to insert.
  530. */
  531. private void enlargeIfNeeded(int n) {
  532. int neededSize = components.length ;
  533. while (componentCount + n > neededSize) {
  534. neededSize = neededSize * 2 ;
  535. }
  536. if (neededSize > components.length) {
  537. long[] newComponents = new long[neededSize] ;
  538. for (int i = 0 ; i < components.length ; i++) {
  539. newComponents[i] = components[i] ;
  540. }
  541. components = newComponents ;
  542. }
  543. }
  544. // PRIVATE METHODS
  545. //----------------
  546. private String handleLong(String oid, int index) throws NumberFormatException, SnmpStatusException {
  547. String str;
  548. if (index >0) {
  549. str= oid.substring(0, index);
  550. } else {
  551. str= oid ;
  552. }
  553. // just parse the element.
  554. //
  555. Long.parseLong(str);
  556. return oid;
  557. }
  558. // VARIABLES
  559. //----------
  560. /**
  561. * The components' array.
  562. * @serial
  563. */
  564. protected long components[] = null ;
  565. /**
  566. * The length of the components' array.
  567. * @serial
  568. */
  569. protected int componentCount = 0 ;
  570. /**
  571. * The name of the type.
  572. */
  573. final static String name = "Object Identifier";
  574. /**
  575. * Reference to a mib table. If no mib table is available,
  576. * the class will not be able to resolve names contained in the Object Identifier.
  577. */
  578. private static SnmpOidTable meta= null;
  579. /**
  580. * Ensure serialization compatibility with version 4.1 FCS
  581. *
  582. */
  583. static final long serialVersionUID = 8956237235607885096L;
  584. }