View Javadoc
1   /*
2    * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.print;
27  
28  import java.net.URI;
29  import java.io.BufferedInputStream;
30  import java.io.BufferedOutputStream;
31  import java.io.File;
32  import java.io.FileOutputStream;
33  import java.io.InputStream;
34  import java.io.OutputStream;
35  import java.io.InputStream;
36  import java.io.IOException;
37  import java.io.FileNotFoundException;
38  import java.io.Reader;
39  import java.net.URL;
40  import java.util.Vector;
41  
42  import javax.print.CancelablePrintJob;
43  import javax.print.Doc;
44  import javax.print.DocFlavor;
45  import javax.print.DocPrintJob;
46  import javax.print.PrintService;
47  import javax.print.PrintException;
48  import javax.print.event.PrintJobEvent;
49  import javax.print.event.PrintJobListener;
50  import javax.print.event.PrintJobAttributeListener;
51  
52  import javax.print.attribute.Attribute;
53  import javax.print.attribute.AttributeSet;
54  import javax.print.attribute.AttributeSetUtilities;
55  import javax.print.attribute.DocAttributeSet;
56  import javax.print.attribute.HashPrintJobAttributeSet;
57  import javax.print.attribute.HashPrintRequestAttributeSet;
58  import javax.print.attribute.PrintJobAttribute;
59  import javax.print.attribute.PrintJobAttributeSet;
60  import javax.print.attribute.PrintRequestAttribute;
61  import javax.print.attribute.PrintRequestAttributeSet;
62  import javax.print.attribute.standard.Copies;
63  import javax.print.attribute.standard.DocumentName;
64  import javax.print.attribute.standard.Fidelity;
65  import javax.print.attribute.standard.JobName;
66  import javax.print.attribute.standard.JobOriginatingUserName;
67  import javax.print.attribute.standard.Media;
68  import javax.print.attribute.standard.MediaSize;
69  import javax.print.attribute.standard.MediaSizeName;
70  import javax.print.attribute.standard.OrientationRequested;
71  import javax.print.attribute.standard.RequestingUserName;
72  import javax.print.attribute.standard.Destination;
73  import javax.print.attribute.standard.PrinterIsAcceptingJobs;
74  import javax.print.attribute.standard.PrinterState;
75  import javax.print.attribute.standard.PrinterStateReason;
76  import javax.print.attribute.standard.PrinterStateReasons;
77  
78  import java.awt.print.*;
79  
80  public class Win32PrintJob implements CancelablePrintJob {
81  
82      transient private Vector jobListeners;
83      transient private Vector attrListeners;
84      transient private Vector listenedAttributeSets;
85  
86      private Win32PrintService service;
87      private boolean fidelity;
88      private boolean printing = false;
89      private boolean printReturned = false;
90      private PrintRequestAttributeSet reqAttrSet = null;
91      private PrintJobAttributeSet jobAttrSet = null;
92      private PrinterJob job;
93      private Doc doc;
94      private String mDestination = null;
95  
96      /* these variables used globally to store reference to the print
97       * data retrieved as a stream. On completion these are always closed
98       * if non-null.
99       */
100     private InputStream instream = null;
101     private Reader reader = null;
102 
103     /* default values overridden by those extracted from the attributes */
104     private String jobName = "Java Printing";
105     private int copies = 0;
106     private MediaSizeName mediaName = null;
107     private MediaSize     mediaSize = null;
108     private OrientationRequested orient = null;
109 
110     /* print job handle used by native code */
111     private long hPrintJob;
112 
113     /* buffer length for printing raw data */
114     private static final int PRINTBUFFERLEN = 8192;
115 
116     Win32PrintJob(Win32PrintService service) {
117         this.service = service;
118     }
119 
120     public PrintService getPrintService() {
121         return service;
122     }
123 
124     public PrintJobAttributeSet getAttributes() {
125         synchronized (this) {
126             if (jobAttrSet == null) {
127                 /* just return an empty set until the job is submitted */
128                 PrintJobAttributeSet jobSet = new HashPrintJobAttributeSet();
129                 return AttributeSetUtilities.unmodifiableView(jobSet);
130             } else {
131               return jobAttrSet;
132             }
133         }
134     }
135 
136     public void addPrintJobListener(PrintJobListener listener) {
137         synchronized (this) {
138             if (listener == null) {
139                 return;
140             }
141             if (jobListeners == null) {
142                 jobListeners = new Vector();
143             }
144             jobListeners.add(listener);
145         }
146     }
147 
148     public void removePrintJobListener(PrintJobListener listener) {
149         synchronized (this) {
150             if (listener == null || jobListeners == null ) {
151                 return;
152             }
153             jobListeners.remove(listener);
154             if (jobListeners.isEmpty()) {
155                 jobListeners = null;
156             }
157         }
158     }
159 
160 
161     /* Closes any stream already retrieved for the data.
162      * We want to avoid unnecessarily asking the Doc to create a stream only
163      * to get a reference in order to close it because the job failed.
164      * If the representation class is itself a "stream", this
165      * closes that stream too.
166      */
167     private void closeDataStreams() {
168 
169         if (doc == null) {
170             return;
171         }
172 
173         Object data = null;
174 
175         try {
176             data = doc.getPrintData();
177         } catch (IOException e) {
178             return;
179         }
180 
181         if (instream != null) {
182             try {
183                 instream.close();
184             } catch (IOException e) {
185             } finally {
186                 instream = null;
187             }
188         }
189         else if (reader != null) {
190             try {
191                 reader.close();
192             } catch (IOException e) {
193             } finally {
194                 reader = null;
195             }
196         }
197         else if (data instanceof InputStream) {
198             try {
199                 ((InputStream)data).close();
200             } catch (IOException e) {
201             }
202         }
203         else if (data instanceof Reader) {
204             try {
205                 ((Reader)data).close();
206             } catch (IOException e) {
207             }
208         }
209     }
210 
211     private void notifyEvent(int reason) {
212 
213         /* since this method should always get called, here's where
214          * we will perform the clean up of any data stream supplied.
215          */
216         switch (reason) {
217             case PrintJobEvent.DATA_TRANSFER_COMPLETE:
218             case PrintJobEvent.JOB_CANCELED :
219             case PrintJobEvent.JOB_FAILED :
220             case PrintJobEvent.NO_MORE_EVENTS :
221             case PrintJobEvent.JOB_COMPLETE :
222                 closeDataStreams();
223         }
224 
225         synchronized (this) {
226             if (jobListeners != null) {
227                 PrintJobListener listener;
228                 PrintJobEvent event = new PrintJobEvent(this, reason);
229                 for (int i = 0; i < jobListeners.size(); i++) {
230                     listener = (PrintJobListener)(jobListeners.elementAt(i));
231                     switch (reason) {
232 
233                         case PrintJobEvent.JOB_COMPLETE :
234                             listener.printJobCompleted(event);
235                             break;
236 
237                         case PrintJobEvent.JOB_CANCELED :
238                             listener.printJobCanceled(event);
239                             break;
240 
241                         case PrintJobEvent.JOB_FAILED :
242                             listener.printJobFailed(event);
243                             break;
244 
245                         case PrintJobEvent.DATA_TRANSFER_COMPLETE :
246                             listener.printDataTransferCompleted(event);
247                             break;
248 
249                         case PrintJobEvent.NO_MORE_EVENTS :
250                             listener.printJobNoMoreEvents(event);
251                             break;
252 
253                         default:
254                             break;
255                     }
256                 }
257             }
258        }
259     }
260 
261     public void addPrintJobAttributeListener(
262                                   PrintJobAttributeListener listener,
263                                   PrintJobAttributeSet attributes) {
264         synchronized (this) {
265             if (listener == null) {
266                 return;
267             }
268             if (attrListeners == null) {
269                 attrListeners = new Vector();
270                 listenedAttributeSets = new Vector();
271             }
272             attrListeners.add(listener);
273             if (attributes == null) {
274                 attributes = new HashPrintJobAttributeSet();
275             }
276             listenedAttributeSets.add(attributes);
277         }
278     }
279 
280     public void removePrintJobAttributeListener(
281                                         PrintJobAttributeListener listener) {
282         synchronized (this) {
283             if (listener == null || attrListeners == null ) {
284                 return;
285             }
286             int index = attrListeners.indexOf(listener);
287             if (index == -1) {
288                 return;
289             } else {
290                 attrListeners.remove(index);
291                 listenedAttributeSets.remove(index);
292                 if (attrListeners.isEmpty()) {
293                     attrListeners = null;
294                     listenedAttributeSets = null;
295                 }
296             }
297         }
298     }
299 
300     public void print(Doc doc, PrintRequestAttributeSet attributes)
301         throws PrintException {
302 
303         synchronized (this) {
304             if (printing) {
305                 throw new PrintException("already printing");
306             } else {
307                 printing = true;
308             }
309         }
310 
311         PrinterState prnState = (PrinterState)service.getAttribute(
312                                                   PrinterState.class);
313         if (prnState == PrinterState.STOPPED) {
314             PrinterStateReasons prnStateReasons =
315                     (PrinterStateReasons)service.getAttribute(
316                                                  PrinterStateReasons.class);
317                 if ((prnStateReasons != null) &&
318                     (prnStateReasons.containsKey(PrinterStateReason.SHUTDOWN)))
319                 {
320                     throw new PrintException("PrintService is no longer available.");
321                 }
322         }
323 
324         if ((PrinterIsAcceptingJobs)(service.getAttribute(
325                          PrinterIsAcceptingJobs.class)) ==
326                          PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS) {
327             throw new PrintException("Printer is not accepting job.");
328         }
329 
330 
331         this.doc = doc;
332         /* check if the parameters are valid before doing much processing */
333         DocFlavor flavor = doc.getDocFlavor();
334         Object data;
335 
336         try {
337             data = doc.getPrintData();
338         } catch (IOException e) {
339             notifyEvent(PrintJobEvent.JOB_FAILED);
340             throw new PrintException("can't get print data: " + e.toString());
341         }
342 
343         if (data == null) {
344             throw new PrintException("Null print data.");
345         }
346 
347         if (flavor == null || (!service.isDocFlavorSupported(flavor))) {
348             notifyEvent(PrintJobEvent.JOB_FAILED);
349             throw new PrintJobFlavorException("invalid flavor", flavor);
350         }
351 
352         initializeAttributeSets(doc, attributes);
353 
354         getAttributeValues(flavor);
355 
356         String repClassName = flavor.getRepresentationClassName();
357 
358         if (flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
359             flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
360             flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
361             flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
362             flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
363             flavor.equals(DocFlavor.BYTE_ARRAY.PNG)) {
364             try {
365                 instream = doc.getStreamForBytes();
366                 if (instream == null) {
367                     notifyEvent(PrintJobEvent.JOB_FAILED);
368                     throw new PrintException("No stream for data");
369                 }
370                 printableJob(new ImagePrinter(instream));
371                 service.wakeNotifier();
372                 return;
373             } catch (ClassCastException cce) {
374                 notifyEvent(PrintJobEvent.JOB_FAILED);
375                 throw new PrintException(cce);
376             } catch (IOException ioe) {
377                 notifyEvent(PrintJobEvent.JOB_FAILED);
378                 throw new PrintException(ioe);
379             }
380         } else if (flavor.equals(DocFlavor.URL.GIF) ||
381                    flavor.equals(DocFlavor.URL.JPEG) ||
382                    flavor.equals(DocFlavor.URL.PNG)) {
383             try {
384                 printableJob(new ImagePrinter((URL)data));
385                 service.wakeNotifier();
386                 return;
387             } catch (ClassCastException cce) {
388                 notifyEvent(PrintJobEvent.JOB_FAILED);
389                 throw new PrintException(cce);
390             }
391         } else if (repClassName.equals("java.awt.print.Pageable")) {
392             try {
393                 pageableJob((Pageable)doc.getPrintData());
394                 service.wakeNotifier();
395                 return;
396             } catch (ClassCastException cce) {
397                 notifyEvent(PrintJobEvent.JOB_FAILED);
398                 throw new PrintException(cce);
399             } catch (IOException ioe) {
400                 notifyEvent(PrintJobEvent.JOB_FAILED);
401                 throw new PrintException(ioe);
402             }
403         } else if (repClassName.equals("java.awt.print.Printable")) {
404             try {
405                 printableJob((Printable)doc.getPrintData());
406                 service.wakeNotifier();
407                 return;
408             } catch (ClassCastException cce) {
409                 notifyEvent(PrintJobEvent.JOB_FAILED);
410                 throw new PrintException(cce);
411             } catch (IOException ioe) {
412                 notifyEvent(PrintJobEvent.JOB_FAILED);
413                 throw new PrintException(ioe);
414             }
415         } else if (repClassName.equals("[B") ||
416                    repClassName.equals("java.io.InputStream") ||
417                    repClassName.equals("java.net.URL")) {
418 
419             if (repClassName.equals("java.net.URL")) {
420                 URL url = (URL)data;
421                 try {
422                     instream = url.openStream();
423                 } catch (IOException e) {
424                     notifyEvent(PrintJobEvent.JOB_FAILED);
425                     throw new PrintException(e.toString());
426                 }
427             } else {
428                 try {
429                     instream = doc.getStreamForBytes();
430                 } catch (IOException ioe) {
431                     notifyEvent(PrintJobEvent.JOB_FAILED);
432                     throw new PrintException(ioe.toString());
433                 }
434             }
435 
436             if (instream == null) {
437                 notifyEvent(PrintJobEvent.JOB_FAILED);
438                 throw new PrintException("No stream for data");
439             }
440 
441             if (mDestination != null) { // if destination attribute is set
442                 try {
443                     FileOutputStream fos = new FileOutputStream(mDestination);
444                     byte []buffer = new byte[1024];
445                     int cread;
446 
447                     while ((cread = instream.read(buffer, 0, buffer.length)) >=0) {
448                         fos.write(buffer, 0, cread);
449                     }
450                     fos.flush();
451                     fos.close();
452                 } catch (FileNotFoundException fnfe) {
453                     notifyEvent(PrintJobEvent.JOB_FAILED);
454                     throw new PrintException(fnfe.toString());
455                 } catch (IOException ioe) {
456                     notifyEvent(PrintJobEvent.JOB_FAILED);
457                     throw new PrintException(ioe.toString());
458                 }
459                 notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
460                 notifyEvent(PrintJobEvent.JOB_COMPLETE);
461                 service.wakeNotifier();
462                 return;
463             }
464 
465             if (!startPrintRawData(service.getName(), jobName)) {
466                 notifyEvent(PrintJobEvent.JOB_FAILED);
467                 throw new PrintException("Print job failed to start.");
468             }
469             BufferedInputStream  bin = new BufferedInputStream(instream);
470             int bread = 0;
471             try {
472                 byte[] buffer = new byte[PRINTBUFFERLEN];
473 
474                 while ((bread = bin.read(buffer, 0, PRINTBUFFERLEN)) >=0) {
475                     if (!printRawData(buffer, bread)) {
476                         bin.close();
477                         notifyEvent(PrintJobEvent.JOB_FAILED);
478                         throw new PrintException ("Problem while spooling data");
479                     }
480                 }
481                 bin.close();
482                 if (!endPrintRawData()) {
483                     notifyEvent(PrintJobEvent.JOB_FAILED);
484                     throw new PrintException("Print job failed to close properly.");
485                 }
486                 notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
487             } catch (IOException e) {
488                 notifyEvent(PrintJobEvent.JOB_FAILED);
489                 throw new PrintException (e.toString());
490             } finally {
491                 notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
492             }
493         } else {
494             notifyEvent(PrintJobEvent.JOB_FAILED);
495             throw new PrintException("unrecognized class: "+repClassName);
496         }
497         service.wakeNotifier();
498     }
499 
500     public void printableJob(Printable printable) throws PrintException {
501         try {
502             synchronized(this) {
503                 if (job != null) { // shouldn't happen
504                     throw new PrintException("already printing");
505                 } else {
506                     job = new sun.awt.windows.WPrinterJob();
507                 }
508             }
509             PrintService svc = getPrintService();
510             job.setPrintService(svc);
511             if (copies == 0) {
512                 Copies c = (Copies)svc.getDefaultAttributeValue(Copies.class);
513                 copies = c.getValue();
514             }
515 
516             if (mediaName == null) {
517                 Object media = svc.getDefaultAttributeValue(Media.class);
518                 if (media instanceof MediaSizeName) {
519                     mediaName = (MediaSizeName) media;
520                     mediaSize = MediaSize.getMediaSizeForName(mediaName);
521                 }
522             }
523 
524             if (orient == null) {
525                 orient =
526                     (OrientationRequested)svc.getDefaultAttributeValue(OrientationRequested.class);
527             }
528 
529             job.setCopies(copies);
530             job.setJobName(jobName);
531             PageFormat pf = new PageFormat();
532             if (mediaSize != null) {
533                 Paper p = new Paper();
534                 p.setSize(mediaSize.getX(MediaSize.INCH)*72.0,
535                           mediaSize.getY(MediaSize.INCH)*72.0);
536                 p.setImageableArea(72.0, 72.0, p.getWidth()-144.0,
537                                    p.getHeight()-144.0);
538                 pf.setPaper(p);
539             }
540             if (orient == OrientationRequested.REVERSE_LANDSCAPE) {
541                 pf.setOrientation(PageFormat.REVERSE_LANDSCAPE);
542             } else if (orient == OrientationRequested.LANDSCAPE) {
543                 pf.setOrientation(PageFormat.LANDSCAPE);
544             }
545             job.setPrintable(printable, pf);
546             job.print(reqAttrSet);
547             notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
548             return;
549         } catch (PrinterException pe) {
550             notifyEvent(PrintJobEvent.JOB_FAILED);
551             throw new PrintException(pe);
552         } finally {
553             printReturned = true;
554             notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
555         }
556     }
557 
558     public void pageableJob(Pageable pageable) throws PrintException {
559         try {
560             synchronized(this) {
561                 if (job != null) { // shouldn't happen
562                     throw new PrintException("already printing");
563                 } else {
564                     job = new sun.awt.windows.WPrinterJob();
565                 }
566             }
567             PrintService svc = getPrintService();
568             job.setPrintService(svc);
569             if (copies == 0) {
570                 Copies c = (Copies)svc.getDefaultAttributeValue(Copies.class);
571                 copies = c.getValue();
572             }
573             job.setCopies(copies);
574             job.setJobName(jobName);
575             job.setPageable(pageable);
576             job.print(reqAttrSet);
577             notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
578             return;
579         } catch (PrinterException pe) {
580             notifyEvent(PrintJobEvent.JOB_FAILED);
581             throw new PrintException(pe);
582         } finally {
583             printReturned = true;
584             notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
585         }
586     }
587 
588     /* There's some inefficiency here as the job set is created even though
589      * it may never be requested.
590      */
591     private synchronized void
592         initializeAttributeSets(Doc doc, PrintRequestAttributeSet reqSet) {
593 
594         reqAttrSet = new HashPrintRequestAttributeSet();
595         jobAttrSet = new HashPrintJobAttributeSet();
596 
597         Attribute[] attrs;
598         if (reqSet != null) {
599             reqAttrSet.addAll(reqSet);
600             attrs = reqSet.toArray();
601             for (int i=0; i<attrs.length; i++) {
602                 if (attrs[i] instanceof PrintJobAttribute) {
603                     jobAttrSet.add(attrs[i]);
604                 }
605             }
606         }
607 
608         DocAttributeSet docSet = doc.getAttributes();
609         if (docSet != null) {
610             attrs = docSet.toArray();
611             for (int i=0; i<attrs.length; i++) {
612                 if (attrs[i] instanceof PrintRequestAttribute) {
613                     reqAttrSet.add(attrs[i]);
614                 }
615                 if (attrs[i] instanceof PrintJobAttribute) {
616                     jobAttrSet.add(attrs[i]);
617                 }
618             }
619         }
620 
621         /* add the user name to the job */
622         String userName = "";
623         try {
624           userName = System.getProperty("user.name");
625         } catch (SecurityException se) {
626         }
627 
628         if (userName == null || userName.equals("")) {
629             RequestingUserName ruName =
630                 (RequestingUserName)reqSet.get(RequestingUserName.class);
631             if (ruName != null) {
632                 jobAttrSet.add(
633                     new JobOriginatingUserName(ruName.getValue(),
634                                                ruName.getLocale()));
635             } else {
636                 jobAttrSet.add(new JobOriginatingUserName("", null));
637             }
638         } else {
639             jobAttrSet.add(new JobOriginatingUserName(userName, null));
640         }
641 
642         /* if no job name supplied use doc name (if supplied), if none and
643          * its a URL use that, else finally anything .. */
644         if (jobAttrSet.get(JobName.class) == null) {
645             JobName jobName;
646             if (docSet != null && docSet.get(DocumentName.class) != null) {
647                 DocumentName docName =
648                     (DocumentName)docSet.get(DocumentName.class);
649                 jobName = new JobName(docName.getValue(), docName.getLocale());
650                 jobAttrSet.add(jobName);
651             } else {
652                 String str = "JPS Job:" + doc;
653                 try {
654                     Object printData = doc.getPrintData();
655                     if (printData instanceof URL) {
656                         str = ((URL)(doc.getPrintData())).toString();
657                     }
658                 } catch (IOException e) {
659                 }
660                 jobName = new JobName(str, null);
661                 jobAttrSet.add(jobName);
662             }
663         }
664 
665         jobAttrSet = AttributeSetUtilities.unmodifiableView(jobAttrSet);
666     }
667 
668     private void getAttributeValues(DocFlavor flavor) throws PrintException {
669 
670         if (reqAttrSet.get(Fidelity.class) == Fidelity.FIDELITY_TRUE) {
671             fidelity = true;
672         } else {
673             fidelity = false;
674         }
675 
676         Class category;
677         Attribute [] attrs = reqAttrSet.toArray();
678         for (int i=0; i<attrs.length; i++) {
679             Attribute attr = attrs[i];
680             category = attr.getCategory();
681             if (fidelity == true) {
682                 if (!service.isAttributeCategorySupported(category)) {
683                     notifyEvent(PrintJobEvent.JOB_FAILED);
684                     throw new PrintJobAttributeException(
685                         "unsupported category: " + category, category, null);
686                 } else if
687                     (!service.isAttributeValueSupported(attr, flavor, null)) {
688                     notifyEvent(PrintJobEvent.JOB_FAILED);
689                     throw new PrintJobAttributeException(
690                         "unsupported attribute: " + attr, null, attr);
691                 }
692             }
693             if (category == Destination.class) {
694               URI uri = ((Destination)attr).getURI();
695               if (!"file".equals(uri.getScheme())) {
696                 notifyEvent(PrintJobEvent.JOB_FAILED);
697                 throw new PrintException("Not a file: URI");
698               } else {
699                 try {
700                   mDestination = (new File(uri)).getPath();
701                 } catch (Exception e) {
702                   throw new PrintException(e);
703                 }
704                 // check write access
705                 SecurityManager security = System.getSecurityManager();
706                 if (security != null) {
707                   try {
708                     security.checkWrite(mDestination);
709                   } catch (SecurityException se) {
710                     notifyEvent(PrintJobEvent.JOB_FAILED);
711                     throw new PrintException(se);
712                   }
713                 }
714               }
715             } else if (category == JobName.class) {
716                 jobName = ((JobName)attr).getValue();
717             } else if (category == Copies.class) {
718                 copies = ((Copies)attr).getValue();
719             } else if (category == Media.class) {
720               if (attr instanceof MediaSizeName) {
721                     mediaName = (MediaSizeName)attr;
722                     // If requested MediaSizeName is not supported,
723                     // get the corresponding media size - this will
724                     // be used to create a new PageFormat.
725                     if (!service.isAttributeValueSupported(attr, null, null)) {
726                         mediaSize = MediaSize.getMediaSizeForName(mediaName);
727                     }
728                 }
729             } else if (category == OrientationRequested.class) {
730                 orient = (OrientationRequested)attr;
731             }
732         }
733     }
734 
735     private native boolean startPrintRawData(String printerName,
736                                              String jobName);
737     private native boolean printRawData(byte[] data, int count);
738     private native boolean endPrintRawData();
739 
740     /* Cancel PrinterJob jobs that haven't yet completed. */
741    public void cancel() throws PrintException {
742         synchronized (this) {
743             if (!printing) {
744                 throw new PrintException("Job is not yet submitted.");
745             } else if (job != null && !printReturned) {
746                 job.cancel();
747                 notifyEvent(PrintJobEvent.JOB_CANCELED);
748                 return;
749             } else {
750                 throw new PrintException("Job could not be cancelled.");
751             }
752         }
753     }
754 }