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.Serializable;
  29 
  30 /**
  31  * Class {@code AttributeSetUtilities} provides static methods for manipulating
  32  * {@code AttributeSets}.
  33  * <ul>
  34  *   <li>Methods for creating unmodifiable and synchronized views of attribute
  35  *   sets.
  36  *   <li>operations useful for building implementations of interface
  37  *   {@link AttributeSet AttributeSet}
  38  * </ul>
  39  * An <b>unmodifiable view</b> <i>U</i> of an {@code AttributeSet} <i>S</i>
  40  * provides a client with "read-only" access to <i>S</i>. Query operations on
  41  * <i>U</i> "read through" to <i>S</i>; thus, changes in <i>S</i> are reflected
  42  * in <i>U</i>. However, any attempt to modify <i>U</i>, results in an
  43  * {@code UnmodifiableSetException}. The unmodifiable view object <i>U</i> will
  44  * be serializable if the attribute set object <i>S</i> is serializable.
  45  * <p>
  46  * A <b>synchronized view</b> <i>V</i> of an attribute set <i>S</i> provides a
  47  * client with synchronized (multiple thread safe) access to <i>S</i>. Each
  48  * operation of <i>V</i> is synchronized using <i>V</i> itself as the lock
  49  * object and then merely invokes the corresponding operation of <i>S</i>. In
  50  * order to guarantee mutually exclusive access, it is critical that all access
  51  * to <i>S</i> is accomplished through <i>V</i>. The synchronized view object
  52  * <i>V</i> will be serializable if the attribute set object <i>S</i> is
  53  * serializable.
  54  * <p>
  55  * As mentioned in the package description of {@code javax.print}, a
  56  * {@code null} reference parameter to methods is incorrect unless explicitly
  57  * documented on the method as having a meaningful interpretation. Usage to the
  58  * contrary is incorrect coding and may result in a run time exception either
  59  * immediately or at some later time. {@code IllegalArgumentException} and
  60  * {@code NullPointerException} are examples of typical and acceptable run time
  61  * exceptions for such cases.
  62  *
  63  * @author Alan Kaminsky
  64  */
  65 public final class AttributeSetUtilities {
  66 
  67     /**
  68      * Suppress default constructor, ensuring non-instantiability.
  69      */
  70     private AttributeSetUtilities() {
  71     }
  72 
  73     /**
  74      * Unmodifiable view of {@code AttributeSet}.
  75      *
  76      * @serial include
  77      */
  78     private static class UnmodifiableAttributeSet
  79         implements AttributeSet, Serializable {
  80 
  81         /**
  82          * Use serialVersionUID from JDK 1.4 for interoperability.
  83          */
  84         private static final long serialVersionUID = -6131802583863447813L;
  85 
  86         /**
  87          * The attribute set.
  88          */
  89         @SuppressWarnings("serial") // Not statically typed as Serializable
  90         private AttributeSet attrset;
  91 
  92         /**
  93          * Constructs unmodifiable view of the underlying attribute set.
  94          *
  95          * @param  attributeSet the attribute set
  96          */
  97         public UnmodifiableAttributeSet(AttributeSet attributeSet) {
  98 
  99             attrset = attributeSet;
 100         }
 101 
 102         public Attribute get(Class<?> key) {
 103             return attrset.get(key);
 104         }
 105 
 106         public boolean add(Attribute attribute) {
 107             throw new UnmodifiableSetException();
 108         }
 109 
 110         public synchronized boolean remove(Class<?> category) {
 111             throw new UnmodifiableSetException();
 112         }
 113 
 114         public boolean remove(Attribute attribute) {
 115             throw new UnmodifiableSetException();
 116         }
 117 
 118         public boolean containsKey(Class<?> category) {
 119             return attrset.containsKey(category);
 120         }
 121 
 122         public boolean containsValue(Attribute attribute) {
 123             return attrset.containsValue(attribute);
 124         }
 125 
 126         public boolean addAll(AttributeSet attributes) {
 127             throw new UnmodifiableSetException();
 128         }
 129 
 130         public int size() {
 131             return attrset.size();
 132         }
 133 
 134         public Attribute[] toArray() {
 135             return attrset.toArray();
 136         }
 137 
 138         public void clear() {
 139             throw new UnmodifiableSetException();
 140         }
 141 
 142         public boolean isEmpty() {
 143             return attrset.isEmpty();
 144         }
 145 
 146         public boolean equals(Object o) {
 147             return attrset.equals (o);
 148         }
 149 
 150         public int hashCode() {
 151             return attrset.hashCode();
 152         }
 153     }
 154 
 155     /**
 156      * Unmodifiable view of {@code DocAttributeSet}.
 157      *
 158      * @serial include
 159      */
 160     private static class UnmodifiableDocAttributeSet
 161         extends UnmodifiableAttributeSet
 162         implements DocAttributeSet, Serializable {
 163 
 164         /**
 165          * Use serialVersionUID from JDK 1.4 for interoperability.
 166          */
 167         private static final long serialVersionUID = -6349408326066898956L;
 168 
 169         /**
 170          * Constructs a new unmodifiable doc attribute set.
 171          *
 172          * @param  attributeSet the doc attribute set
 173          */
 174         public UnmodifiableDocAttributeSet(DocAttributeSet attributeSet) {
 175 
 176             super (attributeSet);
 177         }
 178     }
 179 
 180     /**
 181      * Unmodifiable view of {@code PrintRequestAttributeSet}.
 182      *
 183      * @serial include
 184      */
 185     private static class UnmodifiablePrintRequestAttributeSet
 186         extends UnmodifiableAttributeSet
 187         implements PrintRequestAttributeSet, Serializable
 188     {
 189 
 190         /**
 191          * Use serialVersionUID from JDK 1.4 for interoperability.
 192          */
 193         private static final long serialVersionUID = 7799373532614825073L;
 194 
 195         /**
 196          * Constructs a new unmodifiable print request attribute set.
 197          *
 198          * @param  attributeSet the print request attribute set
 199          */
 200         public UnmodifiablePrintRequestAttributeSet
 201             (PrintRequestAttributeSet attributeSet) {
 202 
 203             super (attributeSet);
 204         }
 205     }
 206 
 207     /**
 208      * Unmodifiable view of {@code PrintJobAttributeSet}.
 209      *
 210      * @serial include
 211      */
 212     private static class UnmodifiablePrintJobAttributeSet
 213         extends UnmodifiableAttributeSet
 214         implements PrintJobAttributeSet, Serializable
 215     {
 216         /**
 217          * Use serialVersionUID from JDK 1.4 for interoperability.
 218          */
 219         private static final long serialVersionUID = -8002245296274522112L;
 220 
 221         /**
 222          * Constructs a new unmodifiable print job attribute set.
 223          *
 224          * @param  attributeSet the print job attribute set
 225          */
 226         public UnmodifiablePrintJobAttributeSet
 227             (PrintJobAttributeSet attributeSet) {
 228 
 229             super (attributeSet);
 230         }
 231     }
 232 
 233     /**
 234      * Unmodifiable view of {@code PrintServiceAttributeSet}.
 235      *
 236      * @serial include
 237      */
 238     private static class UnmodifiablePrintServiceAttributeSet
 239         extends UnmodifiableAttributeSet
 240         implements PrintServiceAttributeSet, Serializable
 241     {
 242         /**
 243          * Use serialVersionUID from JDK 1.4 for interoperability.
 244          */
 245         private static final long serialVersionUID = -7112165137107826819L;
 246 
 247         /**
 248          * Constructs a new unmodifiable print service attribute set.
 249          *
 250          * @param  attributeSet the print service attribute set
 251          */
 252         public UnmodifiablePrintServiceAttributeSet
 253             (PrintServiceAttributeSet attributeSet) {
 254 
 255             super (attributeSet);
 256         }
 257     }
 258 
 259     /**
 260      * Creates an unmodifiable view of the given attribute set.
 261      *
 262      * @param  attributeSet underlying attribute set
 263      * @return unmodifiable view of {@code attributeSet}
 264      * @throws NullPointerException if {@code attributeSet} is {@code null}
 265      */
 266     public static AttributeSet unmodifiableView(AttributeSet attributeSet) {
 267         if (attributeSet == null) {
 268             throw new NullPointerException();
 269         }
 270 
 271         return new UnmodifiableAttributeSet(attributeSet);
 272     }
 273 
 274     /**
 275      * Creates an unmodifiable view of the given doc attribute set.
 276      *
 277      * @param  attributeSet underlying doc attribute set
 278      * @return unmodifiable view of {@code attributeSet}
 279      * @throws NullPointerException if {@code attributeSet} is {@code null}
 280      */
 281     public static DocAttributeSet unmodifiableView
 282         (DocAttributeSet attributeSet) {
 283         if (attributeSet == null) {
 284             throw new NullPointerException();
 285         }
 286         return new UnmodifiableDocAttributeSet(attributeSet);
 287     }
 288 
 289     /**
 290      * Creates an unmodifiable view of the given print request attribute set.
 291      *
 292      * @param  attributeSet underlying print request attribute set
 293      * @return unmodifiable view of {@code attributeSet}
 294      * @throws NullPointerException if {@code attributeSet} is {@code null}
 295      */
 296     public static PrintRequestAttributeSet
 297         unmodifiableView(PrintRequestAttributeSet attributeSet) {
 298         if (attributeSet == null) {
 299             throw new NullPointerException();
 300         }
 301         return new UnmodifiablePrintRequestAttributeSet(attributeSet);
 302     }
 303 
 304     /**
 305      * Creates an unmodifiable view of the given print job attribute set.
 306      *
 307      * @param  attributeSet underlying print job attribute set
 308      * @return unmodifiable view of {@code attributeSet}
 309      * @throws NullPointerException if {@code attributeSet} is {@code null}
 310      */
 311     public static PrintJobAttributeSet
 312         unmodifiableView(PrintJobAttributeSet attributeSet) {
 313         if (attributeSet == null) {
 314             throw new NullPointerException();
 315         }
 316         return new UnmodifiablePrintJobAttributeSet(attributeSet);
 317     }
 318 
 319     /**
 320      * Creates an unmodifiable view of the given print service attribute set.
 321      *
 322      * @param  attributeSet underlying print service attribute set
 323      * @return unmodifiable view of {@code attributeSet}
 324      * @throws NullPointerException if {@code attributeSet} is {@code null}
 325      */
 326     public static PrintServiceAttributeSet
 327         unmodifiableView(PrintServiceAttributeSet attributeSet) {
 328         if (attributeSet == null) {
 329             throw new NullPointerException();
 330         }
 331         return new UnmodifiablePrintServiceAttributeSet (attributeSet);
 332     }
 333 
 334     /**
 335      * Synchronized view of {@code AttributeSet}.
 336      *
 337      * @serial include
 338      */
 339     private static class SynchronizedAttributeSet
 340                         implements AttributeSet, Serializable {
 341 
 342         /**
 343          * Use serialVersionUID from JDK 1.4 for interoperability.
 344          */
 345         private static final long serialVersionUID = 8365731020128564925L;
 346 
 347         /**
 348          * The attribute set.
 349          */
 350         @SuppressWarnings("serial") // Not statically typed as Serializable
 351         private AttributeSet attrset;
 352 
 353         /**
 354          * Constructs a new synchronized attribute set.
 355          *
 356          * @param  attributeSet the attribute set
 357          */
 358         public SynchronizedAttributeSet(AttributeSet attributeSet) {
 359             attrset = attributeSet;
 360         }
 361 
 362         public synchronized Attribute get(Class<?> category) {
 363             return attrset.get(category);
 364         }
 365 
 366         public synchronized boolean add(Attribute attribute) {
 367             return attrset.add(attribute);
 368         }
 369 
 370         public synchronized boolean remove(Class<?> category) {
 371             return attrset.remove(category);
 372         }
 373 
 374         public synchronized boolean remove(Attribute attribute) {
 375             return attrset.remove(attribute);
 376         }
 377 
 378         public synchronized boolean containsKey(Class<?> category) {
 379             return attrset.containsKey(category);
 380         }
 381 
 382         public synchronized boolean containsValue(Attribute attribute) {
 383             return attrset.containsValue(attribute);
 384         }
 385 
 386         public synchronized boolean addAll(AttributeSet attributes) {
 387             return attrset.addAll(attributes);
 388         }
 389 
 390         public synchronized int size() {
 391             return attrset.size();
 392         }
 393 
 394         public synchronized Attribute[] toArray() {
 395             return attrset.toArray();
 396         }
 397 
 398         public synchronized void clear() {
 399             attrset.clear();
 400         }
 401 
 402         public synchronized boolean isEmpty() {
 403             return attrset.isEmpty();
 404         }
 405 
 406         public synchronized boolean equals(Object o) {
 407             return attrset.equals (o);
 408         }
 409 
 410         public synchronized int hashCode() {
 411             return attrset.hashCode();
 412         }
 413     }
 414 
 415     /**
 416      * Synchronized view of {@code DocAttributeSet}.
 417      *
 418      * @serial include
 419      */
 420     private static class SynchronizedDocAttributeSet
 421         extends SynchronizedAttributeSet
 422         implements DocAttributeSet, Serializable {
 423 
 424         /**
 425          * Use serialVersionUID from JDK 1.4 for interoperability.
 426          */
 427         private static final long serialVersionUID = 6455869095246629354L;
 428 
 429         /**
 430          * Constructs a new synchronized doc attribute set.
 431          *
 432          * @param  attributeSet the doc attribute set
 433          */
 434         public SynchronizedDocAttributeSet(DocAttributeSet attributeSet) {
 435             super(attributeSet);
 436         }
 437     }
 438 
 439     /**
 440      * Synchronized view of {@code PrintRequestAttributeSet}.
 441      *
 442      * @serial include
 443      */
 444     private static class SynchronizedPrintRequestAttributeSet
 445         extends SynchronizedAttributeSet
 446         implements PrintRequestAttributeSet, Serializable {
 447 
 448         /**
 449          * Use serialVersionUID from JDK 1.4 for interoperability.
 450          */
 451         private static final long serialVersionUID = 5671237023971169027L;
 452 
 453         /**
 454          * Constructs a new synchronized print request attribute set.
 455          *
 456          * @param  attributeSet the print request attribute set
 457          */
 458         public SynchronizedPrintRequestAttributeSet
 459             (PrintRequestAttributeSet attributeSet) {
 460             super(attributeSet);
 461         }
 462     }
 463 
 464     /**
 465      * Synchronized view of {@code PrintJobAttributeSet}.
 466      *
 467      * @serial include
 468      */
 469     private static class SynchronizedPrintJobAttributeSet
 470         extends SynchronizedAttributeSet
 471         implements PrintJobAttributeSet, Serializable {
 472 
 473         /**
 474          * Use serialVersionUID from JDK 1.4 for interoperability.
 475          */
 476         private static final long serialVersionUID = 2117188707856965749L;
 477 
 478         /**
 479          * Constructs a new synchronized print job attribute set.
 480          *
 481          * @param  attributeSet the print job attribute set
 482          */
 483         public SynchronizedPrintJobAttributeSet
 484             (PrintJobAttributeSet attributeSet) {
 485             super(attributeSet);
 486         }
 487     }
 488 
 489     /**
 490      * Synchronized view of {@code PrintServiceAttributeSet}.
 491      *
 492      * @serial include
 493      */
 494     private static class SynchronizedPrintServiceAttributeSet
 495         extends SynchronizedAttributeSet
 496         implements PrintServiceAttributeSet, Serializable {
 497 
 498         /**
 499          * Use serialVersionUID from JDK 1.4 for interoperability.
 500          */
 501         private static final long serialVersionUID = -2830705374001675073L;
 502 
 503         /**
 504          * Constructs a new synchronized print service attribute set.
 505          *
 506          * @param  attributeSet the print service attribute set
 507          */
 508         public SynchronizedPrintServiceAttributeSet
 509             (PrintServiceAttributeSet attributeSet) {
 510             super(attributeSet);
 511         }
 512     }
 513 
 514     /**
 515      * Creates a synchronized view of the given attribute set.
 516      *
 517      * @param  attributeSet underlying attribute set
 518      * @return synchronized view of {@code attributeSet}
 519      * @throws NullPointerException if {@code attributeSet} is {@code null}
 520      */
 521     public static AttributeSet synchronizedView
 522         (AttributeSet attributeSet) {
 523         if (attributeSet == null) {
 524             throw new NullPointerException();
 525         }
 526         return new SynchronizedAttributeSet(attributeSet);
 527     }
 528 
 529     /**
 530      * Creates a synchronized view of the given doc attribute set.
 531      *
 532      * @param  attributeSet underlying doc attribute set
 533      * @return synchronized view of {@code attributeSet}
 534      * @throws NullPointerException if {@code attributeSet} is {@code null}
 535      */
 536     public static DocAttributeSet
 537         synchronizedView(DocAttributeSet attributeSet) {
 538         if (attributeSet == null) {
 539             throw new NullPointerException();
 540         }
 541         return new SynchronizedDocAttributeSet(attributeSet);
 542     }
 543 
 544     /**
 545      * Creates a synchronized view of the given print request attribute set.
 546      *
 547      * @param  attributeSet underlying print request attribute set
 548      * @return synchronized view of {@code attributeSet}
 549      * @throws NullPointerException if {@code attributeSet} is {@code null}
 550      */
 551     public static PrintRequestAttributeSet
 552         synchronizedView(PrintRequestAttributeSet attributeSet) {
 553         if (attributeSet == null) {
 554             throw new NullPointerException();
 555         }
 556         return new SynchronizedPrintRequestAttributeSet(attributeSet);
 557     }
 558 
 559     /**
 560      * Creates a synchronized view of the given print job attribute set.
 561      *
 562      * @param  attributeSet underlying print job attribute set
 563      * @return synchronized view of {@code attributeSet}
 564      * @throws NullPointerException if {@code attributeSet} is {@code null}
 565      */
 566     public static PrintJobAttributeSet
 567         synchronizedView(PrintJobAttributeSet attributeSet) {
 568         if (attributeSet == null) {
 569             throw new NullPointerException();
 570         }
 571         return new SynchronizedPrintJobAttributeSet(attributeSet);
 572     }
 573 
 574     /**
 575      * Creates a synchronized view of the given print service attribute set.
 576      *
 577      * @param  attributeSet underlying print service attribute set
 578      * @return synchronized view of {@code attributeSet}
 579      * @throws NullPointerException if {@code attributeSet} is {@code null}
 580      */
 581     public static PrintServiceAttributeSet
 582         synchronizedView(PrintServiceAttributeSet attributeSet) {
 583         if (attributeSet == null) {
 584             throw new NullPointerException();
 585         }
 586         return new SynchronizedPrintServiceAttributeSet(attributeSet);
 587     }
 588 
 589     /**
 590      * Verify that the given object is a {@link Class Class} that implements the
 591      * given interface, which is assumed to be interface
 592      * {@link Attribute Attribute} or a subinterface thereof.
 593      *
 594      * @param  object {@code Object} to test
 595      * @param  interfaceName interface the object must implement
 596      * @return if {@code object} is a {@link Class Class} that implements
 597      *         {@code interfaceName}, {@code object} is returned downcast to
 598      *         type {@link Class Class}; otherwise an exception is thrown
 599      * @throws NullPointerException if {@code object} is {@code null}
 600      * @throws ClassCastException if {@code object} is not a
 601      *         {@link Class Class} that implements {@code interfaceName}
 602      */
 603     public static Class<?>
 604         verifyAttributeCategory(Object object, Class<?> interfaceName) {
 605 
 606         Class<?> result = (Class<?>) object;
 607         if (interfaceName.isAssignableFrom (result)) {
 608             return result;
 609         }
 610         else {
 611             throw new ClassCastException();
 612         }
 613     }
 614 
 615     /**
 616      * Verify that the given object is an instance of the given interface, which
 617      * is assumed to be interface {@link Attribute Attribute} or a subinterface
 618      * thereof.
 619      *
 620      * @param  object {@code Object} to test
 621      * @param  interfaceName interface of which the object must be an instance
 622      * @return if {@code object} is an instance of {@code interfaceName},
 623      *         {@code object} is returned downcast to type
 624      *         {@link Attribute Attribute}; otherwise an exception is thrown
 625      * @throws NullPointerException if {@code object} is {@code null}
 626      * @throws ClassCastException if {@code object} is not an instance of
 627      *         {@code interfaceName}
 628      */
 629     public static Attribute
 630         verifyAttributeValue(Object object, Class<?> interfaceName) {
 631 
 632         if (object == null) {
 633             throw new NullPointerException();
 634         }
 635         else if (interfaceName.isInstance (object)) {
 636             return (Attribute) object;
 637         } else {
 638             throw new ClassCastException();
 639         }
 640     }
 641 
 642     /**
 643      * Verify that the given attribute category object is equal to the category
 644      * of the given attribute value object. If so, this method returns doing
 645      * nothing. If not, this method throws an exception.
 646      *
 647      * @param  category attribute category to test
 648      * @param  attribute attribute value to test
 649      * @throws NullPointerException if the {@code category} or {@code attribute}
 650      *         are {@code null}
 651      * @throws IllegalArgumentException if the {@code category} is not equal to
 652      *         the category of the {@code attribute}
 653      */
 654     public static void
 655         verifyCategoryForValue(Class<?> category, Attribute attribute) {
 656 
 657         if (!category.equals (attribute.getCategory())) {
 658             throw new IllegalArgumentException();
 659         }
 660     }
 661 }