KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > snmp4j > smi > AbstractVariable


1 /*_############################################################################
2   _##
3   _## SNMP4J - AbstractVariable.java
4   _##
5   _## Copyright 2003-2007 Frank Fock and Jochen Katz (SNMP4J.org)
6   _##
7   _## Licensed under the Apache License, Version 2.0 (the "License");
8   _## you may not use this file except in compliance with the License.
9   _## You may obtain a copy of the License at
10   _##
11   _## http://www.apache.org/licenses/LICENSE-2.0
12   _##
13   _## Unless required by applicable law or agreed to in writing, software
14   _## distributed under the License is distributed on an "AS IS" BASIS,
15   _## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   _## See the License for the specific language governing permissions and
17   _## limitations under the License.
18   _##
19   _##########################################################################*/

20
21 package org.snmp4j.smi;
22
23 import java.io.*;
24 import java.util.*;
25 import org.snmp4j.log.*;
26 import org.snmp4j.asn1.*;
27 import org.snmp4j.SNMP4JSettings;
28 // For JavaDoc:
29
import org.snmp4j.PDU;
30
31 /**
32  * The <code>Variable</code> abstract class is the base class for all SNMP
33  * variables.
34  * <p>
35  * All derived classes need to be registered with their SMI BER type in the
36  * <code>smisyntaxes.properties</code>so that the
37  * {@link #createFromBER(BERInputStream inputStream)} method
38  * is able to decode a variable from a BER encoded stream.
39  * <p>
40  * To register additional syntaxes, set the system property
41  * {@link #SMISYNTAXES_PROPERTIES} before decoding a Variable for the first
42  * time. The path of the property file must be accessible from the classpath
43  * and it has to be specified relative to the <code>Variable</code> class.
44  *
45  * @author Jochen Katz & Frank Fock
46  * @version 1.8
47  * @since 1.8
48  */

49 public abstract class AbstractVariable implements Variable, Serializable {
50
51   private static final long serialVersionUID = 1395840752909725320L;
52
53   public static final String JavaDoc SMISYNTAXES_PROPERTIES =
54       "org.snmp4j.smisyntaxes";
55   private static final String JavaDoc SMISYNTAXES_PROPERTIES_DEFAULT =
56       "smisyntaxes.properties";
57
58   private static final Object JavaDoc[][] SYNTAX_NAME_MAPPING = {
59       { "Integer32", new Integer JavaDoc(BER.INTEGER32) },
60       { "BIT STRING", new Integer JavaDoc(BER.BITSTRING) },
61       { "OCTET STRING", new Integer JavaDoc(BER.OCTETSTRING) },
62       { "OBJECT IDENTIFIER", new Integer JavaDoc(BER.OID) },
63       { "TimeTicks", new Integer JavaDoc(BER.TIMETICKS) },
64       { "Counter", new Integer JavaDoc(BER.COUNTER) },
65       { "Counter64", new Integer JavaDoc(BER.COUNTER64) },
66       { "EndOfMibView", new Integer JavaDoc(BER.ENDOFMIBVIEW) },
67       { "Gauge", new Integer JavaDoc(BER.GAUGE32) },
68       { "IpAddress", new Integer JavaDoc(BER.IPADDRESS) },
69       { "NoSuchInstance", new Integer JavaDoc(BER.NOSUCHINSTANCE) },
70       { "NoSuchObject", new Integer JavaDoc(BER.NOSUCHOBJECT) },
71       { "Null", new Integer JavaDoc(BER.NULL) },
72       { "Opaque", new Integer JavaDoc(BER.OPAQUE) }
73   };
74
75   private static Hashtable registeredSyntaxes = null;
76
77   private static final LogAdapter logger =
78       LogFactory.getLogger(AbstractVariable.class);
79
80   /**
81    * The abstract <code>Variable</code> class serves as the base class for all
82    * specific SNMP syntax types.
83    */

84   public AbstractVariable() {
85   }
86
87   public abstract boolean equals(Object JavaDoc o);
88
89   public abstract int compareTo(Object JavaDoc o);
90
91   public abstract int hashCode();
92
93   /**
94    * Returns the length of this <code>Variable</code> in bytes when encoded
95    * according to the Basic Encoding Rules (BER).
96    * @return
97    * the BER encoded length of this variable.
98    */

99   public abstract int getBERLength();
100
101   public int getBERPayloadLength() {
102     return getBERLength();
103   }
104
105   /**
106    * Decodes a <code>Variable</code> from an <code>InputStream</code>.
107    * @param inputStream
108    * an <code>InputStream</code> containing a BER encoded byte stream.
109    * @throws IOException
110    * if the stream could not be decoded by using BER rules.
111    */

112   public abstract void decodeBER(BERInputStream inputStream) throws IOException;
113
114   /**
115    * Encodes a <code>Variable</code> to an <code>OutputStream</code>.
116    * @param outputStream
117    * an <code>OutputStream</code>.
118    * @throws IOException
119    * if an error occurs while writing to the stream.
120    */

121   public abstract void encodeBER(OutputStream outputStream) throws IOException;
122
123   /**
124    * Creates a <code>Variable</code> from a BER encoded <code>InputStream</code>.
125    * Subclasses of <code>Variable</code> are registered using the properties file
126    * <code>smisyntaxes.properties</code> in this package. The properties are
127    * read when this method is called first.
128    *
129    * @param inputStream
130    * an <code>BERInputStream</code> containing a BER encoded byte stream.
131    * @return
132    * an instance of a subclass of <code>Variable</code>.
133    * @throws IOException
134    */

135   public static Variable createFromBER(BERInputStream inputStream) throws
136       IOException {
137     if (!inputStream.markSupported()) {
138       throw new IOException(
139           "InputStream for decoding a Variable must support marks");
140     }
141     if (SNMP4JSettings.isExtensibilityEnabled() &&
142         (registeredSyntaxes == null)) {
143       registerSyntaxes();
144     }
145     inputStream.mark(2);
146     int type = inputStream.read();
147     Variable variable;
148     if (SNMP4JSettings.isExtensibilityEnabled()) {
149       Class JavaDoc c = (Class JavaDoc) registeredSyntaxes.get(new Integer JavaDoc(type));
150       if (c == null) {
151         throw new IOException("Encountered unsupported variable syntax: " +
152                               type);
153       }
154       try {
155         variable = (Variable) c.newInstance();
156       }
157       catch (IllegalAccessException JavaDoc aex) {
158         throw new IOException("Could not access variable syntax class for: " +
159                               c.getName());
160       }
161       catch (InstantiationException JavaDoc iex) {
162         throw new IOException(
163             "Could not instantiate variable syntax class for: " +
164             c.getName());
165       }
166     }
167     else {
168       variable = createVariable(type);
169     }
170     inputStream.reset();
171     variable.decodeBER(inputStream);
172     return variable;
173   }
174
175   private static Variable createVariable(int smiSyntax) {
176     switch (smiSyntax) {
177       case SMIConstants.SYNTAX_OBJECT_IDENTIFIER: {
178         return new OID();
179       }
180       case SMIConstants.SYNTAX_INTEGER: {
181         return new Integer32();
182       }
183       case SMIConstants.SYNTAX_OCTET_STRING: {
184         return new OctetString();
185       }
186       case SMIConstants.SYNTAX_GAUGE32: {
187         return new Gauge32();
188       }
189       case SMIConstants.SYNTAX_COUNTER32: {
190         return new Counter32();
191       }
192       case SMIConstants.SYNTAX_COUNTER64: {
193         return new Counter64();
194       }
195       case SMIConstants.SYNTAX_NULL: {
196         return new Null();
197       }
198       case SMIConstants.SYNTAX_TIMETICKS: {
199         return new TimeTicks();
200       }
201       case SMIConstants.EXCEPTION_END_OF_MIB_VIEW: {
202         return new Null(SMIConstants.EXCEPTION_END_OF_MIB_VIEW);
203       }
204       case SMIConstants.EXCEPTION_NO_SUCH_INSTANCE: {
205         return new Null(SMIConstants.EXCEPTION_NO_SUCH_INSTANCE);
206       }
207       case SMIConstants.EXCEPTION_NO_SUCH_OBJECT: {
208         return new Null(SMIConstants.EXCEPTION_NO_SUCH_OBJECT);
209       }
210       case SMIConstants.SYNTAX_OPAQUE: {
211         return new Opaque();
212       }
213       case SMIConstants.SYNTAX_IPADDRESS: {
214         return new IpAddress();
215       }
216       default: {
217         throw new IllegalArgumentException JavaDoc("Unsupported variable syntax: " +
218                                            smiSyntax);
219       }
220     }
221   }
222
223   /**
224    * Creates a <code>Variable</code> from the supplied SMI syntax identifier.
225    * Subclasses of <code>Variable</code> are registered using the properties
226    * file <code>smisyntaxes.properties</code> in this package. The properties
227    * are read when this method is called for the first time.
228    *
229    * @param smiSyntax
230    * an SMI syntax identifier of the registered types, which is typically
231    * defined by {@link SMIConstants}.
232    * @return
233    * a <code>Variable</code> variable instance of the supplied SMI syntax.
234    */

235   public static Variable createFromSyntax(int smiSyntax) {
236     if (!SNMP4JSettings.isExtensibilityEnabled()) {
237       return createVariable(smiSyntax);
238     }
239     if (registeredSyntaxes == null) {
240       registerSyntaxes();
241     }
242     Class JavaDoc c = (Class JavaDoc) registeredSyntaxes.get(new Integer JavaDoc(smiSyntax));
243     if (c == null) {
244       throw new IllegalArgumentException JavaDoc("Unsupported variable syntax: " +
245                                          smiSyntax);
246     }
247     try {
248       Variable variable = (Variable) c.newInstance();
249       return variable;
250     }
251     catch (IllegalAccessException JavaDoc aex) {
252       throw new RuntimeException JavaDoc("Could not access variable syntax class for: " +
253                                  c.getName());
254     }
255     catch (InstantiationException JavaDoc iex) {
256       throw new RuntimeException JavaDoc(
257           "Could not instantiate variable syntax class for: " +
258           c.getName());
259     }
260   }
261
262   /**
263    * Register SNMP syntax classes from a properties file. The registered
264    * syntaxes are used by the {@link createFromBER} method to type-safe
265    * instantiate sub-classes from <code>Variable</code> from an BER encoded
266    * <code>InputStream</code>.
267    */

268   private synchronized static void registerSyntaxes() {
269     String JavaDoc syntaxes = System.getProperty(SMISYNTAXES_PROPERTIES,
270                                          SMISYNTAXES_PROPERTIES_DEFAULT);
271     InputStream is = Variable.class.getResourceAsStream(syntaxes);
272     if (is == null) {
273       throw new InternalError JavaDoc("Could not read '" + syntaxes +
274                               "' from classpath!");
275     }
276     Properties props = new Properties();
277     try {
278       props.load(is);
279       Hashtable regSyntaxes = new Hashtable(props.size());
280       for (Enumeration en = props.propertyNames(); en.hasMoreElements(); ) {
281         String JavaDoc id = (String JavaDoc) en.nextElement();
282         String JavaDoc className = props.getProperty(id);
283         try {
284           Class JavaDoc c = Class.forName(className);
285           regSyntaxes.put(new Integer JavaDoc(id), c);
286         }
287         catch (ClassNotFoundException JavaDoc cnfe) {
288           logger.error(cnfe);
289         }
290       }
291       // atomic syntax registration
292
registeredSyntaxes = regSyntaxes;
293     }
294     catch (IOException iox) {
295       String JavaDoc txt = "Could not read '" + syntaxes + "': " +
296           iox.getMessage();
297       logger.error(txt);
298       throw new InternalError JavaDoc(txt);
299     }
300     finally {
301       try {
302         is.close();
303       }
304       catch (IOException ex) {
305         logger.warn(ex);
306       }
307     }
308   }
309
310   /**
311    * Gets the ASN.1 syntax identifier value of this SNMP variable.
312    * @return
313    * an integer value < 128 for regular SMI objects and a value >= 128
314    * for exception values like noSuchObject, noSuchInstance, and
315    * endOfMibView.
316    */

317   public abstract int getSyntax();
318
319   /**
320    * Checks whether this variable represents an exception like
321    * noSuchObject, noSuchInstance, and endOfMibView.
322    * @return
323    * <code>true</code> if the syntax of this variable is an instance of
324    * <code>Null</code> and its syntax equals one of the following:
325    * <UL>
326    * <LI>{@link SMIConstants#EXCEPTION_NO_SUCH_OBJECT}</LI>
327    * <LI>{@link SMIConstants#EXCEPTION_NO_SUCH_INSTANCE}</LI>
328    * <LI>{@link SMIConstants#EXCEPTION_END_OF_MIB_VIEW}</LI>
329    * </UL>
330    */

331   public boolean isException() {
332     return Null.isExceptionSyntax(getSyntax());
333   }
334
335   /**
336    * Gets a string representation of the variable.
337    * @return
338    * a string representation of the variable's value.
339    */

340   public abstract String JavaDoc toString();
341
342   /**
343    * Returns an integer representation of this variable if
344    * such a representation exists.
345    * @return
346    * an integer value (if the native representation of this variable
347    * would be a long, then the long value will be casted to int).
348    * @throws UnsupportedOperationException if an integer representation
349    * does not exists for this Variable.
350    * @since 1.7
351    */

352   public abstract int toInt();
353
354   /**
355    * Returns a long representation of this variable if
356    * such a representation exists.
357    * @return
358    * a long value.
359    * @throws UnsupportedOperationException if a long representation
360    * does not exists for this Variable.
361    * @since 1.7
362    */

363   public abstract long toLong();
364
365   public abstract Object JavaDoc clone();
366
367   /**
368    * Gets a textual description of the supplied syntax type.
369    * @param syntax
370    * the BER code of the syntax.
371    * @return
372    * a textual description like 'Integer32' for <code>syntax</code>
373    * as used in the Structure of Management Information (SMI) modules.
374    * '?' is returned if the supplied syntax is unknown.
375    */

376   public static String JavaDoc getSyntaxString(int syntax) {
377     switch (syntax) {
378       case BER.INTEGER:
379         return "Integer32";
380       case BER.BITSTRING:
381         return "BIT STRING";
382       case BER.OCTETSTRING:
383         return "OCTET STRING";
384       case BER.OID:
385         return "OBJECT IDENTIFIER";
386       case BER.TIMETICKS:
387         return "TimeTicks";
388       case BER.COUNTER:
389         return "Counter";
390       case BER.COUNTER64:
391         return "Counter64";
392       case BER.ENDOFMIBVIEW:
393         return "EndOfMibView";
394       case BER.GAUGE32:
395         return "Gauge";
396       case BER.IPADDRESS:
397         return "IpAddress";
398       case BER.NOSUCHINSTANCE:
399         return "NoSuchInstance";
400       case BER.NOSUCHOBJECT:
401         return "NoSuchObject";
402       case BER.NULL:
403         return "Null";
404       case BER.OPAQUE:
405         return "Opaque";
406     }
407     return "?";
408   }
409
410   /**
411    * Gets a textual description of this Variable.
412    * @return
413    * a textual description like 'Integer32'
414    * as used in the Structure of Management Information (SMI) modules.
415    * '?' is returned if the syntax is unknown.
416    * @since 1.7
417    */

418   public final String JavaDoc getSyntaxString() {
419     return getSyntaxString(getSyntax());
420   }
421
422   /**
423    * Returns the BER syntax ID for the supplied syntax string (as returned
424    * by {@link #getSyntaxString(int)}).
425    * @param syntaxString
426    * the textual representation of the syntax.
427    * @return
428    * the corresponding BER ID.
429    * @since 1.6
430    */

431   public static int getSyntaxFromString(String JavaDoc syntaxString) {
432     for (int i=0; i<SYNTAX_NAME_MAPPING.length; i++) {
433       if (SYNTAX_NAME_MAPPING[i][0].equals(syntaxString)) {
434         return ((Integer JavaDoc)SYNTAX_NAME_MAPPING[i][1]).intValue();
435       }
436     }
437     return BER.NULL;
438   }
439
440   /**
441    * Converts the value of this <code>Variable</code> to a (sub-)index
442    * value.
443    * @param impliedLength
444    * specifies if the sub-index has an implied length. This parameter applies
445    * to variable length variables only (e.g. {@link OctetString} and
446    * {@link OID}). For other variables it has no effect.
447    * @return
448    * an OID that represents this value as an (sub-)index.
449    * @throws UnsupportedOperationException
450    * if this variable cannot be used in an index.
451    * @since 1.7
452    */

453   public abstract OID toSubIndex(boolean impliedLength);
454
455   /**
456    * Sets the value of this <code>Variable</code> from the supplied (sub-)index.
457    * @param subIndex
458    * the sub-index OID.
459    * @param impliedLength
460    * specifies if the sub-index has an implied length. This parameter applies
461    * to variable length variables only (e.g. {@link OctetString} and
462    * {@link OID}). For other variables it has no effect.
463    * @throws UnsupportedOperationException
464    * if this variable cannot be used in an index.
465    * @since 1.7
466    */

467   public abstract void fromSubIndex(OID subIndex, boolean impliedLength);
468
469   /**
470    * Indicates whether this variable is dynamic, which means that it might
471    * change its value while it is being (BER) serialized. If a variable is
472    * dynamic, it will be cloned on-the-fly when it is added to a {@link PDU}
473    * with {@link PDU#add(VariableBinding)}. By cloning the value, it is
474    * ensured that there are no inconsistent changes between determining the
475    * length with {@link #getBERLength()} for encoding enclosing SEQUENCES and
476    * the actual encoding of the Variable itself with {@link #encodeBER}.
477    *
478    * @return
479    * <code>false</code> by default. Derived classes may override this
480    * if implementing dynamic {@link Variable} instances.
481    * @since 1.8
482    */

483   public boolean isDynamic() {
484     return false;
485   }
486
487 }
488
Popular Tags