1 /*
   2  * Copyright (c) 2000, 2006, 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 }