Path: blob/master/src/java.desktop/share/classes/javax/print/attribute/HashAttributeSet.java
41159 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.print.attribute;2627import java.io.IOException;28import java.io.ObjectInputStream;29import java.io.ObjectOutputStream;30import java.io.Serial;31import java.io.Serializable;32import java.util.HashMap;3334/**35* Class {@code HashAttributeSet} provides an {@code AttributeSet}36* implementation with characteristics of a hash map.37*38* @author Alan Kaminsky39*/40public class HashAttributeSet implements AttributeSet, Serializable {4142/**43* Use serialVersionUID from JDK 1.4 for interoperability.44*/45@Serial46private static final long serialVersionUID = 5311560590283707917L;4748/**49* The interface of which all members of this attribute set must be an50* instance. It is assumed to be interface {@link Attribute Attribute} or a51* subinterface thereof.52*53* @serial54*/55private Class<?> myInterface;5657/**58* A {@code HashMap} used by the implementation. The serialised form doesn't59* include this instance variable.60*/61private transient HashMap<Class<?>, Attribute> attrMap = new HashMap<>();6263/**64* Write the instance to a stream (ie serialize the object).65*66* @param s the output stream67* @throws IOException if an I/O exception has occurred68* @serialData The serialized form of an attribute set explicitly writes the69* number of attributes in the set, and each of the attributes.70* This does not guarantee equality of serialized forms since71* the order in which the attributes are written is not defined.72*/73@Serial74private void writeObject(ObjectOutputStream s) throws IOException {7576s.defaultWriteObject();77Attribute [] attrs = toArray();78s.writeInt(attrs.length);79for (int i = 0; i < attrs.length; i++) {80s.writeObject(attrs[i]);81}82}8384/**85* Reconstitute an instance from a stream that is, deserialize it).86*87* @param s the input stream88* @throws ClassNotFoundException if the class is not found89* @throws IOException if an I/O exception has occurred90*/91@Serial92private void readObject(ObjectInputStream s)93throws ClassNotFoundException, IOException {9495s.defaultReadObject();96attrMap = new HashMap<>();97int count = s.readInt();98Attribute attr;99for (int i = 0; i < count; i++) {100attr = (Attribute)s.readObject();101add(attr);102}103}104105/**106* Construct a new, empty attribute set.107*/108public HashAttributeSet() {109this(Attribute.class);110}111112/**113* Construct a new attribute set, initially populated with the given114* attribute.115*116* @param attribute attribute value to add to the set117* @throws NullPointerException if {@code attribute} is {@code null}118*/119public HashAttributeSet(Attribute attribute) {120this (attribute, Attribute.class);121}122123/**124* Construct a new attribute set, initially populated with the values from125* the given array. The new attribute set is populated by adding the126* elements of {@code attributes} array to the set in sequence, starting at127* index 0. Thus, later array elements may replace earlier array elements if128* the array contains duplicate attribute values or attribute categories.129*130* @param attributes array of attribute values to add to the set. If131* {@code null}, an empty attribute set is constructed.132* @throws NullPointerException if any element of {@code attributes} is133* {@code null}134*/135public HashAttributeSet(Attribute[] attributes) {136this (attributes, Attribute.class);137}138139/**140* Construct a new attribute set, initially populated with the values from141* the given set.142*143* @param attributes set of attributes from which to initialise this set.144* If {@code null}, an empty attribute set is constructed.145*/146public HashAttributeSet(AttributeSet attributes) {147this (attributes, Attribute.class);148}149150/**151* Construct a new, empty attribute set, where the members of the attribute152* set are restricted to the given interface.153*154* @param interfaceName the interface of which all members of this155* attribute set must be an instance. It is assumed to be interface156* {@link Attribute Attribute} or a subinterface thereof.157* @throws NullPointerException if {@code interfaceName} is {@code null}158*/159protected HashAttributeSet(Class<?> interfaceName) {160if (interfaceName == null) {161throw new NullPointerException("null interface");162}163myInterface = interfaceName;164}165166/**167* Construct a new attribute set, initially populated with the given168* attribute, where the members of the attribute set are restricted to the169* given interface.170*171* @param attribute attribute value to add to the set172* @param interfaceName the interface of which all members of this173* attribute set must be an instance. It is assumed to be interface174* {@link Attribute Attribute} or a subinterface thereof.175* @throws NullPointerException if {@code attribute} or176* {@code interfaceName} are {@code null}177* @throws ClassCastException if {@code attribute} is not an instance of178* {@code interfaceName}179*/180protected HashAttributeSet(Attribute attribute, Class<?> interfaceName) {181if (interfaceName == null) {182throw new NullPointerException("null interface");183}184myInterface = interfaceName;185add (attribute);186}187188/**189* Construct a new attribute set, where the members of the attribute set are190* restricted to the given interface. The new attribute set is populated by191* adding the elements of {@code attributes} array to the set in sequence,192* starting at index 0. Thus, later array elements may replace earlier array193* elements if the array contains duplicate attribute values or attribute194* categories.195*196* @param attributes array of attribute values to add to the set. If197* {@code null}, an empty attribute set is constructed.198* @param interfaceName the interface of which all members of this199* attribute set must be an instance. It is assumed to be interface200* {@link Attribute Attribute} or a subinterface thereof.201* @throws NullPointerException if {@code interfaceName} is {@code null}, or202* if any element of {@code attributes} is {@code null}203* @throws ClassCastException if any element of {@code attributes} is not an204* instance of {@code interfaceName}205*/206protected HashAttributeSet(Attribute[] attributes, Class<?> interfaceName) {207if (interfaceName == null) {208throw new NullPointerException("null interface");209}210myInterface = interfaceName;211int n = attributes == null ? 0 : attributes.length;212for (int i = 0; i < n; ++ i) {213add (attributes[i]);214}215}216217/**218* Construct a new attribute set, initially populated with the values from219* the given set where the members of the attribute set are restricted to220* the given interface.221*222* @param attributes set of attribute values to initialise the set. If223* {@code null}, an empty attribute set is constructed.224* @param interfaceName The interface of which all members of this225* attribute set must be an instance. It is assumed to be interface226* {@link Attribute Attribute} or a subinterface thereof.227* @throws ClassCastException if any element of {@code attributes} is not an228* instance of {@code interfaceName}229*/230protected HashAttributeSet(AttributeSet attributes, Class<?> interfaceName) {231myInterface = interfaceName;232if (attributes != null) {233Attribute[] attribArray = attributes.toArray();234int n = attribArray == null ? 0 : attribArray.length;235for (int i = 0; i < n; ++ i) {236add (attribArray[i]);237}238}239}240241/**242* Returns the attribute value which this attribute set contains in the243* given attribute category. Returns {@code null} if this attribute set does244* not contain any attribute value in the given attribute category.245*246* @param category attribute category whose associated attribute value is247* to be returned. It must be a {@link Class Class} that implements248* interface {@link Attribute Attribute}.249* @return the attribute value in the given attribute category contained in250* this attribute set, or {@code null} if this attribute set does251* not contain any attribute value in the given attribute category252* @throws NullPointerException if the {@code category} is {@code null}253* @throws ClassCastException if the {@code category} is not a254* {@link Class Class} that implements interface255* {@link Attribute Attribute}256*/257public Attribute get(Class<?> category) {258return attrMap.get(AttributeSetUtilities.259verifyAttributeCategory(category,260Attribute.class));261}262263/**264* Adds the specified attribute to this attribute set if it is not already265* present, first removing any existing in the same attribute category as266* the specified attribute value.267*268* @param attribute attribute value to be added to this attribute set269* @return {@code true} if this attribute set changed as a result of the270* call, i.e., the given attribute value was not already a member of271* this attribute set272* @throws NullPointerException if the {@code attribute} is {@code null}273* @throws UnmodifiableSetException if this attribute set does not support274* the {@code add()} operation275*/276public boolean add(Attribute attribute) {277Object oldAttribute =278attrMap.put(attribute.getCategory(),279AttributeSetUtilities.280verifyAttributeValue(attribute, myInterface));281return (!attribute.equals(oldAttribute));282}283284/**285* Removes any attribute for this category from this attribute set if286* present. If {@code category} is {@code null}, then {@code remove()} does287* nothing and returns {@code false}.288*289* @param category attribute category to be removed from this attribute set290* @return {@code true} if this attribute set changed as a result of the291* call, i.e., the given attribute category had been a member of292* this attribute set293* @throws UnmodifiableSetException if this attribute set does not support294* the {@code remove()} operation295*/296public boolean remove(Class<?> category) {297return298category != null &&299AttributeSetUtilities.300verifyAttributeCategory(category, Attribute.class) != null &&301attrMap.remove(category) != null;302}303304/**305* Removes the specified attribute from this attribute set if present. If306* {@code attribute} is {@code null}, then {@code remove()} does nothing and307* returns {@code false}.308*309* @param attribute attribute value to be removed from this attribute set310* @return {@code true} if this attribute set changed as a result of the311* call, i.e., the given attribute value had been a member of this312* attribute set313* @throws UnmodifiableSetException if this attribute set does not support314* the {@code remove()} operation315*/316public boolean remove(Attribute attribute) {317return318attribute != null &&319attrMap.remove(attribute.getCategory()) != null;320}321322/**323* Returns {@code true} if this attribute set contains an attribute for the324* specified category.325*326* @param category whose presence in this attribute set is to be tested327* @return {@code true} if this attribute set contains an attribute value328* for the specified category329*/330public boolean containsKey(Class<?> category) {331return332category != null &&333AttributeSetUtilities.334verifyAttributeCategory(category, Attribute.class) != null &&335attrMap.get(category) != null;336}337338/**339* Returns {@code true} if this attribute set contains the given attribute.340*341* @param attribute value whose presence in this attribute set is to be342* tested343* @return {@code true} if this attribute set contains the given attribute344* value345*/346public boolean containsValue(Attribute attribute) {347return348attribute != null &&349attribute instanceof Attribute &&350attribute.equals(attrMap.get(attribute.getCategory()));351}352353/**354* Adds all of the elements in the specified set to this attribute. The355* outcome is the same as if the {@link #add(Attribute) add(Attribute)}356* operation had been applied to this attribute set successively with each357* element from the specified set. The behavior of the358* {@code addAll(AttributeSet)} operation is unspecified if the specified359* set is modified while the operation is in progress.360* <p>361* If the {@code addAll(AttributeSet)} operation throws an exception, the362* effect on this attribute set's state is implementation dependent;363* elements from the specified set before the point of the exception may or364* may not have been added to this attribute set.365*366* @param attributes whose elements are to be added to this attribute set367* @return {@code true} if this attribute set changed as a result of the368* call369* @throws UnmodifiableSetException if this attribute set does not support370* the {@code addAll(AttributeSet)} method371* @throws NullPointerException if some element in the specified set is372* {@code null}, or the set is {@code null}373* @see #add(Attribute)374*/375public boolean addAll(AttributeSet attributes) {376377Attribute []attrs = attributes.toArray();378boolean result = false;379for (int i=0; i<attrs.length; i++) {380Attribute newValue =381AttributeSetUtilities.verifyAttributeValue(attrs[i],382myInterface);383Object oldValue = attrMap.put(newValue.getCategory(), newValue);384result = (! newValue.equals(oldValue)) || result;385}386return result;387}388389/**390* Returns the number of attributes in this attribute set. If this attribute391* set contains more than {@code Integer.MAX_VALUE} elements, returns392* {@code Integer.MAX_VALUE}.393*394* @return the number of attributes in this attribute set395*/396public int size() {397return attrMap.size();398}399400/**401* Returns an array of the attributes contained in this set.402*403* @return the attributes contained in this set as an array, zero length if404* the {@code AttributeSet} is empty405*/406public Attribute[] toArray() {407Attribute []attrs = new Attribute[size()];408attrMap.values().toArray(attrs);409return attrs;410}411412/**413* Removes all attributes from this attribute set.414*415* @throws UnmodifiableSetException if this attribute set does not support416* the {@code clear()} operation417*/418public void clear() {419attrMap.clear();420}421422/**423* Returns {@code true} if this attribute set contains no attributes.424*425* @return {@code true} if this attribute set contains no attributes426*/427public boolean isEmpty() {428return attrMap.isEmpty();429}430431/**432* Compares the specified object with this attribute set for equality.433* Returns {@code true} if the given object is also an attribute set and the434* two attribute sets contain the same attribute category-attribute value435* mappings. This ensures that the {@code equals()} method works properly436* across different implementations of the {@code AttributeSet} interface.437*438* @param object to be compared for equality with this attribute set439* @return {@code true} if the specified object is equal to this attribute440* set441*/442public boolean equals(Object object) {443if (object == null || !(object instanceof AttributeSet)) {444return false;445}446447AttributeSet aset = (AttributeSet)object;448if (aset.size() != size()) {449return false;450}451452Attribute[] attrs = toArray();453for (int i=0;i<attrs.length; i++) {454if (!aset.containsValue(attrs[i])) {455return false;456}457}458return true;459}460461/**462* Returns the hash code value for this attribute set. The hash code of an463* attribute set is defined to be the sum of the hash codes of each entry in464* the {@code AttributeSet}. This ensures that {@code t1.equals(t2)} implies465* that {@code t1.hashCode()==t2.hashCode()} for any two attribute sets466* {@code t1} and {@code t2}, as required by the general contract of467* {@link Object#hashCode() Object.hashCode()}.468*469* @return the hash code value for this attribute set470*/471public int hashCode() {472int hcode = 0;473Attribute[] attrs = toArray();474for (int i=0;i<attrs.length; i++) {475hcode += attrs[i].hashCode();476}477return hcode;478}479}480481482