All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.snmp4j.smi.AbstractVariable Maven / Gradle / Ivy

There is a newer version: 3.8.2
Show newest version
/*_############################################################################
  _## 
  _##  SNMP4J 2 - AbstractVariable.java  
  _## 
  _##  Copyright (C) 2003-2016  Frank Fock and Jochen Katz (SNMP4J.org)
  _##  
  _##  Licensed under the Apache License, Version 2.0 (the "License");
  _##  you may not use this file except in compliance with the License.
  _##  You may obtain a copy of the License at
  _##  
  _##      http://www.apache.org/licenses/LICENSE-2.0
  _##  
  _##  Unless required by applicable law or agreed to in writing, software
  _##  distributed under the License is distributed on an "AS IS" BASIS,
  _##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  _##  See the License for the specific language governing permissions and
  _##  limitations under the License.
  _##  
  _##########################################################################*/
package org.snmp4j.smi;

import java.io.*;
import java.util.*;
import org.snmp4j.log.*;
import org.snmp4j.asn1.*;
import org.snmp4j.SNMP4JSettings;
// For JavaDoc:
import org.snmp4j.PDU;

/**
 * The {@code Variable} abstract class is the base class for all SNMP
 * variables.
 * 

* All derived classes need to be registered with their SMI BER type in the * {@code smisyntaxes.properties}so that the * {@link #createFromBER(BERInputStream inputStream)} method * is able to decode a variable from a BER encoded stream. *

* To register additional syntaxes, set the system property * {@link #SMISYNTAXES_PROPERTIES} before decoding a Variable for the first * time. The path of the property file must be accessible from the classpath * and it has to be specified relative to the {@code Variable} class. * * @author Frank Fock * @author Jochen Katz * @version 1.8 * @since 1.8 */ public abstract class AbstractVariable implements Variable, Serializable { private static final long serialVersionUID = 1395840752909725320L; public static final String SMISYNTAXES_PROPERTIES = "org.snmp4j.smisyntaxes"; private static final String SMISYNTAXES_PROPERTIES_DEFAULT = "smisyntaxes.properties"; private static final Object[][] SYNTAX_NAME_MAPPING = { { "Integer32", (int) BER.INTEGER32}, { "BIT STRING", (int) BER.BITSTRING}, { "OCTET STRING", (int) BER.OCTETSTRING}, { "OBJECT IDENTIFIER", (int) BER.OID}, { "TimeTicks", (int) BER.TIMETICKS}, { "Counter", (int) BER.COUNTER}, { "Counter64", (int) BER.COUNTER64}, { "EndOfMibView", BER.ENDOFMIBVIEW}, { "Gauge", (int) BER.GAUGE32}, { "Unsigned32", (int) BER.GAUGE32}, { "IpAddress", (int) BER.IPADDRESS}, { "NoSuchInstance", BER.NOSUCHINSTANCE}, { "NoSuchObject", BER.NOSUCHOBJECT}, { "Null", (int) BER.NULL}, { "Opaque", (int) BER.OPAQUE} }; private static Hashtable> registeredSyntaxes = null; private static final LogAdapter logger = LogFactory.getLogger(AbstractVariable.class); /** * The abstract {@code Variable} class serves as the base class for all * specific SNMP syntax types. */ public AbstractVariable() { } public abstract boolean equals(Object o); public abstract int compareTo(Variable o); public abstract int hashCode(); /** * Returns the length of this {@code Variable} in bytes when encoded * according to the Basic Encoding Rules (BER). * @return * the BER encoded length of this variable. */ public abstract int getBERLength(); public int getBERPayloadLength() { return getBERLength(); } /** * Decodes a {@link Variable} from an {@link BERInputStream}. * @param inputStream * an {@code BERInputStream} containing a BER encoded byte stream. * @throws IOException * if the stream could not be decoded by using BER rules. */ public abstract void decodeBER(BERInputStream inputStream) throws IOException; /** * Encodes a {@link Variable} to an {@link OutputStream}. * @param outputStream * an {@code OutputStream}. * @throws IOException * if an error occurs while writing to the stream. */ public abstract void encodeBER(OutputStream outputStream) throws IOException; /** * Creates a {@link Variable} from a BER encoded {@link BERInputStream}. * Subclasses of {@code Variable} are registered using the properties file * {@code smisyntaxes.properties} in this package. The properties are * read when this method is called first. * * @param inputStream * an {@code BERInputStream} containing a BER encoded byte stream. * @return * an instance of a subclass of {@code Variable}. * @throws IOException * if the {@code inputStream} is not properly BER encoded. */ public static Variable createFromBER(BERInputStream inputStream) throws IOException { if (!inputStream.markSupported()) { throw new IOException( "InputStream for decoding a Variable must support marks"); } if (SNMP4JSettings.isExtensibilityEnabled() && (registeredSyntaxes == null)) { registerSyntaxes(); } inputStream.mark(2); int type = inputStream.read(); Variable variable; if (SNMP4JSettings.isExtensibilityEnabled()) { Class c = registeredSyntaxes.get(type); if (c == null) { throw new IOException("Encountered unsupported variable syntax: " + type); } try { variable = c.newInstance(); } catch (IllegalAccessException aex) { throw new IOException("Could not access variable syntax class for: " + c.getName()); } catch (InstantiationException iex) { throw new IOException( "Could not instantiate variable syntax class for: " + c.getName()); } } else { variable = createVariable(type); } inputStream.reset(); variable.decodeBER(inputStream); return variable; } private static Variable createVariable(int smiSyntax) { switch (smiSyntax) { case SMIConstants.SYNTAX_OBJECT_IDENTIFIER: { return new OID(); } case SMIConstants.SYNTAX_INTEGER: { return new Integer32(); } case SMIConstants.SYNTAX_OCTET_STRING: { return new OctetString(); } case SMIConstants.SYNTAX_GAUGE32: { return new Gauge32(); } case SMIConstants.SYNTAX_COUNTER32: { return new Counter32(); } case SMIConstants.SYNTAX_COUNTER64: { return new Counter64(); } case SMIConstants.SYNTAX_NULL: { return new Null(); } case SMIConstants.SYNTAX_TIMETICKS: { return new TimeTicks(); } case SMIConstants.EXCEPTION_END_OF_MIB_VIEW: { return new Null(SMIConstants.EXCEPTION_END_OF_MIB_VIEW); } case SMIConstants.EXCEPTION_NO_SUCH_INSTANCE: { return new Null(SMIConstants.EXCEPTION_NO_SUCH_INSTANCE); } case SMIConstants.EXCEPTION_NO_SUCH_OBJECT: { return new Null(SMIConstants.EXCEPTION_NO_SUCH_OBJECT); } case SMIConstants.SYNTAX_OPAQUE: { return new Opaque(); } case SMIConstants.SYNTAX_IPADDRESS: { return new IpAddress(); } default: { throw new IllegalArgumentException("Unsupported variable syntax: " + smiSyntax); } } } /** * Creates a {@code Variable} from the supplied SMI syntax identifier. * Subclasses of {@code Variable} are registered using the properties * file {@code smisyntaxes.properties} in this package. The properties * are read when this method is called for the first time. * * @param smiSyntax * an SMI syntax identifier of the registered types, which is typically * defined by {@link SMIConstants}. * @return * a {@code Variable} variable instance of the supplied SMI syntax. */ public static Variable createFromSyntax(int smiSyntax) { if (!SNMP4JSettings.isExtensibilityEnabled()) { return createVariable(smiSyntax); } if (registeredSyntaxes == null) { registerSyntaxes(); } Class c = registeredSyntaxes.get(smiSyntax); if (c == null) { throw new IllegalArgumentException("Unsupported variable syntax: " + smiSyntax); } try { Variable variable = c.newInstance(); return variable; } catch (IllegalAccessException aex) { throw new RuntimeException("Could not access variable syntax class for: " + c.getName()); } catch (InstantiationException iex) { throw new RuntimeException( "Could not instantiate variable syntax class for: " + c.getName()); } } /** * Register SNMP syntax classes from a properties file. The registered * syntaxes are used by the {@link #createFromBER} method to type-safe * instantiate sub-classes from {@code Variable} from an BER encoded * {@code InputStream}. */ @SuppressWarnings("unchecked") private synchronized static void registerSyntaxes() { String syntaxes = System.getProperty(SMISYNTAXES_PROPERTIES, SMISYNTAXES_PROPERTIES_DEFAULT); InputStream is = Variable.class.getResourceAsStream(syntaxes); if (is == null) { throw new InternalError("Could not read '" + syntaxes + "' from classpath!"); } Properties props = new Properties(); try { props.load(is); Hashtable> regSyntaxes = new Hashtable>(props.size()); for (Enumeration en = props.propertyNames(); en.hasMoreElements(); ) { String id = en.nextElement().toString(); String className = props.getProperty(id); try { Class c = (Class) Class.forName(className); regSyntaxes.put(new Integer(id), c); } catch (ClassNotFoundException cnfe) { logger.error(cnfe); } catch (ClassCastException ccex) { logger.error(ccex); } } // atomic syntax registration registeredSyntaxes = regSyntaxes; } catch (IOException iox) { String txt = "Could not read '" + syntaxes + "': " + iox.getMessage(); logger.error(txt); throw new InternalError(txt); } finally { try { is.close(); } catch (IOException ex) { logger.warn(ex); } } } /** * Gets the ASN.1 syntax identifier value of this SNMP variable. * @return * an integer value less than 128 for regular SMI objects and a value greater or equal than 128 * for exception values like noSuchObject, noSuchInstance, and * endOfMibView. */ public abstract int getSyntax(); /** * Checks whether this variable represents an exception like * noSuchObject, noSuchInstance, and endOfMibView. * @return * {@code true} if the syntax of this variable is an instance of * {@code Null} and its syntax equals one of the following: *

    *
  • {@link SMIConstants#EXCEPTION_NO_SUCH_OBJECT}
  • *
  • {@link SMIConstants#EXCEPTION_NO_SUCH_INSTANCE}
  • *
  • {@link SMIConstants#EXCEPTION_END_OF_MIB_VIEW}
  • *
*/ public boolean isException() { return Null.isExceptionSyntax(getSyntax()); } /** * Gets a string representation of the variable. * @return * a string representation of the variable's value. */ public abstract String toString(); /** * Returns an integer representation of this variable if * such a representation exists. * @return * an integer value (if the native representation of this variable * would be a long, then the long value will be casted to int). * @throws UnsupportedOperationException if an integer representation * does not exists for this Variable. * @since 1.7 */ public abstract int toInt(); /** * Returns a long representation of this variable if * such a representation exists. * @return * a long value. * @throws UnsupportedOperationException if a long representation * does not exists for this Variable. * @since 1.7 */ public abstract long toLong(); public abstract Object clone(); /** * Gets a textual description of the supplied syntax type. * @param syntax * the BER code of the syntax. * @return * a textual description like 'Integer32' for {@code syntax} * as used in the Structure of Management Information (SMI) modules. * '?' is returned if the supplied syntax is unknown. */ public static String getSyntaxString(int syntax) { switch (syntax) { case BER.INTEGER: return "Integer32"; case BER.BITSTRING: return "BIT STRING"; case BER.OCTETSTRING: return "OCTET STRING"; case BER.OID: return "OBJECT IDENTIFIER"; case BER.TIMETICKS: return "TimeTicks"; case BER.COUNTER: return "Counter"; case BER.COUNTER64: return "Counter64"; case BER.ENDOFMIBVIEW: return "EndOfMibView"; case BER.GAUGE32: return "Gauge"; case BER.IPADDRESS: return "IpAddress"; case BER.NOSUCHINSTANCE: return "NoSuchInstance"; case BER.NOSUCHOBJECT: return "NoSuchObject"; case BER.NULL: return "Null"; case BER.OPAQUE: return "Opaque"; } return "?"; } /** * Gets a textual description of this Variable. * @return * a textual description like 'Integer32' * as used in the Structure of Management Information (SMI) modules. * '?' is returned if the syntax is unknown. * @since 1.7 */ public final String getSyntaxString() { return getSyntaxString(getSyntax()); } /** * Returns the BER syntax ID for the supplied syntax string (as returned * by {@link #getSyntaxString(int)}). * @param syntaxString * the textual representation of the syntax. * @return * the corresponding BER ID. * @since 1.6 */ public static int getSyntaxFromString(String syntaxString) { for (Object[] aSYNTAX_NAME_MAPPING : SYNTAX_NAME_MAPPING) { if (aSYNTAX_NAME_MAPPING[0].equals(syntaxString)) { return (Integer) aSYNTAX_NAME_MAPPING[1]; } } return BER.NULL; } /** * Converts the value of this {@code Variable} to a (sub-)index * value. * @param impliedLength * specifies if the sub-index has an implied length. This parameter applies * to variable length variables only (e.g. {@link OctetString} and * {@link OID}). For other variables it has no effect. * @return * an OID that represents this value as an (sub-)index. * @throws UnsupportedOperationException * if this variable cannot be used in an index. * @since 1.7 */ public abstract OID toSubIndex(boolean impliedLength); /** * Sets the value of this {@code Variable} from the supplied (sub-)index. * @param subIndex * the sub-index OID. * @param impliedLength * specifies if the sub-index has an implied length. This parameter applies * to variable length variables only (e.g. {@link OctetString} and * {@link OID}). For other variables it has no effect. * @throws UnsupportedOperationException * if this variable cannot be used in an index. * @since 1.7 */ public abstract void fromSubIndex(OID subIndex, boolean impliedLength); /** * Indicates whether this variable is dynamic, which means that it might * change its value while it is being (BER) serialized. If a variable is * dynamic, it will be cloned on-the-fly when it is added to a {@link PDU} * with {@link PDU#add(VariableBinding)}. By cloning the value, it is * ensured that there are no inconsistent changes between determining the * length with {@link #getBERLength()} for encoding enclosing SEQUENCES and * the actual encoding of the Variable itself with {@link #encodeBER}. * * @return * {@code false} by default. Derived classes may override this * if implementing dynamic {@link Variable} instances. * @since 1.8 */ public boolean isDynamic() { return false; } /** * Tests if two variables have the same value. * @param a * a variable. * @param b * another variable. * @return * {@code true} if * {@code a == null) ? (b == null) : a.equals(b)}. * @since 2.0 */ public static boolean equal(AbstractVariable a, AbstractVariable b) { return (a == null) ? (b == null) : a.equals(b); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy