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