1 /* 2 * Copyright (c) 2000, 2005, 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.URL; 29 import java.io.InputStream; 30 import java.io.IOException; 31 import java.io.Reader; 32 import java.util.Vector; 33 34 import javax.print.CancelablePrintJob; 35 import javax.print.Doc; 36 import javax.print.DocFlavor; 37 import javax.print.DocPrintJob; 38 import javax.print.PrintService; 39 import javax.print.PrintException; 40 import javax.print.event.PrintJobEvent; 41 import javax.print.event.PrintJobListener; 42 import javax.print.event.PrintJobAttributeListener; 43 44 import javax.print.attribute.Attribute; 45 import javax.print.attribute.AttributeSet; 46 import javax.print.attribute.AttributeSetUtilities; 47 import javax.print.attribute.DocAttributeSet; 48 import javax.print.attribute.HashPrintJobAttributeSet; 49 import javax.print.attribute.HashPrintRequestAttributeSet; 50 import javax.print.attribute.PrintJobAttribute; 51 import javax.print.attribute.PrintJobAttributeSet; 52 import javax.print.attribute.PrintRequestAttribute; 53 import javax.print.attribute.PrintRequestAttributeSet; 54 import javax.print.attribute.standard.Copies; 55 import javax.print.attribute.standard.DocumentName; 56 import javax.print.attribute.standard.Fidelity; 57 import javax.print.attribute.standard.JobName; 58 import javax.print.attribute.standard.JobOriginatingUserName; 59 import javax.print.attribute.standard.Media; 60 import javax.print.attribute.standard.MediaSize; 61 import javax.print.attribute.standard.MediaSizeName; 62 import javax.print.attribute.standard.OrientationRequested; 63 import javax.print.attribute.standard.RequestingUserName; 64 65 import java.awt.print.*; 66 67 public class PSStreamPrintJob implements CancelablePrintJob { 68 69 transient private Vector jobListeners; 70 transient private Vector attrListeners; 71 transient private Vector listenedAttributeSets; 72 73 private PSStreamPrintService service; 74 private boolean fidelity; 75 private boolean printing = false; 76 private boolean printReturned = false; 77 private PrintRequestAttributeSet reqAttrSet = null; 78 private PrintJobAttributeSet jobAttrSet = null; 79 private PrinterJob job; 80 private Doc doc; 81 /* these variables used globally to store reference to the print 82 * data retrieved as a stream. On completion these are always closed 83 * if non-null. 84 */ 85 private InputStream instream = null; 86 private Reader reader = null; 87 88 /* default values overridden by those extracted from the attributes */ 89 private String jobName = "Java Printing"; 90 private int copies = 1; 91 private MediaSize mediaSize = MediaSize.NA.LETTER; 92 private OrientationRequested orient = OrientationRequested.PORTRAIT; 93 94 PSStreamPrintJob(PSStreamPrintService service) { 95 this.service = service; 96 } 97 98 public PrintService getPrintService() { 99 return service; 100 } 101 102 public PrintJobAttributeSet getAttributes() { 103 synchronized (this) { 104 if (jobAttrSet == null) { 105 /* just return an empty set until the job is submitted */ 106 PrintJobAttributeSet jobSet = new HashPrintJobAttributeSet(); 107 return AttributeSetUtilities.unmodifiableView(jobSet); 108 } else { 109 return jobAttrSet; 110 } 111 } 112 } 113 114 public void addPrintJobListener(PrintJobListener listener) { 115 synchronized (this) { 116 if (listener == null) { 117 return; 118 } 119 if (jobListeners == null) { 120 jobListeners = new Vector(); 121 } 122 jobListeners.add(listener); 123 } 124 } 125 126 public void removePrintJobListener(PrintJobListener listener) { 127 synchronized (this) { 128 if (listener == null || jobListeners == null ) { 129 return; 130 } 131 jobListeners.remove(listener); 132 if (jobListeners.isEmpty()) { 133 jobListeners = null; 134 } 135 } 136 } 137 138 /* Closes any stream already retrieved for the data. 139 * We want to avoid unnecessarily asking the Doc to create a stream only 140 * to get a reference in order to close it because the job failed. 141 * If the representation class is itself a "stream", this 142 * closes that stream too. 143 */ 144 private void closeDataStreams() { 145 146 if (doc == null) { 147 return; 148 } 149 150 Object data = null; 151 152 try { 153 data = doc.getPrintData(); 154 } catch (IOException e) { 155 return; 156 } 157 158 if (instream != null) { 159 try { 160 instream.close(); 161 } catch (IOException e) { 162 } finally { 163 instream = null; 164 } 165 } 166 else if (reader != null) { 167 try { 168 reader.close(); 169 } catch (IOException e) { 170 } finally { 171 reader = null; 172 } 173 } 174 else if (data instanceof InputStream) { 175 try { 176 ((InputStream)data).close(); 177 } catch (IOException e) { 178 } 179 } 180 else if (data instanceof Reader) { 181 try { 182 ((Reader)data).close(); 183 } catch (IOException e) { 184 } 185 } 186 } 187 188 private void notifyEvent(int reason) { 189 synchronized (this) { 190 if (jobListeners != null) { 191 PrintJobListener listener; 192 PrintJobEvent event = new PrintJobEvent(this, reason); 193 for (int i = 0; i < jobListeners.size(); i++) { 194 listener = (PrintJobListener)(jobListeners.elementAt(i)); 195 switch (reason) { 196 197 case PrintJobEvent.JOB_CANCELED : 198 listener.printJobCanceled(event); 199 break; 200 201 case PrintJobEvent.JOB_FAILED : 202 listener.printJobFailed(event); 203 break; 204 205 case PrintJobEvent.DATA_TRANSFER_COMPLETE : 206 listener.printDataTransferCompleted(event); 207 break; 208 209 case PrintJobEvent.NO_MORE_EVENTS : 210 listener.printJobNoMoreEvents(event); 211 break; 212 213 case PrintJobEvent.JOB_COMPLETE : 214 listener.printJobCompleted(event); 215 break; 216 217 default: 218 break; 219 } 220 } 221 } 222 } 223 } 224 225 public void addPrintJobAttributeListener( 226 PrintJobAttributeListener listener, 227 PrintJobAttributeSet attributes) { 228 synchronized (this) { 229 if (listener == null) { 230 return; 231 } 232 if (attrListeners == null) { 233 attrListeners = new Vector(); 234 listenedAttributeSets = new Vector(); 235 } 236 attrListeners.add(listener); 237 if (attributes == null) { 238 attributes = new HashPrintJobAttributeSet(); 239 } 240 listenedAttributeSets.add(attributes); 241 } 242 } 243 244 public void removePrintJobAttributeListener( 245 PrintJobAttributeListener listener) { 246 synchronized (this) { 247 if (listener == null || attrListeners == null ) { 248 return; 249 } 250 int index = attrListeners.indexOf(listener); 251 if (index == -1) { 252 return; 253 } else { 254 attrListeners.remove(index); 255 listenedAttributeSets.remove(index); 256 if (attrListeners.isEmpty()) { 257 attrListeners = null; 258 listenedAttributeSets = null; 259 } 260 } 261 } 262 } 263 264 public void print(Doc doc, PrintRequestAttributeSet attributes) 265 throws PrintException { 266 267 synchronized (this) { 268 if (printing) { 269 throw new PrintException("already printing"); 270 } else { 271 printing = true; 272 } 273 } 274 275 this.doc = doc; 276 /* check if the parameters are valid before doing much processing */ 277 DocFlavor flavor = doc.getDocFlavor(); 278 Object data; 279 280 try { 281 data = doc.getPrintData(); 282 } catch (IOException e) { 283 notifyEvent(PrintJobEvent.JOB_FAILED); 284 throw new PrintException("can't get print data: " + e.toString()); 285 } 286 287 if (flavor == null || (!service.isDocFlavorSupported(flavor))) { 288 notifyEvent(PrintJobEvent.JOB_FAILED); 289 throw new PrintJobFlavorException("invalid flavor", flavor); 290 } 291 292 initializeAttributeSets(doc, attributes); 293 294 getAttributeValues(flavor); 295 296 String repClassName = flavor.getRepresentationClassName(); 297 if (flavor.equals(DocFlavor.INPUT_STREAM.GIF) || 298 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) || 299 flavor.equals(DocFlavor.INPUT_STREAM.PNG) || 300 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) || 301 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) || 302 flavor.equals(DocFlavor.BYTE_ARRAY.PNG)) { 303 try { 304 instream = doc.getStreamForBytes(); 305 printableJob(new ImagePrinter(instream), reqAttrSet); 306 return; 307 } catch (ClassCastException cce) { 308 notifyEvent(PrintJobEvent.JOB_FAILED); 309 throw new PrintException(cce); 310 } catch (IOException ioe) { 311 notifyEvent(PrintJobEvent.JOB_FAILED); 312 throw new PrintException(ioe); 313 } 314 } else if (flavor.equals(DocFlavor.URL.GIF) || 315 flavor.equals(DocFlavor.URL.JPEG) || 316 flavor.equals(DocFlavor.URL.PNG)) { 317 try { 318 printableJob(new ImagePrinter((URL)data), reqAttrSet); 319 return; 320 } catch (ClassCastException cce) { 321 notifyEvent(PrintJobEvent.JOB_FAILED); 322 throw new PrintException(cce); 323 } 324 } else if (repClassName.equals("java.awt.print.Pageable")) { 325 try { 326 pageableJob((Pageable)doc.getPrintData(), reqAttrSet); 327 return; 328 } catch (ClassCastException cce) { 329 notifyEvent(PrintJobEvent.JOB_FAILED); 330 throw new PrintException(cce); 331 } catch (IOException ioe) { 332 notifyEvent(PrintJobEvent.JOB_FAILED); 333 throw new PrintException(ioe); 334 } 335 } else if (repClassName.equals("java.awt.print.Printable")) { 336 try { 337 printableJob((Printable)doc.getPrintData(), reqAttrSet); 338 return; 339 } catch (ClassCastException cce) { 340 notifyEvent(PrintJobEvent.JOB_FAILED); 341 throw new PrintException(cce); 342 } catch (IOException ioe) { 343 notifyEvent(PrintJobEvent.JOB_FAILED); 344 throw new PrintException(ioe); 345 } 346 } else { 347 notifyEvent(PrintJobEvent.JOB_FAILED); 348 throw new PrintException("unrecognized class: "+repClassName); 349 } 350 } 351 352 public void printableJob(Printable printable, 353 PrintRequestAttributeSet attributes) 354 throws PrintException { 355 try { 356 synchronized(this) { 357 if (job != null) { // shouldn't happen 358 throw new PrintException("already printing"); 359 } else { 360 job = new PSPrinterJob(); 361 } 362 } 363 job.setPrintService(getPrintService()); 364 PageFormat pf = new PageFormat(); 365 if (mediaSize != null) { 366 Paper p = new Paper(); 367 p.setSize(mediaSize.getX(MediaSize.INCH)*72.0, 368 mediaSize.getY(MediaSize.INCH)*72.0); 369 p.setImageableArea(72.0, 72.0, p.getWidth()-144.0, 370 p.getHeight()-144.0); 371 pf.setPaper(p); 372 } 373 if (orient == OrientationRequested.REVERSE_LANDSCAPE) { 374 pf.setOrientation(PageFormat.REVERSE_LANDSCAPE); 375 } else if (orient == OrientationRequested.LANDSCAPE) { 376 pf.setOrientation(PageFormat.LANDSCAPE); 377 } 378 job.setPrintable(printable, pf); 379 job.print(attributes); 380 notifyEvent(PrintJobEvent.JOB_COMPLETE); 381 return; 382 } catch (PrinterException pe) { 383 notifyEvent(PrintJobEvent.JOB_FAILED); 384 throw new PrintException(pe); 385 } finally { 386 printReturned = true; 387 } 388 } 389 390 public void pageableJob(Pageable pageable, 391 PrintRequestAttributeSet attributes) 392 throws PrintException { 393 try { 394 synchronized(this) { 395 if (job != null) { // shouldn't happen 396 throw new PrintException("already printing"); 397 } else { 398 job = new PSPrinterJob(); 399 } 400 } 401 job.setPrintService(getPrintService()); 402 job.setPageable(pageable); 403 job.print(attributes); 404 notifyEvent(PrintJobEvent.JOB_COMPLETE); 405 return; 406 } catch (PrinterException pe) { 407 notifyEvent(PrintJobEvent.JOB_FAILED); 408 throw new PrintException(pe); 409 } finally { 410 printReturned = true; 411 } 412 } 413 414 /* There's some inefficiency here as the job set is created even though 415 * it may never be requested. 416 */ 417 private synchronized void 418 initializeAttributeSets(Doc doc, PrintRequestAttributeSet reqSet) { 419 420 reqAttrSet = new HashPrintRequestAttributeSet(); 421 jobAttrSet = new HashPrintJobAttributeSet(); 422 423 Attribute[] attrs; 424 if (reqSet != null) { 425 reqAttrSet.addAll(reqSet); 426 attrs = reqSet.toArray(); 427 for (int i=0; i<attrs.length; i++) { 428 if (attrs[i] instanceof PrintJobAttribute) { 429 jobAttrSet.add(attrs[i]); 430 } 431 } 432 } 433 434 DocAttributeSet docSet = doc.getAttributes(); 435 if (docSet != null) { 436 attrs = docSet.toArray(); 437 for (int i=0; i<attrs.length; i++) { 438 if (attrs[i] instanceof PrintRequestAttribute) { 439 reqAttrSet.add(attrs[i]); 440 } 441 if (attrs[i] instanceof PrintJobAttribute) { 442 jobAttrSet.add(attrs[i]); 443 } 444 } 445 } 446 447 /* add the user name to the job */ 448 String userName = ""; 449 try { 450 userName = System.getProperty("user.name"); 451 } catch (SecurityException se) { 452 } 453 454 if (userName == null || userName.equals("")) { 455 RequestingUserName ruName = 456 (RequestingUserName)reqSet.get(RequestingUserName.class); 457 if (ruName != null) { 458 jobAttrSet.add( 459 new JobOriginatingUserName(ruName.getValue(), 460 ruName.getLocale())); 461 } else { 462 jobAttrSet.add(new JobOriginatingUserName("", null)); 463 } 464 } else { 465 jobAttrSet.add(new JobOriginatingUserName(userName, null)); 466 } 467 468 /* if no job name supplied use doc name (if supplied), if none and 469 * its a URL use that, else finally anything .. */ 470 if (jobAttrSet.get(JobName.class) == null) { 471 JobName jobName; 472 if (docSet != null && docSet.get(DocumentName.class) != null) { 473 DocumentName docName = 474 (DocumentName)docSet.get(DocumentName.class); 475 jobName = new JobName(docName.getValue(), docName.getLocale()); 476 jobAttrSet.add(jobName); 477 } else { 478 String str = "JPS Job:" + doc; 479 try { 480 Object printData = doc.getPrintData(); 481 if (printData instanceof URL) { 482 str = ((URL)(doc.getPrintData())).toString(); 483 } 484 } catch (IOException e) { 485 } 486 jobName = new JobName(str, null); 487 jobAttrSet.add(jobName); 488 } 489 } 490 491 jobAttrSet = AttributeSetUtilities.unmodifiableView(jobAttrSet); 492 } 493 494 private void getAttributeValues(DocFlavor flavor) throws PrintException { 495 496 Attribute attr; 497 Class category; 498 499 if (reqAttrSet.get(Fidelity.class) == Fidelity.FIDELITY_TRUE) { 500 fidelity = true; 501 } else { 502 fidelity = false; 503 } 504 505 Attribute []attrs = reqAttrSet.toArray(); 506 for (int i=0; i<attrs.length; i++) { 507 attr = attrs[i]; 508 category = attr.getCategory(); 509 if (fidelity == true) { 510 if (!service.isAttributeCategorySupported(category)) { 511 notifyEvent(PrintJobEvent.JOB_FAILED); 512 throw new PrintJobAttributeException( 513 "unsupported category: " + category, category, null); 514 } else if 515 (!service.isAttributeValueSupported(attr, flavor, null)) { 516 notifyEvent(PrintJobEvent.JOB_FAILED); 517 throw new PrintJobAttributeException( 518 "unsupported attribute: " + attr, null, attr); 519 } 520 } 521 if (category == JobName.class) { 522 jobName = ((JobName)attr).getValue(); 523 } else if (category == Copies.class) { 524 copies = ((Copies)attr).getValue(); 525 } else if (category == Media.class) { 526 if (attr instanceof MediaSizeName && 527 service.isAttributeValueSupported(attr, null, null)) { 528 mediaSize = 529 MediaSize.getMediaSizeForName((MediaSizeName)attr); 530 } 531 } else if (category == OrientationRequested.class) { 532 orient = (OrientationRequested)attr; 533 } 534 } 535 } 536 537 /* Cancel PrinterJob jobs that haven't yet completed. */ 538 public void cancel() throws PrintException { 539 synchronized (this) { 540 if (!printing) { 541 throw new PrintException("Job is not yet submitted."); 542 } else if (job != null && !printReturned) { 543 job.cancel(); 544 notifyEvent(PrintJobEvent.JOB_CANCELED); 545 return; 546 } else { 547 throw new PrintException("Job could not be cancelled."); 548 } 549 } 550 } 551 552 }