/* * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ 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 {@code HashAttributeSet} provides an {@code AttributeSet} * implementation with characteristics of a hash map. * * @author Alan Kaminsky */ public class HashAttributeSet implements AttributeSet, Serializable { /** * Use serialVersionUID from JDK 1.4 for interoperability. */ 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 {@code HashMap} used by the implementation. The serialised form doesn't * include this instance variable. */ private transient HashMap, Attribute> attrMap = new HashMap<>(); /** * Write the instance to a stream (ie serialize the object). * * @param s the output stream * @throws IOException if an I/O exception has occurred * @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). * * @param s the input stream * @throws ClassNotFoundException if the class is not found * @throws IOException if an I/O exception has occurred */ 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 * @throws NullPointerException if {@code attribute} is {@code 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} 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 * {@code null}, an empty attribute set is constructed. * @throws NullPointerException if any element of {@code attributes} is * {@code 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 {@code 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. * @throws NullPointerException if {@code interfaceName} is {@code 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. * @throws NullPointerException if {@code attribute} or * {@code interfaceName} are {@code null} * @throws ClassCastException if {@code attribute} is not an instance of * {@code interfaceName} */ 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} 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 * {@code 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. * @throws NullPointerException if {@code interfaceName} is {@code null}, or * if any element of {@code attributes} is {@code null} * @throws ClassCastException if any element of {@code attributes} is not an * instance of {@code interfaceName} */ 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 * {@code 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. * @throws ClassCastException if any element of {@code attributes} is not an * instance of {@code interfaceName} */ 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 {@code null} 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 Class Class} that implements * interface {@link Attribute Attribute}. * @return the attribute value in the given attribute category contained in * this attribute set, or {@code null} if this attribute set does * not contain any attribute value in the given attribute category * @throws NullPointerException if the {@code category} is {@code null} * @throws ClassCastException if the {@code category} is not a * {@link Class Class} that implements interface * {@link Attribute Attribute} */ public Attribute get(Class category) { return 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 {@code true} 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 if the {@code attribute} is {@code null} * @throws UnmodifiableSetException if this attribute set does not support * the {@code add()} 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} is {@code null}, then {@code remove()} does * nothing and returns {@code false}. * * @param category attribute category to be removed from this attribute set * @return {@code true} 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 if this attribute set does not support * the {@code remove()} 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} is {@code null}, then {@code remove()} does nothing and * returns {@code false}. * * @param attribute attribute value to be removed from this attribute set * @return {@code true} 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 if this attribute set does not support * the {@code remove()} operation */ public boolean remove(Attribute attribute) { return attribute != null && attrMap.remove(attribute.getCategory()) != null; } /** * Returns {@code true} if this attribute set contains an attribute for the * specified category. * * @param category whose presence in this attribute set is to be tested * @return {@code true} 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 {@code true} if this attribute set contains the given attribute. * * @param attribute value whose presence in this attribute set is to be * tested * @return {@code true} 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.getCategory())); } /** * Adds all of the elements in the specified set to this attribute. The * outcome is the same as if the {@link #add(Attribute) add(Attribute)} * operation had been applied to this attribute set successively with each * element from the specified set. The behavior of the * {@code addAll(AttributeSet)} operation is unspecified if the specified * set is modified while the operation is in progress. *

* If the {@code addAll(AttributeSet)} 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 {@code true} if this attribute set changed as a result of the * call * @throws UnmodifiableSetException if this attribute set does not support * the {@code addAll(AttributeSet)} method * @throws NullPointerException if some element in the specified set is * {@code null}, or the set is {@code null} * @see #add(Attribute) */ public boolean addAll(AttributeSet attributes) { Attribute []attrs = attributes.toArray(); boolean result = false; for (int i=0; i