1 /*
   2  * Copyright (c) 2000, 2013, 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 sun.print;
  27 
  28 import java.awt.Dimension;
  29 import java.awt.Frame;
  30 import java.awt.Graphics;
  31 import java.awt.Graphics2D;
  32 import java.awt.PrintJob;
  33 import java.awt.JobAttributes;
  34 import java.awt.JobAttributes.*;
  35 import java.awt.PageAttributes;
  36 import java.awt.PageAttributes.*;
  37 
  38 import java.awt.print.PageFormat;
  39 import java.awt.print.Paper;
  40 import java.awt.print.Printable;
  41 import java.awt.print.PrinterException;
  42 import java.awt.print.PrinterJob;
  43 
  44 import java.io.File;
  45 import java.io.FilePermission;
  46 import java.io.IOException;
  47 
  48 import java.net.URI;
  49 import java.net.URISyntaxException;
  50 
  51 import java.util.ArrayList;
  52 import java.util.Properties;
  53 
  54 import javax.print.PrintService;
  55 import javax.print.attribute.HashPrintRequestAttributeSet;
  56 import javax.print.attribute.PrintRequestAttributeSet;
  57 import javax.print.attribute.ResolutionSyntax;
  58 import javax.print.attribute.Size2DSyntax;
  59 import javax.print.attribute.standard.Chromaticity;
  60 import javax.print.attribute.standard.Copies;
  61 import javax.print.attribute.standard.Destination;
  62 import javax.print.attribute.standard.DialogTypeSelection;
  63 import javax.print.attribute.standard.JobName;
  64 import javax.print.attribute.standard.MediaSize;
  65 import javax.print.attribute.standard.PrintQuality;
  66 import javax.print.attribute.standard.PrinterResolution;
  67 import javax.print.attribute.standard.SheetCollate;
  68 import javax.print.attribute.standard.Sides;
  69 import javax.print.attribute.standard.Media;
  70 import javax.print.attribute.standard.OrientationRequested;
  71 import javax.print.attribute.standard.MediaSizeName;
  72 import javax.print.attribute.standard.PageRanges;
  73 
  74 import sun.misc.ManagedLocalsThread;
  75 import sun.print.SunPageSelection;
  76 import sun.print.SunMinMaxPage;
  77 
  78 /**
  79  * A class which initiates and executes a print job using
  80  * the underlying PrinterJob graphics conversions.
  81  *
  82  * @see Toolkit#getPrintJob
  83  *
  84  */
  85 public class PrintJob2D extends PrintJob implements Printable, Runnable {
  86 
  87     private static final MediaType SIZES[] = {
  88         MediaType.ISO_4A0, MediaType.ISO_2A0, MediaType.ISO_A0,
  89         MediaType.ISO_A1, MediaType.ISO_A2, MediaType.ISO_A3,
  90         MediaType.ISO_A4, MediaType.ISO_A5, MediaType.ISO_A6,
  91         MediaType.ISO_A7, MediaType.ISO_A8, MediaType.ISO_A9,
  92         MediaType.ISO_A10, MediaType.ISO_B0, MediaType.ISO_B1,
  93         MediaType.ISO_B2, MediaType.ISO_B3, MediaType.ISO_B4,
  94         MediaType.ISO_B5, MediaType.ISO_B6, MediaType.ISO_B7,
  95         MediaType.ISO_B8, MediaType.ISO_B9, MediaType.ISO_B10,
  96         MediaType.JIS_B0, MediaType.JIS_B1, MediaType.JIS_B2,
  97         MediaType.JIS_B3, MediaType.JIS_B4, MediaType.JIS_B5,
  98         MediaType.JIS_B6, MediaType.JIS_B7, MediaType.JIS_B8,
  99         MediaType.JIS_B9, MediaType.JIS_B10, MediaType.ISO_C0,
 100         MediaType.ISO_C1, MediaType.ISO_C2, MediaType.ISO_C3,
 101         MediaType.ISO_C4, MediaType.ISO_C5, MediaType.ISO_C6,
 102         MediaType.ISO_C7, MediaType.ISO_C8, MediaType.ISO_C9,
 103         MediaType.ISO_C10, MediaType.ISO_DESIGNATED_LONG,
 104         MediaType.EXECUTIVE, MediaType.FOLIO, MediaType.INVOICE,
 105         MediaType.LEDGER, MediaType.NA_LETTER, MediaType.NA_LEGAL,
 106         MediaType.QUARTO, MediaType.A, MediaType.B,
 107         MediaType.C, MediaType.D, MediaType.E,
 108         MediaType.NA_10X15_ENVELOPE, MediaType.NA_10X14_ENVELOPE,
 109         MediaType.NA_10X13_ENVELOPE, MediaType.NA_9X12_ENVELOPE,
 110         MediaType.NA_9X11_ENVELOPE, MediaType.NA_7X9_ENVELOPE,
 111         MediaType.NA_6X9_ENVELOPE, MediaType.NA_NUMBER_9_ENVELOPE,
 112         MediaType.NA_NUMBER_10_ENVELOPE, MediaType.NA_NUMBER_11_ENVELOPE,
 113         MediaType.NA_NUMBER_12_ENVELOPE, MediaType.NA_NUMBER_14_ENVELOPE,
 114         MediaType.INVITE_ENVELOPE, MediaType.ITALY_ENVELOPE,
 115         MediaType.MONARCH_ENVELOPE, MediaType.PERSONAL_ENVELOPE
 116     };
 117 
 118     /* This array maps the above array to the objects used by the
 119      * javax.print APIs
 120          */
 121     private static final MediaSizeName JAVAXSIZES[] = {
 122         null, null, MediaSizeName.ISO_A0,
 123         MediaSizeName.ISO_A1, MediaSizeName.ISO_A2, MediaSizeName.ISO_A3,
 124         MediaSizeName.ISO_A4, MediaSizeName.ISO_A5, MediaSizeName.ISO_A6,
 125         MediaSizeName.ISO_A7, MediaSizeName.ISO_A8, MediaSizeName.ISO_A9,
 126         MediaSizeName.ISO_A10, MediaSizeName.ISO_B0, MediaSizeName.ISO_B1,
 127         MediaSizeName.ISO_B2, MediaSizeName.ISO_B3, MediaSizeName.ISO_B4,
 128         MediaSizeName.ISO_B5,  MediaSizeName.ISO_B6, MediaSizeName.ISO_B7,
 129         MediaSizeName.ISO_B8, MediaSizeName.ISO_B9, MediaSizeName.ISO_B10,
 130         MediaSizeName.JIS_B0, MediaSizeName.JIS_B1, MediaSizeName.JIS_B2,
 131         MediaSizeName.JIS_B3, MediaSizeName.JIS_B4, MediaSizeName.JIS_B5,
 132         MediaSizeName.JIS_B6, MediaSizeName.JIS_B7, MediaSizeName.JIS_B8,
 133         MediaSizeName.JIS_B9, MediaSizeName.JIS_B10, MediaSizeName.ISO_C0,
 134         MediaSizeName.ISO_C1, MediaSizeName.ISO_C2, MediaSizeName.ISO_C3,
 135         MediaSizeName.ISO_C4, MediaSizeName.ISO_C5, MediaSizeName.ISO_C6,
 136         null, null, null, null,
 137         MediaSizeName.ISO_DESIGNATED_LONG, MediaSizeName.EXECUTIVE,
 138         MediaSizeName.FOLIO, MediaSizeName.INVOICE, MediaSizeName.LEDGER,
 139         MediaSizeName.NA_LETTER, MediaSizeName.NA_LEGAL,
 140         MediaSizeName.QUARTO, MediaSizeName.A, MediaSizeName.B,
 141         MediaSizeName.C, MediaSizeName.D, MediaSizeName.E,
 142         MediaSizeName.NA_10X15_ENVELOPE, MediaSizeName.NA_10X14_ENVELOPE,
 143         MediaSizeName.NA_10X13_ENVELOPE, MediaSizeName.NA_9X12_ENVELOPE,
 144         MediaSizeName.NA_9X11_ENVELOPE, MediaSizeName.NA_7X9_ENVELOPE,
 145         MediaSizeName.NA_6X9_ENVELOPE,
 146         MediaSizeName.NA_NUMBER_9_ENVELOPE,
 147         MediaSizeName.NA_NUMBER_10_ENVELOPE,
 148         MediaSizeName.NA_NUMBER_11_ENVELOPE,
 149         MediaSizeName.NA_NUMBER_12_ENVELOPE,
 150         MediaSizeName.NA_NUMBER_14_ENVELOPE,
 151         null, MediaSizeName.ITALY_ENVELOPE,
 152         MediaSizeName.MONARCH_ENVELOPE, MediaSizeName.PERSONAL_ENVELOPE,
 153     };
 154 
 155 
 156     // widths and lengths in PostScript points (1/72 in.)
 157     private static final int WIDTHS[] = {
 158         /*iso-4a0*/ 4768, /*iso-2a0*/ 3370, /*iso-a0*/ 2384, /*iso-a1*/ 1684,
 159         /*iso-a2*/ 1191, /*iso-a3*/ 842, /*iso-a4*/ 595, /*iso-a5*/ 420,
 160         /*iso-a6*/ 298, /*iso-a7*/ 210, /*iso-a8*/ 147, /*iso-a9*/ 105,
 161         /*iso-a10*/ 74, /*iso-b0*/ 2835, /*iso-b1*/ 2004, /*iso-b2*/ 1417,
 162         /*iso-b3*/ 1001, /*iso-b4*/ 709, /*iso-b5*/ 499, /*iso-b6*/ 354,
 163         /*iso-b7*/ 249, /*iso-b8*/ 176, /*iso-b9*/ 125, /*iso-b10*/ 88,
 164         /*jis-b0*/ 2920, /*jis-b1*/ 2064, /*jis-b2*/ 1460, /*jis-b3*/ 1032,
 165         /*jis-b4*/ 729, /*jis-b5*/ 516, /*jis-b6*/ 363, /*jis-b7*/ 258,
 166         /*jis-b8*/ 181, /*jis-b9*/ 128, /*jis-b10*/ 91, /*iso-c0*/ 2599,
 167         /*iso-c1*/ 1837, /*iso-c2*/ 1298, /*iso-c3*/ 918, /*iso-c4*/ 649,
 168         /*iso-c5*/ 459, /*iso-c6*/ 323, /*iso-c7*/ 230, /*iso-c8*/ 162,
 169         /*iso-c9*/ 113, /*iso-c10*/ 79, /*iso-designated-long*/ 312,
 170         /*executive*/ 522, /*folio*/ 612, /*invoice*/ 396, /*ledger*/ 792,
 171         /*na-letter*/ 612, /*na-legal*/ 612, /*quarto*/ 609, /*a*/ 612,
 172         /*b*/ 792, /*c*/ 1224, /*d*/ 1584, /*e*/ 2448,
 173         /*na-10x15-envelope*/ 720, /*na-10x14-envelope*/ 720,
 174         /*na-10x13-envelope*/ 720, /*na-9x12-envelope*/ 648,
 175         /*na-9x11-envelope*/ 648, /*na-7x9-envelope*/ 504,
 176         /*na-6x9-envelope*/ 432, /*na-number-9-envelope*/ 279,
 177         /*na-number-10-envelope*/ 297, /*na-number-11-envelope*/ 324,
 178         /*na-number-12-envelope*/ 342, /*na-number-14-envelope*/ 360,
 179         /*invite-envelope*/ 624, /*italy-envelope*/ 312,
 180         /*monarch-envelope*/ 279, /*personal-envelope*/ 261
 181     };
 182     private static final int LENGTHS[] = {
 183         /*iso-4a0*/ 6741, /*iso-2a0*/ 4768, /*iso-a0*/ 3370, /*iso-a1*/ 2384,
 184         /*iso-a2*/ 1684, /*iso-a3*/ 1191, /*iso-a4*/ 842, /*iso-a5*/ 595,
 185         /*iso-a6*/ 420, /*iso-a7*/ 298, /*iso-a8*/ 210, /*iso-a9*/ 147,
 186         /*iso-a10*/ 105, /*iso-b0*/ 4008, /*iso-b1*/ 2835, /*iso-b2*/ 2004,
 187         /*iso-b3*/ 1417, /*iso-b4*/ 1001, /*iso-b5*/ 729, /*iso-b6*/ 499,
 188         /*iso-b7*/ 354, /*iso-b8*/ 249, /*iso-b9*/ 176, /*iso-b10*/ 125,
 189         /*jis-b0*/ 4127, /*jis-b1*/ 2920, /*jis-b2*/ 2064, /*jis-b3*/ 1460,
 190         /*jis-b4*/ 1032, /*jis-b5*/ 729, /*jis-b6*/ 516, /*jis-b7*/ 363,
 191         /*jis-b8*/ 258, /*jis-b9*/ 181, /*jis-b10*/ 128, /*iso-c0*/ 3677,
 192         /*iso-c1*/ 2599, /*iso-c2*/ 1837, /*iso-c3*/ 1298, /*iso-c4*/ 918,
 193         /*iso-c5*/ 649, /*iso-c6*/ 459, /*iso-c7*/ 323, /*iso-c8*/ 230,
 194         /*iso-c9*/ 162, /*iso-c10*/ 113, /*iso-designated-long*/ 624,
 195         /*executive*/ 756, /*folio*/ 936, /*invoice*/ 612, /*ledger*/ 1224,
 196         /*na-letter*/ 792, /*na-legal*/ 1008, /*quarto*/ 780, /*a*/ 792,
 197         /*b*/ 1224, /*c*/ 1584, /*d*/ 2448, /*e*/ 3168,
 198         /*na-10x15-envelope*/ 1080, /*na-10x14-envelope*/ 1008,
 199         /*na-10x13-envelope*/ 936, /*na-9x12-envelope*/ 864,
 200         /*na-9x11-envelope*/ 792, /*na-7x9-envelope*/ 648,
 201         /*na-6x9-envelope*/ 648, /*na-number-9-envelope*/ 639,
 202         /*na-number-10-envelope*/ 684, /*na-number-11-envelope*/ 747,
 203         /*na-number-12-envelope*/ 792, /*na-number-14-envelope*/ 828,
 204         /*invite-envelope*/ 624, /*italy-envelope*/ 652,
 205         /*monarch-envelope*/ 540, /*personal-envelope*/ 468
 206     };
 207 
 208 
 209     private Frame frame;
 210     private String docTitle = "";
 211     private JobAttributes jobAttributes;
 212     private PageAttributes pageAttributes;
 213     private PrintRequestAttributeSet attributes;
 214 
 215     /*
 216      * Displays the native or cross-platform dialog and allows the
 217      * user to update job & page attributes
 218      */
 219 
 220     /**
 221      * The PrinterJob being uses to implement the PrintJob.
 222      */
 223     private PrinterJob printerJob;
 224 
 225     /**
 226      * The size of the page being used for the PrintJob.
 227      */
 228     private PageFormat pageFormat;
 229 
 230     /**
 231      * The PrinterJob and the application run on different
 232      * threads and communicate through a pair of message
 233      * queues. This queue is the list of Graphics that
 234      * the PrinterJob has requested rendering for, but
 235      * for which the application has not yet called getGraphics().
 236      * In practice the length of this message queue is always
 237      * 0 or 1.
 238      */
 239     private MessageQ graphicsToBeDrawn = new MessageQ("tobedrawn");
 240 
 241     /**
 242      * Used to communicate between the application's thread
 243      * and the PrinterJob's thread this message queue holds
 244      * the list of Graphics into which the application has
 245      * finished drawing, but that have not yet been returned
 246      * to the PrinterJob thread. Again, in practice, the
 247      * length of this message queue is always 0 or 1.
 248      */
 249     private MessageQ graphicsDrawn = new MessageQ("drawn");
 250 
 251     /**
 252      * The last Graphics returned to the application via
 253      * getGraphics. This is the Graphics into which the
 254      * application is currently drawing.
 255      */
 256     private Graphics2D currentGraphics;
 257 
 258     /**
 259      * The zero based index of the page currently being rendered
 260      * by the application.
 261      */
 262     private int pageIndex = -1;
 263 
 264     // The following Strings are maintained for backward-compatibility with
 265     // Properties based print control.
 266     private final static String DEST_PROP = "awt.print.destination";
 267     private final static String PRINTER = "printer";
 268     private final static String FILE = "file";
 269 
 270     private final static String PRINTER_PROP = "awt.print.printer";
 271 
 272     private final static String FILENAME_PROP = "awt.print.fileName";
 273 
 274     private final static String NUMCOPIES_PROP = "awt.print.numCopies";
 275 
 276     private final static String OPTIONS_PROP = "awt.print.options";
 277 
 278     private final static String ORIENT_PROP = "awt.print.orientation";
 279     private final static String PORTRAIT = "portrait";
 280     private final static String LANDSCAPE = "landscape";
 281 
 282     private final static String PAPERSIZE_PROP = "awt.print.paperSize";
 283     private final static String LETTER = "letter";
 284     private final static String LEGAL = "legal";
 285     private final static String EXECUTIVE = "executive";
 286     private final static String A4 = "a4";
 287 
 288     private Properties props;
 289 
 290     private String options = ""; // REMIND: needs implementation
 291 
 292     /**
 293      * The thread on which PrinterJob is running.
 294      * This is different than the applications thread.
 295      */
 296     private Thread printerJobThread;
 297 
 298     public PrintJob2D(Frame frame,  String doctitle,
 299                       final Properties props) {
 300         this.props = props;
 301         this.jobAttributes = new JobAttributes();
 302         this.pageAttributes = new PageAttributes();
 303         translateInputProps();
 304         initPrintJob2D(frame, doctitle,
 305                        this.jobAttributes, this.pageAttributes);
 306     }
 307 
 308     public PrintJob2D(Frame frame,  String doctitle,
 309                       JobAttributes jobAttributes,
 310                       PageAttributes pageAttributes) {
 311         initPrintJob2D(frame, doctitle, jobAttributes, pageAttributes);
 312     }
 313 
 314     private void initPrintJob2D(Frame frame,  String doctitle,
 315                                 JobAttributes jobAttributes,
 316                                 PageAttributes pageAttributes) {
 317 
 318         SecurityManager security = System.getSecurityManager();
 319         if (security != null) {
 320             security.checkPrintJobAccess();
 321         }
 322 
 323         if (frame == null &&
 324             (jobAttributes == null ||
 325              jobAttributes.getDialog() == DialogType.NATIVE)) {
 326             throw new NullPointerException("Frame must not be null");
 327         }
 328         this.frame = frame;
 329 
 330         this.docTitle = (doctitle == null) ? "" : doctitle;
 331         this.jobAttributes = (jobAttributes != null)
 332             ? jobAttributes : new JobAttributes();
 333         this.pageAttributes = (pageAttributes != null)
 334             ? pageAttributes : new PageAttributes();
 335 
 336         // Currently, we always reduce page ranges to xxx or xxx-xxx
 337         int[][] pageRanges = this.jobAttributes.getPageRanges();
 338         int first = pageRanges[0][0];
 339         int last = pageRanges[pageRanges.length - 1][1];
 340         this.jobAttributes.setPageRanges(new int[][] {
 341             new int[] { first, last }
 342         });
 343         this.jobAttributes.setToPage(last);
 344         this.jobAttributes.setFromPage(first);
 345 
 346 
 347         // Verify that the cross feed and feed resolutions are the same
 348         int[] res = this.pageAttributes.getPrinterResolution();
 349         if (res[0] != res[1]) {
 350             throw new IllegalArgumentException("Differing cross feed and feed"+
 351                                                " resolutions not supported.");
 352         }
 353 
 354         // Verify that the app has access to the file system
 355         DestinationType dest= this.jobAttributes.getDestination();
 356         if (dest == DestinationType.FILE) {
 357             throwPrintToFile();
 358 
 359             // check if given filename is valid
 360             String destStr = jobAttributes.getFileName();
 361             if ((destStr != null) &&
 362                 (jobAttributes.getDialog() == JobAttributes.DialogType.NONE)) {
 363 
 364                 File f = new File(destStr);
 365                 try {
 366                     // check if this is a new file and if filename chars are valid
 367                     // createNewFile returns false if file exists
 368                     if (f.createNewFile()) {
 369                         f.delete();
 370                     }
 371                 } catch (IOException ioe) {
 372                     throw new IllegalArgumentException("Cannot write to file:"+
 373                                                        destStr);
 374                 } catch (SecurityException se) {
 375                     //There is already file read/write access so at this point
 376                     // only delete access is denied.  Just ignore it because in
 377                     // most cases the file created in createNewFile gets overwritten
 378                     // anyway.
 379                 }
 380 
 381                  File pFile = f.getParentFile();
 382                  if ((f.exists() &&
 383                       (!f.isFile() || !f.canWrite())) ||
 384                      ((pFile != null) &&
 385                       (!pFile.exists() || (pFile.exists() && !pFile.canWrite())))) {
 386                      throw new IllegalArgumentException("Cannot write to file:"+
 387                                                         destStr);
 388                  }
 389             }
 390         }
 391     }
 392 
 393     public boolean printDialog() {
 394 
 395         boolean proceedWithPrint = false;
 396 
 397         printerJob = PrinterJob.getPrinterJob();
 398         if (printerJob == null) {
 399             return false;
 400         }
 401         DialogType d = this.jobAttributes.getDialog();
 402         PrintService pServ = printerJob.getPrintService();
 403         if ((pServ == null) &&  (d == DialogType.NONE)){
 404             return false;
 405         }
 406         copyAttributes(pServ);
 407 
 408         DefaultSelectionType select =
 409             this.jobAttributes.getDefaultSelection();
 410         if (select == DefaultSelectionType.RANGE) {
 411             attributes.add(SunPageSelection.RANGE);
 412         } else if (select == DefaultSelectionType.SELECTION) {
 413             attributes.add(SunPageSelection.SELECTION);
 414         } else {
 415             attributes.add(SunPageSelection.ALL);
 416         }
 417 
 418         if (frame != null) {
 419              attributes.add(new DialogOwner(frame));
 420          }
 421 
 422         if ( d == DialogType.NONE) {
 423             proceedWithPrint = true;
 424         } else {
 425             if (d == DialogType.NATIVE) {
 426                 attributes.add(DialogTypeSelection.NATIVE);
 427             }  else { //  (d == DialogType.COMMON)
 428                 attributes.add(DialogTypeSelection.COMMON);
 429             }
 430             if (proceedWithPrint = printerJob.printDialog(attributes)) {
 431                 if (pServ == null) {
 432                     // Windows gives an option to install a service
 433                     // when it detects there are no printers so
 434                     // we make sure we get the updated print service.
 435                     pServ = printerJob.getPrintService();
 436                     if (pServ == null) {
 437                         return false;
 438                     }
 439                 }
 440                 updateAttributes();
 441                 translateOutputProps();
 442             }
 443         }
 444 
 445         if (proceedWithPrint) {
 446 
 447             JobName jname = (JobName)attributes.get(JobName.class);
 448             if (jname != null) {
 449                 printerJob.setJobName(jname.toString());
 450             }
 451 
 452             pageFormat = new PageFormat();
 453 
 454             Media media = (Media)attributes.get(Media.class);
 455             MediaSize mediaSize =  null;
 456             if (media != null  && media instanceof MediaSizeName) {
 457                 mediaSize = MediaSize.getMediaSizeForName((MediaSizeName)media);
 458             }
 459 
 460             Paper p = pageFormat.getPaper();
 461             if (mediaSize != null) {
 462                 p.setSize(mediaSize.getX(MediaSize.INCH)*72.0,
 463                           mediaSize.getY(MediaSize.INCH)*72.0);
 464             }
 465 
 466             if (pageAttributes.getOrigin()==OriginType.PRINTABLE) {
 467                 // AWT uses 1/4" borders by default
 468                 p.setImageableArea(18.0, 18.0,
 469                                    p.getWidth()-36.0,
 470                                    p.getHeight()-36.0);
 471             } else {
 472                 p.setImageableArea(0.0,0.0,p.getWidth(),p.getHeight());
 473             }
 474 
 475             pageFormat.setPaper(p);
 476 
 477             OrientationRequested orient =
 478                (OrientationRequested)attributes.get(OrientationRequested.class);
 479             if (orient!= null &&
 480                 orient == OrientationRequested.REVERSE_LANDSCAPE) {
 481                 pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE);
 482             } else if (orient == OrientationRequested.LANDSCAPE) {
 483                 pageFormat.setOrientation(PageFormat.LANDSCAPE);
 484             } else {
 485                 pageFormat.setOrientation(PageFormat.PORTRAIT);
 486                 }
 487 
 488             printerJob.setPrintable(this, pageFormat);
 489 
 490         }
 491 
 492         return proceedWithPrint;
 493     }
 494 
 495     private void updateAttributes() {
 496         Copies c = (Copies)attributes.get(Copies.class);
 497         jobAttributes.setCopies(c.getValue());
 498 
 499         SunPageSelection sel =
 500             (SunPageSelection)attributes.get(SunPageSelection.class);
 501         if (sel == SunPageSelection.RANGE) {
 502             jobAttributes.setDefaultSelection(DefaultSelectionType.RANGE);
 503         } else if (sel == SunPageSelection.SELECTION) {
 504             jobAttributes.setDefaultSelection(DefaultSelectionType.SELECTION);
 505         } else {
 506             jobAttributes.setDefaultSelection(DefaultSelectionType.ALL);
 507         }
 508 
 509         Destination dest = (Destination)attributes.get(Destination.class);
 510         if (dest != null) {
 511             jobAttributes.setDestination(DestinationType.FILE);
 512             jobAttributes.setFileName(dest.getURI().getPath());
 513         } else {
 514             jobAttributes.setDestination(DestinationType.PRINTER);
 515         }
 516 
 517         PrintService serv = printerJob.getPrintService();
 518         if (serv != null) {
 519             jobAttributes.setPrinter(serv.getName());
 520         }
 521 
 522         PageRanges range = (PageRanges)attributes.get(PageRanges.class);
 523         int[][] members = range.getMembers();
 524         jobAttributes.setPageRanges(members);
 525 
 526         SheetCollate collation =
 527             (SheetCollate)attributes.get(SheetCollate.class);
 528         if (collation == SheetCollate.COLLATED) {
 529             jobAttributes.setMultipleDocumentHandling(
 530             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES);
 531         } else {
 532             jobAttributes.setMultipleDocumentHandling(
 533             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES);
 534         }
 535 
 536         Sides sides = (Sides)attributes.get(Sides.class);
 537         if (sides == Sides.TWO_SIDED_LONG_EDGE) {
 538             jobAttributes.setSides(SidesType.TWO_SIDED_LONG_EDGE);
 539         } else if (sides == Sides.TWO_SIDED_SHORT_EDGE) {
 540             jobAttributes.setSides(SidesType.TWO_SIDED_SHORT_EDGE);
 541         } else {
 542             jobAttributes.setSides(SidesType.ONE_SIDED);
 543         }
 544 
 545         // PageAttributes
 546 
 547         Chromaticity color =
 548             (Chromaticity)attributes.get(Chromaticity.class);
 549         if (color == Chromaticity.COLOR) {
 550             pageAttributes.setColor(ColorType.COLOR);
 551         } else {
 552             pageAttributes.setColor(ColorType.MONOCHROME);
 553         }
 554 
 555         OrientationRequested orient =
 556             (OrientationRequested)attributes.get(OrientationRequested.class);
 557         if (orient == OrientationRequested.LANDSCAPE) {
 558             pageAttributes.setOrientationRequested(
 559                                        OrientationRequestedType.LANDSCAPE);
 560         } else {
 561             pageAttributes.setOrientationRequested(
 562                                        OrientationRequestedType.PORTRAIT);
 563         }
 564 
 565         PrintQuality qual = (PrintQuality)attributes.get(PrintQuality.class);
 566         if (qual == PrintQuality.DRAFT) {
 567             pageAttributes.setPrintQuality(PrintQualityType.DRAFT);
 568         } else if (qual == PrintQuality.HIGH) {
 569             pageAttributes.setPrintQuality(PrintQualityType.HIGH);
 570         } else { // NORMAL
 571             pageAttributes.setPrintQuality(PrintQualityType.NORMAL);
 572         }
 573 
 574         Media msn = (Media)attributes.get(Media.class);
 575         if (msn != null && msn instanceof MediaSizeName) {
 576             MediaType mType = unMapMedia((MediaSizeName)msn);
 577 
 578             if (mType != null) {
 579                 pageAttributes.setMedia(mType);
 580             }
 581         }
 582         debugPrintAttributes(false, false);
 583     }
 584 
 585     private void debugPrintAttributes(boolean ja, boolean pa ) {
 586         if (ja) {
 587             System.out.println("new Attributes\ncopies = "+
 588                                jobAttributes.getCopies()+
 589                                "\nselection = "+
 590                                jobAttributes.getDefaultSelection()+
 591                                "\ndest "+jobAttributes.getDestination()+
 592                                "\nfile "+jobAttributes.getFileName()+
 593                                "\nfromPage "+jobAttributes.getFromPage()+
 594                                "\ntoPage "+jobAttributes.getToPage()+
 595                                "\ncollation "+
 596                                jobAttributes.getMultipleDocumentHandling()+
 597                                "\nPrinter "+jobAttributes.getPrinter()+
 598                                "\nSides2 "+jobAttributes.getSides()
 599                                );
 600         }
 601 
 602         if (pa) {
 603             System.out.println("new Attributes\ncolor = "+
 604                                pageAttributes.getColor()+
 605                                "\norientation = "+
 606                                pageAttributes.getOrientationRequested()+
 607                                "\nquality "+pageAttributes.getPrintQuality()+
 608                                "\nMedia2 "+pageAttributes.getMedia()
 609                                );
 610         }
 611     }
 612 
 613 
 614     /* From JobAttributes we will copy job name and duplex printing
 615      * and destination.
 616      * The majority of the rest of the attributes are reflected
 617      * attributes.
 618      *
 619      * From PageAttributes we copy color, media size, orientation,
 620      * origin type, resolution and print quality.
 621      * We use the media, orientation in creating the page format, and
 622      * the origin type to set its imageable area.
 623      *
 624      * REMIND: Interpretation of resolution, additional media sizes.
 625      */
 626     private void copyAttributes(PrintService printServ) {
 627 
 628         attributes = new HashPrintRequestAttributeSet();
 629         attributes.add(new JobName(docTitle, null));
 630         PrintService pServ = printServ;
 631 
 632         String printerName = jobAttributes.getPrinter();
 633         if (printerName != null && printerName != ""
 634             && !printerName.equals(pServ.getName())) {
 635 
 636             // Search for the given printerName in the list of PrintServices
 637             PrintService []services = PrinterJob.lookupPrintServices();
 638             try {
 639                 for (int i=0; i<services.length; i++) {
 640                     if (printerName.equals(services[i].getName())) {
 641                         printerJob.setPrintService(services[i]);
 642                         pServ = services[i];
 643                         break;
 644                     }
 645                 }
 646             } catch (PrinterException pe) {
 647             }
 648         }
 649 
 650         DestinationType dest = jobAttributes.getDestination();
 651         if (dest == DestinationType.FILE &&
 652             pServ.isAttributeCategorySupported(Destination.class)) {
 653 
 654             String fileName = jobAttributes.getFileName();
 655 
 656             Destination defaultDest;
 657             if (fileName == null && (defaultDest = (Destination)pServ.
 658                     getDefaultAttributeValue(Destination.class)) != null) {
 659                 attributes.add(defaultDest);
 660             } else {
 661                 URI uri = null;
 662                 try {
 663                     if (fileName != null) {
 664                         if (fileName.equals("")) {
 665                             fileName = ".";
 666                         }
 667                     } else {
 668                         // defaultDest should not be null.  The following code
 669                         // is only added to safeguard against a possible
 670                         // buggy implementation of a PrintService having a
 671                         // null default Destination.
 672                         fileName = "out.prn";
 673                     }
 674                     uri = (new File(fileName)).toURI();
 675                 } catch (SecurityException se) {
 676                     try {
 677                         // '\\' file separator is illegal character in opaque
 678                         // part and causes URISyntaxException, so we replace
 679                         // it with '/'
 680                         fileName = fileName.replace('\\', '/');
 681                         uri = new URI("file:"+fileName);
 682                     } catch (URISyntaxException e) {
 683                     }
 684                 }
 685                 if (uri != null) {
 686                     attributes.add(new Destination(uri));
 687                 }
 688             }
 689         }
 690         attributes.add(new SunMinMaxPage(jobAttributes.getMinPage(),
 691                                          jobAttributes.getMaxPage()));
 692         SidesType sType = jobAttributes.getSides();
 693         if (sType == SidesType.TWO_SIDED_LONG_EDGE) {
 694             attributes.add(Sides.TWO_SIDED_LONG_EDGE);
 695         } else if (sType == SidesType.TWO_SIDED_SHORT_EDGE) {
 696             attributes.add(Sides.TWO_SIDED_SHORT_EDGE);
 697         } else if (sType == SidesType.ONE_SIDED) {
 698             attributes.add(Sides.ONE_SIDED);
 699         }
 700 
 701         MultipleDocumentHandlingType hType =
 702           jobAttributes.getMultipleDocumentHandling();
 703         if (hType ==
 704             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES) {
 705           attributes.add(SheetCollate.COLLATED);
 706         } else {
 707           attributes.add(SheetCollate.UNCOLLATED);
 708         }
 709 
 710         attributes.add(new Copies(jobAttributes.getCopies()));
 711 
 712         attributes.add(new PageRanges(jobAttributes.getFromPage(),
 713                                       jobAttributes.getToPage()));
 714 
 715         if (pageAttributes.getColor() == ColorType.COLOR) {
 716             attributes.add(Chromaticity.COLOR);
 717         } else {
 718             attributes.add(Chromaticity.MONOCHROME);
 719         }
 720 
 721         pageFormat = printerJob.defaultPage();
 722         if (pageAttributes.getOrientationRequested() ==
 723             OrientationRequestedType.LANDSCAPE) {
 724             pageFormat.setOrientation(PageFormat.LANDSCAPE);
 725                 attributes.add(OrientationRequested.LANDSCAPE);
 726         } else {
 727                 pageFormat.setOrientation(PageFormat.PORTRAIT);
 728                 attributes.add(OrientationRequested.PORTRAIT);
 729         }
 730 
 731         MediaType media = pageAttributes.getMedia();
 732         MediaSizeName msn = mapMedia(media);
 733         if (msn != null) {
 734             attributes.add(msn);
 735         }
 736 
 737         PrintQualityType qType =
 738             pageAttributes.getPrintQuality();
 739         if (qType == PrintQualityType.DRAFT) {
 740             attributes.add(PrintQuality.DRAFT);
 741         } else if (qType == PrintQualityType.NORMAL) {
 742             attributes.add(PrintQuality.NORMAL);
 743         } else if (qType == PrintQualityType.HIGH) {
 744             attributes.add(PrintQuality.HIGH);
 745         }
 746     }
 747 
 748     /**
 749      * Gets a Graphics object that will draw to the next page.
 750      * The page is sent to the printer when the graphics
 751      * object is disposed.  This graphics object will also implement
 752      * the PrintGraphics interface.
 753      * @see PrintGraphics
 754      */
 755     public Graphics getGraphics() {
 756 
 757         Graphics printGraphics = null;
 758 
 759         synchronized (this) {
 760             ++pageIndex;
 761 
 762             // Thread should not be created after end has been called.
 763             // One way to detect this is if any of the graphics queue
 764             //  has been closed.
 765             if (pageIndex == 0 && !graphicsToBeDrawn.isClosed()) {
 766 
 767             /* We start a thread on which the PrinterJob will run.
 768              * The PrinterJob will ask for pages on that thread
 769              * and will use a message queue to fulfill the application's
 770              * requests for a Graphics on the application's
 771              * thread.
 772              */
 773 
 774                 startPrinterJobThread();
 775 
 776             }
 777             notify();
 778         }
 779 
 780         /* If the application has already been handed back
 781          * a graphics then we need to put that graphics into
 782          * the drawn queue so that the PrinterJob thread can
 783          * return to the print system.
 784          */
 785         if (currentGraphics != null) {
 786             graphicsDrawn.append(currentGraphics);
 787             currentGraphics = null;
 788         }
 789 
 790         /* We'll block here until a new graphics becomes
 791          * available.
 792          */
 793 
 794         currentGraphics = graphicsToBeDrawn.pop();
 795 
 796         if (currentGraphics instanceof PeekGraphics) {
 797             ( (PeekGraphics) currentGraphics).setAWTDrawingOnly();
 798             graphicsDrawn.append(currentGraphics);
 799             currentGraphics = graphicsToBeDrawn.pop();
 800         }
 801 
 802 
 803         if (currentGraphics != null) {
 804 
 805             /* In the PrintJob API, the origin is at the upper-
 806              * left of the imageable area when using the new "printable"
 807              * origin attribute, otherwise its the physical origin (for
 808              * backwards compatibility. We emulate this by createing
 809              * a PageFormat which matches and then performing the
 810              * translate to the origin. This is a no-op if physical
 811              * origin is specified.
 812              */
 813             currentGraphics.translate(pageFormat.getImageableX(),
 814                                       pageFormat.getImageableY());
 815 
 816             /* Scale to accommodate AWT's notion of printer resolution */
 817             double awtScale = 72.0/getPageResolutionInternal();
 818             currentGraphics.scale(awtScale, awtScale);
 819 
 820             /* The caller wants a Graphics instance but we do
 821              * not want them to make 2D calls. We can't hand
 822              * back a Graphics2D. The returned Graphics also
 823              * needs to implement PrintGraphics, so we wrap
 824              * the Graphics2D instance. The PrintJob API has
 825              * the application dispose of the Graphics so
 826              * we create a copy of the one returned by PrinterJob.
 827              */
 828             printGraphics = new ProxyPrintGraphics(currentGraphics.create(),
 829                                                    this);
 830 
 831         }
 832 
 833         return printGraphics;
 834     }
 835 
 836     /**
 837      * Returns the dimensions of the page in pixels.
 838      * The resolution of the page is chosen so that it
 839      * is similar to the screen resolution.
 840      * Except (since 1.3) when the application specifies a resolution.
 841      * In that case it is scaled accordingly.
 842      */
 843     public Dimension getPageDimension() {
 844         double wid, hgt, scale;
 845         if (pageAttributes != null &&
 846             pageAttributes.getOrigin()==OriginType.PRINTABLE) {
 847             wid = pageFormat.getImageableWidth();
 848             hgt = pageFormat.getImageableHeight();
 849         } else {
 850             wid = pageFormat.getWidth();
 851             hgt = pageFormat.getHeight();
 852         }
 853         scale = getPageResolutionInternal() / 72.0;
 854         return new Dimension((int)(wid * scale), (int)(hgt * scale));
 855     }
 856 
 857      private double getPageResolutionInternal() {
 858         if (pageAttributes != null) {
 859             int []res = pageAttributes.getPrinterResolution();
 860             if (res[2] == 3) {
 861                 return res[0];
 862             } else /* if (res[2] == 4) */ {
 863                 return (res[0] * 2.54);
 864             }
 865         } else {
 866             return 72.0;
 867         }
 868     }
 869 
 870     /**
 871      * Returns the resolution of the page in pixels per inch.
 872      * Note that this doesn't have to correspond to the physical
 873      * resolution of the printer.
 874      */
 875     public int getPageResolution() {
 876         return (int)getPageResolutionInternal();
 877     }
 878 
 879     /**
 880      * Returns true if the last page will be printed first.
 881      */
 882     public boolean lastPageFirst() {
 883         return false;
 884     }
 885 
 886     /**
 887      * Ends the print job and does any necessary cleanup.
 888      */
 889     public synchronized void end() {
 890 
 891         /* Prevent the PrinterJob thread from appending any more
 892          * graphics to the to-be-drawn queue
 893          */
 894         graphicsToBeDrawn.close();
 895 
 896         /* If we have a currentGraphics it was the last one returned to the
 897          * PrintJob client. Append it to the drawn queue so that print()
 898          * will return allowing the page to be flushed.
 899          * This really ought to happen in dispose() but for whatever reason
 900          * that isn't how the old PrintJob worked even though its spec
 901          * said dispose() flushed the page.
 902          */
 903         if (currentGraphics != null) {
 904             graphicsDrawn.append(currentGraphics);
 905         }
 906         graphicsDrawn.closeWhenEmpty();
 907 
 908         /* Wait for the PrinterJob.print() thread to terminate, ensuring
 909          * that RasterPrinterJob has made its end doc call, and resources
 910          * are released, files closed etc.
 911          */
 912         if( printerJobThread != null && printerJobThread.isAlive() ){
 913             try {
 914                 printerJobThread.join();
 915             } catch (InterruptedException e) {
 916             }
 917         }
 918     }
 919 
 920     /**
 921      * Ends this print job once it is no longer referenced.
 922      * @see #end
 923      */
 924     public void finalize() {
 925         end();
 926     }
 927 
 928     /**
 929      * Prints the page at the specified index into the specified
 930      * {@link Graphics} context in the specified
 931      * format.  A <code>PrinterJob</code> calls the
 932      * <code>Printable</code> interface to request that a page be
 933      * rendered into the context specified by
 934      * <code>graphics</code>.  The format of the page to be drawn is
 935      * specified by <code>pageFormat</code>.  The zero based index
 936      * of the requested page is specified by <code>pageIndex</code>.
 937      * If the requested page does not exist then this method returns
 938      * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned.
 939      * The <code>Graphics</code> class or subclass implements the
 940      * {@link PrinterGraphics} interface to provide additional
 941      * information.  If the <code>Printable</code> object
 942      * aborts the print job then it throws a {@link PrinterException}.
 943      * @param graphics the context into which the page is drawn
 944      * @param pageFormat the size and orientation of the page being drawn
 945      * @param pageIndex the zero based index of the page to be drawn
 946      * @return PAGE_EXISTS if the page is rendered successfully
 947      *         or NO_SUCH_PAGE if <code>pageIndex</code> specifies a
 948      *         non-existent page.
 949      * @exception java.awt.print.PrinterException
 950      *         thrown when the print job is terminated.
 951      */
 952     public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
 953                  throws PrinterException {
 954 
 955         int result;
 956 
 957         /* This method will be called by the PrinterJob on a thread other
 958          * that the application's thread. We hold on to the graphics
 959          * until we can rendevous with the application's thread and
 960          * hand over the graphics. The application then does all the
 961          * drawing. When the application is done drawing we rendevous
 962          * again with the PrinterJob thread and release the Graphics
 963          * so that it knows we are done.
 964          */
 965 
 966         /* Add the graphics to the message queue of graphics to
 967          * be rendered. This is really a one slot queue. The
 968          * application's thread will come along and remove the
 969          * graphics from the queue when the app asks for a graphics.
 970          */
 971         graphicsToBeDrawn.append( (Graphics2D) graphics);
 972 
 973         /* We now wait for the app's thread to finish drawing on
 974          * the Graphics. This thread will sleep until the application
 975          * release the graphics by placing it in the graphics drawn
 976          * message queue. If the application signals that it is
 977          * finished drawing the entire document then we'll get null
 978          * returned when we try and pop a finished graphic.
 979          */
 980         if (graphicsDrawn.pop() != null) {
 981             result = PAGE_EXISTS;
 982         } else {
 983             result = NO_SUCH_PAGE;
 984         }
 985 
 986         return result;
 987     }
 988 
 989     private void startPrinterJobThread() {
 990         String name = "printerJobThread";
 991         if (System.getSecurityManager() == null) {
 992             printerJobThread = new Thread(this, name);
 993         } else {
 994             printerJobThread = new ManagedLocalsThread(this, name);
 995         }
 996         printerJobThread.start();
 997     }
 998 
 999 
1000     public void run() {
1001 
1002         try {
1003             printerJob.print(attributes);
1004         } catch (PrinterException e) {
1005             //REMIND: need to store this away and not rethrow it.
1006         }
1007 
1008         /* Close the message queues so that nobody is stuck
1009          * waiting for one.
1010          */
1011         graphicsToBeDrawn.closeWhenEmpty();
1012         graphicsDrawn.close();
1013     }
1014 
1015     private class MessageQ {
1016 
1017         private String qid="noname";
1018 
1019         private ArrayList<Graphics2D> queue = new ArrayList<>();
1020 
1021         MessageQ(String id) {
1022           qid = id;
1023         }
1024 
1025         synchronized void closeWhenEmpty() {
1026 
1027             while (queue != null && queue.size() > 0) {
1028                 try {
1029                     wait(1000);
1030                 } catch (InterruptedException e) {
1031                     // do nothing.
1032                 }
1033             }
1034 
1035             queue = null;
1036             notifyAll();
1037         }
1038 
1039         synchronized void close() {
1040             queue = null;
1041             notifyAll();
1042         }
1043 
1044         synchronized boolean append(Graphics2D g) {
1045 
1046             boolean queued = false;
1047 
1048             if (queue != null) {
1049                 queue.add(g);
1050                 queued = true;
1051                 notify();
1052             }
1053 
1054             return queued;
1055         }
1056 
1057         synchronized Graphics2D pop() {
1058             Graphics2D g = null;
1059 
1060             while (g == null && queue != null) {
1061 
1062                 if (queue.size() > 0) {
1063                     g = queue.remove(0);
1064                     notify();
1065 
1066                 } else {
1067                     try {
1068                         wait(2000);
1069                     } catch (InterruptedException e) {
1070                         // do nothing.
1071                     }
1072                 }
1073             }
1074 
1075             return g;
1076         }
1077 
1078         synchronized boolean isClosed() {
1079             return queue == null;
1080         }
1081 
1082     }
1083 
1084 
1085     private static int[] getSize(MediaType mType) {
1086         int []dim = new int[2];
1087         dim[0] = 612;
1088         dim[1] = 792;
1089 
1090         for (int i=0; i < SIZES.length; i++) {
1091             if (SIZES[i] == mType) {
1092                 dim[0] = WIDTHS[i];
1093                 dim[1] = LENGTHS[i];
1094                 break;
1095             }
1096         }
1097         return dim;
1098     }
1099 
1100     public static MediaSizeName mapMedia(MediaType mType) {
1101         MediaSizeName media = null;
1102 
1103         // JAVAXSIZES.length and SIZES.length must be equal!
1104         // Attempt to recover by getting the smaller size.
1105         int length = Math.min(SIZES.length, JAVAXSIZES.length);
1106 
1107         for (int i=0; i < length; i++) {
1108             if (SIZES[i] == mType) {
1109                 if ((JAVAXSIZES[i] != null) &&
1110                     MediaSize.getMediaSizeForName(JAVAXSIZES[i]) != null) {
1111                     media = JAVAXSIZES[i];
1112                     break;
1113                 } else {
1114                     /* create Custom Media */
1115                     media = new CustomMediaSizeName(SIZES[i].toString());
1116 
1117                     float w = (float)Math.rint(WIDTHS[i]  / 72.0);
1118                     float h = (float)Math.rint(LENGTHS[i] / 72.0);
1119                     if (w > 0.0 && h > 0.0) {
1120                         // add new created MediaSize to our static map
1121                         // so it will be found when we call findMedia
1122                         new MediaSize(w, h, Size2DSyntax.INCH, media);
1123                     }
1124 
1125                     break;
1126                 }
1127             }
1128         }
1129         return media;
1130     }
1131 
1132 
1133     public static MediaType unMapMedia(MediaSizeName mSize) {
1134         MediaType media = null;
1135 
1136         // JAVAXSIZES.length and SIZES.length must be equal!
1137         // Attempt to recover by getting the smaller size.
1138         int length = Math.min(SIZES.length, JAVAXSIZES.length);
1139 
1140         for (int i=0; i < length; i++) {
1141             if (JAVAXSIZES[i] == mSize) {
1142                 if (SIZES[i] != null) {
1143                     media = SIZES[i];
1144                     break;
1145                 }
1146             }
1147         }
1148         return media;
1149     }
1150 
1151     private void translateInputProps() {
1152         if (props == null) {
1153             return;
1154         }
1155 
1156         String str;
1157 
1158         str = props.getProperty(DEST_PROP);
1159         if (str != null) {
1160             if (str.equals(PRINTER)) {
1161                 jobAttributes.setDestination(DestinationType.PRINTER);
1162             } else if (str.equals(FILE)) {
1163                 jobAttributes.setDestination(DestinationType.FILE);
1164             }
1165         }
1166         str = props.getProperty(PRINTER_PROP);
1167         if (str != null) {
1168             jobAttributes.setPrinter(str);
1169         }
1170         str = props.getProperty(FILENAME_PROP);
1171         if (str != null) {
1172             jobAttributes.setFileName(str);
1173         }
1174         str = props.getProperty(NUMCOPIES_PROP);
1175         if (str != null) {
1176             jobAttributes.setCopies(Integer.parseInt(str));
1177         }
1178 
1179         this.options = props.getProperty(OPTIONS_PROP, "");
1180 
1181         str = props.getProperty(ORIENT_PROP);
1182         if (str != null) {
1183             if (str.equals(PORTRAIT)) {
1184                 pageAttributes.setOrientationRequested(
1185                                         OrientationRequestedType.PORTRAIT);
1186             } else if (str.equals(LANDSCAPE)) {
1187                 pageAttributes.setOrientationRequested(
1188                                         OrientationRequestedType.LANDSCAPE);
1189             }
1190         }
1191         str = props.getProperty(PAPERSIZE_PROP);
1192         if (str != null) {
1193             if (str.equals(LETTER)) {
1194                 pageAttributes.setMedia(SIZES[MediaType.LETTER.hashCode()]);
1195             } else if (str.equals(LEGAL)) {
1196                 pageAttributes.setMedia(SIZES[MediaType.LEGAL.hashCode()]);
1197             } else if (str.equals(EXECUTIVE)) {
1198                 pageAttributes.setMedia(SIZES[MediaType.EXECUTIVE.hashCode()]);
1199             } else if (str.equals(A4)) {
1200                 pageAttributes.setMedia(SIZES[MediaType.A4.hashCode()]);
1201             }
1202         }
1203     }
1204 
1205     private void translateOutputProps() {
1206         if (props == null) {
1207             return;
1208         }
1209 
1210         String str;
1211 
1212         props.setProperty(DEST_PROP,
1213             (jobAttributes.getDestination() == DestinationType.PRINTER) ?
1214                           PRINTER : FILE);
1215         str = jobAttributes.getPrinter();
1216         if (str != null && !str.equals("")) {
1217             props.setProperty(PRINTER_PROP, str);
1218         }
1219         str = jobAttributes.getFileName();
1220         if (str != null && !str.equals("")) {
1221             props.setProperty(FILENAME_PROP, str);
1222         }
1223         int copies = jobAttributes.getCopies();
1224         if (copies > 0) {
1225             props.setProperty(NUMCOPIES_PROP, "" + copies);
1226         }
1227         str = this.options;
1228         if (str != null && !str.equals("")) {
1229             props.setProperty(OPTIONS_PROP, str);
1230         }
1231         props.setProperty(ORIENT_PROP,
1232             (pageAttributes.getOrientationRequested() ==
1233              OrientationRequestedType.PORTRAIT)
1234                           ? PORTRAIT : LANDSCAPE);
1235         MediaType media = SIZES[pageAttributes.getMedia().hashCode()];
1236         if (media == MediaType.LETTER) {
1237             str = LETTER;
1238         } else if (media == MediaType.LEGAL) {
1239             str = LEGAL;
1240         } else if (media == MediaType.EXECUTIVE) {
1241             str = EXECUTIVE;
1242         } else if (media == MediaType.A4) {
1243             str = A4;
1244         } else {
1245             str = media.toString();
1246         }
1247         props.setProperty(PAPERSIZE_PROP, str);
1248     }
1249 
1250     private void throwPrintToFile() {
1251         SecurityManager security = System.getSecurityManager();
1252         FilePermission printToFilePermission = null;
1253         if (security != null) {
1254             if (printToFilePermission == null) {
1255                 printToFilePermission =
1256                     new FilePermission("<<ALL FILES>>", "read,write");
1257             }
1258             security.checkPermission(printToFilePermission);
1259         }
1260     }
1261 
1262 }