Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java
41152 views
1
/*
2
* Copyright (c) 2000, 2021, 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.net.URL;
30
import java.io.BufferedInputStream;
31
import java.io.BufferedOutputStream;
32
import java.io.BufferedReader;
33
import java.io.BufferedWriter;
34
import java.io.File;
35
import java.io.FileOutputStream;
36
import java.io.InputStream;
37
import java.io.InputStreamReader;
38
import java.io.OutputStream;
39
import java.io.OutputStreamWriter;
40
import java.io.IOException;
41
import java.io.PrintWriter;
42
import java.io.Reader;
43
import java.io.StringWriter;
44
import java.nio.file.Files;
45
import java.util.Vector;
46
47
import javax.print.CancelablePrintJob;
48
import javax.print.Doc;
49
import javax.print.DocFlavor;
50
import javax.print.PrintService;
51
import javax.print.PrintException;
52
import javax.print.event.PrintJobEvent;
53
import javax.print.event.PrintJobListener;
54
import javax.print.event.PrintJobAttributeListener;
55
56
import javax.print.attribute.Attribute;
57
import javax.print.attribute.AttributeSetUtilities;
58
import javax.print.attribute.DocAttributeSet;
59
import javax.print.attribute.HashPrintJobAttributeSet;
60
import javax.print.attribute.HashPrintRequestAttributeSet;
61
import javax.print.attribute.PrintJobAttribute;
62
import javax.print.attribute.PrintJobAttributeSet;
63
import javax.print.attribute.PrintRequestAttribute;
64
import javax.print.attribute.PrintRequestAttributeSet;
65
import javax.print.attribute.standard.Copies;
66
import javax.print.attribute.standard.Destination;
67
import javax.print.attribute.standard.DocumentName;
68
import javax.print.attribute.standard.Fidelity;
69
import javax.print.attribute.standard.JobName;
70
import javax.print.attribute.standard.JobOriginatingUserName;
71
import javax.print.attribute.standard.JobSheets;
72
import javax.print.attribute.standard.Media;
73
import javax.print.attribute.standard.MediaSize;
74
import javax.print.attribute.standard.MediaSizeName;
75
import javax.print.attribute.standard.OrientationRequested;
76
import javax.print.attribute.standard.RequestingUserName;
77
import javax.print.attribute.standard.NumberUp;
78
import javax.print.attribute.standard.Sides;
79
import javax.print.attribute.standard.PrinterIsAcceptingJobs;
80
81
import java.awt.print.PageFormat;
82
import java.awt.print.PrinterJob;
83
import java.awt.print.Pageable;
84
import java.awt.print.Paper;
85
import java.awt.print.Printable;
86
import java.awt.print.PrinterException;
87
88
89
90
public class UnixPrintJob implements CancelablePrintJob {
91
private static String debugPrefix = "UnixPrintJob>> ";
92
93
private transient Vector<PrintJobListener> jobListeners;
94
private transient Vector<PrintJobAttributeListener> attrListeners;
95
private transient Vector<PrintJobAttributeSet> listenedAttributeSets;
96
97
private PrintService service;
98
private boolean fidelity;
99
private boolean printing = false;
100
private boolean printReturned = false;
101
private PrintRequestAttributeSet reqAttrSet = null;
102
private PrintJobAttributeSet jobAttrSet = null;
103
private PrinterJob job;
104
private Doc doc;
105
/* these variables used globally to store reference to the print
106
* data retrieved as a stream. On completion these are always closed
107
* if non-null.
108
*/
109
private InputStream instream = null;
110
private Reader reader = null;
111
112
/* default values overridden by those extracted from the attributes */
113
private String jobName = "Java Printing";
114
private int copies = 1;
115
private MediaSizeName mediaName = MediaSizeName.NA_LETTER;
116
private MediaSize mediaSize = MediaSize.NA.LETTER;
117
private CustomMediaTray customTray = null;
118
private OrientationRequested orient = OrientationRequested.PORTRAIT;
119
private NumberUp nUp = null;
120
private Sides sides = null;
121
122
UnixPrintJob(PrintService service) {
123
this.service = service;
124
mDestination = service.getName();
125
if (PrintServiceLookupProvider.isMac()) {
126
mDestination = ((IPPPrintService)service).getDest();
127
}
128
mDestType = UnixPrintJob.DESTPRINTER;
129
JobSheets js = (JobSheets)(service.
130
getDefaultAttributeValue(JobSheets.class));
131
if (js != null && js.equals(JobSheets.NONE)) {
132
mNoJobSheet = true;
133
}
134
}
135
136
public PrintService getPrintService() {
137
return service;
138
}
139
140
public PrintJobAttributeSet getAttributes() {
141
synchronized (this) {
142
if (jobAttrSet == null) {
143
/* just return an empty set until the job is submitted */
144
PrintJobAttributeSet jobSet = new HashPrintJobAttributeSet();
145
return AttributeSetUtilities.unmodifiableView(jobSet);
146
} else {
147
return jobAttrSet;
148
}
149
}
150
}
151
152
public void addPrintJobListener(PrintJobListener listener) {
153
synchronized (this) {
154
if (listener == null) {
155
return;
156
}
157
if (jobListeners == null) {
158
jobListeners = new Vector<>();
159
}
160
jobListeners.add(listener);
161
}
162
}
163
164
public void removePrintJobListener(PrintJobListener listener) {
165
synchronized (this) {
166
if (listener == null || jobListeners == null ) {
167
return;
168
}
169
jobListeners.remove(listener);
170
if (jobListeners.isEmpty()) {
171
jobListeners = null;
172
}
173
}
174
}
175
176
177
/* Closes any stream already retrieved for the data.
178
* We want to avoid unnecessarily asking the Doc to create a stream only
179
* to get a reference in order to close it because the job failed.
180
* If the representation class is itself a "stream", this
181
* closes that stream too.
182
*/
183
private void closeDataStreams() {
184
185
if (doc == null) {
186
return;
187
}
188
189
Object data = null;
190
191
try {
192
data = doc.getPrintData();
193
} catch (IOException e) {
194
return;
195
}
196
197
if (instream != null) {
198
try {
199
instream.close();
200
} catch (IOException e) {
201
} finally {
202
instream = null;
203
}
204
}
205
else if (reader != null) {
206
try {
207
reader.close();
208
} catch (IOException e) {
209
} finally {
210
reader = null;
211
}
212
}
213
else if (data instanceof InputStream) {
214
try {
215
((InputStream)data).close();
216
} catch (IOException e) {
217
}
218
}
219
else if (data instanceof Reader) {
220
try {
221
((Reader)data).close();
222
} catch (IOException e) {
223
}
224
}
225
}
226
227
private void notifyEvent(int reason) {
228
229
/* since this method should always get called, here's where
230
* we will perform the clean up of any data stream supplied.
231
*/
232
switch (reason) {
233
case PrintJobEvent.DATA_TRANSFER_COMPLETE:
234
case PrintJobEvent.JOB_CANCELED :
235
case PrintJobEvent.JOB_FAILED :
236
case PrintJobEvent.NO_MORE_EVENTS :
237
case PrintJobEvent.JOB_COMPLETE :
238
closeDataStreams();
239
}
240
241
synchronized (this) {
242
if (jobListeners != null) {
243
PrintJobListener listener;
244
PrintJobEvent event = new PrintJobEvent(this, reason);
245
for (int i = 0; i < jobListeners.size(); i++) {
246
listener = jobListeners.elementAt(i);
247
switch (reason) {
248
249
case PrintJobEvent.JOB_CANCELED :
250
listener.printJobCanceled(event);
251
break;
252
253
case PrintJobEvent.JOB_FAILED :
254
listener.printJobFailed(event);
255
break;
256
257
case PrintJobEvent.DATA_TRANSFER_COMPLETE :
258
listener.printDataTransferCompleted(event);
259
break;
260
261
case PrintJobEvent.NO_MORE_EVENTS :
262
listener.printJobNoMoreEvents(event);
263
break;
264
265
default:
266
break;
267
}
268
}
269
}
270
}
271
}
272
273
public void addPrintJobAttributeListener(
274
PrintJobAttributeListener listener,
275
PrintJobAttributeSet attributes) {
276
synchronized (this) {
277
if (listener == null) {
278
return;
279
}
280
if (attrListeners == null) {
281
attrListeners = new Vector<>();
282
listenedAttributeSets = new Vector<>();
283
}
284
attrListeners.add(listener);
285
if (attributes == null) {
286
attributes = new HashPrintJobAttributeSet();
287
}
288
listenedAttributeSets.add(attributes);
289
}
290
}
291
292
public void removePrintJobAttributeListener(
293
PrintJobAttributeListener listener) {
294
synchronized (this) {
295
if (listener == null || attrListeners == null ) {
296
return;
297
}
298
int index = attrListeners.indexOf(listener);
299
if (index == -1) {
300
return;
301
} else {
302
attrListeners.remove(index);
303
listenedAttributeSets.remove(index);
304
if (attrListeners.isEmpty()) {
305
attrListeners = null;
306
listenedAttributeSets = null;
307
}
308
}
309
}
310
}
311
312
@SuppressWarnings("removal")
313
public void print(Doc doc, PrintRequestAttributeSet attributes)
314
throws PrintException {
315
316
synchronized (this) {
317
if (printing) {
318
throw new PrintException("already printing");
319
} else {
320
printing = true;
321
}
322
}
323
324
if ((service.getAttribute(PrinterIsAcceptingJobs.class)) ==
325
PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS) {
326
throw new PrintException("Printer is not accepting job.");
327
}
328
329
this.doc = doc;
330
/* check if the parameters are valid before doing much processing */
331
DocFlavor flavor = doc.getDocFlavor();
332
333
Object data;
334
335
try {
336
data = doc.getPrintData();
337
} catch (IOException e) {
338
notifyEvent(PrintJobEvent.JOB_FAILED);
339
throw new PrintException("can't get print data: " + e.toString());
340
}
341
342
if (data == null) {
343
throw new PrintException("Null print data.");
344
}
345
346
if (flavor == null || (!service.isDocFlavorSupported(flavor))) {
347
notifyEvent(PrintJobEvent.JOB_FAILED);
348
throw new PrintJobFlavorException("invalid flavor", flavor);
349
}
350
351
initializeAttributeSets(doc, attributes);
352
353
getAttributeValues(flavor);
354
355
// set up mOptions
356
if ((service instanceof IPPPrintService) &&
357
CUPSPrinter.isCupsRunning()) {
358
359
IPPPrintService.debug_println(debugPrefix+
360
"instanceof IPPPrintService");
361
362
if (mediaName != null) {
363
CustomMediaSizeName customMedia =
364
((IPPPrintService)service).findCustomMedia(mediaName);
365
if (customMedia != null) {
366
mOptions = " media="+ customMedia.getChoiceName();
367
}
368
}
369
370
if (customTray != null &&
371
customTray instanceof CustomMediaTray) {
372
String choice = customTray.getChoiceName();
373
if (choice != null) {
374
mOptions += " InputSlot="+choice;
375
}
376
}
377
378
if (nUp != null) {
379
mOptions += " number-up="+nUp.getValue();
380
}
381
382
if (orient != OrientationRequested.PORTRAIT &&
383
(flavor != null) &&
384
!flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE)) {
385
mOptions += " orientation-requested="+orient.getValue();
386
}
387
388
if (sides != null) {
389
mOptions += " sides="+sides;
390
}
391
392
}
393
394
IPPPrintService.debug_println(debugPrefix+"mOptions "+mOptions);
395
String repClassName = flavor.getRepresentationClassName();
396
String val = flavor.getParameter("charset");
397
String encoding = "us-ascii";
398
if (val != null && !val.isEmpty()) {
399
encoding = val;
400
}
401
402
if (flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
403
flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
404
flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
405
flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
406
flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
407
flavor.equals(DocFlavor.BYTE_ARRAY.PNG)) {
408
try {
409
instream = doc.getStreamForBytes();
410
if (instream == null) {
411
notifyEvent(PrintJobEvent.JOB_FAILED);
412
throw new PrintException("No stream for data");
413
}
414
if (!(service instanceof IPPPrintService &&
415
((IPPPrintService)service).isIPPSupportedImages(
416
flavor.getMimeType()))) {
417
printableJob(new ImagePrinter(instream));
418
if (service instanceof IPPPrintService) {
419
((IPPPrintService)service).wakeNotifier();
420
} else {
421
((UnixPrintService)service).wakeNotifier();
422
}
423
return;
424
}
425
} catch (ClassCastException cce) {
426
notifyEvent(PrintJobEvent.JOB_FAILED);
427
throw new PrintException(cce);
428
} catch (IOException ioe) {
429
notifyEvent(PrintJobEvent.JOB_FAILED);
430
throw new PrintException(ioe);
431
}
432
} else if (flavor.equals(DocFlavor.URL.GIF) ||
433
flavor.equals(DocFlavor.URL.JPEG) ||
434
flavor.equals(DocFlavor.URL.PNG)) {
435
try {
436
URL url = (URL)data;
437
if ((service instanceof IPPPrintService) &&
438
((IPPPrintService)service).isIPPSupportedImages(
439
flavor.getMimeType())) {
440
instream = url.openStream();
441
} else {
442
printableJob(new ImagePrinter(url));
443
if (service instanceof IPPPrintService) {
444
((IPPPrintService)service).wakeNotifier();
445
} else {
446
((UnixPrintService)service).wakeNotifier();
447
}
448
return;
449
}
450
} catch (ClassCastException cce) {
451
notifyEvent(PrintJobEvent.JOB_FAILED);
452
throw new PrintException(cce);
453
} catch (IOException e) {
454
notifyEvent(PrintJobEvent.JOB_FAILED);
455
throw new PrintException(e.toString());
456
}
457
} else if (flavor.equals(DocFlavor.CHAR_ARRAY.TEXT_PLAIN) ||
458
flavor.equals(DocFlavor.READER.TEXT_PLAIN) ||
459
flavor.equals(DocFlavor.STRING.TEXT_PLAIN)) {
460
try {
461
reader = doc.getReaderForText();
462
if (reader == null) {
463
notifyEvent(PrintJobEvent.JOB_FAILED);
464
throw new PrintException("No reader for data");
465
}
466
} catch (IOException ioe) {
467
notifyEvent(PrintJobEvent.JOB_FAILED);
468
throw new PrintException(ioe.toString());
469
}
470
} else if (repClassName.equals("[B") ||
471
repClassName.equals("java.io.InputStream")) {
472
try {
473
instream = doc.getStreamForBytes();
474
if (instream == null) {
475
notifyEvent(PrintJobEvent.JOB_FAILED);
476
throw new PrintException("No stream for data");
477
}
478
} catch (IOException ioe) {
479
notifyEvent(PrintJobEvent.JOB_FAILED);
480
throw new PrintException(ioe.toString());
481
}
482
} else if (repClassName.equals("java.net.URL")) {
483
/*
484
* This extracts the data from the URL and passes it the content
485
* directly to the print service as a file.
486
* This is appropriate for the current implementation where lp or
487
* lpr is always used to spool the data. We expect to revise the
488
* implementation to provide more complete IPP support (ie not just
489
* CUPS) and at that time the job will be spooled via IPP
490
* and the URL
491
* itself should be sent to the IPP print service not the content.
492
*/
493
URL url = (URL)data;
494
try {
495
instream = url.openStream();
496
} catch (IOException e) {
497
notifyEvent(PrintJobEvent.JOB_FAILED);
498
throw new PrintException(e.toString());
499
}
500
} else if (repClassName.equals("java.awt.print.Pageable")) {
501
try {
502
pageableJob((Pageable)doc.getPrintData());
503
if (service instanceof IPPPrintService) {
504
((IPPPrintService)service).wakeNotifier();
505
} else {
506
((UnixPrintService)service).wakeNotifier();
507
}
508
return;
509
} catch (ClassCastException cce) {
510
notifyEvent(PrintJobEvent.JOB_FAILED);
511
throw new PrintException(cce);
512
} catch (IOException ioe) {
513
notifyEvent(PrintJobEvent.JOB_FAILED);
514
throw new PrintException(ioe);
515
}
516
} else if (repClassName.equals("java.awt.print.Printable")) {
517
try {
518
printableJob((Printable)doc.getPrintData());
519
if (service instanceof IPPPrintService) {
520
((IPPPrintService)service).wakeNotifier();
521
} else {
522
((UnixPrintService)service).wakeNotifier();
523
}
524
return;
525
} catch (ClassCastException cce) {
526
notifyEvent(PrintJobEvent.JOB_FAILED);
527
throw new PrintException(cce);
528
} catch (IOException ioe) {
529
notifyEvent(PrintJobEvent.JOB_FAILED);
530
throw new PrintException(ioe);
531
}
532
} else {
533
notifyEvent(PrintJobEvent.JOB_FAILED);
534
throw new PrintException("unrecognized class: "+repClassName);
535
}
536
537
// now spool the print data.
538
PrinterOpener po = new PrinterOpener();
539
java.security.AccessController.doPrivileged(po);
540
if (po.pex != null) {
541
throw po.pex;
542
}
543
OutputStream output = po.result;
544
545
/* There are three cases:
546
* 1) Text data from a Reader, just pass through.
547
* 2) Text data from an input stream which we must read using the
548
* correct encoding
549
* 3) Raw byte data from an InputStream we don't interpret as text,
550
* just pass through: eg postscript.
551
*/
552
553
BufferedWriter bw = null;
554
if ((instream == null && reader != null)) {
555
BufferedReader br = new BufferedReader(reader);
556
OutputStreamWriter osw = new OutputStreamWriter(output);
557
bw = new BufferedWriter(osw);
558
char []buffer = new char[1024];
559
int cread;
560
561
try {
562
while ((cread = br.read(buffer, 0, buffer.length)) >=0) {
563
bw.write(buffer, 0, cread);
564
}
565
br.close();
566
bw.flush();
567
bw.close();
568
} catch (IOException e) {
569
notifyEvent(PrintJobEvent.JOB_FAILED);
570
throw new PrintException (e);
571
}
572
} else if (instream != null &&
573
flavor.getMediaType().equalsIgnoreCase("text")) {
574
try {
575
576
InputStreamReader isr = new InputStreamReader(instream,
577
encoding);
578
BufferedReader br = new BufferedReader(isr);
579
OutputStreamWriter osw = new OutputStreamWriter(output);
580
bw = new BufferedWriter(osw);
581
char []buffer = new char[1024];
582
int cread;
583
584
while ((cread = br.read(buffer, 0, buffer.length)) >=0) {
585
bw.write(buffer, 0, cread);
586
}
587
bw.flush();
588
} catch (IOException e) {
589
notifyEvent(PrintJobEvent.JOB_FAILED);
590
throw new PrintException (e);
591
} finally {
592
try {
593
if (bw != null) {
594
bw.close();
595
}
596
} catch (IOException e) {
597
}
598
}
599
} else if (instream != null) {
600
try (BufferedInputStream bin = new BufferedInputStream(instream);
601
BufferedOutputStream bout = new BufferedOutputStream(output)) {
602
bin.transferTo(bout);
603
} catch (IOException e) {
604
notifyEvent(PrintJobEvent.JOB_FAILED);
605
throw new PrintException(e);
606
}
607
}
608
notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
609
610
if (mDestType == UnixPrintJob.DESTPRINTER) {
611
PrinterSpooler spooler = new PrinterSpooler();
612
java.security.AccessController.doPrivileged(spooler);
613
if (spooler.pex != null) {
614
throw spooler.pex;
615
}
616
}
617
notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
618
if (service instanceof IPPPrintService) {
619
((IPPPrintService)service).wakeNotifier();
620
} else {
621
((UnixPrintService)service).wakeNotifier();
622
}
623
}
624
625
public void printableJob(Printable printable) throws PrintException {
626
try {
627
synchronized(this) {
628
if (job != null) { // shouldn't happen
629
throw new PrintException("already printing");
630
} else {
631
job = new PSPrinterJob();
632
}
633
}
634
job.setPrintService(getPrintService());
635
job.setCopies(copies);
636
job.setJobName(jobName);
637
PageFormat pf = new PageFormat();
638
if (mediaSize != null) {
639
Paper p = new Paper();
640
p.setSize(mediaSize.getX(MediaSize.INCH)*72.0,
641
mediaSize.getY(MediaSize.INCH)*72.0);
642
p.setImageableArea(72.0, 72.0, p.getWidth()-144.0,
643
p.getHeight()-144.0);
644
pf.setPaper(p);
645
}
646
if (orient == OrientationRequested.REVERSE_LANDSCAPE) {
647
pf.setOrientation(PageFormat.REVERSE_LANDSCAPE);
648
} else if (orient == OrientationRequested.LANDSCAPE) {
649
pf.setOrientation(PageFormat.LANDSCAPE);
650
}
651
job.setPrintable(printable, pf);
652
job.print(reqAttrSet);
653
notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
654
return;
655
} catch (PrinterException pe) {
656
notifyEvent(PrintJobEvent.JOB_FAILED);
657
throw new PrintException(pe);
658
} finally {
659
printReturned = true;
660
notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
661
}
662
}
663
664
public void pageableJob(Pageable pageable) throws PrintException {
665
try {
666
synchronized(this) {
667
if (job != null) { // shouldn't happen
668
throw new PrintException("already printing");
669
} else {
670
job = new PSPrinterJob();
671
}
672
}
673
job.setPrintService(getPrintService());
674
job.setCopies(copies);
675
job.setJobName(jobName);
676
job.setPageable(pageable);
677
job.print(reqAttrSet);
678
notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
679
return;
680
} catch (PrinterException pe) {
681
notifyEvent(PrintJobEvent.JOB_FAILED);
682
throw new PrintException(pe);
683
} finally {
684
printReturned = true;
685
notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
686
}
687
}
688
/* There's some inefficiency here as the job set is created even though
689
* it may never be requested.
690
*/
691
private synchronized void
692
initializeAttributeSets(Doc doc, PrintRequestAttributeSet reqSet) {
693
694
reqAttrSet = new HashPrintRequestAttributeSet();
695
jobAttrSet = new HashPrintJobAttributeSet();
696
697
Attribute[] attrs;
698
if (reqSet != null) {
699
reqAttrSet.addAll(reqSet);
700
attrs = reqSet.toArray();
701
for (int i=0; i<attrs.length; i++) {
702
if (attrs[i] instanceof PrintJobAttribute) {
703
jobAttrSet.add(attrs[i]);
704
}
705
}
706
}
707
708
DocAttributeSet docSet = doc.getAttributes();
709
if (docSet != null) {
710
attrs = docSet.toArray();
711
for (int i=0; i<attrs.length; i++) {
712
if (attrs[i] instanceof PrintRequestAttribute) {
713
reqAttrSet.add(attrs[i]);
714
}
715
if (attrs[i] instanceof PrintJobAttribute) {
716
jobAttrSet.add(attrs[i]);
717
}
718
}
719
}
720
721
/* add the user name to the job */
722
String userName = "";
723
try {
724
userName = System.getProperty("user.name");
725
} catch (SecurityException se) {
726
}
727
728
if (userName == null || userName.isEmpty()) {
729
RequestingUserName ruName =
730
(RequestingUserName)reqSet.get(RequestingUserName.class);
731
if (ruName != null) {
732
jobAttrSet.add(
733
new JobOriginatingUserName(ruName.getValue(),
734
ruName.getLocale()));
735
} else {
736
jobAttrSet.add(new JobOriginatingUserName("", null));
737
}
738
} else {
739
jobAttrSet.add(new JobOriginatingUserName(userName, null));
740
}
741
742
/* if no job name supplied use doc name (if supplied), if none and
743
* its a URL use that, else finally anything .. */
744
if (jobAttrSet.get(JobName.class) == null) {
745
JobName jobName;
746
if (docSet != null && docSet.get(DocumentName.class) != null) {
747
DocumentName docName =
748
(DocumentName)docSet.get(DocumentName.class);
749
jobName = new JobName(docName.getValue(), docName.getLocale());
750
jobAttrSet.add(jobName);
751
} else {
752
String str = "JPS Job:" + doc;
753
try {
754
Object printData = doc.getPrintData();
755
if (printData instanceof URL) {
756
str = ((URL)(doc.getPrintData())).toString();
757
}
758
} catch (IOException e) {
759
}
760
jobName = new JobName(str, null);
761
jobAttrSet.add(jobName);
762
}
763
}
764
765
jobAttrSet = AttributeSetUtilities.unmodifiableView(jobAttrSet);
766
}
767
768
private void getAttributeValues(DocFlavor flavor) throws PrintException {
769
Attribute attr;
770
Class<? extends Attribute> category;
771
772
if (reqAttrSet.get(Fidelity.class) == Fidelity.FIDELITY_TRUE) {
773
fidelity = true;
774
} else {
775
fidelity = false;
776
}
777
778
Attribute []attrs = reqAttrSet.toArray();
779
for (int i=0; i<attrs.length; i++) {
780
attr = attrs[i];
781
category = attr.getCategory();
782
if (fidelity == true) {
783
if (!service.isAttributeCategorySupported(category)) {
784
notifyEvent(PrintJobEvent.JOB_FAILED);
785
throw new PrintJobAttributeException(
786
"unsupported category: " + category, category, null);
787
} else if
788
(!service.isAttributeValueSupported(attr, flavor, null)) {
789
notifyEvent(PrintJobEvent.JOB_FAILED);
790
throw new PrintJobAttributeException(
791
"unsupported attribute: " + attr, null, attr);
792
}
793
}
794
if (category == Destination.class) {
795
URI uri = ((Destination)attr).getURI();
796
if (!"file".equals(uri.getScheme())) {
797
notifyEvent(PrintJobEvent.JOB_FAILED);
798
throw new PrintException("Not a file: URI");
799
} else {
800
try {
801
mDestType = DESTFILE;
802
mDestination = (new File(uri)).getPath();
803
} catch (Exception e) {
804
throw new PrintException(e);
805
}
806
// check write access
807
@SuppressWarnings("removal")
808
SecurityManager security = System.getSecurityManager();
809
if (security != null) {
810
try {
811
security.checkWrite(mDestination);
812
} catch (SecurityException se) {
813
notifyEvent(PrintJobEvent.JOB_FAILED);
814
throw new PrintException(se);
815
}
816
}
817
}
818
} else if (category == JobSheets.class) {
819
if ((JobSheets)attr == JobSheets.NONE) {
820
mNoJobSheet = true;
821
}
822
} else if (category == JobName.class) {
823
jobName = ((JobName)attr).getValue();
824
} else if (category == Copies.class) {
825
copies = ((Copies)attr).getValue();
826
} else if (category == Media.class) {
827
if (attr instanceof MediaSizeName) {
828
mediaName = (MediaSizeName)attr;
829
IPPPrintService.debug_println(debugPrefix+
830
"mediaName "+mediaName);
831
if (!service.isAttributeValueSupported(attr, null, null)) {
832
mediaSize = MediaSize.getMediaSizeForName(mediaName);
833
}
834
} else if (attr instanceof CustomMediaTray) {
835
customTray = (CustomMediaTray)attr;
836
}
837
} else if (category == OrientationRequested.class) {
838
orient = (OrientationRequested)attr;
839
} else if (category == NumberUp.class) {
840
nUp = (NumberUp)attr;
841
} else if (category == Sides.class) {
842
sides = (Sides)attr;
843
}
844
}
845
}
846
847
private String[] printExecCmd(String printer, String options,
848
boolean noJobSheet,
849
String jobTitle, int copies, String spoolFile) {
850
int PRINTER = 0x1;
851
int OPTIONS = 0x2;
852
int JOBTITLE = 0x4;
853
int COPIES = 0x8;
854
int NOSHEET = 0x10;
855
int pFlags = 0;
856
String[] execCmd;
857
int ncomps = 2; // minimum number of print args
858
int n = 0;
859
860
// conveniently "lp" is the default destination for both lp and lpr.
861
if (printer != null && !printer.isEmpty() && !printer.equals("lp")) {
862
pFlags |= PRINTER;
863
ncomps+=1;
864
}
865
if (options != null && !options.isEmpty()) {
866
pFlags |= OPTIONS;
867
ncomps+=1;
868
}
869
if (jobTitle != null && !jobTitle.isEmpty()) {
870
pFlags |= JOBTITLE;
871
ncomps+=1;
872
}
873
if (copies > 1) {
874
pFlags |= COPIES;
875
ncomps+=1;
876
}
877
if (noJobSheet) {
878
pFlags |= NOSHEET;
879
ncomps+=1;
880
} else if (getPrintService().
881
isAttributeCategorySupported(JobSheets.class)) {
882
ncomps+=1;
883
}
884
execCmd = new String[ncomps];
885
execCmd[n++] = "/usr/bin/lpr";
886
if ((pFlags & PRINTER) != 0) {
887
execCmd[n++] = "-P" + printer;
888
}
889
if ((pFlags & JOBTITLE) != 0) {
890
execCmd[n++] = "-J " + jobTitle;
891
}
892
if ((pFlags & COPIES) != 0) {
893
execCmd[n++] = "-#" + copies;
894
}
895
if ((pFlags & NOSHEET) != 0) {
896
execCmd[n++] = "-h";
897
} else if (getPrintService().
898
isAttributeCategorySupported(JobSheets.class)) {
899
execCmd[n++] = "-o job-sheets=standard";
900
}
901
if ((pFlags & OPTIONS) != 0) {
902
execCmd[n++] = "-o" + options;
903
}
904
execCmd[n++] = spoolFile;
905
if (IPPPrintService.debugPrint) {
906
System.out.println("UnixPrintJob>> execCmd");
907
for (int i=0; i<execCmd.length; i++) {
908
System.out.print(" "+execCmd[i]);
909
}
910
System.out.println();
911
}
912
return execCmd;
913
}
914
915
private static int DESTPRINTER = 1;
916
private static int DESTFILE = 2;
917
private int mDestType = DESTPRINTER;
918
919
private File spoolFile;
920
private String mDestination, mOptions="";
921
private boolean mNoJobSheet = false;
922
923
// Inner class to run "privileged" to open the printer output stream.
924
925
private class PrinterOpener implements java.security.PrivilegedAction<OutputStream> {
926
PrintException pex;
927
OutputStream result;
928
929
public OutputStream run() {
930
try {
931
if (mDestType == UnixPrintJob.DESTFILE) {
932
spoolFile = new File(mDestination);
933
} else {
934
/* Write to a temporary file which will be spooled to
935
* the printer then deleted. In the case that the file
936
* is not removed for some reason, request that it is
937
* removed when the VM exits.
938
*/
939
spoolFile = Files.createTempFile("javaprint", "").toFile();
940
spoolFile.deleteOnExit();
941
}
942
result = new FileOutputStream(spoolFile);
943
return result;
944
} catch (IOException ex) {
945
// If there is an IOError we subvert it to a PrinterException.
946
notifyEvent(PrintJobEvent.JOB_FAILED);
947
pex = new PrintException(ex);
948
}
949
return null;
950
}
951
}
952
953
// Inner class to run "privileged" to invoke the system print command
954
955
private class PrinterSpooler implements java.security.PrivilegedAction<Object> {
956
PrintException pex;
957
958
private void handleProcessFailure(final Process failedProcess,
959
final String[] execCmd, final int result) throws IOException {
960
try (StringWriter sw = new StringWriter();
961
PrintWriter pw = new PrintWriter(sw)) {
962
pw.append("error=").append(Integer.toString(result));
963
pw.append(" running:");
964
for (String arg: execCmd) {
965
pw.append(" '").append(arg).append("'");
966
}
967
try (InputStream is = failedProcess.getErrorStream();
968
InputStreamReader isr = new InputStreamReader(is);
969
BufferedReader br = new BufferedReader(isr)) {
970
while (br.ready()) {
971
pw.println();
972
pw.append("\t\t").append(br.readLine());
973
}
974
} finally {
975
pw.flush();
976
}
977
throw new IOException(sw.toString());
978
}
979
}
980
981
public Object run() {
982
if (spoolFile == null || !spoolFile.exists()) {
983
pex = new PrintException("No spool file");
984
notifyEvent(PrintJobEvent.JOB_FAILED);
985
return null;
986
}
987
try {
988
/**
989
* Spool to the printer.
990
*/
991
String fileName = spoolFile.getAbsolutePath();
992
String[] execCmd = printExecCmd(mDestination, mOptions,
993
mNoJobSheet, jobName, copies, fileName);
994
995
Process process = Runtime.getRuntime().exec(execCmd);
996
process.waitFor();
997
final int result = process.exitValue();
998
if (0 != result) {
999
handleProcessFailure(process, execCmd, result);
1000
}
1001
notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE);
1002
} catch (IOException ex) {
1003
notifyEvent(PrintJobEvent.JOB_FAILED);
1004
// REMIND : 2d printing throws PrinterException
1005
pex = new PrintException(ex);
1006
} catch (InterruptedException ie) {
1007
notifyEvent(PrintJobEvent.JOB_FAILED);
1008
pex = new PrintException(ie);
1009
} finally {
1010
spoolFile.delete();
1011
notifyEvent(PrintJobEvent.NO_MORE_EVENTS);
1012
}
1013
return null;
1014
}
1015
}
1016
1017
public void cancel() throws PrintException {
1018
synchronized (this) {
1019
if (!printing) {
1020
throw new PrintException("Job is not yet submitted.");
1021
} else if (job != null && !printReturned) {
1022
job.cancel();
1023
notifyEvent(PrintJobEvent.JOB_CANCELED);
1024
return;
1025
} else {
1026
throw new PrintException("Job could not be cancelled.");
1027
}
1028
}
1029
}
1030
}
1031
1032