FileDocCategorySizeDatePackage
HashAttributeSet.javaAPI DocJava SE 5 API18256Fri Aug 26 14:57:42 BST 2005javax.print.attribute

HashAttributeSet.java

/*
 * @(#)HashAttributeSet.java	1.12 04/05/05
 *
 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package javax.print.attribute;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;

/**
 * Class HashAttributeSet provides an <code>AttributeSet</code>
 * implementation with characteristics of a hash map.
 * <P>
 *
 * @author  Alan Kaminsky
 */
public class HashAttributeSet implements AttributeSet, Serializable {

    private static final long serialVersionUID = 5311560590283707917L;

    /**
     * The interface of which all members of this attribute set must be an 
     * instance. It is assumed to be interface {@link Attribute Attribute}
     * or a subinterface thereof. 
     * @serial
     */
    private Class myInterface;

    /*
     * A HashMap used by the implementation.
     * The serialised form doesn't include this instance variable.
     */
    private transient HashMap attrMap = new HashMap();

    /**
     * Write the instance to a stream (ie serialize the object)
     *
     * @serialData
     * The serialized form of an attribute set explicitly writes the
     * number of attributes in the set, and each of the attributes.
     * This does not guarantee equality of serialized forms since
     * the order in which the attributes are written is not defined.
     */
    private void writeObject(ObjectOutputStream s) throws IOException {

	s.defaultWriteObject();
	Attribute [] attrs = toArray();
	s.writeInt(attrs.length);
	for (int i = 0; i < attrs.length; i++) {
	    s.writeObject(attrs[i]);
	}
    }

    /**
     * Reconstitute an instance from a stream that is, deserialize it).
     */
    private void readObject(ObjectInputStream s)
	throws ClassNotFoundException, IOException {
	
	s.defaultReadObject();
	attrMap = new HashMap();
	int count = s.readInt();
	Attribute attr;
	for (int i = 0; i < count; i++) {
	    attr = (Attribute)s.readObject();
	    add(attr);
	}	
    }

    /**
     * Construct a new, empty attribute set. 
     */
    public HashAttributeSet() {
	this(Attribute.class);
    }

    /**
     * Construct a new attribute set,
     * initially populated with the given attribute. 
     *
     * @param  attribute  Attribute value to add to the set.
     *
     * @exception  NullPointerException
     *     (unchecked exception) Thrown if <CODE>attribute</CODE> is null.
     */
    public HashAttributeSet(Attribute attribute) {
	this (attribute, Attribute.class);
    }

    /**
     * Construct a new attribute set,
     * initially populated with the values from the 
     * given array. The new attribute set is populated by 
     * adding the elements of <CODE>attributes</CODE> array to the set in 
     * sequence, starting at index 0. Thus, later array elements may replace 
     * earlier array elements if the array contains duplicate attribute 
     * values or attribute categories. 
     *
     * @param  attributes  Array of attribute values to add to the set. 
     *                    If null, an empty attribute set is constructed.
     *
     * @exception  NullPointerException
     *     (unchecked exception) Thrown if any element of
     *     <CODE>attributes</CODE> is null. 
     */
    public HashAttributeSet(Attribute[] attributes) {
	this (attributes, Attribute.class);
    }

    /**
     * Construct a new attribute set,
     * initially populated with the values from the  given set.
     *
     * @param  attributes Set of attributes from which to initialise this set.
     *                 If null, an empty attribute set is constructed.
     *
     */
    public HashAttributeSet(AttributeSet attributes) {
	this (attributes, Attribute.class);
    }
    
    /**
     * Construct a new, empty attribute set, where the members of
     * the attribute set are restricted to the given interface. 
     *
     * @param  interfaceName  The interface of which all members of this
     *                     attribute set must be an instance. It is assumed to 
     *                     be interface {@link Attribute Attribute} or a 
     *                     subinterface thereof.
     * @exception NullPointerException if interfaceName is null.
     */
    protected HashAttributeSet(Class<?> interfaceName) {
	if (interfaceName == null) {
	    throw new NullPointerException("null interface");
	}
	myInterface = interfaceName;
    }

    /**
     * Construct a new attribute set, initially populated with the given
     * attribute, where the members of the attribute set are restricted to the
     * given interface. 
     *
     * @param  attribute      Attribute value to add to the set.
     * @param  interfaceName  The interface of which all members of this
     *                    attribute set must be an instance. It is assumed to 
     *                    be interface {@link Attribute Attribute} or a 
     *                    subinterface thereof. 
     *
     * @exception  NullPointerException
     *     (unchecked exception) Thrown if <CODE>attribute</CODE> is null.
     * @exception NullPointerException if interfaceName is null.
     * @exception  ClassCastException
     *     (unchecked exception) Thrown if <CODE>attribute</CODE> is not an 
     *     instance of <CODE>interfaceName</CODE>. 
     */
    protected HashAttributeSet(Attribute attribute, Class<?> interfaceName) {
	if (interfaceName == null) {
	    throw new NullPointerException("null interface");
	}
	myInterface = interfaceName;
	add (attribute);
    }

    /**
     * Construct a new attribute set, where the members of the attribute
     * set are restricted to the given interface.
     * The new attribute set is populated 
     * by adding the elements of <CODE>attributes</CODE> array to the set in 
     * sequence, starting at index 0. Thus, later array elements may replace 
     * earlier array elements if the array contains duplicate attribute 
     * values or attribute categories. 
     *
     * @param  attributes Array of attribute values to add to the set. If
     *                    null, an empty attribute set is constructed.
     * @param  interfaceName  The interface of which all members of this
     *                    attribute set must be an instance. It is assumed to 
     *                    be interface {@link Attribute Attribute} or a 
     *                    subinterface thereof. 
     *
     * @exception  NullPointerException
     *     (unchecked exception) Thrown if any element of
     * <CODE>attributes</CODE> is null.
     * @exception NullPointerException if interfaceName is null.
     * @exception  ClassCastException
     *     (unchecked exception) Thrown if any element of
     * <CODE>attributes</CODE> is not an instance of
     * <CODE>interfaceName</CODE>. 
     */
    protected HashAttributeSet(Attribute[] attributes, Class<?> interfaceName) {
	if (interfaceName == null) {
	    throw new NullPointerException("null interface");
	}
	myInterface = interfaceName;
	int n = attributes == null ? 0 : attributes.length;
	for (int i = 0; i < n; ++ i) {
	    add (attributes[i]);
	}
    }

    /**
     * Construct a new attribute set, initially populated with the
     * values from the  given set where the members of the attribute
     * set are restricted to the given interface.
     *
     * @param  attributes set of attribute values to initialise the set. If
     *                    null, an empty attribute set is constructed.
     * @param  interfaceName  The interface of which all members of this
     *                    attribute set must be an instance. It is assumed to 
     *                    be interface {@link Attribute Attribute} or a 
     *                    subinterface thereof. 
     *
     * @exception  ClassCastException
     *     (unchecked exception) Thrown if any element of
     * <CODE>attributes</CODE> is not an instance of
     * <CODE>interfaceName</CODE>. 
     */
    protected HashAttributeSet(AttributeSet attributes, Class<?> interfaceName) {
      myInterface = interfaceName;
      if (attributes != null) {
	Attribute[] attribArray = attributes.toArray();	    
	int n = attribArray == null ? 0 : attribArray.length;
	for (int i = 0; i < n; ++ i) {
	  add (attribArray[i]);
	}
      }
    }

    /**
     * Returns the attribute value which this attribute set contains in the 
     * given attribute category. Returns <tt>null</tt> if this attribute set 
     * does not contain any attribute value in the given attribute category.
     *
     * @param  category  Attribute category whose associated attribute value
     *                   is to be returned. It must be a
     *                   {@link java.lang.Class Class}
     *                   that implements interface {@link Attribute 
     *                   Attribute}. 
     *
     * @return  The attribute value in the given attribute category contained
     *          in this attribute set, or <tt>null</tt> if this attribute set
     *          does not contain any attribute value in the given attribute
     *          category. 
     * 
     * @throws  NullPointerException
     *     (unchecked exception) Thrown if the <CODE>category</CODE> is null.
     * @throws  ClassCastException
     *     (unchecked exception) Thrown if the <CODE>category</CODE> is not a 
     *     {@link java.lang.Class Class} that implements interface {@link 
     *     Attribute Attribute}. 
     */    
    public Attribute get(Class<?> category) {
	return (Attribute)
	    attrMap.get(AttributeSetUtilities.
			verifyAttributeCategory(category,
						Attribute.class));
    }

    /**
     * Adds the specified attribute to this attribute set if it is not 
     * already present, first removing any existing in the same
     * attribute category as the specified attribute value. 
     *
     * @param  attribute  Attribute value to be added to this attribute set.
     *
     * @return  <tt>true</tt> if this attribute set changed as a result of the
     *          call, i.e., the given attribute value was not already a 
     *          member of this attribute set. 
     * 
     * @throws  NullPointerException
     *    (unchecked exception) Thrown if the <CODE>attribute</CODE> is null. 
     * @throws  UnmodifiableSetException
     *    (unchecked exception) Thrown if this attribute set does not support 
     *     the <CODE>add()</CODE> operation. 
     */
    public boolean add(Attribute attribute) {
	Object oldAttribute = 
	    attrMap.put(attribute.getCategory(),
			AttributeSetUtilities.
			verifyAttributeValue(attribute, myInterface));
	return (!attribute.equals(oldAttribute));
    }

    /**
     * Removes any attribute for this category from this attribute set if  
     * present. If <CODE>category</CODE> is null, then 
     * <CODE>remove()</CODE> does nothing and returns <tt>false</tt>. 
     *
     * @param  category Attribute category to be removed from this
     *                  attribute set.
     *
     * @return  <tt>true</tt> if this attribute set changed as a result of the
     *         call, i.e., the given attribute category had been a member of 
     *         this attribute set. 
     * 
     * @throws  UnmodifiableSetException
     *     (unchecked exception) Thrown if this attribute set does not 
     *     support the <CODE>remove()</CODE> operation. 
     */
    public boolean remove(Class<?> category) {
	return
	    category != null &&
	    AttributeSetUtilities.
	    verifyAttributeCategory(category, Attribute.class) != null &&
	    attrMap.remove(category) != null;
    }

    /**
     * Removes the specified attribute from this attribute set if  
     * present. If <CODE>attribute</CODE> is null, then 
     * <CODE>remove()</CODE> does nothing and returns <tt>false</tt>. 
     *
     * @param attribute Attribute value to be removed from this attribute set.
     *
     * @return  <tt>true</tt> if this attribute set changed as a result of the
     *         call, i.e., the given attribute value had been a member of 
     *         this attribute set. 
     * 
     * @throws  UnmodifiableSetException
     *     (unchecked exception) Thrown if this attribute set does not 
     *     support the <CODE>remove()</CODE> operation. 
     */
    public boolean remove(Attribute attribute) {
	return
	    attribute != null &&
	    attrMap.remove(attribute.getCategory()) != null;
    }

    /**
     * Returns <tt>true</tt> if this attribute set contains an 
     * attribute for the specified category.
     *
     * @param  category whose presence in this attribute set is
     *            to be tested.
     *
     * @return  <tt>true</tt> if this attribute set contains an attribute 
     *         value for the specified category.
     */
    public boolean containsKey(Class<?> category) {
	return
	    category != null &&
	    AttributeSetUtilities.
	    verifyAttributeCategory(category, Attribute.class) != null &&
	    attrMap.get(category) != null;
    }

    /**
     * Returns <tt>true</tt> if this attribute set contains the given  
     * attribute.
     *
     * @param  attribute  value whose presence in this attribute set is
     *            to be tested.
     *
     * @return  <tt>true</tt> if this attribute set contains the given 
     *      attribute    value.
     */
    public boolean containsValue(Attribute attribute) {
	return
	   attribute != null &&
	   attribute instanceof Attribute &&
	   attribute.equals(attrMap.get(((Attribute)attribute).getCategory()));
    }

    /**
     * Adds all of the elements in the specified set to this attribute.
     * The outcome is the same as if the
     * {@link #add(Attribute) <CODE>add(Attribute)</CODE>} 
     * operation had been applied to this attribute set successively with 
     * each element from the specified set.
     * The behavior of the <CODE>addAll(AttributeSet)</CODE>
     * operation is unspecified if the specified set is modified while
     * the operation is in progress.
     * <P>
     * If the <CODE>addAll(AttributeSet)</CODE> operation throws an exception,
     * the effect on this attribute set's state is implementation dependent;
     * elements from the specified set before the point of the exception may
     * or may not have been added to this attribute set. 
     *
     * @param  attributes  whose elements are to be added to this attribute 
     *            set.
     *
     * @return  <tt>true</tt> if this attribute set changed as a result of the
     *          call.
     * 
     * @throws  UnmodifiableSetException
     *    (Unchecked exception) Thrown if this attribute set does not 
     *     support the <tt>addAll(AttributeSet)</tt> method. 
     * @throws  NullPointerException
     *     (Unchecked exception) Thrown if some element in the specified 
     *     set is null, or the set is null.
     *
     * @see #add(Attribute)
     */
    public boolean addAll(AttributeSet attributes) {
	
	Attribute []attrs = attributes.toArray();
	boolean result = false;
	for (int i=0; i<attrs.length; i++) {
	    Attribute newValue =
		AttributeSetUtilities.verifyAttributeValue(attrs[i], 
							   myInterface);
	    Object oldValue = attrMap.put(newValue.getCategory(), newValue);
	    result = (! newValue.equals(oldValue)) || result;
	}
	return result;
    }
 
    /**
     * Returns the number of attributes in this attribute set. If this
     * attribute set contains more than <tt>Integer.MAX_VALUE</tt> elements,
     * returns  <tt>Integer.MAX_VALUE</tt>.
     *
     * @return  The number of attributes in this attribute set.
     */
    public int size() {
	return attrMap.size();
    }
    
    /**
     * 
     * @return the Attributes contained in this set as an array, zero length
     * if the AttributeSet is empty.
     */
    public Attribute[] toArray() {
	Attribute []attrs = new Attribute[size()];
	attrMap.values().toArray(attrs);
	return attrs;
    }


    /**
     * Removes all attributes from this attribute set.
     *
     * @throws  UnmodifiableSetException
     *   (unchecked exception) Thrown if this attribute set does not support 
     *     the <CODE>clear()</CODE> operation. 
     */
    public void clear() {
	attrMap.clear();
    }

   /**
     * Returns true if this attribute set contains no attributes.
     *
     * @return true if this attribute set contains no attributes.
     */
    public boolean isEmpty() {
	return attrMap.isEmpty();
    }

    /**
     * Compares the specified object with this attribute set for equality. 
     * Returns <tt>true</tt> if the given object is also an attribute set and 
     * the two attribute sets contain the same attribute category-attribute 
     * value mappings. This ensures that the 
     * <tt>equals()</tt> method works properly across different  
     * implementations of the AttributeSet interface. 
     *
     * @param  object to be compared for equality with this attribute set.
     *
     * @return  <tt>true</tt> if the specified object is equal to this 
     *       attribute   set.
     */
 
    public boolean equals(Object object) {
	if (object == null || !(object instanceof AttributeSet)) {
	    return false;
	}

	AttributeSet aset = (AttributeSet)object;
	if (aset.size() != size()) {
	    return false;
	}

	Attribute[] attrs = toArray();    
	for (int i=0;i<attrs.length; i++) {
	    if (!aset.containsValue(attrs[i])) {
		return false;
	    }
	}
	return true;
    }
    
    /**
     * Returns the hash code value for this attribute set.
     * The hash code of an attribute set is defined to be the sum
     * of the hash codes of each entry in the AttributeSet. 
     * This ensures that <tt>t1.equals(t2)</tt> implies that 
     * <tt>t1.hashCode()==t2.hashCode()</tt> for any two attribute sets 
     * <tt>t1</tt> and <tt>t2</tt>, as required by the general contract of 
     * {@link java.lang.Object#hashCode() <CODE>Object.hashCode()</CODE>}. 
     *
     * @return  The hash code value for this attribute set.
     */
    public int hashCode() {
	int hcode = 0;
	Attribute[] attrs = toArray();    
	for (int i=0;i<attrs.length; i++) {
	    hcode += attrs[i].hashCode();
	}
	return hcode;
    }

}