1 /* 2 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.print.attribute; 27 28 import java.io.IOException; 29 import java.io.ObjectInputStream; 30 import java.io.ObjectOutputStream; 31 import java.io.Serializable; 32 import java.util.HashMap; 33 34 /** 35 * Class HashAttributeSet provides an {@code AttributeSet} 36 * implementation with characteristics of a hash map. 37 * 38 * @author Alan Kaminsky 39 */ 40 public class HashAttributeSet implements AttributeSet, Serializable { 41 42 private static final long serialVersionUID = 5311560590283707917L; 43 44 /** 45 * The interface of which all members of this attribute set must be an 46 * instance. It is assumed to be interface {@link Attribute Attribute} 47 * or a subinterface thereof. 48 * @serial 49 */ 50 private Class<?> myInterface; 51 52 /* 53 * A HashMap used by the implementation. 54 * The serialised form doesn't include this instance variable. 55 */ 56 private transient HashMap<Class<?>, Attribute> attrMap = new HashMap<>(); 57 58 /** 59 * Write the instance to a stream (ie serialize the object) 60 * 61 * @serialData 62 * The serialized form of an attribute set explicitly writes the 63 * number of attributes in the set, and each of the attributes. 64 * This does not guarantee equality of serialized forms since 65 * the order in which the attributes are written is not defined. 66 */ 67 private void writeObject(ObjectOutputStream s) throws IOException { 68 69 s.defaultWriteObject(); 70 Attribute [] attrs = toArray(); 71 s.writeInt(attrs.length); 72 for (int i = 0; i < attrs.length; i++) { 73 s.writeObject(attrs[i]); 74 } 75 } 76 77 /** 78 * Reconstitute an instance from a stream that is, deserialize it). 79 */ 80 private void readObject(ObjectInputStream s) 81 throws ClassNotFoundException, IOException { 82 83 s.defaultReadObject(); 84 attrMap = new HashMap<>(); 85 int count = s.readInt(); 86 Attribute attr; 87 for (int i = 0; i < count; i++) { 88 attr = (Attribute)s.readObject(); 89 add(attr); 90 } 91 } 92 93 /** 94 * Construct a new, empty attribute set. 95 */ 96 public HashAttributeSet() { 97 this(Attribute.class); 98 } 99 100 /** 101 * Construct a new attribute set, 102 * initially populated with the given attribute. 103 * 104 * @param attribute Attribute value to add to the set. 105 * 106 * @exception NullPointerException 107 * (unchecked exception) Thrown if {@code attribute} is null. 108 */ 109 public HashAttributeSet(Attribute attribute) { 110 this (attribute, Attribute.class); 111 } 112 113 /** 114 * Construct a new attribute set, 115 * initially populated with the values from the 116 * given array. The new attribute set is populated by 117 * adding the elements of {@code attributes} array to the set in 118 * sequence, starting at index 0. Thus, later array elements may replace 119 * earlier array elements if the array contains duplicate attribute 120 * values or attribute categories. 121 * 122 * @param attributes Array of attribute values to add to the set. 123 * If null, an empty attribute set is constructed. 124 * 125 * @exception NullPointerException 126 * (unchecked exception) Thrown if any element of 127 * {@code attributes} is null. 128 */ 129 public HashAttributeSet(Attribute[] attributes) { 130 this (attributes, Attribute.class); 131 } 132 133 /** 134 * Construct a new attribute set, 135 * initially populated with the values from the given set. 136 * 137 * @param attributes Set of attributes from which to initialise this set. 138 * If null, an empty attribute set is constructed. 139 * 140 */ 141 public HashAttributeSet(AttributeSet attributes) { 142 this (attributes, Attribute.class); 143 } 144 145 /** 146 * Construct a new, empty attribute set, where the members of 147 * the attribute set are restricted to the given interface. 148 * 149 * @param interfaceName The interface of which all members of this 150 * attribute set must be an instance. It is assumed to 151 * be interface {@link Attribute Attribute} or a 152 * subinterface thereof. 153 * @exception NullPointerException if interfaceName is null. 154 */ 155 protected HashAttributeSet(Class<?> interfaceName) { 156 if (interfaceName == null) { 157 throw new NullPointerException("null interface"); 158 } 159 myInterface = interfaceName; 160 } 161 162 /** 163 * Construct a new attribute set, initially populated with the given 164 * attribute, where the members of the attribute set are restricted to the 165 * given interface. 166 * 167 * @param attribute Attribute value to add to the set. 168 * @param interfaceName The interface of which all members of this 169 * attribute set must be an instance. It is assumed to 170 * be interface {@link Attribute Attribute} or a 171 * subinterface thereof. 172 * 173 * @exception NullPointerException 174 * (unchecked exception) Thrown if {@code attribute} is null. 175 * @exception NullPointerException if interfaceName is null. 176 * @exception ClassCastException 177 * (unchecked exception) Thrown if {@code attribute} is not an 178 * instance of {@code interfaceName}. 179 */ 180 protected HashAttributeSet(Attribute attribute, Class<?> interfaceName) { 181 if (interfaceName == null) { 182 throw new NullPointerException("null interface"); 183 } 184 myInterface = interfaceName; 185 add (attribute); 186 } 187 188 /** 189 * Construct a new attribute set, where the members of the attribute 190 * set are restricted to the given interface. 191 * The new attribute set is populated 192 * by adding the elements of {@code attributes} array to the set in 193 * sequence, starting at index 0. Thus, later array elements may replace 194 * earlier array elements if the array contains duplicate attribute 195 * values or attribute categories. 196 * 197 * @param attributes Array of attribute values to add to the set. If 198 * null, an empty attribute set is constructed. 199 * @param interfaceName The interface of which all members of this 200 * attribute set must be an instance. It is assumed to 201 * be interface {@link Attribute Attribute} or a 202 * subinterface thereof. 203 * 204 * @exception NullPointerException 205 * (unchecked exception) Thrown if any element of 206 * {@code attributes} is null. 207 * @exception NullPointerException if interfaceName is null. 208 * @exception ClassCastException 209 * (unchecked exception) Thrown if any element of 210 * {@code attributes} is not an instance of 211 * {@code interfaceName}. 212 */ 213 protected HashAttributeSet(Attribute[] attributes, Class<?> interfaceName) { 214 if (interfaceName == null) { 215 throw new NullPointerException("null interface"); 216 } 217 myInterface = interfaceName; 218 int n = attributes == null ? 0 : attributes.length; 219 for (int i = 0; i < n; ++ i) { 220 add (attributes[i]); 221 } 222 } 223 224 /** 225 * Construct a new attribute set, initially populated with the 226 * values from the given set where the members of the attribute 227 * set are restricted to the given interface. 228 * 229 * @param attributes set of attribute values to initialise the set. If 230 * null, an empty attribute set is constructed. 231 * @param interfaceName The interface of which all members of this 232 * attribute set must be an instance. It is assumed to 233 * be interface {@link Attribute Attribute} or a 234 * subinterface thereof. 235 * 236 * @exception ClassCastException 237 * (unchecked exception) Thrown if any element of 238 * {@code attributes} is not an instance of 239 * {@code interfaceName}. 240 */ 241 protected HashAttributeSet(AttributeSet attributes, Class<?> interfaceName) { 242 myInterface = interfaceName; 243 if (attributes != null) { 244 Attribute[] attribArray = attributes.toArray(); 245 int n = attribArray == null ? 0 : attribArray.length; 246 for (int i = 0; i < n; ++ i) { 247 add (attribArray[i]); 248 } 249 } 250 } 251 252 /** 253 * Returns the attribute value which this attribute set contains in the 254 * given attribute category. Returns {@code null} if this attribute set 255 * does not contain any attribute value in the given attribute category. 256 * 257 * @param category Attribute category whose associated attribute value 258 * is to be returned. It must be a 259 * {@link java.lang.Class Class} 260 * that implements interface {@link Attribute 261 * Attribute}. 262 * 263 * @return The attribute value in the given attribute category contained 264 * in this attribute set, or {@code null} if this attribute set 265 * does not contain any attribute value in the given attribute 266 * category. 267 * 268 * @throws NullPointerException 269 * (unchecked exception) Thrown if the {@code category} is null. 270 * @throws ClassCastException 271 * (unchecked exception) Thrown if the {@code category} is not a 272 * {@link java.lang.Class Class} that implements interface {@link 273 * Attribute Attribute}. 274 */ 275 public Attribute get(Class<?> category) { 276 return attrMap.get(AttributeSetUtilities. 277 verifyAttributeCategory(category, 278 Attribute.class)); 279 } 280 281 /** 282 * Adds the specified attribute to this attribute set if it is not 283 * already present, first removing any existing in the same 284 * attribute category as the specified attribute value. 285 * 286 * @param attribute Attribute value to be added to this attribute set. 287 * 288 * @return {@code true} if this attribute set changed as a result of the 289 * call, i.e., the given attribute value was not already a 290 * member of this attribute set. 291 * 292 * @throws NullPointerException 293 * (unchecked exception) Thrown if the {@code attribute} is null. 294 * @throws UnmodifiableSetException 295 * (unchecked exception) Thrown if this attribute set does not support 296 * the {@code add()} operation. 297 */ 298 public boolean add(Attribute attribute) { 299 Object oldAttribute = 300 attrMap.put(attribute.getCategory(), 301 AttributeSetUtilities. 302 verifyAttributeValue(attribute, myInterface)); 303 return (!attribute.equals(oldAttribute)); 304 } 305 306 /** 307 * Removes any attribute for this category from this attribute set if 308 * present. If {@code category} is null, then 309 * {@code remove()} does nothing and returns {@code false}. 310 * 311 * @param category Attribute category to be removed from this 312 * attribute set. 313 * 314 * @return {@code true} if this attribute set changed as a result of the 315 * call, i.e., the given attribute category had been a member of 316 * this attribute set. 317 * 318 * @throws UnmodifiableSetException 319 * (unchecked exception) Thrown if this attribute set does not 320 * support the {@code remove()} operation. 321 */ 322 public boolean remove(Class<?> category) { 323 return 324 category != null && 325 AttributeSetUtilities. 326 verifyAttributeCategory(category, Attribute.class) != null && 327 attrMap.remove(category) != null; 328 } 329 330 /** 331 * Removes the specified attribute from this attribute set if 332 * present. If {@code attribute} is null, then 333 * {@code remove()} does nothing and returns {@code false}. 334 * 335 * @param attribute Attribute value to be removed from this attribute set. 336 * 337 * @return {@code true} if this attribute set changed as a result of the 338 * call, i.e., the given attribute value had been a member of 339 * this attribute set. 340 * 341 * @throws UnmodifiableSetException 342 * (unchecked exception) Thrown if this attribute set does not 343 * support the {@code remove()} operation. 344 */ 345 public boolean remove(Attribute attribute) { 346 return 347 attribute != null && 348 attrMap.remove(attribute.getCategory()) != null; 349 } 350 351 /** 352 * Returns {@code true} if this attribute set contains an 353 * attribute for the specified category. 354 * 355 * @param category whose presence in this attribute set is 356 * to be tested. 357 * 358 * @return {@code true} if this attribute set contains an attribute 359 * value for the specified category. 360 */ 361 public boolean containsKey(Class<?> category) { 362 return 363 category != null && 364 AttributeSetUtilities. 365 verifyAttributeCategory(category, Attribute.class) != null && 366 attrMap.get(category) != null; 367 } 368 369 /** 370 * Returns {@code true} if this attribute set contains the given 371 * attribute. 372 * 373 * @param attribute value whose presence in this attribute set is 374 * to be tested. 375 * 376 * @return {@code true} if this attribute set contains the given 377 * attribute value. 378 */ 379 public boolean containsValue(Attribute attribute) { 380 return 381 attribute != null && 382 attribute instanceof Attribute && 383 attribute.equals(attrMap.get(attribute.getCategory())); 384 } 385 386 /** 387 * Adds all of the elements in the specified set to this attribute. 388 * The outcome is the same as if the 389 * {@link #add(Attribute) add(Attribute)} 390 * operation had been applied to this attribute set successively with 391 * each element from the specified set. 392 * The behavior of the {@code addAll(AttributeSet)} 393 * operation is unspecified if the specified set is modified while 394 * the operation is in progress. 395 * <P> 396 * If the {@code addAll(AttributeSet)} operation throws an exception, 397 * the effect on this attribute set's state is implementation dependent; 398 * elements from the specified set before the point of the exception may 399 * or may not have been added to this attribute set. 400 * 401 * @param attributes whose elements are to be added to this attribute 402 * set. 403 * 404 * @return {@code true} if this attribute set changed as a result of the 405 * call. 406 * 407 * @throws UnmodifiableSetException 408 * (Unchecked exception) Thrown if this attribute set does not 409 * support the {@code addAll(AttributeSet)} method. 410 * @throws NullPointerException 411 * (Unchecked exception) Thrown if some element in the specified 412 * set is null, or the set is null. 413 * 414 * @see #add(Attribute) 415 */ 416 public boolean addAll(AttributeSet attributes) { 417 418 Attribute []attrs = attributes.toArray(); 419 boolean result = false; 420 for (int i=0; i<attrs.length; i++) { 421 Attribute newValue = 422 AttributeSetUtilities.verifyAttributeValue(attrs[i], 423 myInterface); 424 Object oldValue = attrMap.put(newValue.getCategory(), newValue); 425 result = (! newValue.equals(oldValue)) || result; 426 } 427 return result; 428 } 429 430 /** 431 * Returns the number of attributes in this attribute set. If this 432 * attribute set contains more than {@code Integer.MAX_VALUE} elements, 433 * returns {@code Integer.MAX_VALUE}. 434 * 435 * @return The number of attributes in this attribute set. 436 */ 437 public int size() { 438 return attrMap.size(); 439 } 440 441 /** 442 * 443 * @return the Attributes contained in this set as an array, zero length 444 * if the AttributeSet is empty. 445 */ 446 public Attribute[] toArray() { 447 Attribute []attrs = new Attribute[size()]; 448 attrMap.values().toArray(attrs); 449 return attrs; 450 } 451 452 453 /** 454 * Removes all attributes from this attribute set. 455 * 456 * @throws UnmodifiableSetException 457 * (unchecked exception) Thrown if this attribute set does not support 458 * the {@code clear()} operation. 459 */ 460 public void clear() { 461 attrMap.clear(); 462 } 463 464 /** 465 * Returns true if this attribute set contains no attributes. 466 * 467 * @return true if this attribute set contains no attributes. 468 */ 469 public boolean isEmpty() { 470 return attrMap.isEmpty(); 471 } 472 473 /** 474 * Compares the specified object with this attribute set for equality. 475 * Returns {@code true} if the given object is also an attribute set and 476 * the two attribute sets contain the same attribute category-attribute 477 * value mappings. This ensures that the 478 * {@code equals()} method works properly across different 479 * implementations of the AttributeSet interface. 480 * 481 * @param object to be compared for equality with this attribute set. 482 * 483 * @return {@code true} if the specified object is equal to this 484 * attribute set. 485 */ 486 487 public boolean equals(Object object) { 488 if (object == null || !(object instanceof AttributeSet)) { 489 return false; 490 } 491 492 AttributeSet aset = (AttributeSet)object; 493 if (aset.size() != size()) { 494 return false; 495 } 496 497 Attribute[] attrs = toArray(); 498 for (int i=0;i<attrs.length; i++) { 499 if (!aset.containsValue(attrs[i])) { 500 return false; 501 } 502 } 503 return true; 504 } 505 506 /** 507 * Returns the hash code value for this attribute set. 508 * The hash code of an attribute set is defined to be the sum 509 * of the hash codes of each entry in the AttributeSet. 510 * This ensures that {@code t1.equals(t2)} implies that 511 * {@code t1.hashCode()==t2.hashCode()} for any two attribute sets 512 * {@code t1} and {@code t2}, as required by the general contract of 513 * {@link java.lang.Object#hashCode() Object.hashCode()}. 514 * 515 * @return The hash code value for this attribute set. 516 */ 517 public int hashCode() { 518 int hcode = 0; 519 Attribute[] attrs = toArray(); 520 for (int i=0;i<attrs.length; i++) { 521 hcode += attrs[i].hashCode(); 522 } 523 return hcode; 524 } 525 526 } | 1 /* 2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.print.attribute; 27 28 import java.io.IOException; 29 import java.io.ObjectInputStream; 30 import java.io.ObjectOutputStream; 31 import java.io.Serializable; 32 import java.util.HashMap; 33 34 /** 35 * Class {@code HashAttributeSet} provides an {@code AttributeSet} 36 * implementation with characteristics of a hash map. 37 * 38 * @author Alan Kaminsky 39 */ 40 public class HashAttributeSet implements AttributeSet, Serializable { 41 42 /** 43 * Use serialVersionUID from JDK 1.4 for interoperability. 44 */ 45 private static final long serialVersionUID = 5311560590283707917L; 46 47 /** 48 * The interface of which all members of this attribute set must be an 49 * instance. It is assumed to be interface {@link Attribute Attribute} or a 50 * subinterface thereof. 51 * 52 * @serial 53 */ 54 private Class<?> myInterface; 55 56 /** 57 * A {@code HashMap} used by the implementation. The serialised form doesn't 58 * include this instance variable. 59 */ 60 private transient HashMap<Class<?>, Attribute> attrMap = new HashMap<>(); 61 62 /** 63 * Write the instance to a stream (ie serialize the object). 64 * 65 * @param s the output stream 66 * @throws IOException if an I/O exception has occurred 67 * @serialData The serialized form of an attribute set explicitly writes the 68 * number of attributes in the set, and each of the attributes. 69 * This does not guarantee equality of serialized forms since 70 * the order in which the attributes are written is not defined. 71 */ 72 private void writeObject(ObjectOutputStream s) throws IOException { 73 74 s.defaultWriteObject(); 75 Attribute [] attrs = toArray(); 76 s.writeInt(attrs.length); 77 for (int i = 0; i < attrs.length; i++) { 78 s.writeObject(attrs[i]); 79 } 80 } 81 82 /** 83 * Reconstitute an instance from a stream that is, deserialize it). 84 * 85 * @param s the input stream 86 * @throws ClassNotFoundException if the class is not found 87 * @throws IOException if an I/O exception has occurred 88 */ 89 private void readObject(ObjectInputStream s) 90 throws ClassNotFoundException, IOException { 91 92 s.defaultReadObject(); 93 attrMap = new HashMap<>(); 94 int count = s.readInt(); 95 Attribute attr; 96 for (int i = 0; i < count; i++) { 97 attr = (Attribute)s.readObject(); 98 add(attr); 99 } 100 } 101 102 /** 103 * Construct a new, empty attribute set. 104 */ 105 public HashAttributeSet() { 106 this(Attribute.class); 107 } 108 109 /** 110 * Construct a new attribute set, initially populated with the given 111 * attribute. 112 * 113 * @param attribute attribute value to add to the set 114 * @throws NullPointerException if {@code attribute} is {@code null} 115 */ 116 public HashAttributeSet(Attribute attribute) { 117 this (attribute, Attribute.class); 118 } 119 120 /** 121 * Construct a new attribute set, initially populated with the values from 122 * the given array. The new attribute set is populated by adding the 123 * elements of {@code attributes} array to the set in sequence, starting at 124 * index 0. Thus, later array elements may replace earlier array elements if 125 * the array contains duplicate attribute values or attribute categories. 126 * 127 * @param attributes array of attribute values to add to the set. If 128 * {@code null}, an empty attribute set is constructed. 129 * @throws NullPointerException if any element of {@code attributes} is 130 * {@code null} 131 */ 132 public HashAttributeSet(Attribute[] attributes) { 133 this (attributes, Attribute.class); 134 } 135 136 /** 137 * Construct a new attribute set, initially populated with the values from 138 * the given set. 139 * 140 * @param attributes set of attributes from which to initialise this set. 141 * If {@code null}, an empty attribute set is constructed. 142 */ 143 public HashAttributeSet(AttributeSet attributes) { 144 this (attributes, Attribute.class); 145 } 146 147 /** 148 * Construct a new, empty attribute set, where the members of the attribute 149 * set are restricted to the given interface. 150 * 151 * @param interfaceName the interface of which all members of this 152 * attribute set must be an instance. It is assumed to be interface 153 * {@link Attribute Attribute} or a subinterface thereof. 154 * @throws NullPointerException if {@code interfaceName} is {@code null} 155 */ 156 protected HashAttributeSet(Class<?> interfaceName) { 157 if (interfaceName == null) { 158 throw new NullPointerException("null interface"); 159 } 160 myInterface = interfaceName; 161 } 162 163 /** 164 * Construct a new attribute set, initially populated with the given 165 * attribute, where the members of the attribute set are restricted to the 166 * given interface. 167 * 168 * @param attribute attribute value to add to the set 169 * @param interfaceName the interface of which all members of this 170 * attribute set must be an instance. It is assumed to be interface 171 * {@link Attribute Attribute} or a subinterface thereof. 172 * @throws NullPointerException if {@code attribute} or 173 * {@code interfaceName} are {@code null} 174 * @throws ClassCastException if {@code attribute} is not an instance of 175 * {@code interfaceName} 176 */ 177 protected HashAttributeSet(Attribute attribute, Class<?> interfaceName) { 178 if (interfaceName == null) { 179 throw new NullPointerException("null interface"); 180 } 181 myInterface = interfaceName; 182 add (attribute); 183 } 184 185 /** 186 * Construct a new attribute set, where the members of the attribute set are 187 * restricted to the given interface. The new attribute set is populated by 188 * adding the elements of {@code attributes} array to the set in sequence, 189 * starting at index 0. Thus, later array elements may replace earlier array 190 * elements if the array contains duplicate attribute values or attribute 191 * categories. 192 * 193 * @param attributes array of attribute values to add to the set. If 194 * {@code null}, an empty attribute set is constructed. 195 * @param interfaceName the interface of which all members of this 196 * attribute set must be an instance. It is assumed to be interface 197 * {@link Attribute Attribute} or a subinterface thereof. 198 * @throws NullPointerException if {@code interfaceName} is {@code null}, or 199 * if any element of {@code attributes} is {@code null} 200 * @throws ClassCastException if any element of {@code attributes} is not an 201 * instance of {@code interfaceName} 202 */ 203 protected HashAttributeSet(Attribute[] attributes, Class<?> interfaceName) { 204 if (interfaceName == null) { 205 throw new NullPointerException("null interface"); 206 } 207 myInterface = interfaceName; 208 int n = attributes == null ? 0 : attributes.length; 209 for (int i = 0; i < n; ++ i) { 210 add (attributes[i]); 211 } 212 } 213 214 /** 215 * Construct a new attribute set, initially populated with the values from 216 * the given set where the members of the attribute set are restricted to 217 * the given interface. 218 * 219 * @param attributes set of attribute values to initialise the set. If 220 * {@code null}, an empty attribute set is constructed. 221 * @param interfaceName The interface of which all members of this 222 * attribute set must be an instance. It is assumed to be interface 223 * {@link Attribute Attribute} or a subinterface thereof. 224 * @throws ClassCastException if any element of {@code attributes} is not an 225 * instance of {@code interfaceName} 226 */ 227 protected HashAttributeSet(AttributeSet attributes, Class<?> interfaceName) { 228 myInterface = interfaceName; 229 if (attributes != null) { 230 Attribute[] attribArray = attributes.toArray(); 231 int n = attribArray == null ? 0 : attribArray.length; 232 for (int i = 0; i < n; ++ i) { 233 add (attribArray[i]); 234 } 235 } 236 } 237 238 /** 239 * Returns the attribute value which this attribute set contains in the 240 * given attribute category. Returns {@code null} if this attribute set does 241 * not contain any attribute value in the given attribute category. 242 * 243 * @param category attribute category whose associated attribute value is 244 * to be returned. It must be a {@link Class Class} that implements 245 * interface {@link Attribute Attribute}. 246 * @return the attribute value in the given attribute category contained in 247 * this attribute set, or {@code null} if this attribute set does 248 * not contain any attribute value in the given attribute category 249 * @throws NullPointerException if the {@code category} is {@code null} 250 * @throws ClassCastException if the {@code category} is not a 251 * {@link Class Class} that implements interface 252 * {@link Attribute Attribute} 253 */ 254 public Attribute get(Class<?> category) { 255 return attrMap.get(AttributeSetUtilities. 256 verifyAttributeCategory(category, 257 Attribute.class)); 258 } 259 260 /** 261 * Adds the specified attribute to this attribute set if it is not already 262 * present, first removing any existing in the same attribute category as 263 * the specified attribute value. 264 * 265 * @param attribute attribute value to be added to this attribute set 266 * @return {@code true} if this attribute set changed as a result of the 267 * call, i.e., the given attribute value was not already a member of 268 * this attribute set 269 * @throws NullPointerException if the {@code attribute} is {@code null} 270 * @throws UnmodifiableSetException if this attribute set does not support 271 * the {@code add()} operation 272 */ 273 public boolean add(Attribute attribute) { 274 Object oldAttribute = 275 attrMap.put(attribute.getCategory(), 276 AttributeSetUtilities. 277 verifyAttributeValue(attribute, myInterface)); 278 return (!attribute.equals(oldAttribute)); 279 } 280 281 /** 282 * Removes any attribute for this category from this attribute set if 283 * present. If {@code category} is {@code null}, then {@code remove()} does 284 * nothing and returns {@code false}. 285 * 286 * @param category attribute category to be removed from this attribute set 287 * @return {@code true} if this attribute set changed as a result of the 288 * call, i.e., the given attribute category had been a member of 289 * this attribute set 290 * @throws UnmodifiableSetException if this attribute set does not support 291 * the {@code remove()} operation 292 */ 293 public boolean remove(Class<?> category) { 294 return 295 category != null && 296 AttributeSetUtilities. 297 verifyAttributeCategory(category, Attribute.class) != null && 298 attrMap.remove(category) != null; 299 } 300 301 /** 302 * Removes the specified attribute from this attribute set if present. If 303 * {@code attribute} is {@code null}, then {@code remove()} does nothing and 304 * returns {@code false}. 305 * 306 * @param attribute attribute value to be removed from this attribute set 307 * @return {@code true} if this attribute set changed as a result of the 308 * call, i.e., the given attribute value had been a member of this 309 * attribute set 310 * @throws UnmodifiableSetException if this attribute set does not support 311 * the {@code remove()} operation 312 */ 313 public boolean remove(Attribute attribute) { 314 return 315 attribute != null && 316 attrMap.remove(attribute.getCategory()) != null; 317 } 318 319 /** 320 * Returns {@code true} if this attribute set contains an attribute for the 321 * specified category. 322 * 323 * @param category whose presence in this attribute set is to be tested 324 * @return {@code true} if this attribute set contains an attribute value 325 * for the specified category 326 */ 327 public boolean containsKey(Class<?> category) { 328 return 329 category != null && 330 AttributeSetUtilities. 331 verifyAttributeCategory(category, Attribute.class) != null && 332 attrMap.get(category) != null; 333 } 334 335 /** 336 * Returns {@code true} if this attribute set contains the given attribute. 337 * 338 * @param attribute value whose presence in this attribute set is to be 339 * tested 340 * @return {@code true} if this attribute set contains the given attribute 341 * value 342 */ 343 public boolean containsValue(Attribute attribute) { 344 return 345 attribute != null && 346 attribute instanceof Attribute && 347 attribute.equals(attrMap.get(attribute.getCategory())); 348 } 349 350 /** 351 * Adds all of the elements in the specified set to this attribute. The 352 * outcome is the same as if the {@link #add(Attribute) add(Attribute)} 353 * operation had been applied to this attribute set successively with each 354 * element from the specified set. The behavior of the 355 * {@code addAll(AttributeSet)} operation is unspecified if the specified 356 * set is modified while the operation is in progress. 357 * <p> 358 * If the {@code addAll(AttributeSet)} operation throws an exception, the 359 * effect on this attribute set's state is implementation dependent; 360 * elements from the specified set before the point of the exception may or 361 * may not have been added to this attribute set. 362 * 363 * @param attributes whose elements are to be added to this attribute set 364 * @return {@code true} if this attribute set changed as a result of the 365 * call 366 * @throws UnmodifiableSetException if this attribute set does not support 367 * the {@code addAll(AttributeSet)} method 368 * @throws NullPointerException if some element in the specified set is 369 * {@code null}, or the set is {@code null} 370 * @see #add(Attribute) 371 */ 372 public boolean addAll(AttributeSet attributes) { 373 374 Attribute []attrs = attributes.toArray(); 375 boolean result = false; 376 for (int i=0; i<attrs.length; i++) { 377 Attribute newValue = 378 AttributeSetUtilities.verifyAttributeValue(attrs[i], 379 myInterface); 380 Object oldValue = attrMap.put(newValue.getCategory(), newValue); 381 result = (! newValue.equals(oldValue)) || result; 382 } 383 return result; 384 } 385 386 /** 387 * Returns the number of attributes in this attribute set. If this attribute 388 * set contains more than {@code Integer.MAX_VALUE} elements, returns 389 * {@code Integer.MAX_VALUE}. 390 * 391 * @return the number of attributes in this attribute set 392 */ 393 public int size() { 394 return attrMap.size(); 395 } 396 397 /** 398 * Returns an array of the attributes contained in this set. 399 * 400 * @return the attributes contained in this set as an array, zero length if 401 * the {@code AttributeSet} is empty 402 */ 403 public Attribute[] toArray() { 404 Attribute []attrs = new Attribute[size()]; 405 attrMap.values().toArray(attrs); 406 return attrs; 407 } 408 409 /** 410 * Removes all attributes from this attribute set. 411 * 412 * @throws UnmodifiableSetException if this attribute set does not support 413 * the {@code clear()} operation 414 */ 415 public void clear() { 416 attrMap.clear(); 417 } 418 419 /** 420 * Returns {@code true} if this attribute set contains no attributes. 421 * 422 * @return {@code true} if this attribute set contains no attributes 423 */ 424 public boolean isEmpty() { 425 return attrMap.isEmpty(); 426 } 427 428 /** 429 * Compares the specified object with this attribute set for equality. 430 * Returns {@code true} if the given object is also an attribute set and the 431 * two attribute sets contain the same attribute category-attribute value 432 * mappings. This ensures that the {@code equals()} method works properly 433 * across different implementations of the {@code AttributeSet} interface. 434 * 435 * @param object to be compared for equality with this attribute set 436 * @return {@code true} if the specified object is equal to this attribute 437 * set 438 */ 439 public boolean equals(Object object) { 440 if (object == null || !(object instanceof AttributeSet)) { 441 return false; 442 } 443 444 AttributeSet aset = (AttributeSet)object; 445 if (aset.size() != size()) { 446 return false; 447 } 448 449 Attribute[] attrs = toArray(); 450 for (int i=0;i<attrs.length; i++) { 451 if (!aset.containsValue(attrs[i])) { 452 return false; 453 } 454 } 455 return true; 456 } 457 458 /** 459 * Returns the hash code value for this attribute set. The hash code of an 460 * attribute set is defined to be the sum of the hash codes of each entry in 461 * the {@code AttributeSet}. This ensures that {@code t1.equals(t2)} implies 462 * that {@code t1.hashCode()==t2.hashCode()} for any two attribute sets 463 * {@code t1} and {@code t2}, as required by the general contract of 464 * {@link Object#hashCode() Object.hashCode()}. 465 * 466 * @return the hash code value for this attribute set 467 */ 468 public int hashCode() { 469 int hcode = 0; 470 Attribute[] attrs = toArray(); 471 for (int i=0;i<attrs.length; i++) { 472 hcode += attrs[i].hashCode(); 473 } 474 return hcode; 475 } 476 } |