title: Printing with Attributes(Tray Control, Duplex, etc...) using javax.print library
body: <p>I've been trying for some time to determine a way to use the <strong>standard Java Print library</strong> to print files - specifically, PDF documents - with <strong>certain attributes</strong> - specifically, to certain trays or using duplex.</p>
  
  <p>There exists plenty of documentation on how this should be done, and indeed, I've researched and tried these methods.  The typical way is something like this:</p>
  
  <pre><code>public static void main (String [] args) {
      try {
  
          PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null);
  
          //Acquire Printer
          PrintService printer = null;
          for (PrintService serv: pservices) {
              System.out.println(serv.toString());
              if (serv.getName().equals("PRINTER_NAME_BLAH")) {
                  printer = serv;
              }
          }
  
          if (printer != null) {
              System.out.println("Found!");
  
  
              //Open File
              FileInputStream fis = new FileInputStream("FILENAME_BLAH_BLAH.pdf");
  
              //Create Doc out of file, autosense filetype
              Doc pdfDoc = new SimpleDoc(fis, DocFlavor.INPUT_STREAM.AUTOSENSE, null);
  
              //Create job for printer
              DocPrintJob printJob = printer.createPrintJob();
  
              //Create AttributeSet
              PrintRequestAttributeSet pset = new HashPrintRequestAttributeSet();
  
              //Add MediaTray to AttributeSet
              pset.add(MediaTray.TOP);
  
              //Add Duplex Option to AttributeSet
              pset.add(Sides.DUPLEX);
  
              //Print using Doc and Attributes
              printJob.print(pdfDoc, pset);
  
              //Close File
              fis.close();
  
          }
  
      }
      catch (Throwable t) {
          t.printStackTrace();
      }
  }
  </code></pre>
  
  <p>In short, you do the following</p>
  
  <ol>
  <li>Find the Printer</li>
  <li>Create a PrinterJob</li>
  <li>Create an AttributeSet</li>
  <li>Add Attributes to the AttributeSet, such as Tray and Duplex</li>
  <li>Call print on the printer job using the AttributeSet</li>
  </ol>
  
  <p>The problem here is that, despite being the documented way of doing this, as well as what I've found from several tutorials, this method... <strong>doesn't work</strong>.  Now keep in mind, I know that doesn't sound very descript, but hear me out.  <strong>I don't say that lightly</strong>...</p>
  
  <p><a href="http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/print/PrinterJob.html#print%28javax.print.attribute.PrintRequestAttributeSet%29">The official documentation for PrinterJob</a> actually mentions that the AttributeSet is ignored in the default implementation.  <a href="http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/awt/print/PrinterJob.java">Source code seen here</a> shows this to be true - the attributes are passed in and ignored entirely.</p>
  
  <p>So apparently, you need some sort of extended version of the class, which is possibly based on the specific printers and their capabilities?  I attempted to write some test code that would tell me such capabilities - we have a large variety of printers set up at the office, large or small, simple or full of bells and whistles - not to mention several drivers on my computer just for pseudo-printer drivers that just create documents and simulate printers without going to any sort of hardware.  The test code is as follows:</p>
  
  <pre><code>public static void main (String [] args) {
  
      PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null);
  
      for (PrintService serv: pservices) {
          System.out.println(serv.toString());
  
          printFunctionality(serv, "Trays", MediaTray.class);
          printFunctionality(serv, "Copies", Copies.class);
          printFunctionality(serv, "Print Quality", PrintQuality.class);
          printFunctionality(serv, "Color", ColorSupported.class);
          printFunctionality(serv, "Media Size", MediaSize.class);
          printFunctionality(serv, "Accepting Jobs", PrinterIsAcceptingJobs.class);
      }
  }
  
  private static void printFunctionality(PrintService serv, String attrName, Class&lt;? extends Attribute&gt; attr) {
      boolean isSupported = serv.isAttributeCategorySupported(attr);
      System.out.println("    " + attrName + ": " + (isSupported ? "Y" : "N"));
  }
  </code></pre>
  
  <p>The results I found were that every printer, without exception, returned that "copies" were supported, and all other attributes were not.  Furthermore, every printer's capabilities were identical, regardless of how implausible that would seem.</p>
  
  <p>The inevitable question is multi-layered:  How does one send in attributes in a way that they are registered?  Additionally, how does one properly detect the capabilities of a printer?  Indeed, is the PrinterJob class actually extended in a usable way at all, or are the Attributes always ignored?</p>
  
  <p>Examples I've found throughout The Internet seem to suggest to me that the answer to the latter question is "No, they are always ignored", which seems ridiculous to me (but increasingly more believable as I sift through hundreds of pages).  <strong>Is this code that Sun simply set up but never got working</strong> to a completed state?  If so, <strong>are there any alternatives?</strong></p>