/*
* Mibble MIB Parser (www.mibble.org)
*
* See LICENSE.txt for licensing information.
*
* Copyright (c) 2004-2017 Per Cederberg. All rights reserved.
*/
package net.percederberg.mibble;
import java.util.ArrayList;
import net.percederberg.mibble.type.Constraint;
/**
* The base MIB type class. There are two categories of MIB types
* extending this class, primitive ASN.1 type and SNMP macro types.
* The primitive types are used in SNMP for transferring data on the
* wire. The SNMP macro types are used in the MIB files for adding
* additional information to the primitive types or values, such as
* descriptions and similar. Most of the SNMP macro types only
* support object identifier values, and can only be used at the top
* level. The primitive types support whatever values are appropriate
* for the specific type, and are normally used inside the SNMP macro
* types in a MIB file.<p>
*
* The best way to extract the specific type information from a MIB
* type is to check the type instance and then cast the MibType
* object to the corresponding subtype. Each subtype have very
* different properties, which is why the API in this class is rather
* limited. The example below shows some skeleton code for extracting
* type information.
*
* <pre> if (type instanceof SnmpObjectType) {
* objectType = (SnmpObjectType) type;
* ...
* }</pre>
*
* Another way to check which type is at hand, is to query the type
* tags with the hasTag() method. In this way it is possible to
* distinguish between types using the same or a similar primitive
* ASN.1 type representation (such as DisplayString and IpAddress).
* This should normally be done in order to create a correct BER-
* or DER-encoding of the type. The example below illustrates how
* this could be done.
*
* <pre> tag = type.getTag();
* if (tag.getCategory() == MibTypeTag.UNIVERSAL) {
* // Set BER and DER identifier bits 8 & 7 to 00
* } else if (tag.getCategory() == MibTypeTag.APPLICATION) {
* // Set BER and DER identifier bits 8 & 7 to 01
* }
* ...
* if (!type.isPrimitive()) {
* // Set BER and DER constructed bit
* }</pre>
*
* @author Per Cederberg
* @version 2.10
* @since 2.0
*/
public abstract class MibType {
/**
* The type name.
*/
private String name;
/**
* The primitive type flag.
*/
private boolean primitive;
/**
* The type tag.
*/
private MibTypeTag tag = null;
/**
* The type reference symbol. This is set to the referenced type
* symbol when resolving this type.
*/
private MibTypeSymbol reference = null;
/**
* The type comment.
*/
private String comment = null;
/**
* Creates a new MIB type instance.
*
* @param name the type name
* @param primitive the primitive type flag
*/
protected MibType(String name, boolean primitive) {
this.name = name;
this.primitive = primitive;
}
/**
* Initializes the MIB type. This will remove all levels of
* indirection present, such as references to types or values. No
* information is lost by this operation. This method may modify
* this object as a side-effect, and will return the basic
* type.<p>
*
* <strong>NOTE:</strong> This is an internal method that should
* only be called by the MIB loader.
*
* @param symbol the MIB symbol containing this type
* @param log the MIB loader log
*
* @return the basic MIB type
*
* @throws MibException if an error was encountered during the
* initialization
*
* @since 2.2
*/
public abstract MibType initialize(MibSymbol symbol, MibLoaderLog log)
throws MibException;
/**
* Creates a type reference to this type. The type reference is
* normally an identical type, but with the primitive flag set to
* false. Only certain types support being referenced, and the
* default implementation of this method throws an exception.<p>
*
* <strong>NOTE:</strong> This is an internal method that should
* only be called by the MIB loader.
*
* @return the MIB type reference
*
* @throws UnsupportedOperationException if a type reference
* couldn't be created
*
* @since 2.2
*/
public MibType createReference()
throws UnsupportedOperationException {
String msg = name + " type cannot be referenced";
throw new UnsupportedOperationException(msg);
}
/**
* Creates a constrained type reference to this type. The type
* reference is normally an identical type, but with the
* primitive flag set to false. Only certain types support being
* referenced, and the default implementation of this method
* throws an exception.<p>
*
* <strong>NOTE:</strong> This is an internal method that should
* only be called by the MIB loader.
*
* @param constraint the type constraint
*
* @return the MIB type reference
*
* @throws UnsupportedOperationException if a type reference
* couldn't be created with constraints
*
* @since 2.2
*/
public MibType createReference(Constraint constraint)
throws UnsupportedOperationException {
String msg = name + " type cannot be referenced with constraints";
throw new UnsupportedOperationException(msg);
}
/**
* Creates a constrained type reference to this type. The type
* reference is normally an identical type, but with the
* primitive flag set to false. Only certain types support being
* referenced, and the default implementation of this method
* throws an exception.<p>
*
* <strong>NOTE:</strong> This is an internal method that should
* only be called by the MIB loader.
*
* @param values the type value symbols
*
* @return the MIB type reference
*
* @throws UnsupportedOperationException if a type reference
* couldn't be created with value constraints
*
* @since 2.2
*/
public MibType createReference(ArrayList<?> values)
throws UnsupportedOperationException {
String msg = name + " type cannot be referenced with " +
"defined values";
throw new UnsupportedOperationException(msg);
}
/**
* Checks if the specified value is compatible with this type. A
* value is compatible if it has a type that matches this one and
* a value that satisfies all constraints.
*
* @param value the value to check
*
* @return true if the value is compatible, or
* false otherwise
*/
public abstract boolean isCompatible(MibValue value);
/**
* Checks if this type represents a primitive type. The primitive
* types are the basic building blocks of the ASN.1 type system.
* By defining new types (that may be identical to a primitive
* type), the new type looses it's primitive status.
*
* @return true if this type represents a primitive type, or
* false otherwise
*
* @since 2.2
*/
public boolean isPrimitive() {
return primitive;
}
/**
* Checks if this type has a specific type tag. This method will
* check the whole type tag chain.
*
* @param tag the type tag to search for
*
* @return true if the specified type tag was present, or
* false otherwise
*
* @see #hasTag(int, int)
*
* @since 2.2
*/
public boolean hasTag(MibTypeTag tag) {
return hasTag(tag.getCategory(), tag.getValue());
}
/**
* Checks if this type has a specific type tag. This method will
* check the whole type tag chain.
*
* @param category the tag category to search for
* @param value the tag value to search for
*
* @return true if the specified type tag was present, or
* false otherwise
*
* @see #hasTag(MibTypeTag)
*
* @since 2.2
*/
public boolean hasTag(int category, int value) {
MibTypeTag iter = getTag();
while (iter != null) {
if (iter.equals(category, value)) {
return true;
}
iter = iter.getNext();
}
return false;
}
/**
* Checks if this type referenced the specified type symbol. This
* method should be avoided if possible, as it is much better to
* rely on type tags to distinguish between two types with the
* same base type (such as DisplayString and IpAddress).
*
* @param name the type symbol name
*
* @return true if this type was a reference to the symbol, or
* false otherwise
*
* @see #hasTag(int, int)
* @see #hasTag(MibTypeTag)
* @see #getReferenceSymbol()
* @see net.percederberg.mibble.snmp.SnmpTextualConvention#findReference(MibType)
*
* @since 2.2
*/
public boolean hasReferenceTo(String name) {
if (reference == null) {
return false;
} else if (reference.getName().equals(name)) {
return true;
} else {
return reference.getType().hasReferenceTo(name);
}
}
/**
* Checks if this type referenced the specified type symbol. This
* method should be avoided if possible, as it is much better to
* rely on type tags to distinguish between two types with the
* same base type (such as DisplayString and IpAddress).
*
* @param module the type symbol module (MIB) name
* @param name the type symbol name
*
* @return true if this type was a reference to the symbol, or
* false otherwise
*
* @see #hasTag(int, int)
* @see #hasTag(MibTypeTag)
* @see #getReferenceSymbol()
* @see net.percederberg.mibble.snmp.SnmpTextualConvention#findReference(MibType)
*
* @since 2.2
*/
public boolean hasReferenceTo(String module, String name) {
if (reference == null) {
return false;
}
Mib mib = reference.getMib();
if (mib.getName().equals(module) && reference.getName().equals(name)) {
return true;
} else {
return reference.getType().hasReferenceTo(module, name);
}
}
/**
* Returns the type name.
*
* @return the type name, or
* an empty string if not applicable
*
* @since 2.2
*/
public String getName() {
return name;
}
/**
* Returns the type tag. The type tags consist of a category and
* value number, and are used to identify a specific type
* uniquely (such as IpAddress and similar). Most (if not all)
* SNMP types have unique tags that are normally inherited when
* the type is referenced. Type tags may also be chained
* together, in which case this method returns the first tag in
* the chain.
*
* @return the type tag, or
* null if no type tag has been set
*
* @since 2.2
*/
public MibTypeTag getTag() {
return tag;
}
/**
* Sets the type tag. The old type tag is kept to some extent,
* depending on if the implicit flag is set to true or false. For
* implicit inheritance, the first tag in the old tag chain is
* replaced with the new tag. For explicit inheritance, the new
* tag is added first in the tag chain without removing any old
* tag.<p>
*
* <strong>NOTE:</strong> This is an internal method that should
* only be called by the MIB loader.
*
* @param implicit the implicit inheritance flag
* @param tag the new type tag
*
* @since 2.2
*/
public void setTag(boolean implicit, MibTypeTag tag) {
MibTypeTag next = this.tag;
if (implicit && next != null) {
next = next.getNext();
}
if (tag != null) {
tag.setNext(next);
}
this.tag = tag;
}
/**
* Returns the type reference symbol. A type reference is created
* whenever a type is defined in a type assignment, and later
* referenced by name from some other symbol. The complete chain
* of type references is available by calling getReference()
* recursively on the type of the returned type symbol.<p>
*
* In general, this method should be avoided as it is much better
* to rely on type tags to distinguish between two types with the
* same base type (such as DisplayString and IpAddress).
*
* @return the type reference symbol, or
* null if this type never referenced another type
*
* @see #getTag()
* @see net.percederberg.mibble.snmp.SnmpTextualConvention#findReference(MibType)
*
* @since 2.2
*/
public MibTypeSymbol getReferenceSymbol() {
return reference;
}
/**
* Sets the type reference symbol. The type reference is set
* whenever a type is defined in a type assignment, and later
* referenced by name from some other symbol.<p>
*
* <strong>NOTE:</strong> This is an internal method that should
* only be called by the MIB loader.
*
* @param symbol the referenced type symbol
*
* @since 2.2
*/
public void setReferenceSymbol(MibTypeSymbol symbol) {
this.reference = symbol;
}
/**
* Returns the type comment.
*
* @return the type comment, or
* null if no comment was set
*
* @since 2.9
*/
public String getComment() {
return comment;
}
/**
* Sets the type comment.
*
* @param comment the type comment
*
* @since 2.9
*/
void setComment(String comment) {
this.comment = comment;
}
/**
* Returns a string representation of this object.
*
* @return a string representation of this object
*/
public String toString() {
if (tag != null) {
return tag.toString() + " " + name;
} else {
return name;
}
}
}