ddf.catalog.data.AttributeImpl.java Source code

Java tutorial

Introduction

Here is the source code for ddf.catalog.data.AttributeImpl.java

Source

/**
 * Copyright (c) Codice Foundation
 *
 * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either
 * version 3 of the License, or any later version.
 *
 * This program 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 Lesser General Public License for more details. A copy of the GNU Lesser General Public License is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 *
 **/
package ddf.catalog.data;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.builder.ToStringBuilder;

/**
 * A simple implementation of {@link Attribute}.
 * 
 * <p>
 * This class is {@link Serializable} and care should be taken with
 * compatibility if changes are made.
 * </p>
 * 
 * <p>
 * For what constitutes a compatible change in serialization, see <a href=
 * "http://docs.oracle.com/javase/6/docs/platform/serialization/spec/version.html#6678"
 * >Sun's Guidelines</a>.
 * </p>
 * 
 * @author ddf.isgs@lmco.com
 * 
 */
public class AttributeImpl implements Attribute {

    private static final long serialVersionUID = 1L;

    /**
     * Nontransient field that holds the name of the {@link Attribute}.  
     * @serial
     */
    protected String name;

    private transient List<Serializable> values;

    @Override
    public String getName() {
        return name;
    }

    @Override
    public Serializable getValue() {
        if (!values.isEmpty())
            return values.get(0);
        else
            return null;
    }

    /**
     * Constructor
     * 
     * @param name
     *            - the name of this {@link Attribute}
     * @param value
     *            - the value of this {@link Attribute}
     */
    public AttributeImpl(String name, Serializable value) {
        /*
         * If any defensive logic is added to this constructor, then that logic
         * should be reflected in the deserialization (readObject()) of this
         * object so that the integrity of a serialized object is maintained.
         * For instance, if a null check is added in the constructor, the same
         * check should be added in the readObject() method.
         */
        this.name = name;
        this.values = createPopulatedList(value);
    }

    private List<Serializable> createPopulatedList(Serializable value) {
        List<Serializable> list = new LinkedList<Serializable>();
        list.add(value);
        return list;
    }

    @Override
    public List<Serializable> getValues() {
        return values;
    }

    /**
     * Adds a value to this {@link Attribute}
     * 
     * @param value
     *            the value to add
     */
    public void addValue(Serializable value) {
        values.add(value);
    }

    /**
     * Clears all {@link Attribute} values
     */
    public void clearValues() {
        values.clear();
    }

    /**
     * Serializes this {@link AttributeImpl} instance.
     * 
     * @serialData First, all non-transient fields are written out by the
     *             default Java serialization implementation
     *             (ObjectInputStream.defaultWriteObject()). Then the number of
     *             "value" objects is written out as an ({@code int}). After the
     *             number of objects, each "value" object is written out (each
     *             as {@code Serializable}).
     * @param s
     *            - the {@link ObjectOutputStream} which contains the object to
     *            be serialized
     * @throws IOException
     */
    private void writeObject(ObjectOutputStream s) throws IOException {

        /*
         * defaultWriteObject() is invoked for greater flexibility and
         * compatibility. See the *Serialization Note* in MetacardImpl's class
         * Javadoc.
         */
        s.defaultWriteObject();

        s.writeInt(values.size());

        for (Serializable ser : values) {
            s.writeObject(ser);
        }
    }

    /**
     * Deserializes this {@link AttributeImpl}'s instance.
     * 
     * @param stream
     *            the {@link ObjectInputStream} that contains the bytes of the
     *            object
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {

        /*
         * defaultReadObject() is invoked for greater flexibility and
         * compatibility. See the *Serialization Note* in MetacardImpl's class
         * Javadoc.
         */
        s.defaultReadObject();

        int numElements = s.readInt();

        validateNonEmpty(numElements);

        values = new LinkedList<Serializable>();
        for (int i = 0; i < numElements; i++) {
            values.add((Serializable) s.readObject());
        }

        validateUntampered(numElements);

    }

    private void validateUntampered(int numElements) throws InvalidObjectException {
        // Invariant: When the object was serialized, the integer written to
        // disk matched the number of value objects written to disk.
        if (values.size() != numElements) {
            throw new InvalidObjectException(
                    "Corrupt object: written number of values does not match actual number of values.");
        }
    }

    private void validateNonEmpty(int numElements) throws InvalidObjectException {
        // Invariant: This implementation does not allow an Attribute object
        // with no values
        if (numElements == 0) {
            throw new InvalidObjectException(
                    "Cannot construct " + this.getClass().getName() + " object without any values.");
        }
    }

    @Override
    public String toString() {
        return getClass().getName() + " {name=" + this.name + ", values=" + this.values + "}";
    }
}