Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/print/IPPPrintService.java
32287 views
1
/*
2
* Copyright (c) 2003, 2013, 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 javax.print.attribute.*;
29
import javax.print.attribute.standard.*;
30
import javax.print.DocFlavor;
31
import javax.print.DocPrintJob;
32
import javax.print.PrintService;
33
import javax.print.ServiceUIFactory;
34
import java.util.ArrayList;
35
import java.util.HashMap;
36
import java.util.Locale;
37
import java.util.Date;
38
import java.util.Arrays;
39
import java.security.AccessController;
40
import java.security.PrivilegedActionException;
41
import java.security.PrivilegedExceptionAction;
42
import javax.print.event.PrintServiceAttributeListener;
43
44
import java.net.URI;
45
import java.net.URISyntaxException;
46
import java.net.URL;
47
import java.net.URLConnection;
48
import java.net.HttpURLConnection;
49
import java.io.File;
50
import java.io.InputStream;
51
import java.io.OutputStream;
52
import java.io.OutputStreamWriter;
53
import java.io.DataInputStream;
54
import java.io.ByteArrayOutputStream;
55
import java.io.ByteArrayInputStream;
56
import java.io.BufferedReader;
57
import java.io.InputStreamReader;
58
import java.nio.charset.Charset;
59
60
import java.util.Iterator;
61
import java.util.HashSet;
62
import java.util.Map;
63
import java.util.Set;
64
65
public class IPPPrintService implements PrintService, SunPrinterJobService {
66
67
public static final boolean debugPrint;
68
private static final String debugPrefix = "IPPPrintService>> ";
69
protected static void debug_println(String str) {
70
if (debugPrint) {
71
System.out.println(str);
72
}
73
}
74
75
private static final String FORCE_PIPE_PROP = "sun.print.ippdebug";
76
77
static {
78
String debugStr =
79
(String)java.security.AccessController.doPrivileged(
80
new sun.security.action.GetPropertyAction(FORCE_PIPE_PROP));
81
82
debugPrint = "true".equalsIgnoreCase(debugStr);
83
}
84
85
private String printer;
86
private URI myURI;
87
private URL myURL;
88
transient private ServiceNotifier notifier = null;
89
90
private static int MAXCOPIES = 1000;
91
private static short MAX_ATTRIBUTE_LENGTH = 255;
92
93
private CUPSPrinter cps;
94
private HttpURLConnection urlConnection = null;
95
private DocFlavor[] supportedDocFlavors;
96
private Class[] supportedCats;
97
private MediaTray[] mediaTrays;
98
private MediaSizeName[] mediaSizeNames;
99
private CustomMediaSizeName[] customMediaSizeNames;
100
private int defaultMediaIndex;
101
private boolean isCupsPrinter;
102
private boolean init;
103
private Boolean isPS;
104
private HashMap getAttMap;
105
private boolean pngImagesAdded = false;
106
private boolean gifImagesAdded = false;
107
private boolean jpgImagesAdded = false;
108
109
110
/**
111
* IPP Status Codes
112
*/
113
private static final byte STATUSCODE_SUCCESS = 0x00;
114
115
/**
116
* IPP Group Tags. Each tag is used once before the first attribute
117
* of that group.
118
*/
119
// operation attributes group
120
private static final byte GRPTAG_OP_ATTRIBUTES = 0x01;
121
// job attributes group
122
private static final byte GRPTAG_JOB_ATTRIBUTES = 0x02;
123
// printer attributes group
124
private static final byte GRPTAG_PRINTER_ATTRIBUTES = 0x04;
125
// used as the last tag in an IPP message.
126
private static final byte GRPTAG_END_ATTRIBUTES = 0x03;
127
128
/**
129
* IPP Operation codes
130
*/
131
// gets the attributes for a printer
132
public static final String OP_GET_ATTRIBUTES = "000B";
133
// gets the default printer
134
public static final String OP_CUPS_GET_DEFAULT = "4001";
135
// gets the list of printers
136
public static final String OP_CUPS_GET_PRINTERS = "4002";
137
138
139
/**
140
* List of all PrintRequestAttributes. This is used
141
* for looping through all the IPP attribute name.
142
*/
143
private static Object[] printReqAttribDefault = {
144
Chromaticity.COLOR,
145
new Copies(1),
146
Fidelity.FIDELITY_FALSE,
147
Finishings.NONE,
148
//new JobHoldUntil(new Date()),
149
//new JobImpressions(0),
150
//JobImpressions,
151
//JobKOctets,
152
//JobMediaSheets,
153
new JobName("", Locale.getDefault()),
154
//JobPriority,
155
JobSheets.NONE,
156
(Media)MediaSizeName.NA_LETTER,
157
//MediaPrintableArea.class, // not an IPP attribute
158
//MultipleDocumentHandling.SINGLE_DOCUMENT,
159
new NumberUp(1),
160
OrientationRequested.PORTRAIT,
161
new PageRanges(1),
162
//PresentationDirection,
163
// CUPS does not supply printer-resolution attribute
164
//new PrinterResolution(300, 300, PrinterResolution.DPI),
165
//PrintQuality.NORMAL,
166
new RequestingUserName("", Locale.getDefault()),
167
//SheetCollate.UNCOLLATED, //CUPS has no sheet collate?
168
Sides.ONE_SIDED,
169
};
170
171
172
/**
173
* List of all PrintServiceAttributes. This is used
174
* for looping through all the IPP attribute name.
175
*/
176
private static Object[][] serviceAttributes = {
177
{ColorSupported.class, "color-supported"},
178
{PagesPerMinute.class, "pages-per-minute"},
179
{PagesPerMinuteColor.class, "pages-per-minute-color"},
180
{PDLOverrideSupported.class, "pdl-override-supported"},
181
{PrinterInfo.class, "printer-info"},
182
{PrinterIsAcceptingJobs.class, "printer-is-accepting-jobs"},
183
{PrinterLocation.class, "printer-location"},
184
{PrinterMakeAndModel.class, "printer-make-and-model"},
185
{PrinterMessageFromOperator.class, "printer-message-from-operator"},
186
{PrinterMoreInfo.class, "printer-more-info"},
187
{PrinterMoreInfoManufacturer.class, "printer-more-info-manufacturer"},
188
{PrinterName.class, "printer-name"},
189
{PrinterState.class, "printer-state"},
190
{PrinterStateReasons.class, "printer-state-reasons"},
191
{PrinterURI.class, "printer-uri"},
192
{QueuedJobCount.class, "queued-job-count"}
193
};
194
195
196
/**
197
* List of DocFlavors, grouped based on matching mime-type.
198
* NOTE: For any change in the predefined DocFlavors, it must be reflected
199
* here also.
200
*/
201
// PDF DocFlavors
202
private static DocFlavor[] appPDF = {
203
DocFlavor.BYTE_ARRAY.PDF,
204
DocFlavor.INPUT_STREAM.PDF,
205
DocFlavor.URL.PDF
206
};
207
208
// Postscript DocFlavors
209
private static DocFlavor[] appPostScript = {
210
DocFlavor.BYTE_ARRAY.POSTSCRIPT,
211
DocFlavor.INPUT_STREAM.POSTSCRIPT,
212
DocFlavor.URL.POSTSCRIPT
213
};
214
215
// Autosense DocFlavors
216
private static DocFlavor[] appOctetStream = {
217
DocFlavor.BYTE_ARRAY.AUTOSENSE,
218
DocFlavor.INPUT_STREAM.AUTOSENSE,
219
DocFlavor.URL.AUTOSENSE
220
};
221
222
// Text DocFlavors
223
private static DocFlavor[] textPlain = {
224
DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_8,
225
DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16,
226
DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16BE,
227
DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16LE,
228
DocFlavor.BYTE_ARRAY.TEXT_PLAIN_US_ASCII,
229
DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_8,
230
DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16,
231
DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16BE,
232
DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16LE,
233
DocFlavor.INPUT_STREAM.TEXT_PLAIN_US_ASCII,
234
DocFlavor.URL.TEXT_PLAIN_UTF_8,
235
DocFlavor.URL.TEXT_PLAIN_UTF_16,
236
DocFlavor.URL.TEXT_PLAIN_UTF_16BE,
237
DocFlavor.URL.TEXT_PLAIN_UTF_16LE,
238
DocFlavor.URL.TEXT_PLAIN_US_ASCII,
239
DocFlavor.CHAR_ARRAY.TEXT_PLAIN,
240
DocFlavor.STRING.TEXT_PLAIN,
241
DocFlavor.READER.TEXT_PLAIN
242
};
243
244
private static DocFlavor[] textPlainHost = {
245
DocFlavor.BYTE_ARRAY.TEXT_PLAIN_HOST,
246
DocFlavor.INPUT_STREAM.TEXT_PLAIN_HOST,
247
DocFlavor.URL.TEXT_PLAIN_HOST
248
};
249
250
// JPG DocFlavors
251
private static DocFlavor[] imageJPG = {
252
DocFlavor.BYTE_ARRAY.JPEG,
253
DocFlavor.INPUT_STREAM.JPEG,
254
DocFlavor.URL.JPEG
255
};
256
257
// GIF DocFlavors
258
private static DocFlavor[] imageGIF = {
259
DocFlavor.BYTE_ARRAY.GIF,
260
DocFlavor.INPUT_STREAM.GIF,
261
DocFlavor.URL.GIF
262
};
263
264
// PNG DocFlavors
265
private static DocFlavor[] imagePNG = {
266
DocFlavor.BYTE_ARRAY.PNG,
267
DocFlavor.INPUT_STREAM.PNG,
268
DocFlavor.URL.PNG
269
};
270
271
// HTML DocFlavors
272
private static DocFlavor[] textHtml = {
273
DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_8,
274
DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_16,
275
DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_16BE,
276
DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_16LE,
277
DocFlavor.BYTE_ARRAY.TEXT_HTML_US_ASCII,
278
DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_8,
279
DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_16,
280
DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_16BE,
281
DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_16LE,
282
DocFlavor.INPUT_STREAM.TEXT_HTML_US_ASCII,
283
DocFlavor.URL.TEXT_HTML_UTF_8,
284
DocFlavor.URL.TEXT_HTML_UTF_16,
285
DocFlavor.URL.TEXT_HTML_UTF_16BE,
286
DocFlavor.URL.TEXT_HTML_UTF_16LE,
287
DocFlavor.URL.TEXT_HTML_US_ASCII,
288
// These are not handled in UnixPrintJob so commenting these
289
// for now.
290
/*
291
DocFlavor.CHAR_ARRAY.TEXT_HTML,
292
DocFlavor.STRING.TEXT_HTML,
293
DocFlavor.READER.TEXT_HTML,
294
*/
295
};
296
297
private static DocFlavor[] textHtmlHost = {
298
DocFlavor.BYTE_ARRAY.TEXT_HTML_HOST,
299
DocFlavor.INPUT_STREAM.TEXT_HTML_HOST,
300
DocFlavor.URL.TEXT_HTML_HOST,
301
};
302
303
304
// PCL DocFlavors
305
private static DocFlavor[] appPCL = {
306
DocFlavor.BYTE_ARRAY.PCL,
307
DocFlavor.INPUT_STREAM.PCL,
308
DocFlavor.URL.PCL
309
};
310
311
// List of all DocFlavors, used in looping
312
// through all supported mime-types
313
private static Object[] allDocFlavors = {
314
appPDF, appPostScript, appOctetStream,
315
textPlain, imageJPG, imageGIF, imagePNG,
316
textHtml, appPCL,
317
};
318
319
320
IPPPrintService(String name, URL url) {
321
if ((name == null) || (url == null)){
322
throw new IllegalArgumentException("null uri or printer name");
323
}
324
printer = name;
325
supportedDocFlavors = null;
326
supportedCats = null;
327
mediaSizeNames = null;
328
customMediaSizeNames = null;
329
mediaTrays = null;
330
myURL = url;
331
cps = null;
332
isCupsPrinter = false;
333
init = false;
334
defaultMediaIndex = -1;
335
336
String host = myURL.getHost();
337
if (host!=null && host.equals(CUPSPrinter.getServer())) {
338
isCupsPrinter = true;
339
try {
340
myURI = new URI("ipp://"+host+
341
"/printers/"+printer);
342
debug_println(debugPrefix+"IPPPrintService myURI : "+myURI);
343
} catch (java.net.URISyntaxException e) {
344
throw new IllegalArgumentException("invalid url");
345
}
346
}
347
}
348
349
350
IPPPrintService(String name, String uriStr, boolean isCups) {
351
if ((name == null) || (uriStr == null)){
352
throw new IllegalArgumentException("null uri or printer name");
353
}
354
printer = name;
355
supportedDocFlavors = null;
356
supportedCats = null;
357
mediaSizeNames = null;
358
customMediaSizeNames = null;
359
mediaTrays = null;
360
cps = null;
361
init = false;
362
defaultMediaIndex = -1;
363
try {
364
myURL =
365
new URL(uriStr.replaceFirst("ipp", "http"));
366
} catch (Exception e) {
367
IPPPrintService.debug_println(debugPrefix+
368
" IPPPrintService, myURL="+
369
myURL+" Exception= "+
370
e);
371
throw new IllegalArgumentException("invalid url");
372
}
373
374
isCupsPrinter = isCups;
375
try {
376
myURI = new URI(uriStr);
377
debug_println(debugPrefix+"IPPPrintService myURI : "+myURI);
378
} catch (java.net.URISyntaxException e) {
379
throw new IllegalArgumentException("invalid uri");
380
}
381
}
382
383
384
/*
385
* Initialize mediaSizeNames, mediaTrays and other attributes.
386
* Media size/trays are initialized to non-null values, may be 0-length
387
* array.
388
* NOTE: Must be called from a synchronized block only.
389
*/
390
private void initAttributes() {
391
if (!init) {
392
// init customMediaSizeNames
393
customMediaSizeNames = new CustomMediaSizeName[0];
394
395
if ((urlConnection = getIPPConnection(myURL)) == null) {
396
mediaSizeNames = new MediaSizeName[0];
397
mediaTrays = new MediaTray[0];
398
debug_println(debugPrefix+"initAttributes, NULL urlConnection ");
399
init = true;
400
return;
401
}
402
403
// get all supported attributes through IPP
404
opGetAttributes();
405
406
if (isCupsPrinter) {
407
// note, it is possible to query media in CUPS using IPP
408
// right now we always get it from PPD.
409
// maybe use "&& (usePPD)" later?
410
// Another reason why we use PPD is because
411
// IPP currently does not support it but PPD does.
412
413
try {
414
cps = new CUPSPrinter(printer);
415
mediaSizeNames = cps.getMediaSizeNames();
416
mediaTrays = cps.getMediaTrays();
417
customMediaSizeNames = cps.getCustomMediaSizeNames();
418
defaultMediaIndex = cps.getDefaultMediaIndex();
419
urlConnection.disconnect();
420
init = true;
421
return;
422
} catch (Exception e) {
423
IPPPrintService.debug_println(debugPrefix+
424
"initAttributes, error creating CUPSPrinter e="+e);
425
}
426
}
427
428
// use IPP to get all media,
429
Media[] allMedia = (Media[])getSupportedMedia();
430
ArrayList sizeList = new ArrayList();
431
ArrayList trayList = new ArrayList();
432
for (int i=0; i<allMedia.length; i++) {
433
if (allMedia[i] instanceof MediaSizeName) {
434
sizeList.add(allMedia[i]);
435
} else if (allMedia[i] instanceof MediaTray) {
436
trayList.add(allMedia[i]);
437
}
438
}
439
440
if (sizeList != null) {
441
mediaSizeNames = new MediaSizeName[sizeList.size()];
442
mediaSizeNames = (MediaSizeName[])sizeList.toArray(
443
mediaSizeNames);
444
}
445
if (trayList != null) {
446
mediaTrays = new MediaTray[trayList.size()];
447
mediaTrays = (MediaTray[])trayList.toArray(
448
mediaTrays);
449
}
450
urlConnection.disconnect();
451
452
init = true;
453
}
454
}
455
456
457
public DocPrintJob createPrintJob() {
458
SecurityManager security = System.getSecurityManager();
459
if (security != null) {
460
security.checkPrintJobAccess();
461
}
462
// REMIND: create IPPPrintJob
463
return new UnixPrintJob(this);
464
}
465
466
467
public synchronized Object
468
getSupportedAttributeValues(Class<? extends Attribute> category,
469
DocFlavor flavor,
470
AttributeSet attributes)
471
{
472
if (category == null) {
473
throw new NullPointerException("null category");
474
}
475
if (!Attribute.class.isAssignableFrom(category)) {
476
throw new IllegalArgumentException(category +
477
" does not implement Attribute");
478
}
479
if (flavor != null) {
480
if (!isDocFlavorSupported(flavor)) {
481
throw new IllegalArgumentException(flavor +
482
" is an unsupported flavor");
483
} else if (isAutoSense(flavor)) {
484
return null;
485
}
486
487
}
488
489
if (!isAttributeCategorySupported(category)) {
490
return null;
491
}
492
493
/* Test if the flavor is compatible with the attributes */
494
if (!isDestinationSupported(flavor, attributes)) {
495
return null;
496
}
497
498
initAttributes();
499
500
/* Test if the flavor is compatible with the category */
501
if ((category == Copies.class) ||
502
(category == CopiesSupported.class)) {
503
if (flavor == null ||
504
!(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) ||
505
flavor.equals(DocFlavor.URL.POSTSCRIPT) ||
506
flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) {
507
CopiesSupported cs = new CopiesSupported(1, MAXCOPIES);
508
AttributeClass attribClass = (getAttMap != null) ?
509
(AttributeClass)getAttMap.get(cs.getName()) : null;
510
if (attribClass != null) {
511
int[] range = attribClass.getIntRangeValue();
512
cs = new CopiesSupported(range[0], range[1]);
513
}
514
return cs;
515
} else {
516
return null;
517
}
518
} else if (category == Chromaticity.class) {
519
if (flavor == null ||
520
flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
521
flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
522
!isIPPSupportedImages(flavor.getMimeType())) {
523
Chromaticity[]arr = new Chromaticity[1];
524
arr[0] = Chromaticity.COLOR;
525
return (arr);
526
} else {
527
return null;
528
}
529
} else if (category == Destination.class) {
530
if (flavor == null ||
531
flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
532
flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
533
try {
534
return new Destination((new File("out.ps")).toURI());
535
} catch (SecurityException se) {
536
try {
537
return new Destination(new URI("file:out.ps"));
538
} catch (URISyntaxException e) {
539
return null;
540
}
541
}
542
}
543
return null;
544
} else if (category == Fidelity.class) {
545
Fidelity []arr = new Fidelity[2];
546
arr[0] = Fidelity.FIDELITY_FALSE;
547
arr[1] = Fidelity.FIDELITY_TRUE;
548
return arr;
549
} else if (category == Finishings.class) {
550
AttributeClass attribClass = (getAttMap != null) ?
551
(AttributeClass)getAttMap.get("finishings-supported")
552
: null;
553
if (attribClass != null) {
554
int[] finArray = attribClass.getArrayOfIntValues();
555
if ((finArray != null) && (finArray.length > 0)) {
556
Finishings[] finSup = new Finishings[finArray.length];
557
for (int i=0; i<finArray.length; i++) {
558
finSup[i] = Finishings.NONE;
559
Finishings[] fAll = (Finishings[])
560
(new ExtFinishing(100)).getAll();
561
for (int j=0; j<fAll.length; j++) {
562
if (finArray[i] == fAll[j].getValue()) {
563
finSup[i] = fAll[j];
564
break;
565
}
566
}
567
}
568
return finSup;
569
}
570
}
571
} else if (category == JobName.class) {
572
return new JobName("Java Printing", null);
573
} else if (category == JobSheets.class) {
574
JobSheets arr[] = new JobSheets[2];
575
arr[0] = JobSheets.NONE;
576
arr[1] = JobSheets.STANDARD;
577
return arr;
578
579
} else if (category == Media.class) {
580
Media[] allMedia = new Media[mediaSizeNames.length+
581
mediaTrays.length];
582
583
for (int i=0; i<mediaSizeNames.length; i++) {
584
allMedia[i] = mediaSizeNames[i];
585
}
586
587
for (int i=0; i<mediaTrays.length; i++) {
588
allMedia[i+mediaSizeNames.length] = mediaTrays[i];
589
}
590
591
if (allMedia.length == 0) {
592
allMedia = new Media[1];
593
allMedia[0] = (Media)getDefaultAttributeValue(Media.class);
594
}
595
596
return allMedia;
597
} else if (category == MediaPrintableArea.class) {
598
MediaPrintableArea[] mpas = null;
599
if (cps != null) {
600
mpas = cps.getMediaPrintableArea();
601
}
602
603
if (mpas == null) {
604
mpas = new MediaPrintableArea[1];
605
mpas[0] = (MediaPrintableArea)
606
getDefaultAttributeValue(MediaPrintableArea.class);
607
}
608
609
if ((attributes == null) || (attributes.size() == 0)) {
610
ArrayList<MediaPrintableArea> printableList =
611
new ArrayList<MediaPrintableArea>();
612
613
for (int i=0; i<mpas.length; i++) {
614
if (mpas[i] != null) {
615
printableList.add(mpas[i]);
616
}
617
}
618
if (printableList.size() > 0) {
619
mpas = new MediaPrintableArea[printableList.size()];
620
printableList.toArray(mpas);
621
}
622
return mpas;
623
}
624
625
int match = -1;
626
Media media = (Media)attributes.get(Media.class);
627
if (media != null && media instanceof MediaSizeName) {
628
MediaSizeName msn = (MediaSizeName)media;
629
630
// case when no supported mediasizenames are reported
631
// check given media against the default
632
if (mediaSizeNames.length == 0 &&
633
msn.equals(getDefaultAttributeValue(Media.class))) {
634
//default printable area is that of default mediasize
635
return mpas;
636
}
637
638
for (int i=0; i<mediaSizeNames.length; i++) {
639
if (msn.equals(mediaSizeNames[i])) {
640
match = i;
641
}
642
}
643
}
644
645
if (match == -1) {
646
return null;
647
} else {
648
MediaPrintableArea []arr = new MediaPrintableArea[1];
649
arr[0] = mpas[match];
650
return arr;
651
}
652
} else if (category == NumberUp.class) {
653
AttributeClass attribClass = (getAttMap != null) ?
654
(AttributeClass)getAttMap.get("number-up-supported") : null;
655
if (attribClass != null) {
656
int[] values = attribClass.getArrayOfIntValues();
657
if (values != null) {
658
NumberUp[] nUp = new NumberUp[values.length];
659
for (int i=0; i<values.length; i++) {
660
nUp[i] = new NumberUp(values[i]);
661
}
662
return nUp;
663
} else {
664
return null;
665
}
666
}
667
} else if (category == OrientationRequested.class) {
668
if ((flavor != null) &&
669
(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) ||
670
flavor.equals(DocFlavor.URL.POSTSCRIPT) ||
671
flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) {
672
return null;
673
}
674
675
boolean revPort = false;
676
OrientationRequested[] orientSup = null;
677
678
AttributeClass attribClass = (getAttMap != null) ?
679
(AttributeClass)getAttMap.get("orientation-requested-supported")
680
: null;
681
if (attribClass != null) {
682
int[] orientArray = attribClass.getArrayOfIntValues();
683
if ((orientArray != null) && (orientArray.length > 0)) {
684
orientSup =
685
new OrientationRequested[orientArray.length];
686
for (int i=0; i<orientArray.length; i++) {
687
switch (orientArray[i]) {
688
default:
689
case 3 :
690
orientSup[i] = OrientationRequested.PORTRAIT;
691
break;
692
case 4:
693
orientSup[i] = OrientationRequested.LANDSCAPE;
694
break;
695
case 5:
696
orientSup[i] =
697
OrientationRequested.REVERSE_LANDSCAPE;
698
break;
699
case 6:
700
orientSup[i] =
701
OrientationRequested.REVERSE_PORTRAIT;
702
revPort = true;
703
break;
704
}
705
}
706
}
707
}
708
if (flavor == null ||
709
flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
710
flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
711
712
if (revPort && flavor == null) {
713
OrientationRequested []orSup = new OrientationRequested[4];
714
orSup[0] = OrientationRequested.PORTRAIT;
715
orSup[1] = OrientationRequested.LANDSCAPE;
716
orSup[2] = OrientationRequested.REVERSE_LANDSCAPE;
717
orSup[3] = OrientationRequested.REVERSE_PORTRAIT;
718
return orSup;
719
} else {
720
OrientationRequested []orSup = new OrientationRequested[3];
721
orSup[0] = OrientationRequested.PORTRAIT;
722
orSup[1] = OrientationRequested.LANDSCAPE;
723
orSup[2] = OrientationRequested.REVERSE_LANDSCAPE;
724
return orSup;
725
}
726
} else {
727
return orientSup;
728
}
729
} else if (category == PageRanges.class) {
730
if (flavor == null ||
731
flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
732
flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
733
PageRanges []arr = new PageRanges[1];
734
arr[0] = new PageRanges(1, Integer.MAX_VALUE);
735
return arr;
736
} else {
737
// Returning null as this is not yet supported in UnixPrintJob.
738
return null;
739
}
740
} else if (category == RequestingUserName.class) {
741
String userName = "";
742
try {
743
userName = System.getProperty("user.name", "");
744
} catch (SecurityException se) {
745
}
746
return new RequestingUserName(userName, null);
747
} else if (category == Sides.class) {
748
// The printer takes care of Sides so if short-edge
749
// is chosen in a job, the rotation is done by the printer.
750
// Orientation is rotated by emulation if pageable
751
// or printable so if the document is in Landscape, this may
752
// result in double rotation.
753
AttributeClass attribClass = (getAttMap != null) ?
754
(AttributeClass)getAttMap.get("sides-supported")
755
: null;
756
if (attribClass != null) {
757
String[] sidesArray = attribClass.getArrayOfStringValues();
758
if ((sidesArray != null) && (sidesArray.length > 0)) {
759
Sides[] sidesSup = new Sides[sidesArray.length];
760
for (int i=0; i<sidesArray.length; i++) {
761
if (sidesArray[i].endsWith("long-edge")) {
762
sidesSup[i] = Sides.TWO_SIDED_LONG_EDGE;
763
} else if (sidesArray[i].endsWith("short-edge")) {
764
sidesSup[i] = Sides.TWO_SIDED_SHORT_EDGE;
765
} else {
766
sidesSup[i] = Sides.ONE_SIDED;
767
}
768
}
769
return sidesSup;
770
}
771
}
772
}
773
774
return null;
775
}
776
777
//This class is for getting all pre-defined Finishings
778
private class ExtFinishing extends Finishings {
779
ExtFinishing(int value) {
780
super(100); // 100 to avoid any conflicts with predefined values.
781
}
782
783
EnumSyntax[] getAll() {
784
EnumSyntax[] es = super.getEnumValueTable();
785
return es;
786
}
787
}
788
789
790
public AttributeSet getUnsupportedAttributes(DocFlavor flavor,
791
AttributeSet attributes) {
792
if (flavor != null && !isDocFlavorSupported(flavor)) {
793
throw new IllegalArgumentException("flavor " + flavor +
794
"is not supported");
795
}
796
797
if (attributes == null) {
798
return null;
799
}
800
801
Attribute attr;
802
AttributeSet unsupp = new HashAttributeSet();
803
Attribute []attrs = attributes.toArray();
804
for (int i=0; i<attrs.length; i++) {
805
try {
806
attr = attrs[i];
807
if (!isAttributeCategorySupported(attr.getCategory())) {
808
unsupp.add(attr);
809
} else if (!isAttributeValueSupported(attr, flavor,
810
attributes)) {
811
unsupp.add(attr);
812
}
813
} catch (ClassCastException e) {
814
}
815
}
816
if (unsupp.isEmpty()) {
817
return null;
818
} else {
819
return unsupp;
820
}
821
}
822
823
824
public synchronized DocFlavor[] getSupportedDocFlavors() {
825
826
if (supportedDocFlavors != null) {
827
int len = supportedDocFlavors.length;
828
DocFlavor[] copyflavors = new DocFlavor[len];
829
System.arraycopy(supportedDocFlavors, 0, copyflavors, 0, len);
830
return copyflavors;
831
}
832
initAttributes();
833
834
if ((getAttMap != null) &&
835
getAttMap.containsKey("document-format-supported")) {
836
837
AttributeClass attribClass =
838
(AttributeClass)getAttMap.get("document-format-supported");
839
if (attribClass != null) {
840
String mimeType;
841
boolean psSupported = false;
842
String[] docFlavors = attribClass.getArrayOfStringValues();
843
DocFlavor[] flavors;
844
HashSet docList = new HashSet();
845
int j;
846
String hostEnc = DocFlavor.hostEncoding.
847
toLowerCase(Locale.ENGLISH);
848
boolean addHostEncoding = !hostEnc.equals("utf-8") &&
849
!hostEnc.equals("utf-16") && !hostEnc.equals("utf-16be") &&
850
!hostEnc.equals("utf-16le") && !hostEnc.equals("us-ascii");
851
852
for (int i = 0; i < docFlavors.length; i++) {
853
for (j=0; j<allDocFlavors.length; j++) {
854
flavors = (DocFlavor[])allDocFlavors[j];
855
856
mimeType = flavors[0].getMimeType();
857
if (mimeType.startsWith(docFlavors[i])) {
858
859
docList.addAll(Arrays.asList(flavors));
860
861
if (mimeType.equals("text/plain") &&
862
addHostEncoding) {
863
docList.add(Arrays.asList(textPlainHost));
864
} else if (mimeType.equals("text/html") &&
865
addHostEncoding) {
866
docList.add(Arrays.asList(textHtmlHost));
867
} else if (mimeType.equals("image/png")) {
868
pngImagesAdded = true;
869
} else if (mimeType.equals("image/gif")) {
870
gifImagesAdded = true;
871
} else if (mimeType.equals("image/jpeg")) {
872
jpgImagesAdded = true;
873
} else if (mimeType.indexOf("postscript") != -1) {
874
psSupported = true;
875
}
876
break;
877
}
878
}
879
880
// Not added? Create new DocFlavors
881
if (j == allDocFlavors.length) {
882
// make new DocFlavors
883
docList.add(new DocFlavor.BYTE_ARRAY(docFlavors[i]));
884
docList.add(new DocFlavor.INPUT_STREAM(docFlavors[i]));
885
docList.add(new DocFlavor.URL(docFlavors[i]));
886
}
887
}
888
889
// check if we need to add image DocFlavors
890
// and Pageable/Printable flavors
891
if (psSupported || isCupsPrinter) {
892
/*
893
Always add Pageable and Printable for CUPS
894
since it uses Filters to convert from Postscript
895
to device printer language.
896
*/
897
docList.add(DocFlavor.SERVICE_FORMATTED.PAGEABLE);
898
docList.add(DocFlavor.SERVICE_FORMATTED.PRINTABLE);
899
900
docList.addAll(Arrays.asList(imageJPG));
901
docList.addAll(Arrays.asList(imagePNG));
902
docList.addAll(Arrays.asList(imageGIF));
903
}
904
supportedDocFlavors = new DocFlavor[docList.size()];
905
docList.toArray(supportedDocFlavors);
906
int len = supportedDocFlavors.length;
907
DocFlavor[] copyflavors = new DocFlavor[len];
908
System.arraycopy(supportedDocFlavors, 0, copyflavors, 0, len);
909
return copyflavors;
910
}
911
}
912
return null;
913
}
914
915
916
public boolean isDocFlavorSupported(DocFlavor flavor) {
917
if (supportedDocFlavors == null) {
918
getSupportedDocFlavors();
919
}
920
if (supportedDocFlavors != null) {
921
for (int f=0; f<supportedDocFlavors.length; f++) {
922
if (flavor.equals(supportedDocFlavors[f])) {
923
return true;
924
}
925
}
926
}
927
return false;
928
}
929
930
931
/**
932
* Finds matching CustomMediaSizeName of given media.
933
*/
934
public CustomMediaSizeName findCustomMedia(MediaSizeName media) {
935
if (customMediaSizeNames == null) {
936
return null;
937
}
938
for (int i=0; i< customMediaSizeNames.length; i++) {
939
CustomMediaSizeName custom =
940
(CustomMediaSizeName)customMediaSizeNames[i];
941
MediaSizeName msn = custom.getStandardMedia();
942
if (media.equals(msn)) {
943
return customMediaSizeNames[i];
944
}
945
}
946
return null;
947
}
948
949
950
/**
951
* Returns the matching standard Media using string comparison of names.
952
*/
953
private Media getIPPMedia(String mediaName) {
954
CustomMediaSizeName sampleSize = new CustomMediaSizeName("sample", "",
955
0, 0);
956
Media[] sizes = sampleSize.getSuperEnumTable();
957
for (int i=0; i<sizes.length; i++) {
958
if (mediaName.equals(""+sizes[i])) {
959
return sizes[i];
960
}
961
}
962
CustomMediaTray sampleTray = new CustomMediaTray("sample", "");
963
Media[] trays = sampleTray.getSuperEnumTable();
964
for (int i=0; i<trays.length; i++) {
965
if (mediaName.equals(""+trays[i])) {
966
return trays[i];
967
}
968
}
969
return null;
970
}
971
972
private Media[] getSupportedMedia() {
973
if ((getAttMap != null) &&
974
getAttMap.containsKey("media-supported")) {
975
976
AttributeClass attribClass =
977
(AttributeClass)getAttMap.get("media-supported");
978
979
if (attribClass != null) {
980
String[] mediaVals = attribClass.getArrayOfStringValues();
981
Media msn;
982
Media[] mediaNames =
983
new Media[mediaVals.length];
984
for (int i=0; i<mediaVals.length; i++) {
985
msn = getIPPMedia(mediaVals[i]);
986
//REMIND: if null, create custom?
987
mediaNames[i] = msn;
988
}
989
return mediaNames;
990
}
991
}
992
return new Media[0];
993
}
994
995
996
public synchronized Class[] getSupportedAttributeCategories() {
997
if (supportedCats != null) {
998
Class<?> [] copyCats = new Class<?>[supportedCats.length];
999
System.arraycopy(supportedCats, 0, copyCats, 0, copyCats.length);
1000
return copyCats;
1001
}
1002
1003
initAttributes();
1004
1005
ArrayList catList = new ArrayList();
1006
Class cl;
1007
1008
for (int i=0; i < printReqAttribDefault.length; i++) {
1009
PrintRequestAttribute pra =
1010
(PrintRequestAttribute)printReqAttribDefault[i];
1011
if (getAttMap != null &&
1012
getAttMap.containsKey(pra.getName()+"-supported")) {
1013
cl = pra.getCategory();
1014
catList.add(cl);
1015
}
1016
}
1017
1018
// Some IPP printers like lexc710 do not have list of supported media
1019
// but CUPS can get the media from PPD, so we still report as
1020
// supported category.
1021
if (isCupsPrinter) {
1022
if (!catList.contains(Media.class)) {
1023
catList.add(Media.class);
1024
}
1025
1026
// Always add MediaPrintable for cups,
1027
// because we can get it from PPD.
1028
catList.add(MediaPrintableArea.class);
1029
1030
// this is already supported in UnixPrintJob
1031
catList.add(Destination.class);
1032
1033
// It is unfortunate that CUPS doesn't provide a way to query
1034
// if printer supports collation but since most printers
1035
// now supports collation and that most OS has a way
1036
// of setting it, it is a safe assumption to just always
1037
// include SheetCollate as supported attribute.
1038
1039
/*
1040
In Linux, we use Postscript for rendering but Linux still
1041
has issues in propagating Postscript-embedded setpagedevice
1042
setting like collation. Therefore, we temporarily exclude
1043
Linux.
1044
*/
1045
if (!PrintServiceLookupProvider.isLinux()) {
1046
catList.add(SheetCollate.class);
1047
}
1048
}
1049
1050
// With the assumption that Chromaticity is equivalent to
1051
// ColorSupported.
1052
if (getAttMap != null && getAttMap.containsKey("color-supported")) {
1053
catList.add(Chromaticity.class);
1054
}
1055
supportedCats = new Class[catList.size()];
1056
catList.toArray(supportedCats);
1057
Class<?>[] copyCats = new Class<?>[supportedCats.length];
1058
System.arraycopy(supportedCats, 0, copyCats, 0, copyCats.length);
1059
return copyCats;
1060
}
1061
1062
1063
public boolean
1064
isAttributeCategorySupported(Class<? extends Attribute> category)
1065
{
1066
if (category == null) {
1067
throw new NullPointerException("null category");
1068
}
1069
if (!(Attribute.class.isAssignableFrom(category))) {
1070
throw new IllegalArgumentException(category +
1071
" is not an Attribute");
1072
}
1073
1074
if (supportedCats == null) {
1075
getSupportedAttributeCategories();
1076
}
1077
1078
// It is safe to assume that Orientation is always supported
1079
// and even if CUPS or an IPP device reports it as not,
1080
// our renderer can do portrait, landscape and
1081
// reverse landscape.
1082
if (category == OrientationRequested.class) {
1083
return true;
1084
}
1085
1086
for (int i=0;i<supportedCats.length;i++) {
1087
if (category == supportedCats[i]) {
1088
return true;
1089
}
1090
}
1091
1092
return false;
1093
}
1094
1095
1096
public synchronized <T extends PrintServiceAttribute>
1097
T getAttribute(Class<T> category)
1098
{
1099
if (category == null) {
1100
throw new NullPointerException("category");
1101
}
1102
if (!(PrintServiceAttribute.class.isAssignableFrom(category))) {
1103
throw new IllegalArgumentException("Not a PrintServiceAttribute");
1104
}
1105
1106
initAttributes();
1107
1108
if (category == PrinterName.class) {
1109
return (T)(new PrinterName(printer, null));
1110
} else if (category == PrinterInfo.class) {
1111
PrinterInfo pInfo = new PrinterInfo(printer, null);
1112
AttributeClass ac = (getAttMap != null) ?
1113
(AttributeClass)getAttMap.get(pInfo.getName())
1114
: null;
1115
if (ac != null) {
1116
return (T)(new PrinterInfo(ac.getStringValue(), null));
1117
}
1118
return (T)pInfo;
1119
} else if (category == QueuedJobCount.class) {
1120
QueuedJobCount qjc = new QueuedJobCount(0);
1121
AttributeClass ac = (getAttMap != null) ?
1122
(AttributeClass)getAttMap.get(qjc.getName())
1123
: null;
1124
if (ac != null) {
1125
qjc = new QueuedJobCount(ac.getIntValue());
1126
}
1127
return (T)qjc;
1128
} else if (category == PrinterIsAcceptingJobs.class) {
1129
PrinterIsAcceptingJobs accJob =
1130
PrinterIsAcceptingJobs.ACCEPTING_JOBS;
1131
AttributeClass ac = (getAttMap != null) ?
1132
(AttributeClass)getAttMap.get(accJob.getName())
1133
: null;
1134
if ((ac != null) && (ac.getByteValue() == 0)) {
1135
accJob = PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS;
1136
}
1137
return (T)accJob;
1138
} else if (category == ColorSupported.class) {
1139
ColorSupported cs = ColorSupported.SUPPORTED;
1140
AttributeClass ac = (getAttMap != null) ?
1141
(AttributeClass)getAttMap.get(cs.getName())
1142
: null;
1143
if ((ac != null) && (ac.getByteValue() == 0)) {
1144
cs = ColorSupported.NOT_SUPPORTED;
1145
}
1146
return (T)cs;
1147
} else if (category == PDLOverrideSupported.class) {
1148
1149
if (isCupsPrinter) {
1150
// Documented: For CUPS this will always be false
1151
return (T)PDLOverrideSupported.NOT_ATTEMPTED;
1152
} else {
1153
// REMIND: check attribute values
1154
return (T)PDLOverrideSupported.NOT_ATTEMPTED;
1155
}
1156
} else if (category == PrinterURI.class) {
1157
return (T)(new PrinterURI(myURI));
1158
} else {
1159
return null;
1160
}
1161
}
1162
1163
1164
public synchronized PrintServiceAttributeSet getAttributes() {
1165
// update getAttMap by sending again get-attributes IPP request
1166
init = false;
1167
initAttributes();
1168
1169
HashPrintServiceAttributeSet attrs =
1170
new HashPrintServiceAttributeSet();
1171
1172
for (int i=0; i < serviceAttributes.length; i++) {
1173
String name = (String)serviceAttributes[i][1];
1174
if (getAttMap != null && getAttMap.containsKey(name)) {
1175
Class c = (Class)serviceAttributes[i][0];
1176
PrintServiceAttribute psa = getAttribute(c);
1177
if (psa != null) {
1178
attrs.add(psa);
1179
}
1180
}
1181
}
1182
return AttributeSetUtilities.unmodifiableView(attrs);
1183
}
1184
1185
public boolean isIPPSupportedImages(String mimeType) {
1186
if (supportedDocFlavors == null) {
1187
getSupportedDocFlavors();
1188
}
1189
1190
if (mimeType.equals("image/png") && pngImagesAdded) {
1191
return true;
1192
} else if (mimeType.equals("image/gif") && gifImagesAdded) {
1193
return true;
1194
} else if (mimeType.equals("image/jpeg") && jpgImagesAdded) {
1195
return true;
1196
}
1197
1198
return false;
1199
}
1200
1201
1202
private boolean isSupportedCopies(Copies copies) {
1203
CopiesSupported cs = (CopiesSupported)
1204
getSupportedAttributeValues(Copies.class, null, null);
1205
int[][] members = cs.getMembers();
1206
int min, max;
1207
if ((members.length > 0) && (members[0].length > 0)) {
1208
min = members[0][0];
1209
max = members[0][1];
1210
} else {
1211
min = 1;
1212
max = MAXCOPIES;
1213
}
1214
1215
int value = copies.getValue();
1216
return (value >= min && value <= max);
1217
}
1218
1219
private boolean isAutoSense(DocFlavor flavor) {
1220
if (flavor.equals(DocFlavor.BYTE_ARRAY.AUTOSENSE) ||
1221
flavor.equals(DocFlavor.INPUT_STREAM.AUTOSENSE) ||
1222
flavor.equals(DocFlavor.URL.AUTOSENSE)) {
1223
return true;
1224
}
1225
else {
1226
return false;
1227
}
1228
}
1229
1230
private synchronized boolean isSupportedMediaTray(MediaTray msn) {
1231
initAttributes();
1232
1233
if (mediaTrays != null) {
1234
for (int i=0; i<mediaTrays.length; i++) {
1235
if (msn.equals(mediaTrays[i])) {
1236
return true;
1237
}
1238
}
1239
}
1240
return false;
1241
}
1242
1243
private synchronized boolean isSupportedMedia(MediaSizeName msn) {
1244
initAttributes();
1245
1246
if (msn.equals((Media)getDefaultAttributeValue(Media.class))) {
1247
return true;
1248
}
1249
for (int i=0; i<mediaSizeNames.length; i++) {
1250
debug_println(debugPrefix+"isSupportedMedia, mediaSizeNames[i] "+mediaSizeNames[i]);
1251
if (msn.equals(mediaSizeNames[i])) {
1252
return true;
1253
}
1254
}
1255
return false;
1256
}
1257
1258
/* Return false if flavor is not null, pageable, nor printable and
1259
* Destination is part of attributes.
1260
*/
1261
private boolean
1262
isDestinationSupported(DocFlavor flavor, AttributeSet attributes) {
1263
1264
if ((attributes != null) &&
1265
(attributes.get(Destination.class) != null) &&
1266
!(flavor == null ||
1267
flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1268
flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
1269
return false;
1270
}
1271
return true;
1272
}
1273
1274
1275
public boolean isAttributeValueSupported(Attribute attr,
1276
DocFlavor flavor,
1277
AttributeSet attributes) {
1278
if (attr == null) {
1279
throw new NullPointerException("null attribute");
1280
}
1281
if (flavor != null) {
1282
if (!isDocFlavorSupported(flavor)) {
1283
throw new IllegalArgumentException(flavor +
1284
" is an unsupported flavor");
1285
} else if (isAutoSense(flavor)) {
1286
return false;
1287
}
1288
}
1289
Class category = attr.getCategory();
1290
if (!isAttributeCategorySupported(category)) {
1291
return false;
1292
}
1293
1294
/* Test if the flavor is compatible with the attributes */
1295
if (!isDestinationSupported(flavor, attributes)) {
1296
return false;
1297
}
1298
1299
/* Test if the flavor is compatible with the category */
1300
if (attr.getCategory() == Chromaticity.class) {
1301
if ((flavor == null) ||
1302
flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1303
flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
1304
!isIPPSupportedImages(flavor.getMimeType())) {
1305
return attr == Chromaticity.COLOR;
1306
} else {
1307
return false;
1308
}
1309
} else if (attr.getCategory() == Copies.class) {
1310
return (flavor == null ||
1311
!(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) ||
1312
flavor.equals(DocFlavor.URL.POSTSCRIPT) ||
1313
flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) &&
1314
isSupportedCopies((Copies)attr);
1315
1316
} else if (attr.getCategory() == Destination.class) {
1317
if (flavor == null ||
1318
flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1319
flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
1320
URI uri = ((Destination)attr).getURI();
1321
if ("file".equals(uri.getScheme()) &&
1322
!(uri.getSchemeSpecificPart().equals(""))) {
1323
return true;
1324
}
1325
}
1326
return false;
1327
} else if (attr.getCategory() == Media.class) {
1328
if (attr instanceof MediaSizeName) {
1329
return isSupportedMedia((MediaSizeName)attr);
1330
}
1331
if (attr instanceof MediaTray) {
1332
return isSupportedMediaTray((MediaTray)attr);
1333
}
1334
} else if (attr.getCategory() == PageRanges.class) {
1335
if (flavor != null &&
1336
!(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1337
flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
1338
return false;
1339
}
1340
} else if (attr.getCategory() == SheetCollate.class) {
1341
if (flavor != null &&
1342
!(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
1343
flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
1344
return false;
1345
}
1346
} else if (attr.getCategory() == Sides.class) {
1347
Sides[] sidesArray = (Sides[])getSupportedAttributeValues(
1348
Sides.class,
1349
flavor,
1350
attributes);
1351
1352
if (sidesArray != null) {
1353
for (int i=0; i<sidesArray.length; i++) {
1354
if (sidesArray[i] == (Sides)attr) {
1355
return true;
1356
}
1357
}
1358
}
1359
return false;
1360
} else if (attr.getCategory() == OrientationRequested.class) {
1361
OrientationRequested[] orientArray =
1362
(OrientationRequested[])getSupportedAttributeValues(
1363
OrientationRequested.class,
1364
flavor,
1365
attributes);
1366
1367
if (orientArray != null) {
1368
for (int i=0; i<orientArray.length; i++) {
1369
if (orientArray[i] == (OrientationRequested)attr) {
1370
return true;
1371
}
1372
}
1373
}
1374
return false;
1375
}
1376
return true;
1377
}
1378
1379
1380
public synchronized Object
1381
getDefaultAttributeValue(Class<? extends Attribute> category)
1382
{
1383
if (category == null) {
1384
throw new NullPointerException("null category");
1385
}
1386
if (!Attribute.class.isAssignableFrom(category)) {
1387
throw new IllegalArgumentException(category +
1388
" is not an Attribute");
1389
}
1390
if (!isAttributeCategorySupported(category)) {
1391
return null;
1392
}
1393
1394
initAttributes();
1395
1396
String catName = null;
1397
for (int i=0; i < printReqAttribDefault.length; i++) {
1398
PrintRequestAttribute pra =
1399
(PrintRequestAttribute)printReqAttribDefault[i];
1400
if (pra.getCategory() == category) {
1401
catName = pra.getName();
1402
break;
1403
}
1404
}
1405
String attribName = catName+"-default";
1406
AttributeClass attribClass = (getAttMap != null) ?
1407
(AttributeClass)getAttMap.get(attribName) : null;
1408
1409
if (category == Copies.class) {
1410
if (attribClass != null) {
1411
return new Copies(attribClass.getIntValue());
1412
} else {
1413
return new Copies(1);
1414
}
1415
} else if (category == Chromaticity.class) {
1416
return Chromaticity.COLOR;
1417
} else if (category == Destination.class) {
1418
try {
1419
return new Destination((new File("out.ps")).toURI());
1420
} catch (SecurityException se) {
1421
try {
1422
return new Destination(new URI("file:out.ps"));
1423
} catch (URISyntaxException e) {
1424
return null;
1425
}
1426
}
1427
} else if (category == Fidelity.class) {
1428
return Fidelity.FIDELITY_FALSE;
1429
} else if (category == Finishings.class) {
1430
return Finishings.NONE;
1431
} else if (category == JobName.class) {
1432
return new JobName("Java Printing", null);
1433
} else if (category == JobSheets.class) {
1434
if (attribClass != null &&
1435
attribClass.getStringValue().equals("none")) {
1436
return JobSheets.NONE;
1437
} else {
1438
return JobSheets.STANDARD;
1439
}
1440
} else if (category == Media.class) {
1441
if (defaultMediaIndex == -1) {
1442
defaultMediaIndex = 0;
1443
}
1444
if (mediaSizeNames.length == 0) {
1445
String defaultCountry = Locale.getDefault().getCountry();
1446
if (defaultCountry != null &&
1447
(defaultCountry.equals("") ||
1448
defaultCountry.equals(Locale.US.getCountry()) ||
1449
defaultCountry.equals(Locale.CANADA.getCountry()))) {
1450
return MediaSizeName.NA_LETTER;
1451
} else {
1452
return MediaSizeName.ISO_A4;
1453
}
1454
}
1455
1456
if (attribClass != null) {
1457
String name = attribClass.getStringValue();
1458
if (isCupsPrinter) {
1459
return mediaSizeNames[defaultMediaIndex];
1460
} else {
1461
for (int i=0; i< mediaSizeNames.length; i++) {
1462
if (mediaSizeNames[i].toString().indexOf(name) != -1) {
1463
defaultMediaIndex = i;
1464
return mediaSizeNames[defaultMediaIndex];
1465
}
1466
}
1467
}
1468
}
1469
return mediaSizeNames[defaultMediaIndex];
1470
1471
} else if (category == MediaPrintableArea.class) {
1472
MediaPrintableArea[] mpas;
1473
if ((cps != null) &&
1474
((mpas = cps.getMediaPrintableArea()) != null)) {
1475
if (defaultMediaIndex == -1) {
1476
// initializes value of defaultMediaIndex
1477
getDefaultAttributeValue(Media.class);
1478
}
1479
return mpas[defaultMediaIndex];
1480
} else {
1481
String defaultCountry = Locale.getDefault().getCountry();
1482
float iw, ih;
1483
if (defaultCountry != null &&
1484
(defaultCountry.equals("") ||
1485
defaultCountry.equals(Locale.US.getCountry()) ||
1486
defaultCountry.equals(Locale.CANADA.getCountry()))) {
1487
iw = MediaSize.NA.LETTER.getX(Size2DSyntax.INCH) - 0.5f;
1488
ih = MediaSize.NA.LETTER.getY(Size2DSyntax.INCH) - 0.5f;
1489
} else {
1490
iw = MediaSize.ISO.A4.getX(Size2DSyntax.INCH) - 0.5f;
1491
ih = MediaSize.ISO.A4.getY(Size2DSyntax.INCH) - 0.5f;
1492
}
1493
return new MediaPrintableArea(0.25f, 0.25f, iw, ih,
1494
MediaPrintableArea.INCH);
1495
}
1496
} else if (category == NumberUp.class) {
1497
return new NumberUp(1); // for CUPS this is always 1
1498
} else if (category == OrientationRequested.class) {
1499
if (attribClass != null) {
1500
switch (attribClass.getIntValue()) {
1501
default:
1502
case 3: return OrientationRequested.PORTRAIT;
1503
case 4: return OrientationRequested.LANDSCAPE;
1504
case 5: return OrientationRequested.REVERSE_LANDSCAPE;
1505
case 6: return OrientationRequested.REVERSE_PORTRAIT;
1506
}
1507
} else {
1508
return OrientationRequested.PORTRAIT;
1509
}
1510
} else if (category == PageRanges.class) {
1511
if (attribClass != null) {
1512
int[] range = attribClass.getIntRangeValue();
1513
return new PageRanges(range[0], range[1]);
1514
} else {
1515
return new PageRanges(1, Integer.MAX_VALUE);
1516
}
1517
} else if (category == RequestingUserName.class) {
1518
String userName = "";
1519
try {
1520
userName = System.getProperty("user.name", "");
1521
} catch (SecurityException se) {
1522
}
1523
return new RequestingUserName(userName, null);
1524
} else if (category == SheetCollate.class) {
1525
return SheetCollate.UNCOLLATED;
1526
} else if (category == Sides.class) {
1527
if (attribClass != null) {
1528
if (attribClass.getStringValue().endsWith("long-edge")) {
1529
return Sides.TWO_SIDED_LONG_EDGE;
1530
} else if (attribClass.getStringValue().endsWith(
1531
"short-edge")) {
1532
return Sides.TWO_SIDED_SHORT_EDGE;
1533
}
1534
}
1535
return Sides.ONE_SIDED;
1536
}
1537
1538
return null;
1539
}
1540
1541
public ServiceUIFactory getServiceUIFactory() {
1542
return null;
1543
}
1544
1545
public void wakeNotifier() {
1546
synchronized (this) {
1547
if (notifier != null) {
1548
notifier.wake();
1549
}
1550
}
1551
}
1552
1553
public void addPrintServiceAttributeListener(
1554
PrintServiceAttributeListener listener) {
1555
synchronized (this) {
1556
if (listener == null) {
1557
return;
1558
}
1559
if (notifier == null) {
1560
notifier = new ServiceNotifier(this);
1561
}
1562
notifier.addListener(listener);
1563
}
1564
}
1565
1566
public void removePrintServiceAttributeListener(
1567
PrintServiceAttributeListener listener) {
1568
synchronized (this) {
1569
if (listener == null || notifier == null ) {
1570
return;
1571
}
1572
notifier.removeListener(listener);
1573
if (notifier.isEmpty()) {
1574
notifier.stopNotifier();
1575
notifier = null;
1576
}
1577
}
1578
}
1579
1580
String getDest() {
1581
return printer;
1582
}
1583
1584
public String getName() {
1585
/*
1586
* Mac is using printer-info IPP attribute for its human-readable printer
1587
* name and is also the identifier used in NSPrintInfo:setPrinter.
1588
*/
1589
if (PrintServiceLookupProvider.isMac()) {
1590
PrintServiceAttributeSet psaSet = this.getAttributes();
1591
if (psaSet != null) {
1592
PrinterInfo pName = (PrinterInfo)psaSet.get(PrinterInfo.class);
1593
if (pName != null) {
1594
return pName.toString();
1595
}
1596
}
1597
}
1598
return printer;
1599
}
1600
1601
1602
public boolean usesClass(Class c) {
1603
return (c == sun.print.PSPrinterJob.class);
1604
}
1605
1606
1607
public static HttpURLConnection getIPPConnection(URL url) {
1608
HttpURLConnection connection;
1609
URLConnection urlc;
1610
try {
1611
urlc = url.openConnection();
1612
} catch (java.io.IOException ioe) {
1613
return null;
1614
}
1615
if (!(urlc instanceof HttpURLConnection)) {
1616
return null;
1617
}
1618
connection = (HttpURLConnection)urlc;
1619
connection.setUseCaches(false);
1620
connection.setDefaultUseCaches(false);
1621
connection.setDoInput(true);
1622
connection.setDoOutput(true);
1623
connection.setRequestProperty("Content-type", "application/ipp");
1624
return connection;
1625
}
1626
1627
1628
public synchronized boolean isPostscript() {
1629
if (isPS == null) {
1630
isPS = Boolean.TRUE;
1631
if (isCupsPrinter) {
1632
try {
1633
urlConnection = getIPPConnection(
1634
new URL(myURL+".ppd"));
1635
1636
InputStream is = urlConnection.getInputStream();
1637
if (is != null) {
1638
BufferedReader d =
1639
new BufferedReader(new InputStreamReader(is,
1640
Charset.forName("ISO-8859-1")));
1641
String lineStr;
1642
while ((lineStr = d.readLine()) != null) {
1643
if (lineStr.startsWith("*cupsFilter:")) {
1644
isPS = Boolean.FALSE;
1645
break;
1646
}
1647
}
1648
}
1649
} catch (java.io.IOException e) {
1650
debug_println(" isPostscript, e= "+e);
1651
/* if PPD is not found, this may be a raw printer
1652
and in this case it is assumed that it is a
1653
Postscript printer */
1654
// do nothing
1655
}
1656
}
1657
}
1658
return isPS.booleanValue();
1659
}
1660
1661
1662
private void opGetAttributes() {
1663
try {
1664
debug_println(debugPrefix+"opGetAttributes myURI "+myURI+" myURL "+myURL);
1665
1666
AttributeClass attClNoUri[] = {
1667
AttributeClass.ATTRIBUTES_CHARSET,
1668
AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE};
1669
1670
AttributeClass attCl[] = {
1671
AttributeClass.ATTRIBUTES_CHARSET,
1672
AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE,
1673
new AttributeClass("printer-uri",
1674
AttributeClass.TAG_URI,
1675
""+myURI)};
1676
1677
OutputStream os = (OutputStream)java.security.AccessController.
1678
doPrivileged(new java.security.PrivilegedAction() {
1679
public Object run() {
1680
try {
1681
return urlConnection.getOutputStream();
1682
} catch (Exception e) {
1683
}
1684
return null;
1685
}
1686
});
1687
1688
if (os == null) {
1689
return;
1690
}
1691
1692
boolean success = (myURI == null) ?
1693
writeIPPRequest(os, OP_GET_ATTRIBUTES, attClNoUri) :
1694
writeIPPRequest(os, OP_GET_ATTRIBUTES, attCl);
1695
if (success) {
1696
InputStream is = null;
1697
if ((is = urlConnection.getInputStream())!=null) {
1698
HashMap[] responseMap = readIPPResponse(is);
1699
1700
if (responseMap != null && responseMap.length > 0) {
1701
getAttMap = responseMap[0];
1702
// If there is extra hashmap created due to duplicate
1703
// key/attribute present in IPPresponse, then use that
1704
// map too by appending to getAttMap after removing the
1705
// duplicate key/value
1706
if (responseMap.length > 1) {
1707
for (int i = 1; i < responseMap.length; i++) {
1708
Set<Map.Entry<String, AttributeClass>> entries = responseMap[i].entrySet();
1709
for (Map.Entry<String, AttributeClass> entry : entries) {
1710
if (!getAttMap.containsKey(entry.getValue())) {
1711
getAttMap.put(entry.getKey(), entry.getValue());
1712
}
1713
}
1714
}
1715
}
1716
}
1717
} else {
1718
debug_println(debugPrefix+"opGetAttributes - null input stream");
1719
}
1720
is.close();
1721
}
1722
os.close();
1723
} catch (java.io.IOException e) {
1724
debug_println(debugPrefix+"opGetAttributes - input/output stream: "+e);
1725
}
1726
}
1727
1728
1729
public static boolean writeIPPRequest(OutputStream os,
1730
String operCode,
1731
AttributeClass[] attCl) {
1732
OutputStreamWriter osw;
1733
try {
1734
osw = new OutputStreamWriter(os, "UTF-8");
1735
} catch (java.io.UnsupportedEncodingException exc) {
1736
debug_println(debugPrefix+"writeIPPRequest, UTF-8 not supported? Exception: "+exc);
1737
return false;
1738
}
1739
debug_println(debugPrefix+"writeIPPRequest, op code= "+operCode);
1740
char[] opCode = new char[2];
1741
opCode[0] = (char)Byte.parseByte(operCode.substring(0,2), 16);
1742
opCode[1] = (char)Byte.parseByte(operCode.substring(2,4), 16);
1743
char[] bytes = {0x01, 0x01, 0x00, 0x01};
1744
try {
1745
osw.write(bytes, 0, 2); // version number
1746
osw.write(opCode, 0, 2); // operation code
1747
bytes[0] = 0x00; bytes[1] = 0x00;
1748
osw.write(bytes, 0, 4); // request ID #1
1749
1750
bytes[0] = 0x01; // operation-group-tag
1751
osw.write(bytes[0]);
1752
1753
String valStr;
1754
char[] lenStr;
1755
1756
AttributeClass ac;
1757
for (int i=0; i < attCl.length; i++) {
1758
ac = attCl[i];
1759
osw.write(ac.getType()); // value tag
1760
1761
lenStr = ac.getLenChars();
1762
osw.write(lenStr, 0, 2); // length
1763
osw.write(""+ac, 0, ac.getName().length());
1764
1765
// check if string range (0x35 -> 0x49)
1766
if (ac.getType() >= AttributeClass.TAG_TEXT_LANGUAGE &&
1767
ac.getType() <= AttributeClass.TAG_MIME_MEDIATYPE){
1768
valStr = (String)ac.getObjectValue();
1769
bytes[0] = 0; bytes[1] = (char)valStr.length();
1770
osw.write(bytes, 0, 2);
1771
osw.write(valStr, 0, valStr.length());
1772
} // REMIND: need to support other value tags but for CUPS
1773
// string is all we need.
1774
}
1775
1776
osw.write(GRPTAG_END_ATTRIBUTES);
1777
osw.flush();
1778
osw.close();
1779
} catch (java.io.IOException ioe) {
1780
debug_println(debugPrefix+"writeIPPRequest, IPPPrintService Exception in writeIPPRequest: "+ioe);
1781
return false;
1782
}
1783
return true;
1784
}
1785
1786
1787
public static HashMap[] readIPPResponse(InputStream inputStream) {
1788
1789
if (inputStream == null) {
1790
return null;
1791
}
1792
1793
byte response[] = new byte[MAX_ATTRIBUTE_LENGTH];
1794
try {
1795
1796
DataInputStream ois = new DataInputStream(inputStream);
1797
1798
// read status and ID
1799
if ((ois.read(response, 0, 8) > -1) &&
1800
(response[2] == STATUSCODE_SUCCESS)) {
1801
1802
ByteArrayOutputStream outObj;
1803
int counter=0;
1804
short len = 0;
1805
String attribStr = null;
1806
// assign default value
1807
byte valTagByte = AttributeClass.TAG_KEYWORD;
1808
ArrayList respList = new ArrayList();
1809
HashMap responseMap = new HashMap();
1810
1811
response[0] = ois.readByte();
1812
1813
// check for group tags
1814
while ((response[0] >= GRPTAG_OP_ATTRIBUTES) &&
1815
(response[0] <= GRPTAG_PRINTER_ATTRIBUTES)
1816
&& (response[0] != GRPTAG_END_ATTRIBUTES)) {
1817
debug_println(debugPrefix+"readIPPResponse, checking group tag, response[0]= "+
1818
response[0]);
1819
1820
outObj = new ByteArrayOutputStream();
1821
//make sure counter and attribStr are re-initialized
1822
counter = 0;
1823
attribStr = null;
1824
1825
// read value tag
1826
response[0] = ois.readByte();
1827
while (response[0] >= AttributeClass.TAG_UNSUPPORTED_VALUE &&
1828
response[0] <= AttributeClass.TAG_MEMBER_ATTRNAME) {
1829
// read name length
1830
len = ois.readShort();
1831
1832
// If current value is not part of previous attribute
1833
// then close stream and add it to HashMap.
1834
// It is part of previous attribute if name length=0.
1835
if ((len != 0) && (attribStr != null)) {
1836
//last byte is the total # of values
1837
outObj.write(counter);
1838
outObj.flush();
1839
outObj.close();
1840
byte outArray[] = outObj.toByteArray();
1841
1842
// if key exists, new HashMap
1843
if (responseMap.containsKey(attribStr)) {
1844
respList.add(responseMap);
1845
responseMap = new HashMap();
1846
}
1847
1848
// exclude those that are unknown
1849
if (valTagByte >= AttributeClass.TAG_INT) {
1850
AttributeClass ac =
1851
new AttributeClass(attribStr,
1852
valTagByte,
1853
outArray);
1854
1855
responseMap.put(ac.getName(), ac);
1856
debug_println(debugPrefix+ "readIPPResponse "+ac);
1857
}
1858
1859
outObj = new ByteArrayOutputStream();
1860
counter = 0; //reset counter
1861
}
1862
//check if this is new value tag
1863
if (counter == 0) {
1864
valTagByte = response[0];
1865
}
1866
// read attribute name
1867
if (len != 0) {
1868
// read "len" characters
1869
// make sure it doesn't exceed the maximum
1870
if (len > MAX_ATTRIBUTE_LENGTH) {
1871
response = new byte[len]; // expand as needed
1872
}
1873
ois.read(response, 0, len);
1874
attribStr = new String(response, 0, len);
1875
}
1876
// read value length
1877
len = ois.readShort();
1878
// write name length
1879
outObj.write(len);
1880
// read value, make sure it doesn't exceed the maximum
1881
if (len > MAX_ATTRIBUTE_LENGTH) {
1882
response = new byte[len]; // expand as needed
1883
}
1884
ois.read(response, 0, len);
1885
// write value of "len" length
1886
outObj.write(response, 0, len);
1887
counter++;
1888
// read next byte
1889
response[0] = ois.readByte();
1890
}
1891
1892
if (attribStr != null) {
1893
outObj.write(counter);
1894
outObj.flush();
1895
outObj.close();
1896
1897
// if key exists in old HashMap, new HashMap
1898
if ((counter != 0) &&
1899
responseMap.containsKey(attribStr)) {
1900
respList.add(responseMap);
1901
responseMap = new HashMap();
1902
}
1903
1904
byte outArray[] = outObj.toByteArray();
1905
1906
AttributeClass ac =
1907
new AttributeClass(attribStr,
1908
valTagByte,
1909
outArray);
1910
responseMap.put(ac.getName(), ac);
1911
}
1912
}
1913
ois.close();
1914
if ((responseMap != null) && (responseMap.size() > 0)) {
1915
respList.add(responseMap);
1916
}
1917
return (HashMap[])respList.toArray(
1918
new HashMap[respList.size()]);
1919
} else {
1920
debug_println(debugPrefix+
1921
"readIPPResponse client error, IPP status code: 0x"+
1922
toHex(response[2]) + toHex(response[3]));
1923
return null;
1924
}
1925
1926
} catch (java.io.IOException e) {
1927
debug_println(debugPrefix+"readIPPResponse: "+e);
1928
if (debugPrint) {
1929
e.printStackTrace();
1930
}
1931
return null;
1932
}
1933
}
1934
1935
private static String toHex(byte v) {
1936
String s = Integer.toHexString(v&0xff);
1937
return (s.length() == 2) ? s : "0"+s;
1938
}
1939
1940
public String toString() {
1941
return "IPP Printer : " + getName();
1942
}
1943
1944
public boolean equals(Object obj) {
1945
return (obj == this ||
1946
(obj instanceof IPPPrintService &&
1947
((IPPPrintService)obj).getName().equals(getName())));
1948
}
1949
1950
public int hashCode() {
1951
return this.getClass().hashCode()+getName().hashCode();
1952
}
1953
}
1954
1955