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