001/* HashAttributeSet.java -- 002 Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038package javax.print.attribute; 039 040import java.io.IOException; 041import java.io.ObjectInputStream; 042import java.io.ObjectOutputStream; 043import java.io.Serializable; 044import java.util.HashMap; 045import java.util.Iterator; 046 047/** 048 * <code>HashAttributeSet</code> provides an implementation of 049 * {@link javax.print.attribute.AttributeSet}. 050 */ 051public class HashAttributeSet implements AttributeSet, Serializable 052{ 053 private static final long serialVersionUID = 5311560590283707917L; 054 055 private Class myInterface; 056 private transient HashMap attributeMap = new HashMap(); 057 058 /** 059 * Creates an empty <code>HashAttributeSet</code> object. 060 */ 061 public HashAttributeSet() 062 { 063 this(Attribute.class); 064 } 065 066 /** 067 * Creates a <code>HashAttributeSet</code> object with the given 068 * attribute in it. 069 * 070 * @param attribute the attribute to put into the set 071 * 072 * @exception NullPointerException if attribute is null 073 */ 074 public HashAttributeSet(Attribute attribute) 075 { 076 this(attribute, Attribute.class); 077 } 078 079 /** 080 * Creates a <code>HashAttributeSet</code> object with the given 081 * attributes in it. 082 * 083 * @param attributes the array of attributes to put into the set. If 084 * <code>null</code> an empty set is created. 085 * 086 * @exception NullPointerException if one of the attributes of the given 087 * array is null. 088 */ 089 public HashAttributeSet(Attribute[] attributes) 090 { 091 this(attributes, Attribute.class); 092 } 093 094 /** 095 * Creates a <code>HashAttributeSet</code> object with attributes 096 * of the given attributes set in it. 097 * 098 * @param attributes the attributes set to put into the set. If 099 * <code>null</code> an empty set is created. 100 */ 101 public HashAttributeSet(AttributeSet attributes) 102 { 103 this(attributes, Attribute.class); 104 } 105 106 /** 107 * Creates an empty <code>HashAttributeSet</code> object. 108 * 109 * @param interfaceName the interface that all members must implement 110 * 111 * @exception NullPointerException if interfaceName is null 112 */ 113 protected HashAttributeSet(Class<?> interfaceName) 114 { 115 if (interfaceName == null) 116 throw new NullPointerException("interfaceName may not be null"); 117 118 myInterface = interfaceName; 119 } 120 121 /** 122 * Creates a <code>HashAttributeSet</code> object with the given 123 * attribute in it. 124 * 125 * @param attribute the attribute to put into the set. 126 * @param interfaceName the interface that all members must implement. 127 * 128 * @exception ClassCastException if attribute is not an interface of 129 * interfaceName 130 * @exception NullPointerException if attribute or interfaceName is null 131 */ 132 protected HashAttributeSet(Attribute attribute, Class<?> interfaceName) 133 { 134 this(interfaceName); 135 136 if (attribute == null) 137 throw new NullPointerException(); 138 139 addInternal(attribute, interfaceName); 140 } 141 142 /** 143 * Creates a <code>HashAttributeSet</code> object with the given 144 * attributes in it. 145 * 146 * @param attributes the array of attributes to put into the set. If 147 * <code>null</code> an empty set is created. 148 * @param interfaceName the interface that all members must implement. 149 * 150 * @exception ClassCastException if any element of attributes is not an 151 * interface of interfaceName 152 * @exception NullPointerException if attributes or interfaceName is null 153 */ 154 protected HashAttributeSet(Attribute[] attributes, Class<?> interfaceName) 155 { 156 this(interfaceName); 157 158 if (attributes != null) 159 { 160 for (int index = 0; index < attributes.length; index++) 161 addInternal(attributes[index], interfaceName); 162 } 163 } 164 165 /** 166 * Creates a <code>HashAttributeSet</code> object with attributes 167 * of the given attributes set in it. 168 * 169 * @param attributes the attributes set to put into the set. If 170 * <code>null</code> an empty set is created. 171 * @param interfaceName the interface that all members must implement. 172 * 173 * @exception ClassCastException if any element of attributes is not an 174 * interface of interfaceName 175 */ 176 protected HashAttributeSet(AttributeSet attributes, Class<?> interfaceName) 177 { 178 this(interfaceName); 179 180 if (attributes != null) 181 addAllInternal(attributes, interfaceName); 182 } 183 184 /** 185 * Adds the specified attribute value to this attribute set 186 * if it is not already present. 187 * 188 * This operation removes any existing attribute of the same category 189 * before adding the given attribute to the set. 190 * 191 * @param attribute the attribute to add. 192 * @return <code>true</code> if the set is changed, false otherwise. 193 * @throws NullPointerException if the attribute is <code>null</code>. 194 * @throws UnmodifiableSetException if the set does not support modification. 195 */ 196 public boolean add(Attribute attribute) 197 { 198 return addInternal(attribute, myInterface); 199 } 200 201 private boolean addInternal(Attribute attribute, Class interfaceName) 202 { 203 if (attribute == null) 204 throw new NullPointerException("attribute may not be null"); 205 206 AttributeSetUtilities.verifyAttributeCategory(interfaceName, 207 myInterface); 208 209 Object old = attributeMap.put 210 (attribute.getCategory(), AttributeSetUtilities.verifyAttributeValue 211 (attribute, interfaceName)); 212 return !attribute.equals(old); 213 } 214 215 /** 216 * Adds all of the elements in the specified set to this attribute set. 217 * 218 * @param attributes the set of attributes to add. 219 * @return <code>true</code> if the set is changed, false otherwise. 220 * @throws UnmodifiableSetException if the set does not support modification. 221 * 222 * @see #add(Attribute) 223 */ 224 public boolean addAll(AttributeSet attributes) 225 { 226 return addAllInternal(attributes, myInterface); 227 } 228 229 private boolean addAllInternal(AttributeSet attributes, Class interfaceName) 230 { 231 boolean modified = false; 232 Attribute[] array = attributes.toArray(); 233 234 for (int index = 0; index < array.length; index++) 235 if (addInternal(array[index], interfaceName)) 236 modified = true; 237 238 return modified; 239 } 240 241 /** 242 * Removes all attributes from this attribute set. 243 * 244 * @throws UnmodifiableSetException if the set does not support modification. 245 */ 246 public void clear() 247 { 248 attributeMap.clear(); 249 } 250 251 /** 252 * Checks if this attributes set contains an attribute with the given 253 * category. 254 * 255 * @param category the category to test for. 256 * @return <code>true</code> if an attribute of the category is contained 257 * in the set, <code>false</code> otherwise. 258 */ 259 public boolean containsKey(Class<?> category) 260 { 261 return attributeMap.containsKey(category); 262 } 263 264 /** 265 * Checks if this attribute set contains the given attribute. 266 * 267 * @param attribute the attribute to test for. 268 * @return <code>true</code> if the attribute is contained in the set, 269 * <code>false</code> otherwise. 270 */ 271 public boolean containsValue(Attribute attribute) 272 { 273 return attributeMap.containsValue(attribute); 274 } 275 276 /** 277 * Tests this set for equality with the given object. <code>true</code> is 278 * returned, if the given object is also of type <code>AttributeSet</code> 279 * and the contained attributes are the same as in this set. 280 * 281 * @param obj the Object to test. 282 * @return <code>true</code> if equal, false otherwise. 283 */ 284 public boolean equals(Object obj) 285 { 286 if (! (obj instanceof HashAttributeSet)) 287 return false; 288 289 return attributeMap.equals(((HashAttributeSet) obj).attributeMap); 290 } 291 292 /** 293 * Returns the attribute object contained in this set for the given attribute 294 * category. 295 * 296 * @param category the category of the attribute. A <code>Class</code> 297 * instance of a class implementing the <code>Attribute</code> interface. 298 * @return The attribute for this category or <code>null</code> if no 299 * attribute is contained for the given category. 300 * @throws NullPointerException if category is null. 301 * @throws ClassCastException if category is not implementing 302 * <code>Attribute</code>. 303 */ 304 public Attribute get(Class<?> category) 305 { 306 if (category == null) 307 throw new NullPointerException("category may not be null"); 308 309 return (Attribute) attributeMap.get(category); 310 } 311 312 /** 313 * Returns the hashcode value. The hashcode value is the sum of all hashcodes 314 * of the attributes contained in this set. 315 * 316 * @return The hashcode for this attribute set. 317 */ 318 public int hashCode() 319 { 320 int hashcode = 0; 321 Iterator it = attributeMap.values().iterator(); 322 while (it.hasNext()) 323 hashcode = hashcode + it.next().hashCode(); 324 325 return hashcode; 326 } 327 328 /** 329 * Checks if the attribute set is empty. 330 * 331 * @return <code>true</code> if the attribute set is empty, false otherwise. 332 */ 333 public boolean isEmpty() 334 { 335 return attributeMap.isEmpty(); 336 } 337 338 /** 339 * Removes the given attribute from the set. If the given attribute is <code>null</code> 340 * nothing is done and <code>false</code> is returned. 341 * 342 * @param attribute the attribute to remove. 343 * @return <code>true</code> if removed, false in all other cases. 344 * @throws UnmodifiableSetException if the set does not support modification. 345 */ 346 public boolean remove(Attribute attribute) 347 { 348 if (attribute == null) 349 return false; 350 351 return attributeMap.remove(attribute.getCategory()) != null; 352 } 353 354 /** 355 * Removes the attribute entry of the given category from the set. If the given 356 * category is <code>null</code> nothing is done and <code>false</code> is returned. 357 * 358 * @param category the category of the entry to be removed. 359 * @return <code>true</code> if an attribute is removed, false in all other cases. 360 * @throws UnmodifiableSetException if the set does not support modification. 361 */ 362 public boolean remove(Class<?> category) 363 { 364 if (category == null) 365 return false; 366 367 return attributeMap.remove(category) != null; 368 } 369 370 /** 371 * Returns the number of elements in this attribute set. 372 * 373 * @return The number of elements. 374 */ 375 public int size() 376 { 377 return attributeMap.size(); 378 } 379 380 /** 381 * Returns the content of the attribute set as an array 382 * 383 * @return An array of attributes. 384 */ 385 public Attribute[] toArray() 386 { 387 int index = 0; 388 Iterator it = attributeMap.values().iterator(); 389 Attribute[] array = new Attribute[size()]; 390 391 while (it.hasNext()) 392 { 393 array[index] = (Attribute) it.next(); 394 index++; 395 } 396 397 return array; 398 } 399 400 // Implemented as specified in serialized form 401 private void readObject(ObjectInputStream s) 402 throws ClassNotFoundException, IOException 403 { 404 myInterface = (Class) s.readObject(); 405 int size = s.readInt(); 406 attributeMap = new HashMap(size); 407 for (int i=0; i < size; i++) 408 add((Attribute) s.readObject()); 409 } 410 411 private void writeObject(ObjectOutputStream s) throws IOException 412 { 413 s.writeObject(myInterface); 414 s.writeInt(size()); 415 Iterator it = attributeMap.values().iterator(); 416 while (it.hasNext()) 417 s.writeObject(it.next()); 418 } 419}