1 /*
2  * Copyright (c) 2000, 2019, 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.DialogOwner;
64 import javax.print.attribute.standard.JobName;
65 import javax.print.attribute.standard.MediaSize;
66 import javax.print.attribute.standard.PrintQuality;
67 import javax.print.attribute.standard.PrinterResolution;
68 import javax.print.attribute.standard.SheetCollate;
69 import javax.print.attribute.standard.Sides;
70 import javax.print.attribute.standard.Media;
71 import javax.print.attribute.standard.OrientationRequested;
72 import javax.print.attribute.standard.MediaSizeName;
73 import javax.print.attribute.standard.PageRanges;
74 
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 java.awt.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 static final String DEST_PROP = "awt.print.destination";
267     private static final String PRINTER = "printer";
268     private static final String FILE = "file";
269 
270     private static final String PRINTER_PROP = "awt.print.printer";
271 
272     private static final String FILENAME_PROP = "awt.print.fileName";
273 
274     private static final String NUMCOPIES_PROP = "awt.print.numCopies";
275 
276     private static final String OPTIONS_PROP = "awt.print.options";
277 
278     private static final String ORIENT_PROP = "awt.print.orientation";
279     private static final String PORTRAIT = "portrait";
280     private static final String LANDSCAPE = "landscape";
281 
282     private static final String PAPERSIZE_PROP = "awt.print.paperSize";
283     private static final String LETTER = "letter";
284     private static final String LEGAL = "legal";
285     private static final String EXECUTIVE = "executive";
286     private static final 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 
PrintJob2D(Frame frame, String doctitle, final Properties props)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 
PrintJob2D(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes)308     public PrintJob2D(Frame frame,  String doctitle,
309                       JobAttributes jobAttributes,
310                       PageAttributes pageAttributes) {
311         initPrintJob2D(frame, doctitle, jobAttributes, pageAttributes);
312     }
313 
initPrintJob2D(Frame frame, String doctitle, JobAttributes jobAttributes, PageAttributes pageAttributes)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 
printDialog()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             PageRanges pageRangesAttr
489                     = (PageRanges) attributes.get(PageRanges.class);
490             if (pageRangesAttr != null) {
491                 // Get the PageRanges from print dialog.
492                 int[][] range = pageRangesAttr.getMembers();
493 
494                 int prevFromPage = this.jobAttributes.getFromPage();
495                 int prevToPage = this.jobAttributes.getToPage();
496 
497                 int currFromPage = range[0][0];
498                 int currToPage = range[range.length - 1][1];
499 
500                 // if from < to update fromPage first followed by toPage
501                 // else update toPage first followed by fromPage
502                 if (currFromPage < prevToPage) {
503                     this.jobAttributes.setFromPage(currFromPage);
504                     this.jobAttributes.setToPage(currToPage);
505                 } else {
506                     this.jobAttributes.setToPage(currToPage);
507                     this.jobAttributes.setFromPage(currFromPage);
508                 }
509             }
510             printerJob.setPrintable(this, pageFormat);
511 
512         }
513 
514         return proceedWithPrint;
515     }
516 
updateAttributes()517     private void updateAttributes() {
518         Copies c = (Copies)attributes.get(Copies.class);
519         jobAttributes.setCopies(c.getValue());
520 
521         SunPageSelection sel =
522             (SunPageSelection)attributes.get(SunPageSelection.class);
523         if (sel == SunPageSelection.RANGE) {
524             jobAttributes.setDefaultSelection(DefaultSelectionType.RANGE);
525         } else if (sel == SunPageSelection.SELECTION) {
526             jobAttributes.setDefaultSelection(DefaultSelectionType.SELECTION);
527         } else {
528             jobAttributes.setDefaultSelection(DefaultSelectionType.ALL);
529         }
530 
531         Destination dest = (Destination)attributes.get(Destination.class);
532         if (dest != null) {
533             jobAttributes.setDestination(DestinationType.FILE);
534             jobAttributes.setFileName(dest.getURI().getPath());
535         } else {
536             jobAttributes.setDestination(DestinationType.PRINTER);
537         }
538 
539         PrintService serv = printerJob.getPrintService();
540         if (serv != null) {
541             jobAttributes.setPrinter(serv.getName());
542         }
543 
544         PageRanges range = (PageRanges)attributes.get(PageRanges.class);
545         int[][] members = range.getMembers();
546         jobAttributes.setPageRanges(members);
547 
548         SheetCollate collation =
549             (SheetCollate)attributes.get(SheetCollate.class);
550         if (collation == SheetCollate.COLLATED) {
551             jobAttributes.setMultipleDocumentHandling(
552             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES);
553         } else {
554             jobAttributes.setMultipleDocumentHandling(
555             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_UNCOLLATED_COPIES);
556         }
557 
558         Sides sides = (Sides)attributes.get(Sides.class);
559         if (sides == Sides.TWO_SIDED_LONG_EDGE) {
560             jobAttributes.setSides(SidesType.TWO_SIDED_LONG_EDGE);
561         } else if (sides == Sides.TWO_SIDED_SHORT_EDGE) {
562             jobAttributes.setSides(SidesType.TWO_SIDED_SHORT_EDGE);
563         } else {
564             jobAttributes.setSides(SidesType.ONE_SIDED);
565         }
566 
567         // PageAttributes
568 
569         Chromaticity color =
570             (Chromaticity)attributes.get(Chromaticity.class);
571         if (color == Chromaticity.COLOR) {
572             pageAttributes.setColor(ColorType.COLOR);
573         } else {
574             pageAttributes.setColor(ColorType.MONOCHROME);
575         }
576 
577         OrientationRequested orient =
578             (OrientationRequested)attributes.get(OrientationRequested.class);
579         if (orient == OrientationRequested.LANDSCAPE) {
580             pageAttributes.setOrientationRequested(
581                                        OrientationRequestedType.LANDSCAPE);
582         } else {
583             pageAttributes.setOrientationRequested(
584                                        OrientationRequestedType.PORTRAIT);
585         }
586 
587         PrintQuality qual = (PrintQuality)attributes.get(PrintQuality.class);
588         if (qual == PrintQuality.DRAFT) {
589             pageAttributes.setPrintQuality(PrintQualityType.DRAFT);
590         } else if (qual == PrintQuality.HIGH) {
591             pageAttributes.setPrintQuality(PrintQualityType.HIGH);
592         } else { // NORMAL
593             pageAttributes.setPrintQuality(PrintQualityType.NORMAL);
594         }
595 
596         Media msn = (Media)attributes.get(Media.class);
597         if (msn != null && msn instanceof MediaSizeName) {
598             MediaType mType = unMapMedia((MediaSizeName)msn);
599 
600             if (mType != null) {
601                 pageAttributes.setMedia(mType);
602             }
603         }
604         debugPrintAttributes(false, false);
605     }
606 
debugPrintAttributes(boolean ja, boolean pa )607     private void debugPrintAttributes(boolean ja, boolean pa ) {
608         if (ja) {
609             System.out.println("new Attributes\ncopies = "+
610                                jobAttributes.getCopies()+
611                                "\nselection = "+
612                                jobAttributes.getDefaultSelection()+
613                                "\ndest "+jobAttributes.getDestination()+
614                                "\nfile "+jobAttributes.getFileName()+
615                                "\nfromPage "+jobAttributes.getFromPage()+
616                                "\ntoPage "+jobAttributes.getToPage()+
617                                "\ncollation "+
618                                jobAttributes.getMultipleDocumentHandling()+
619                                "\nPrinter "+jobAttributes.getPrinter()+
620                                "\nSides2 "+jobAttributes.getSides()
621                                );
622         }
623 
624         if (pa) {
625             System.out.println("new Attributes\ncolor = "+
626                                pageAttributes.getColor()+
627                                "\norientation = "+
628                                pageAttributes.getOrientationRequested()+
629                                "\nquality "+pageAttributes.getPrintQuality()+
630                                "\nMedia2 "+pageAttributes.getMedia()
631                                );
632         }
633     }
634 
635 
636     /* From JobAttributes we will copy job name and duplex printing
637      * and destination.
638      * The majority of the rest of the attributes are reflected
639      * attributes.
640      *
641      * From PageAttributes we copy color, media size, orientation,
642      * origin type, resolution and print quality.
643      * We use the media, orientation in creating the page format, and
644      * the origin type to set its imageable area.
645      *
646      * REMIND: Interpretation of resolution, additional media sizes.
647      */
copyAttributes(PrintService printServ)648     private void copyAttributes(PrintService printServ) {
649 
650         attributes = new HashPrintRequestAttributeSet();
651         attributes.add(new JobName(docTitle, null));
652         PrintService pServ = printServ;
653 
654         String printerName = jobAttributes.getPrinter();
655         if (printerName != null && printerName != ""
656             && pServ != null && !printerName.equals(pServ.getName())) {
657 
658             // Search for the given printerName in the list of PrintServices
659             PrintService []services = PrinterJob.lookupPrintServices();
660             try {
661                 for (int i=0; i<services.length; i++) {
662                     if (printerName.equals(services[i].getName())) {
663                         printerJob.setPrintService(services[i]);
664                         pServ = services[i];
665                         break;
666                     }
667                 }
668             } catch (PrinterException pe) {
669             }
670         }
671 
672         DestinationType dest = jobAttributes.getDestination();
673         if (dest == DestinationType.FILE && pServ != null &&
674             pServ.isAttributeCategorySupported(Destination.class)) {
675 
676             String fileName = jobAttributes.getFileName();
677 
678             Destination defaultDest;
679             if (fileName == null && (defaultDest = (Destination)pServ.
680                     getDefaultAttributeValue(Destination.class)) != null) {
681                 attributes.add(defaultDest);
682             } else {
683                 URI uri = null;
684                 try {
685                     if (fileName != null) {
686                         if (fileName.isEmpty()) {
687                             fileName = ".";
688                         }
689                     } else {
690                         // defaultDest should not be null.  The following code
691                         // is only added to safeguard against a possible
692                         // buggy implementation of a PrintService having a
693                         // null default Destination.
694                         fileName = "out.prn";
695                     }
696                     uri = (new File(fileName)).toURI();
697                 } catch (SecurityException se) {
698                     try {
699                         // '\\' file separator is illegal character in opaque
700                         // part and causes URISyntaxException, so we replace
701                         // it with '/'
702                         fileName = fileName.replace('\\', '/');
703                         uri = new URI("file:"+fileName);
704                     } catch (URISyntaxException e) {
705                     }
706                 }
707                 if (uri != null) {
708                     attributes.add(new Destination(uri));
709                 }
710             }
711         }
712         attributes.add(new SunMinMaxPage(jobAttributes.getMinPage(),
713                                          jobAttributes.getMaxPage()));
714         SidesType sType = jobAttributes.getSides();
715         if (sType == SidesType.TWO_SIDED_LONG_EDGE) {
716             attributes.add(Sides.TWO_SIDED_LONG_EDGE);
717         } else if (sType == SidesType.TWO_SIDED_SHORT_EDGE) {
718             attributes.add(Sides.TWO_SIDED_SHORT_EDGE);
719         } else if (sType == SidesType.ONE_SIDED) {
720             attributes.add(Sides.ONE_SIDED);
721         }
722 
723         MultipleDocumentHandlingType hType =
724           jobAttributes.getMultipleDocumentHandling();
725         if (hType ==
726             MultipleDocumentHandlingType.SEPARATE_DOCUMENTS_COLLATED_COPIES) {
727           attributes.add(SheetCollate.COLLATED);
728         } else {
729           attributes.add(SheetCollate.UNCOLLATED);
730         }
731 
732         attributes.add(new Copies(jobAttributes.getCopies()));
733 
734         attributes.add(new PageRanges(jobAttributes.getFromPage(),
735                                       jobAttributes.getToPage()));
736 
737         if (pageAttributes.getColor() == ColorType.COLOR) {
738             attributes.add(Chromaticity.COLOR);
739         } else {
740             attributes.add(Chromaticity.MONOCHROME);
741         }
742 
743         pageFormat = printerJob.defaultPage();
744         if (pageAttributes.getOrientationRequested() ==
745             OrientationRequestedType.LANDSCAPE) {
746             pageFormat.setOrientation(PageFormat.LANDSCAPE);
747                 attributes.add(OrientationRequested.LANDSCAPE);
748         } else {
749                 pageFormat.setOrientation(PageFormat.PORTRAIT);
750                 attributes.add(OrientationRequested.PORTRAIT);
751         }
752 
753         MediaType media = pageAttributes.getMedia();
754         MediaSizeName msn = mapMedia(media);
755         if (msn != null) {
756             attributes.add(msn);
757         }
758 
759         PrintQualityType qType =
760             pageAttributes.getPrintQuality();
761         if (qType == PrintQualityType.DRAFT) {
762             attributes.add(PrintQuality.DRAFT);
763         } else if (qType == PrintQualityType.NORMAL) {
764             attributes.add(PrintQuality.NORMAL);
765         } else if (qType == PrintQualityType.HIGH) {
766             attributes.add(PrintQuality.HIGH);
767         }
768     }
769 
770     /**
771      * Gets a Graphics object that will draw to the next page.
772      * The page is sent to the printer when the graphics
773      * object is disposed.  This graphics object will also implement
774      * the PrintGraphics interface.
775      * @see java.awt.PrintGraphics
776      */
getGraphics()777     public Graphics getGraphics() {
778 
779         Graphics printGraphics = null;
780 
781         synchronized (this) {
782             ++pageIndex;
783 
784             // Thread should not be created after end has been called.
785             // One way to detect this is if any of the graphics queue
786             //  has been closed.
787             if (pageIndex == 0 && !graphicsToBeDrawn.isClosed()) {
788 
789             /* We start a thread on which the PrinterJob will run.
790              * The PrinterJob will ask for pages on that thread
791              * and will use a message queue to fulfill the application's
792              * requests for a Graphics on the application's
793              * thread.
794              */
795 
796                 startPrinterJobThread();
797 
798             }
799             notify();
800         }
801 
802         /* If the application has already been handed back
803          * a graphics then we need to put that graphics into
804          * the drawn queue so that the PrinterJob thread can
805          * return to the print system.
806          */
807         if (currentGraphics != null) {
808             graphicsDrawn.append(currentGraphics);
809             currentGraphics = null;
810         }
811 
812         /* We'll block here until a new graphics becomes
813          * available.
814          */
815 
816         currentGraphics = graphicsToBeDrawn.pop();
817 
818         if (currentGraphics instanceof PeekGraphics) {
819             ( (PeekGraphics) currentGraphics).setAWTDrawingOnly();
820             graphicsDrawn.append(currentGraphics);
821             currentGraphics = graphicsToBeDrawn.pop();
822         }
823 
824 
825         if (currentGraphics != null) {
826 
827             /* In the PrintJob API, the origin is at the upper-
828              * left of the imageable area when using the new "printable"
829              * origin attribute, otherwise its the physical origin (for
830              * backwards compatibility. We emulate this by createing
831              * a PageFormat which matches and then performing the
832              * translate to the origin. This is a no-op if physical
833              * origin is specified.
834              */
835             currentGraphics.translate(pageFormat.getImageableX(),
836                                       pageFormat.getImageableY());
837 
838             /* Scale to accommodate AWT's notion of printer resolution */
839             double awtScale = 72.0/getPageResolutionInternal();
840             currentGraphics.scale(awtScale, awtScale);
841 
842             /* The caller wants a Graphics instance but we do
843              * not want them to make 2D calls. We can't hand
844              * back a Graphics2D. The returned Graphics also
845              * needs to implement PrintGraphics, so we wrap
846              * the Graphics2D instance. The PrintJob API has
847              * the application dispose of the Graphics so
848              * we create a copy of the one returned by PrinterJob.
849              */
850             printGraphics = new ProxyPrintGraphics(currentGraphics.create(),
851                                                    this);
852 
853         }
854 
855         return printGraphics;
856     }
857 
858     /**
859      * Returns the dimensions of the page in pixels.
860      * The resolution of the page is chosen so that it
861      * is similar to the screen resolution.
862      * Except (since 1.3) when the application specifies a resolution.
863      * In that case it is scaled accordingly.
864      */
getPageDimension()865     public Dimension getPageDimension() {
866         double wid, hgt, scale;
867         if (pageAttributes != null &&
868             pageAttributes.getOrigin()==OriginType.PRINTABLE) {
869             wid = pageFormat.getImageableWidth();
870             hgt = pageFormat.getImageableHeight();
871         } else {
872             wid = pageFormat.getWidth();
873             hgt = pageFormat.getHeight();
874         }
875         scale = getPageResolutionInternal() / 72.0;
876         return new Dimension((int)(wid * scale), (int)(hgt * scale));
877     }
878 
getPageResolutionInternal()879      private double getPageResolutionInternal() {
880         if (pageAttributes != null) {
881             int []res = pageAttributes.getPrinterResolution();
882             if (res[2] == 3) {
883                 return res[0];
884             } else /* if (res[2] == 4) */ {
885                 return (res[0] * 2.54);
886             }
887         } else {
888             return 72.0;
889         }
890     }
891 
892     /**
893      * Returns the resolution of the page in pixels per inch.
894      * Note that this doesn't have to correspond to the physical
895      * resolution of the printer.
896      */
getPageResolution()897     public int getPageResolution() {
898         return (int)getPageResolutionInternal();
899     }
900 
901     /**
902      * Returns true if the last page will be printed first.
903      */
lastPageFirst()904     public boolean lastPageFirst() {
905         return false;
906     }
907 
908     /**
909      * Ends the print job and does any necessary cleanup.
910      */
end()911     public synchronized void end() {
912 
913         /* Prevent the PrinterJob thread from appending any more
914          * graphics to the to-be-drawn queue
915          */
916         graphicsToBeDrawn.close();
917 
918         /* If we have a currentGraphics it was the last one returned to the
919          * PrintJob client. Append it to the drawn queue so that print()
920          * will return allowing the page to be flushed.
921          * This really ought to happen in dispose() but for whatever reason
922          * that isn't how the old PrintJob worked even though its spec
923          * said dispose() flushed the page.
924          */
925         if (currentGraphics != null) {
926             graphicsDrawn.append(currentGraphics);
927         }
928         graphicsDrawn.closeWhenEmpty();
929 
930         /* Wait for the PrinterJob.print() thread to terminate, ensuring
931          * that RasterPrinterJob has made its end doc call, and resources
932          * are released, files closed etc.
933          */
934         if( printerJobThread != null && printerJobThread.isAlive() ){
935             try {
936                 printerJobThread.join();
937             } catch (InterruptedException e) {
938             }
939         }
940     }
941 
942     /**
943      * Ends this print job once it is no longer referenced.
944      * @see #end
945      */
946     @SuppressWarnings("deprecation")
finalize()947     public void finalize() {
948         end();
949     }
950 
951     /**
952      * Prints the page at the specified index into the specified
953      * {@link Graphics} context in the specified
954      * format.  A {@code PrinterJob} calls the
955      * {@code Printable} interface to request that a page be
956      * rendered into the context specified by
957      * {@code graphics}.  The format of the page to be drawn is
958      * specified by {@code pageFormat}.  The zero based index
959      * of the requested page is specified by {@code pageIndex}.
960      * If the requested page does not exist then this method returns
961      * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned.
962      * The {@code Graphics} class or subclass implements the
963      * {@link java.awt.PrintGraphics} interface to provide additional
964      * information.  If the {@code Printable} object
965      * aborts the print job then it throws a {@link PrinterException}.
966      * @param graphics the context into which the page is drawn
967      * @param pageFormat the size and orientation of the page being drawn
968      * @param pageIndex the zero based index of the page to be drawn
969      * @return PAGE_EXISTS if the page is rendered successfully
970      *         or NO_SUCH_PAGE if {@code pageIndex} specifies a
971      *         non-existent page.
972      * @exception java.awt.print.PrinterException
973      *         thrown when the print job is terminated.
974      */
print(Graphics graphics, PageFormat pageFormat, int pageIndex)975     public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
976                  throws PrinterException {
977 
978         int result;
979 
980         /* This method will be called by the PrinterJob on a thread other
981          * that the application's thread. We hold on to the graphics
982          * until we can rendevous with the application's thread and
983          * hand over the graphics. The application then does all the
984          * drawing. When the application is done drawing we rendevous
985          * again with the PrinterJob thread and release the Graphics
986          * so that it knows we are done.
987          */
988 
989         /* Add the graphics to the message queue of graphics to
990          * be rendered. This is really a one slot queue. The
991          * application's thread will come along and remove the
992          * graphics from the queue when the app asks for a graphics.
993          */
994         graphicsToBeDrawn.append( (Graphics2D) graphics);
995 
996         /* We now wait for the app's thread to finish drawing on
997          * the Graphics. This thread will sleep until the application
998          * release the graphics by placing it in the graphics drawn
999          * message queue. If the application signals that it is
1000          * finished drawing the entire document then we'll get null
1001          * returned when we try and pop a finished graphic.
1002          */
1003         if (graphicsDrawn.pop() != null) {
1004             result = PAGE_EXISTS;
1005         } else {
1006             result = NO_SUCH_PAGE;
1007         }
1008 
1009         return result;
1010     }
1011 
startPrinterJobThread()1012     private void startPrinterJobThread() {
1013         printerJobThread =
1014             new Thread(null, this, "printerJobThread", 0, false);
1015         printerJobThread.start();
1016     }
1017 
1018 
run()1019     public void run() {
1020 
1021         try {
1022             attributes.remove(PageRanges.class);
1023             printerJob.print(attributes);
1024         } catch (PrinterException e) {
1025             //REMIND: need to store this away and not rethrow it.
1026         }
1027 
1028         /* Close the message queues so that nobody is stuck
1029          * waiting for one.
1030          */
1031         graphicsToBeDrawn.closeWhenEmpty();
1032         graphicsDrawn.close();
1033     }
1034 
1035     private class MessageQ {
1036 
1037         private String qid="noname";
1038 
1039         private ArrayList<Graphics2D> queue = new ArrayList<>();
1040 
MessageQ(String id)1041         MessageQ(String id) {
1042           qid = id;
1043         }
1044 
closeWhenEmpty()1045         synchronized void closeWhenEmpty() {
1046 
1047             while (queue != null && queue.size() > 0) {
1048                 try {
1049                     wait(1000);
1050                 } catch (InterruptedException e) {
1051                     // do nothing.
1052                 }
1053             }
1054 
1055             queue = null;
1056             notifyAll();
1057         }
1058 
close()1059         synchronized void close() {
1060             queue = null;
1061             notifyAll();
1062         }
1063 
append(Graphics2D g)1064         synchronized boolean append(Graphics2D g) {
1065 
1066             boolean queued = false;
1067 
1068             if (queue != null) {
1069                 queue.add(g);
1070                 queued = true;
1071                 notify();
1072             }
1073 
1074             return queued;
1075         }
1076 
pop()1077         synchronized Graphics2D pop() {
1078             Graphics2D g = null;
1079 
1080             while (g == null && queue != null) {
1081 
1082                 if (queue.size() > 0) {
1083                     g = queue.remove(0);
1084                     notify();
1085 
1086                 } else {
1087                     try {
1088                         wait(2000);
1089                     } catch (InterruptedException e) {
1090                         // do nothing.
1091                     }
1092                 }
1093             }
1094 
1095             return g;
1096         }
1097 
isClosed()1098         synchronized boolean isClosed() {
1099             return queue == null;
1100         }
1101 
1102     }
1103 
1104 
getSize(MediaType mType)1105     private static int[] getSize(MediaType mType) {
1106         int []dim = new int[2];
1107         dim[0] = 612;
1108         dim[1] = 792;
1109 
1110         for (int i=0; i < SIZES.length; i++) {
1111             if (SIZES[i] == mType) {
1112                 dim[0] = WIDTHS[i];
1113                 dim[1] = LENGTHS[i];
1114                 break;
1115             }
1116         }
1117         return dim;
1118     }
1119 
mapMedia(MediaType mType)1120     public static MediaSizeName mapMedia(MediaType mType) {
1121         MediaSizeName media = null;
1122 
1123         // JAVAXSIZES.length and SIZES.length must be equal!
1124         // Attempt to recover by getting the smaller size.
1125         int length = Math.min(SIZES.length, JAVAXSIZES.length);
1126 
1127         for (int i=0; i < length; i++) {
1128             if (SIZES[i] == mType) {
1129                 if ((JAVAXSIZES[i] != null) &&
1130                     MediaSize.getMediaSizeForName(JAVAXSIZES[i]) != null) {
1131                     media = JAVAXSIZES[i];
1132                     break;
1133                 } else {
1134                     /* create Custom Media */
1135                     media = new CustomMediaSizeName(SIZES[i].toString());
1136 
1137                     float w = (float)Math.rint(WIDTHS[i]  / 72.0);
1138                     float h = (float)Math.rint(LENGTHS[i] / 72.0);
1139                     if (w > 0.0 && h > 0.0) {
1140                         // add new created MediaSize to our static map
1141                         // so it will be found when we call findMedia
1142                         new MediaSize(w, h, Size2DSyntax.INCH, media);
1143                     }
1144 
1145                     break;
1146                 }
1147             }
1148         }
1149         return media;
1150     }
1151 
1152 
unMapMedia(MediaSizeName mSize)1153     public static MediaType unMapMedia(MediaSizeName mSize) {
1154         MediaType media = null;
1155 
1156         // JAVAXSIZES.length and SIZES.length must be equal!
1157         // Attempt to recover by getting the smaller size.
1158         int length = Math.min(SIZES.length, JAVAXSIZES.length);
1159 
1160         for (int i=0; i < length; i++) {
1161             if (JAVAXSIZES[i] == mSize) {
1162                 if (SIZES[i] != null) {
1163                     media = SIZES[i];
1164                     break;
1165                 }
1166             }
1167         }
1168         return media;
1169     }
1170 
translateInputProps()1171     private void translateInputProps() {
1172         if (props == null) {
1173             return;
1174         }
1175 
1176         String str;
1177 
1178         str = props.getProperty(DEST_PROP);
1179         if (str != null) {
1180             if (str.equals(PRINTER)) {
1181                 jobAttributes.setDestination(DestinationType.PRINTER);
1182             } else if (str.equals(FILE)) {
1183                 jobAttributes.setDestination(DestinationType.FILE);
1184             }
1185         }
1186         str = props.getProperty(PRINTER_PROP);
1187         if (str != null) {
1188             jobAttributes.setPrinter(str);
1189         }
1190         str = props.getProperty(FILENAME_PROP);
1191         if (str != null) {
1192             jobAttributes.setFileName(str);
1193         }
1194         str = props.getProperty(NUMCOPIES_PROP);
1195         if (str != null) {
1196             jobAttributes.setCopies(Integer.parseInt(str));
1197         }
1198 
1199         this.options = props.getProperty(OPTIONS_PROP, "");
1200 
1201         str = props.getProperty(ORIENT_PROP);
1202         if (str != null) {
1203             if (str.equals(PORTRAIT)) {
1204                 pageAttributes.setOrientationRequested(
1205                                         OrientationRequestedType.PORTRAIT);
1206             } else if (str.equals(LANDSCAPE)) {
1207                 pageAttributes.setOrientationRequested(
1208                                         OrientationRequestedType.LANDSCAPE);
1209             }
1210         }
1211         str = props.getProperty(PAPERSIZE_PROP);
1212         if (str != null) {
1213             if (str.equals(LETTER)) {
1214                 pageAttributes.setMedia(SIZES[MediaType.LETTER.hashCode()]);
1215             } else if (str.equals(LEGAL)) {
1216                 pageAttributes.setMedia(SIZES[MediaType.LEGAL.hashCode()]);
1217             } else if (str.equals(EXECUTIVE)) {
1218                 pageAttributes.setMedia(SIZES[MediaType.EXECUTIVE.hashCode()]);
1219             } else if (str.equals(A4)) {
1220                 pageAttributes.setMedia(SIZES[MediaType.A4.hashCode()]);
1221             }
1222         }
1223     }
1224 
translateOutputProps()1225     private void translateOutputProps() {
1226         if (props == null) {
1227             return;
1228         }
1229 
1230         String str;
1231 
1232         props.setProperty(DEST_PROP,
1233             (jobAttributes.getDestination() == DestinationType.PRINTER) ?
1234                           PRINTER : FILE);
1235         str = jobAttributes.getPrinter();
1236         if (str != null && !str.isEmpty()) {
1237             props.setProperty(PRINTER_PROP, str);
1238         }
1239         str = jobAttributes.getFileName();
1240         if (str != null && !str.isEmpty()) {
1241             props.setProperty(FILENAME_PROP, str);
1242         }
1243         int copies = jobAttributes.getCopies();
1244         if (copies > 0) {
1245             props.setProperty(NUMCOPIES_PROP, "" + copies);
1246         }
1247         str = this.options;
1248         if (str != null && !str.isEmpty()) {
1249             props.setProperty(OPTIONS_PROP, str);
1250         }
1251         props.setProperty(ORIENT_PROP,
1252             (pageAttributes.getOrientationRequested() ==
1253              OrientationRequestedType.PORTRAIT)
1254                           ? PORTRAIT : LANDSCAPE);
1255         MediaType media = SIZES[pageAttributes.getMedia().hashCode()];
1256         if (media == MediaType.LETTER) {
1257             str = LETTER;
1258         } else if (media == MediaType.LEGAL) {
1259             str = LEGAL;
1260         } else if (media == MediaType.EXECUTIVE) {
1261             str = EXECUTIVE;
1262         } else if (media == MediaType.A4) {
1263             str = A4;
1264         } else {
1265             str = media.toString();
1266         }
1267         props.setProperty(PAPERSIZE_PROP, str);
1268     }
1269 
throwPrintToFile()1270     private void throwPrintToFile() {
1271         SecurityManager security = System.getSecurityManager();
1272         FilePermission printToFilePermission = null;
1273         if (security != null) {
1274             if (printToFilePermission == null) {
1275                 printToFilePermission =
1276                     new FilePermission("<<ALL FILES>>", "read,write");
1277             }
1278             security.checkPermission(printToFilePermission);
1279         }
1280     }
1281 
1282 }
1283