Package net.percederberg.mibble.value

Source Code of net.percederberg.mibble.value.ObjectIdentifierValue

/*
* ObjectIdentifierValue.java
*
* This work is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This work is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* Copyright (c) 2004-2006 Per Cederberg. All rights reserved.
*/

package net.percederberg.mibble.value;

import java.util.ArrayList;

import net.percederberg.mibble.FileLocation;
import net.percederberg.mibble.Mib;
import net.percederberg.mibble.MibException;
import net.percederberg.mibble.MibLoaderLog;
import net.percederberg.mibble.MibType;
import net.percederberg.mibble.MibValue;
import net.percederberg.mibble.MibValueSymbol;

/**
* An object identifier value. This class stores the component
* identifier values in a tree hierarchy.
*
* @author   Per Cederberg, <per at percederberg dot net>
* @version  2.8
* @since    2.0
*/
public class ObjectIdentifierValue extends MibValue {

    /**
     * The declaration file location. This variable is only used when
     * resolving value references in order to present correct error
     * messages. After initialization it is set to null to minimize
     * memory impact.
     *
     * @since 2.5
     */
    private FileLocation location = null;

    /**
     * The component parent.
     */
    private MibValue parent;

    /**
     * The component children.
     */
    private ArrayList children = new ArrayList();

    /**
     * The object identifier component name.
     */
    private String name;

    /**
     * The object identifier component value.
     */
    private int value;

    /**
     * The MIB value symbol referenced by this object identifier.
     */
    private MibValueSymbol symbol = null;

    /**
     * The cached numeric string representation of this value. This
     * variable is set when calling the toString() method the first
     * time and is used to optimize performance by avoiding any
     * subsequent recursive calls.
     *
     * @see #toString()
     */
    private String cachedNumericValue = null;

    /**
     * Creates a new root object identifier value.
     *
     * @param name           the component name, or null
     * @param value          the component value
     */
    public ObjectIdentifierValue(String name, int value) {
        super("OBJECT IDENTIFIER");
        this.parent = null;
        this.name = name;
        this.value = value;
    }

    /**
     * Creates a new object identifier value.
     *
     * @param location       the declaration file location
     * @param parent         the component parent
     * @param name           the component name, or null
     * @param value          the component value
     *
     * @throws MibException if the object identifier parent already
     *             had a child with the specified value
     */
    public ObjectIdentifierValue(FileLocation location,
                                 ObjectIdentifierValue parent,
                                 String name,
                                 int value)
        throws MibException {

        super("OBJECT IDENTIFIER");
        this.parent = parent;
        this.name = name;
        this.value = value;
        if (parent.getChildByValue(value) != null) {
            throw new MibException(location,
                                   "cannot add duplicate OID " +
                                   "children with value " + value);
        }
        parent.addChild(null, location, this);
    }

    /**
     * Creates a new object identifier value.
     *
     * @param location       the declaration file location
     * @param parent         the component parent
     * @param name           the component name, or null
     * @param value          the component value
     */
    public ObjectIdentifierValue(FileLocation location,
                                 ValueReference parent,
                                 String name,
                                 int value) {

        super("OBJECT IDENTIFIER");
        this.location = location;
        this.parent = parent;
        this.name = name;
        this.value = value;
    }

    /**
     * Initializes the MIB value. This will remove all levels of
     * indirection present, such as references to other values. No
     * value information is lost by this operation. This method may
     * modify this object as a side-effect, and will return the basic
     * value.<p>
     *
     * <strong>NOTE:</strong> This is an internal method that should
     * only be called by the MIB loader.
     *
     * @param log            the MIB loader log
     * @param type           the value type
     *
     * @return the basic MIB value
     *
     * @throws MibException if an error was encountered during the
     *             initialization
     */
    public MibValue initialize(MibLoaderLog log, MibType type)
        throws MibException {

        ValueReference         ref = null;
        ObjectIdentifierValue  oid;

        if (parent == null) {
            return this;
        } else if (parent instanceof ValueReference) {
            ref = (ValueReference) parent;
        }
        parent = parent.initialize(log, type);
        if (ref != null) {
            if (parent instanceof ObjectIdentifierValue) {
                oid = (ObjectIdentifierValue) parent;
                oid.addChild(log, location, this);
            } else {
                throw new MibException(ref.getLocation(),
                                       "referenced value is not an " +
                                       "object identifier");
            }
        }
        location = null;
        if (parent instanceof ObjectIdentifierValue) {
            return ((ObjectIdentifierValue) parent).getChildByValue(value);
        } else {
            return this;
        }
    }

    /**
     * Creates a value reference to this value. The value reference
     * is normally an identical value. Only certain values 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 value reference
     *
     * @since 2.2
     */
    public MibValue createReference() {
        return this;
    }

    /**
     * Clears and prepares this value for garbage collection. This
     * method will recursively clear any associated types or values,
     * making sure that no data structures references this object.<p>
     *
     * <strong>NOTE:</strong> This is an internal method that should
     * only be called by the MIB loader.
     */
    protected void clear() {
        Mib                    mib;
        ArrayList              copy;
        ObjectIdentifierValue  child;

        // Recursively clear all children in same MIB
        if (children != null) {
            mib = getMib();
            copy = (ArrayList) children.clone();
            for (int i = 0; i < copy.size(); i++) {
                child = (ObjectIdentifierValue) copy.get(i);
                if (mib == null || mib == child.getMib()) {
                    child.clear();
                }
            }
        }

        // Remove parent reference if all children were cleared
        if (getChildCount() <= 0) {
            if (parent != null) {
                getParent().children.remove(this);
                parent = null;
            }
            children = null;
        }

        // Clear other value data
        symbol = null;
        super.clear();
    }

    /**
     * Compares this object with the specified object for order. This
     * method will only compare the string representations with each
     * other.
     *
     * @param obj            the object to compare to
     *
     * @return less than zero if this object is less than the specified,
     *         zero if the objects are equal, or
     *         greater than zero otherwise
     *
     * @since 2.6
     */
    public int compareTo(Object obj) {
        return toString().compareTo(obj.toString());
    }

    /**
     * Checks if this object equals another object. This method will
     * compare the string representations for equality.
     *
     * @param obj            the object to compare with
     *
     * @return true if the objects are equal, or
     *         false otherwise
     */
    public boolean equals(Object obj) {
        return toString().equals(obj.toString());
    }

    /**
     * Returns a hash code for this object.
     *
     * @return a hash code for this object
     */
    public int hashCode() {
        return toString().hashCode();
    }

    /**
     * Returns the parent object identifier value.
     *
     * @return the parent object identifier value, or
     *         null if no parent exists
     */
    public ObjectIdentifierValue getParent() {
        if (parent != null && parent instanceof ObjectIdentifierValue) {
            return (ObjectIdentifierValue) parent;
        } else {
            return null;
        }
    }

    /**
     * Returns this object identifier component name.
     *
     * @return the object identifier component name, or
     *         null if the component has no name
     */
    public String getName() {
        return name;
    }

    /**
     * Returns this object identifier component value.
     *
     * @return the object identifier component value
     */
    public int getValue() {
        return value;
    }

    /**
     * Returns the symbol connected to this object identifier.
     *
     * @return the symbol connected to this object identifier, or
     *         null if no value symbol is connected
     */
    public MibValueSymbol getSymbol() {
        return symbol;
    }

    /**
     * Sets the symbol connected to this object identifier.<p>
     *
     * <strong>NOTE:</strong> This is an internal method that should
     * only be called by the MIB loader.
     *
     * @param symbol         the value symbol
     */
    public void setSymbol(MibValueSymbol symbol) {
        if (name == null) {
            name = symbol.getName();
        }
        this.symbol = symbol;
    }

    /**
     * Returns the MIB that this object identifer is connected to.
     * This method simply returns the symbol MIB.
     *
     * @return the symbol MIB, or
     *         null if no symbol has been set
     */
    private Mib getMib() {
        return symbol == null ? null : symbol.getMib();
    }

    /**
     * Returns the number of child object identifier values.
     *
     * @return the number of child object identifier values
     */
    public int getChildCount() {
        return children == null ? 0 : children.size();
    }

    /**
     * Returns a child object identifier value. The children are
     * ordered by their value, not necessarily in the order in which
     * they appear in the original MIB file.
     *
     * @param index          the child position, 0 <= index < count
     *
     * @return the child object identifier value, or
     *         null if not found
     */
    public ObjectIdentifierValue getChild(int index) {
        return (ObjectIdentifierValue) children.get(index);
    }

    /**
     * Returns a child object identifier value. The children are
     * searched by their component names. This method uses linear
     * search and therefore has time complexity O(n). Note that most
     * OID:s don't have a component name, but only an associated
     * symbol.
     *
     * @param name           the child name
     *
     * @return the child object identifier value, or
     *         null if not found
     *
     * @since 2.5
     */
    public ObjectIdentifierValue getChildByName(String name) {
        ObjectIdentifierValue  child;

        for (int i = 0; i < children.size(); i++) {
            child = (ObjectIdentifierValue) children.get(i);
            if (name.equals(child.getName())) {
                return child;
            }
        }
        return null;
    }

    /**
     * Returns a child object identifier value. The children are
     * searched by their numerical value. This method uses binary
     * search and therefore has time complexity O(log(n)).
     *
     * @param value          the child value
     *
     * @return the child object identifier value, or
     *         null if not found
     *
     * @since 2.5
     */
    public ObjectIdentifierValue getChildByValue(int value) {
        ObjectIdentifierValue  child;
        int                    low = 0;
        int                    high = children.size();
        int                    pos;

        if (low < value && value <= high) {
            // Default to that the value is really the index - 1
            pos = value - 1;
        } else {
            // Otherwise use normal interval midpoint
            pos = (low + high) / 2;
        }
        while (low < high) {
            child = (ObjectIdentifierValue) children.get(pos);
            if (child.getValue() == value) {
                return child;
            } else if (child.getValue() < value) {
                low = pos + 1;
            } else {
                high = pos;
            }
            pos = (low + high) / 2;
        }
        return null;
    }

    /**
     * Returns an array of all child object identifier values. The
     * children are ordered by their value, not necessarily in the
     * order in which they appear in the original MIB file.
     *
     * @return the child object identifier values
     *
     * @since 2.3
     */
    public ObjectIdentifierValue[] getAllChildren() {
        ObjectIdentifierValue[]  values;

        values = new ObjectIdentifierValue[children.size()];
        children.toArray(values);
        return values;
    }

    /**
     * Adds a child component. The children will be inserted in the
     * value order. If a child with the same value has already been
     * added, the new child will be merged with the previous one (if
     * possible) and the resulting child will be returned.
     *
     * @param log            the MIB loader log
     * @param location       the file location on error
     * @param child          the child component
     *
     * @return the child object identifier value added
     *
     * @throws MibException if an irrecoverable conflict between two
     *             children occurred
     */
    private ObjectIdentifierValue addChild(MibLoaderLog log,
                                           FileLocation location,
                                           ObjectIdentifierValue child)
        throws MibException {

        ObjectIdentifierValue  value;
        int                    i = children.size();

        // Insert child in value order, searching backwards to
        // optimize the most common case (ordered insertion)
        while (i > 0) {
            value = (ObjectIdentifierValue) children.get(i - 1);
            if (value.getValue() == child.getValue()) {
                value = value.merge(log, location, child);
                children.set(i - 1, value);
                return value;
            } else if (value.getValue() < child.getValue()) {
                break;
            }
            i--;
        }
        children.add(i, child);
        return child;
    }

    /**
     * Adds all the children from another object identifier value.
     * The children are not copied, but actually transfered from the
     * other value. If this value lacks a name component, it will be
     * set from other value. This operation thus corresponds to a
     * merge and thus can only be made under certain conditions. For
     * example, no child OID:s may have name conflicts. It is assumed
     * that the other OID has the same numerical value as this one.
     *
     * @param log            the MIB loader log
     * @param location       the file location on error
     * @param parent         the OID parent value for the children
     *
     * @throws MibException if an irrecoverable conflict between two
     *             children occurred
     */
    private void addChildren(MibLoaderLog log,
                             FileLocation location,
                             ObjectIdentifierValue parent)
        throws MibException {

        ObjectIdentifierValue  child;
        String                 msg;

        if (name == null) {
            name = parent.name;
        } else if (parent.name != null && !parent.name.equals(name)) {
            msg = "OID component '" + parent.name + "' was previously " +
                  "defined as '" + name + "'";
            if (log == null) {
                throw new MibException(location, msg);
            } else {
                log.addWarning(location, msg);
            }
        }
        if (parent.symbol != null) {
            throw new MibException(location,
                                   "INTERNAL ERROR: OID merge with " +
                                   "symbol reference already set");
        }
        for (int i = 0; i < parent.children.size(); i++) {
            child = (ObjectIdentifierValue) parent.children.get(i);
            child.parent = this;
            addChild(log, location, child);
        }
        parent.children = null;
    }

    /**
     * Merges this object identifier value with another one. One of
     * the two objects will be discarded and the other will be used
     * as the merge destination and returned. Note that this
     * operation modifies both this value and the specified value.
     * The merge can only be made under certain conditions, for
     * example that no child OID:s have name conflicts. It is also
     * assumed that the two OID:s have the same numerical value.
     *
     * @param log            the MIB loader log
     * @param location       the file location on error
     * @param value          the OID value to merge with
     *
     * @return the merged object identifier value
     *
     * @throws MibException if the merge couldn't be performed due to
     *             some conflict or invalid state
     */
    private ObjectIdentifierValue merge(MibLoaderLog log,
                                        FileLocation location,
                                        ObjectIdentifierValue value)
        throws MibException {

        if (symbol != null || (value.symbol == null && children.size() > 0)) {
            addChildren(log, location, value);
            return this;
        } else {
            value.addChildren(log, location, this);
            return value;
        }
    }

    /**
     * Returns a string representation of this value. The string will
     * contain the full numeric object identifier value with each
     * component separated with a dot ('.').
     *
     * @return a string representation of this value
     */
    public Object toObject() {
        return toString();
    }

    /**
     * Returns a string representation of this value. The string will
     * contain the full numeric object identifier value with each
     * component separated with a dot ('.').
     *
     * @return a string representation of this value
     */
    public String toString() {
        StringBuffer  buffer;

        if (cachedNumericValue == null) {
            buffer = new StringBuffer();
            if (parent != null) {
                buffer.append(parent.toString());
                buffer.append(".");
            }
            buffer.append(value);
            cachedNumericValue = buffer.toString();
        }
        return cachedNumericValue;
    }

    /**
     * Returns a detailed string representation of this value. The
     * string will contain the full numeric object identifier value
     * with optional names for each component.
     *
     * @return a detailed string representation of this value
     */
    public String toDetailString() {
        StringBuffer  buffer = new StringBuffer();

        if (parent instanceof ObjectIdentifierValue) {
            buffer.append(((ObjectIdentifierValue) parent).toDetailString());
            buffer.append(".");
        }
        if (name == null) {
            buffer.append(value);
        } else {
            buffer.append(name);
            buffer.append("(");
            buffer.append(value);
            buffer.append(")");
        }
        return buffer.toString();
    }

    /**
     * Returns an ASN.1 representation of this value. The string will
     * contain references to any parent OID value that can be found.
     *
     * @return an ASN.1 representation of this value
     *
     * @since 2.6
     */
    public String toAsn1String() {
        StringBuffer           buffer = new StringBuffer();
        ObjectIdentifierValue  ref;

        if (parent instanceof ObjectIdentifierValue) {
            ref = (ObjectIdentifierValue) parent;
            if (ref.getSymbol() == null) {
                buffer.append(ref.toAsn1String());
            } else {
                buffer.append(ref.getSymbol().getName());
            }
            buffer.append(" ");
        }
        if (name == null || getSymbol() != null) {
            buffer.append(value);
        } else {
            buffer.append(name);
            buffer.append("(");
            buffer.append(value);
            buffer.append(")");
        }
        return buffer.toString();
    }
}
TOP

Related Classes of net.percederberg.mibble.value.ObjectIdentifierValue

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.