blob: e67652a3e376834d2a9efc6b08c4d5982435c382 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.print;
27
28import java.net.URL;
29import java.io.InputStream;
30import java.io.IOException;
31import java.io.Reader;
32import java.util.Vector;
33
34import javax.print.CancelablePrintJob;
35import javax.print.Doc;
36import javax.print.DocFlavor;
37import javax.print.DocPrintJob;
38import javax.print.PrintService;
39import javax.print.PrintException;
40import javax.print.event.PrintJobEvent;
41import javax.print.event.PrintJobListener;
42import javax.print.event.PrintJobAttributeListener;
43
44import javax.print.attribute.Attribute;
45import javax.print.attribute.AttributeSet;
46import javax.print.attribute.AttributeSetUtilities;
47import javax.print.attribute.DocAttributeSet;
48import javax.print.attribute.HashPrintJobAttributeSet;
49import javax.print.attribute.HashPrintRequestAttributeSet;
50import javax.print.attribute.PrintJobAttribute;
51import javax.print.attribute.PrintJobAttributeSet;
52import javax.print.attribute.PrintRequestAttribute;
53import javax.print.attribute.PrintRequestAttributeSet;
54import javax.print.attribute.standard.Copies;
55import javax.print.attribute.standard.DocumentName;
56import javax.print.attribute.standard.Fidelity;
57import javax.print.attribute.standard.JobName;
58import javax.print.attribute.standard.JobOriginatingUserName;
59import javax.print.attribute.standard.Media;
60import javax.print.attribute.standard.MediaSize;
61import javax.print.attribute.standard.MediaSizeName;
62import javax.print.attribute.standard.OrientationRequested;
63import javax.print.attribute.standard.RequestingUserName;
64
65import java.awt.print.*;
66
67public 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}