1 /*
   2  * Copyright (c) 2000, 2014, 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     private transient Vector<PrintJobListener> jobListeners;
  83     private transient Vector<PrintJobAttributeListener> attrListeners;
  84     private transient Vector<PrintJobAttributeSet> 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 = 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 = service.getAttribute(PrinterState.class);
 312         if (prnState == PrinterState.STOPPED) {
 313             PrinterStateReasons prnStateReasons =
 314                 service.getAttribute(PrinterStateReasons.class);
 315                 if ((prnStateReasons != null) &&
 316                     (prnStateReasons.containsKey(PrinterStateReason.SHUTDOWN)))
 317                 {
 318                     throw new PrintException("PrintService is no longer available.");
 319                 }
 320         }
 321 
 322         if (service.getAttribute(PrinterIsAcceptingJobs.class) ==
 323             PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS) {
 324             throw new PrintException("Printer is not accepting job.");
 325         }
 326 
 327 
 328         this.doc = doc;
 329         /* check if the parameters are valid before doing much processing */
 330         DocFlavor flavor = doc.getDocFlavor();
 331         Object data;
 332 
 333         try {
 334             data = doc.getPrintData();
 335         } catch (IOException e) {
 336             notifyEvent(PrintJobEvent.JOB_FAILED);
 337             throw new PrintException("can't get print data: " + e.toString());
 338         }
 339 
 340         if (data == null) {
 341             throw new PrintException("Null print data.");
 342         }
 343 
 344         if (flavor == null || (!service.isDocFlavorSupported(flavor))) {
 345             notifyEvent(PrintJobEvent.JOB_FAILED);
 346             throw new PrintJobFlavorException("invalid flavor", flavor);
 347         }
 348 
 349         initializeAttributeSets(doc, attributes);
 350 
 351         getAttributeValues(flavor);
 352 
 353         String repClassName = flavor.getRepresentationClassName();
 354 
 355         if (flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
 356             flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
 357             flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
 358             flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
 359             flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
 360             flavor.equals(DocFlavor.BYTE_ARRAY.PNG)) {
 361             try {
 362                 instream = doc.getStreamForBytes();
 363                 if (instream == null) {
 364                     notifyEvent(PrintJobEvent.JOB_FAILED);
 365                     throw new PrintException("No stream for data");
 366                 }
 367                 printableJob(new ImagePrinter(instream));
 368                 service.wakeNotifier();
 369                 return;
 370             } catch (ClassCastException cce) {
 371                 notifyEvent(PrintJobEvent.JOB_FAILED);
 372                 throw new PrintException(cce);
 373             } catch (IOException ioe) {
 374                 notifyEvent(PrintJobEvent.JOB_FAILED);
 375                 throw new PrintException(ioe);
 376             }
 377         } else if (flavor.equals(DocFlavor.URL.GIF) ||
 378                    flavor.equals(DocFlavor.URL.JPEG) ||
 379                    flavor.equals(DocFlavor.URL.PNG)) {
 380             try {
 381                 printableJob(new ImagePrinter((URL)data));
 382                 service.wakeNotifier();
 383                 return;
 384             } catch (ClassCastException cce) {
 385                 notifyEvent(PrintJobEvent.JOB_FAILED);
 386                 throw new PrintException(cce);
 387             }
 388         } else if (repClassName.equals("java.awt.print.Pageable")) {
 389             try {
 390                 pageableJob((Pageable)doc.getPrintData());
 391                 service.wakeNotifier();
 392                 return;
 393             } catch (ClassCastException cce) {
 394                 notifyEvent(PrintJobEvent.JOB_FAILED);
 395                 throw new PrintException(cce);
 396             } catch (IOException ioe) {
 397                 notifyEvent(PrintJobEvent.JOB_FAILED);
 398                 throw new PrintException(ioe);
 399             }
 400         } else if (repClassName.equals("java.awt.print.Printable")) {
 401             try {
 402                 printableJob((Printable)doc.getPrintData());
 403                 service.wakeNotifier();
 404                 return;
 405             } catch (ClassCastException cce) {
 406                 notifyEvent(PrintJobEvent.JOB_FAILED);
 407                 throw new PrintException(cce);
 408             } catch (IOException ioe) {
 409                 notifyEvent(PrintJobEvent.JOB_FAILED);
 410                 throw new PrintException(ioe);
 411             }
 412         } else if (repClassName.equals("[B") ||
 413                    repClassName.equals("java.io.InputStream") ||
 414                    repClassName.equals("java.net.URL")) {
 415 
 416             if (repClassName.equals("java.net.URL")) {
 417                 URL url = (URL)data;
 418                 try {
 419                     instream = url.openStream();
 420                 } catch (IOException e) {
 421                     notifyEvent(PrintJobEvent.JOB_FAILED);
 422                     throw new PrintException(e.toString());
 423                 }
 424             } else {
 425                 try {
 426                     instream = doc.getStreamForBytes();
 427                 } catch (IOException ioe) {
 428                     notifyEvent(PrintJobEvent.JOB_FAILED);
 429                     throw new PrintException(ioe.toString());
 430                 }
 431             }
 432 
 433             if (instream == null) {
 434                 notifyEvent(PrintJobEvent.JOB_FAILED);
 435                 throw new PrintException("No stream for data");
 436             }
 437 
 438             if (mDestination != null) { // if destination attribute is set
 439                 try {
 440                     FileOutputStream fos = new FileOutputStream(mDestination);
 441                     byte []buffer = new byte[1024];
 442                     int cread;
 443 
 444                     while ((cread = instream.read(buffer, 0, buffer.length)) >=0) {
 445                         fos.write(buffer, 0, cread);
 446                     }
 447                     fos.flush();
 448                     fos.close();
 449                 } catch (FileNotFoundException fnfe) {
 450                     notifyEvent(PrintJobEvent.JOB_FAILED);
 451                     throw new PrintException(fnfe.toString());
 452                 } catch (IOException ioe) {
 453                     notifyEvent(PrintJobEvent.JOB_FAILED);
 454                     throw new PrintException(ioe.toString());
 455                 }
 456                 notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
 457                 notifyEvent(PrintJobEvent.JOB_COMPLETE);
 458                 service.wakeNotifier();
 459                 return;
 460             }
 461 
 462             if (!startPrintRawData(service.getName(), jobName)) {
 463                 notifyEvent(PrintJobEvent.JOB_FAILED);
 464                 throw new PrintException("Print job failed to start.");
 465             }
 466             BufferedInputStream  bin = new BufferedInputStream(instream);
 467             int bread = 0;
 468             try {
 469                 byte[] buffer = new byte[PRINTBUFFERLEN];
 470 
 471                 while ((bread = bin.read(buffer, 0, PRINTBUFFERLEN)) >=0) {
 472                     if (!printRawData(buffer, bread)) {
 473                         bin.close();
 474                         notifyEvent(PrintJobEvent.JOB_FAILED);
 475                         throw new PrintException ("Problem while spooling data");
 476                     }
 477                 }
 478                 bin.close();
 479                 if (!endPrintRawData()) {
 480                     notifyEvent(PrintJobEvent.JOB_FAILED);
 481                     throw new PrintException("Print job failed to close properly.");
 482                 }
 483                 notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
 484             } catch (IOException e) {
 485                 notifyEvent(PrintJobEvent.JOB_FAILED);
 486                 throw new PrintException (e.toString());
 487             } finally {
 488                 notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
 489             }
 490         } else {
 491             notifyEvent(PrintJobEvent.JOB_FAILED);
 492             throw new PrintException("unrecognized class: "+repClassName);
 493         }
 494         service.wakeNotifier();
 495     }
 496 
 497     public void printableJob(Printable printable) throws PrintException {
 498         try {
 499             synchronized(this) {
 500                 if (job != null) { // shouldn't happen
 501                     throw new PrintException("already printing");
 502                 } else {
 503                     job = new sun.awt.windows.WPrinterJob();
 504                 }
 505             }
 506             PrintService svc = getPrintService();
 507             job.setPrintService(svc);
 508             if (copies == 0) {
 509                 Copies c = (Copies)svc.getDefaultAttributeValue(Copies.class);
 510                 copies = c.getValue();
 511             }
 512 
 513             if (mediaName == null) {
 514                 Object media = svc.getDefaultAttributeValue(Media.class);
 515                 if (media instanceof MediaSizeName) {
 516                     mediaName = (MediaSizeName) media;
 517                     mediaSize = MediaSize.getMediaSizeForName(mediaName);
 518                 }
 519             }
 520 
 521             if (orient == null) {
 522                 orient =
 523                     (OrientationRequested)svc.getDefaultAttributeValue(OrientationRequested.class);
 524             }
 525 
 526             job.setCopies(copies);
 527             job.setJobName(jobName);
 528             PageFormat pf = new PageFormat();
 529             if (mediaSize != null) {
 530                 Paper p = new Paper();
 531                 p.setSize(mediaSize.getX(MediaSize.INCH)*72.0,
 532                           mediaSize.getY(MediaSize.INCH)*72.0);
 533                 p.setImageableArea(72.0, 72.0, p.getWidth()-144.0,
 534                                    p.getHeight()-144.0);
 535                 pf.setPaper(p);
 536             }
 537             if (orient == OrientationRequested.REVERSE_LANDSCAPE) {
 538                 pf.setOrientation(PageFormat.REVERSE_LANDSCAPE);
 539             } else if (orient == OrientationRequested.LANDSCAPE) {
 540                 pf.setOrientation(PageFormat.LANDSCAPE);
 541             }
 542             job.setPrintable(printable, pf);
 543             job.print(reqAttrSet);
 544             notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
 545             return;
 546         } catch (PrinterException pe) {
 547             notifyEvent(PrintJobEvent.JOB_FAILED);
 548             throw new PrintException(pe);
 549         } finally {
 550             printReturned = true;
 551             notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
 552         }
 553     }
 554 
 555     public void pageableJob(Pageable pageable) throws PrintException {
 556         try {
 557             synchronized(this) {
 558                 if (job != null) { // shouldn't happen
 559                     throw new PrintException("already printing");
 560                 } else {
 561                     job = new sun.awt.windows.WPrinterJob();
 562                 }
 563             }
 564             PrintService svc = getPrintService();
 565             job.setPrintService(svc);
 566             if (copies == 0) {
 567                 Copies c = (Copies)svc.getDefaultAttributeValue(Copies.class);
 568                 copies = c.getValue();
 569             }
 570             job.setCopies(copies);
 571             job.setJobName(jobName);
 572             job.setPageable(pageable);
 573             job.print(reqAttrSet);
 574             notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
 575             return;
 576         } catch (PrinterException pe) {
 577             notifyEvent(PrintJobEvent.JOB_FAILED);
 578             throw new PrintException(pe);
 579         } finally {
 580             printReturned = true;
 581             notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
 582         }
 583     }
 584 
 585     /* There's some inefficiency here as the job set is created even though
 586      * it may never be requested.
 587      */
 588     private synchronized void
 589         initializeAttributeSets(Doc doc, PrintRequestAttributeSet reqSet) {
 590 
 591         reqAttrSet = new HashPrintRequestAttributeSet();
 592         jobAttrSet = new HashPrintJobAttributeSet();
 593 
 594         Attribute[] attrs;
 595         if (reqSet != null) {
 596             reqAttrSet.addAll(reqSet);
 597             attrs = reqSet.toArray();
 598             for (int i=0; i<attrs.length; i++) {
 599                 if (attrs[i] instanceof PrintJobAttribute) {
 600                     jobAttrSet.add(attrs[i]);
 601                 }
 602             }
 603         }
 604 
 605         DocAttributeSet docSet = doc.getAttributes();
 606         if (docSet != null) {
 607             attrs = docSet.toArray();
 608             for (int i=0; i<attrs.length; i++) {
 609                 if (attrs[i] instanceof PrintRequestAttribute) {
 610                     reqAttrSet.add(attrs[i]);
 611                 }
 612                 if (attrs[i] instanceof PrintJobAttribute) {
 613                     jobAttrSet.add(attrs[i]);
 614                 }
 615             }
 616         }
 617 
 618         /* add the user name to the job */
 619         String userName = "";
 620         try {
 621           userName = System.getProperty("user.name");
 622         } catch (SecurityException se) {
 623         }
 624 
 625         if (userName == null || userName.equals("")) {
 626             RequestingUserName ruName =
 627                 (RequestingUserName)reqSet.get(RequestingUserName.class);
 628             if (ruName != null) {
 629                 jobAttrSet.add(
 630                     new JobOriginatingUserName(ruName.getValue(),
 631                                                ruName.getLocale()));
 632             } else {
 633                 jobAttrSet.add(new JobOriginatingUserName("", null));
 634             }
 635         } else {
 636             jobAttrSet.add(new JobOriginatingUserName(userName, null));
 637         }
 638 
 639         /* if no job name supplied use doc name (if supplied), if none and
 640          * its a URL use that, else finally anything .. */
 641         if (jobAttrSet.get(JobName.class) == null) {
 642             JobName jobName;
 643             if (docSet != null && docSet.get(DocumentName.class) != null) {
 644                 DocumentName docName =
 645                     (DocumentName)docSet.get(DocumentName.class);
 646                 jobName = new JobName(docName.getValue(), docName.getLocale());
 647                 jobAttrSet.add(jobName);
 648             } else {
 649                 String str = "JPS Job:" + doc;
 650                 try {
 651                     Object printData = doc.getPrintData();
 652                     if (printData instanceof URL) {
 653                         str = ((URL)(doc.getPrintData())).toString();
 654                     }
 655                 } catch (IOException e) {
 656                 }
 657                 jobName = new JobName(str, null);
 658                 jobAttrSet.add(jobName);
 659             }
 660         }
 661 
 662         jobAttrSet = AttributeSetUtilities.unmodifiableView(jobAttrSet);
 663     }
 664 
 665     private void getAttributeValues(DocFlavor flavor) throws PrintException {
 666 
 667         if (reqAttrSet.get(Fidelity.class) == Fidelity.FIDELITY_TRUE) {
 668             fidelity = true;
 669         } else {
 670             fidelity = false;
 671         }
 672 
 673         Class<? extends Attribute> category;
 674         Attribute [] attrs = reqAttrSet.toArray();
 675         for (int i=0; i<attrs.length; i++) {
 676             Attribute attr = attrs[i];
 677             category = attr.getCategory();
 678             if (fidelity == true) {
 679                 if (!service.isAttributeCategorySupported(category)) {
 680                     notifyEvent(PrintJobEvent.JOB_FAILED);
 681                     throw new PrintJobAttributeException(
 682                         "unsupported category: " + category, category, null);
 683                 } else if
 684                     (!service.isAttributeValueSupported(attr, flavor, null)) {
 685                     notifyEvent(PrintJobEvent.JOB_FAILED);
 686                     throw new PrintJobAttributeException(
 687                         "unsupported attribute: " + attr, null, attr);
 688                 }
 689             }
 690             if (category == Destination.class) {
 691               URI uri = ((Destination)attr).getURI();
 692               if (!"file".equals(uri.getScheme())) {
 693                 notifyEvent(PrintJobEvent.JOB_FAILED);
 694                 throw new PrintException("Not a file: URI");
 695               } else {
 696                 try {
 697                   mDestination = (new File(uri)).getPath();
 698                 } catch (Exception e) {
 699                   throw new PrintException(e);
 700                 }
 701                 // check write access
 702                 SecurityManager security = System.getSecurityManager();
 703                 if (security != null) {
 704                   try {
 705                     security.checkWrite(mDestination);
 706                   } catch (SecurityException se) {
 707                     notifyEvent(PrintJobEvent.JOB_FAILED);
 708                     throw new PrintException(se);
 709                   }
 710                 }
 711               }
 712             } else if (category == JobName.class) {
 713                 jobName = ((JobName)attr).getValue();
 714             } else if (category == Copies.class) {
 715                 copies = ((Copies)attr).getValue();
 716             } else if (category == Media.class) {
 717               if (attr instanceof MediaSizeName) {
 718                     mediaName = (MediaSizeName)attr;
 719                     // If requested MediaSizeName is not supported,
 720                     // get the corresponding media size - this will
 721                     // be used to create a new PageFormat.
 722                     if (!service.isAttributeValueSupported(attr, null, null)) {
 723                         mediaSize = MediaSize.getMediaSizeForName(mediaName);
 724                     }
 725                 }
 726             } else if (category == OrientationRequested.class) {
 727                 orient = (OrientationRequested)attr;
 728             }
 729         }
 730     }
 731 
 732     private native boolean startPrintRawData(String printerName,
 733                                              String jobName);
 734     private native boolean printRawData(byte[] data, int count);
 735     private native boolean endPrintRawData();
 736 
 737     /* Cancel PrinterJob jobs that haven't yet completed. */
 738    public void cancel() throws PrintException {
 739         synchronized (this) {
 740             if (!printing) {
 741                 throw new PrintException("Job is not yet submitted.");
 742             } else if (job != null && !printReturned) {
 743                 job.cancel();
 744                 notifyEvent(PrintJobEvent.JOB_CANCELED);
 745                 return;
 746             } else {
 747                 throw new PrintException("Job could not be cancelled.");
 748             }
 749         }
 750     }
 751 }