blob: f451f804c7abefe13cc9c86f2d4c899816251319 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2007 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.io.File;
29import java.net.URI;
30import java.net.URISyntaxException;
31import java.util.Locale;
32
33import javax.print.DocFlavor;
34import javax.print.DocPrintJob;
35import javax.print.PrintService;
36import javax.print.ServiceUIFactory;
37import javax.print.attribute.Attribute;
38import javax.print.attribute.AttributeSet;
39import javax.print.attribute.AttributeSetUtilities;
40import javax.print.attribute.HashAttributeSet;
41import javax.print.attribute.PrintServiceAttribute;
42import javax.print.attribute.PrintServiceAttributeSet;
43import javax.print.attribute.HashPrintServiceAttributeSet;
44import javax.print.attribute.Size2DSyntax;
45import javax.print.attribute.standard.PrinterName;
46import javax.print.attribute.standard.PrinterIsAcceptingJobs;
47import javax.print.attribute.standard.QueuedJobCount;
48import javax.print.attribute.standard.JobName;
49import javax.print.attribute.standard.JobSheets;
50import javax.print.attribute.standard.RequestingUserName;
51import javax.print.attribute.standard.Chromaticity;
52import javax.print.attribute.standard.ColorSupported;
53import javax.print.attribute.standard.Copies;
54import javax.print.attribute.standard.CopiesSupported;
55import javax.print.attribute.standard.Destination;
56import javax.print.attribute.standard.Fidelity;
57import javax.print.attribute.standard.Media;
58import javax.print.attribute.standard.MediaPrintableArea;
59import javax.print.attribute.standard.MediaSize;
60import javax.print.attribute.standard.MediaSizeName;
61import javax.print.attribute.standard.OrientationRequested;
62import javax.print.attribute.standard.PageRanges;
63import javax.print.attribute.standard.PrinterState;
64import javax.print.attribute.standard.PrinterStateReason;
65import javax.print.attribute.standard.PrinterStateReasons;
66import javax.print.attribute.standard.Severity;
67import javax.print.attribute.standard.SheetCollate;
68import javax.print.attribute.standard.Sides;
69import javax.print.event.PrintServiceAttributeListener;
70
71
72public class UnixPrintService implements PrintService, AttributeUpdater,
73 SunPrinterJobService {
74
75 /* define doc flavors for text types in the default encoding of
76 * this platform since we can always read those.
77 */
78 private static String encoding = "ISO8859_1";
79 private static DocFlavor textByteFlavor;
80
81 private static DocFlavor[] supportedDocFlavors = null;
82 private static final DocFlavor[] supportedDocFlavorsInit = {
83 DocFlavor.BYTE_ARRAY.POSTSCRIPT,
84 DocFlavor.INPUT_STREAM.POSTSCRIPT,
85 DocFlavor.URL.POSTSCRIPT,
86 DocFlavor.BYTE_ARRAY.GIF,
87 DocFlavor.INPUT_STREAM.GIF,
88 DocFlavor.URL.GIF,
89 DocFlavor.BYTE_ARRAY.JPEG,
90 DocFlavor.INPUT_STREAM.JPEG,
91 DocFlavor.URL.JPEG,
92 DocFlavor.BYTE_ARRAY.PNG,
93 DocFlavor.INPUT_STREAM.PNG,
94 DocFlavor.URL.PNG,
95
96 DocFlavor.CHAR_ARRAY.TEXT_PLAIN,
97 DocFlavor.READER.TEXT_PLAIN,
98 DocFlavor.STRING.TEXT_PLAIN,
99
100 DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_8,
101 DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16,
102 DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16BE,
103 DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16LE,
104 DocFlavor.BYTE_ARRAY.TEXT_PLAIN_US_ASCII,
105
106
107 DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_8,
108 DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16,
109 DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16BE,
110 DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16LE,
111 DocFlavor.INPUT_STREAM.TEXT_PLAIN_US_ASCII,
112
113
114 DocFlavor.URL.TEXT_PLAIN_UTF_8,
115 DocFlavor.URL.TEXT_PLAIN_UTF_16,
116 DocFlavor.URL.TEXT_PLAIN_UTF_16BE,
117 DocFlavor.URL.TEXT_PLAIN_UTF_16LE,
118 DocFlavor.URL.TEXT_PLAIN_US_ASCII,
119
120 DocFlavor.SERVICE_FORMATTED.PAGEABLE,
121 DocFlavor.SERVICE_FORMATTED.PRINTABLE,
122
123 DocFlavor.BYTE_ARRAY.AUTOSENSE,
124 DocFlavor.URL.AUTOSENSE,
125 DocFlavor.INPUT_STREAM.AUTOSENSE
126 };
127
128 private static final DocFlavor[] supportedHostDocFlavors = {
129 DocFlavor.BYTE_ARRAY.TEXT_PLAIN_HOST,
130 DocFlavor.INPUT_STREAM.TEXT_PLAIN_HOST,
131 DocFlavor.URL.TEXT_PLAIN_HOST
132 };
133
134 String[] lpcStatusCom = {
135 "",
136 "| grep -E '^[ 0-9a-zA-Z_-]*@' | awk '{print $2, $3}'"
137 };
138
139 String[] lpcQueueCom = {
140 "",
141 "| grep -E '^[ 0-9a-zA-Z_-]*@' | awk '{print $4}'"
142 };
143
144 static {
145 encoding = java.security.AccessController.doPrivileged(
146 new sun.security.action.GetPropertyAction("file.encoding"));
147 }
148
149 /* let's try to support a few of these */
150 private static final Class[] serviceAttrCats = {
151 PrinterName.class,
152 PrinterIsAcceptingJobs.class,
153 QueuedJobCount.class,
154 };
155
156 /* it turns out to be inconvenient to store the other categories
157 * separately because many attributes are in multiple categories.
158 */
159 private static final Class[] otherAttrCats = {
160 Chromaticity.class,
161 Copies.class,
162 Destination.class,
163 Fidelity.class,
164 JobName.class,
165 JobSheets.class,
166 Media.class, /* have to support this somehow ... */
167 MediaPrintableArea.class,
168 OrientationRequested.class,
169 PageRanges.class,
170 RequestingUserName.class,
171 SheetCollate.class,
172 Sides.class,
173 };
174
175 private static int MAXCOPIES = 1000;
176
177 private static final MediaSizeName mediaSizes[] = {
178 MediaSizeName.NA_LETTER,
179 MediaSizeName.TABLOID,
180 MediaSizeName.LEDGER,
181 MediaSizeName.NA_LEGAL,
182 MediaSizeName.EXECUTIVE,
183 MediaSizeName.ISO_A3,
184 MediaSizeName.ISO_A4,
185 MediaSizeName.ISO_A5,
186 MediaSizeName.ISO_B4,
187 MediaSizeName.ISO_B5,
188 };
189
190 private String printer;
191 private PrinterName name;
192 private boolean isInvalid;
193
194 transient private PrintServiceAttributeSet lastSet;
195 transient private ServiceNotifier notifier = null;
196
197 UnixPrintService(String name) {
198 if (name == null) {
199 throw new IllegalArgumentException("null printer name");
200 }
201 printer = name;
202 isInvalid = false;
203 }
204
205 public void invalidateService() {
206 isInvalid = true;
207 }
208
209 public String getName() {
210 return printer;
211 }
212
213 private PrinterName getPrinterName() {
214 if (name == null) {
215 name = new PrinterName(printer, null);
216 }
217 return name;
218 }
219
220 private PrinterIsAcceptingJobs getPrinterIsAcceptingJobsSysV() {
221 String command = "/usr/bin/lpstat -a " + printer;
222 String results[]= UnixPrintServiceLookup.execCmd(command);
223
224 if (results != null && results.length > 0) {
225 if (results[0].startsWith(printer + " accepting requests")) {
226 return PrinterIsAcceptingJobs.ACCEPTING_JOBS;
227 }
228 else if (results[0].startsWith(printer)) {
229 /* As well as "myprinter accepting requests", look for
230 * "myprinter@somehost accepting requests".
231 */
232 int index = printer.length();
233 String str = results[0];
234 if (str.length() > index &&
235 str.charAt(index) == '@' &&
236 str.indexOf(" accepting requests", index) > 0 &&
237 str.indexOf(" not accepting requests", index) == -1) {
238 return PrinterIsAcceptingJobs.ACCEPTING_JOBS;
239 }
240 }
241 }
242 return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS ;
243 }
244
245 private PrinterIsAcceptingJobs getPrinterIsAcceptingJobsBSD() {
246 if (UnixPrintServiceLookup.cmdIndex ==
247 UnixPrintServiceLookup.UNINITIALIZED) {
248
249 UnixPrintServiceLookup.cmdIndex =
250 UnixPrintServiceLookup.getBSDCommandIndex();
251 }
252
253 String command = "/usr/sbin/lpc status " + printer
254 + lpcStatusCom[UnixPrintServiceLookup.cmdIndex];
255 String results[]= UnixPrintServiceLookup.execCmd(command);
256
257 if (results != null && results.length > 0) {
258 if (UnixPrintServiceLookup.cmdIndex ==
259 UnixPrintServiceLookup.BSD_LPD_NG) {
260 if (results[0].startsWith("enabled enabled")) {
261 return PrinterIsAcceptingJobs.ACCEPTING_JOBS ;
262 }
263 } else {
264 if ((results[1].trim().startsWith("queuing is enabled") &&
265 results[2].trim().startsWith("printing is enabled")) ||
266 (results.length >= 4 &&
267 results[2].trim().startsWith("queuing is enabled") &&
268 results[3].trim().startsWith("printing is enabled"))) {
269 return PrinterIsAcceptingJobs.ACCEPTING_JOBS ;
270 }
271 }
272 }
273 return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS ;
274 }
275
276 private PrinterIsAcceptingJobs getPrinterIsAcceptingJobs() {
277 if (UnixPrintServiceLookup.isSysV()) {
278 return getPrinterIsAcceptingJobsSysV();
279 } else if (UnixPrintServiceLookup.isBSD()) {
280 return getPrinterIsAcceptingJobsBSD();
281 } else {
282 return PrinterIsAcceptingJobs.ACCEPTING_JOBS;
283 }
284 }
285
286 private PrinterState getPrinterState() {
287 if (isInvalid) {
288 return PrinterState.STOPPED;
289 } else {
290 return null;
291 }
292 }
293
294 private PrinterStateReasons getPrinterStateReasons() {
295 if (isInvalid) {
296 PrinterStateReasons psr = new PrinterStateReasons();
297 psr.put(PrinterStateReason.SHUTDOWN, Severity.ERROR);
298 return psr;
299 } else {
300 return null;
301 }
302 }
303
304 private QueuedJobCount getQueuedJobCountSysV() {
305 String command = "/usr/bin/lpstat -R " + printer;
306 String results[]= UnixPrintServiceLookup.execCmd(command);
307 int qlen = (results == null) ? 0 : results.length;
308
309 return new QueuedJobCount(qlen);
310 }
311
312 private QueuedJobCount getQueuedJobCountBSD() {
313 if (UnixPrintServiceLookup.cmdIndex ==
314 UnixPrintServiceLookup.UNINITIALIZED) {
315
316 UnixPrintServiceLookup.cmdIndex =
317 UnixPrintServiceLookup.getBSDCommandIndex();
318 }
319
320 int qlen = 0;
321 String command = "/usr/sbin/lpc status " + printer
322 + lpcQueueCom[UnixPrintServiceLookup.cmdIndex];
323 String results[] = UnixPrintServiceLookup.execCmd(command);
324
325 if (results != null && results.length > 0) {
326 String queued;
327 if (UnixPrintServiceLookup.cmdIndex ==
328 UnixPrintServiceLookup.BSD_LPD_NG) {
329 queued = results[0];
330 } else {
331 queued = results[3].trim();
332 if (queued.startsWith("no")) {
333 return new QueuedJobCount(0);
334 } else {
335 queued = queued.substring(0, queued.indexOf(' '));
336 }
337 }
338
339 try {
340 qlen = Integer.parseInt(queued);
341 } catch (NumberFormatException e) {
342 }
343 }
344
345 return new QueuedJobCount(qlen);
346 }
347
348 private QueuedJobCount getQueuedJobCount() {
349 if (UnixPrintServiceLookup.isSysV()) {
350 return getQueuedJobCountSysV();
351 } else if (UnixPrintServiceLookup.isBSD()) {
352 return getQueuedJobCountBSD();
353 } else {
354 return new QueuedJobCount(0);
355 }
356 }
357
358 private PrintServiceAttributeSet getSysVServiceAttributes() {
359 PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();
360 attrs.add(getQueuedJobCountSysV());
361 attrs.add(getPrinterIsAcceptingJobsSysV());
362 return attrs;
363 }
364
365 private PrintServiceAttributeSet getBSDServiceAttributes() {
366 PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();
367 attrs.add(getQueuedJobCountBSD());
368 attrs.add(getPrinterIsAcceptingJobsBSD());
369 return attrs;
370 }
371
372 private boolean isSupportedCopies(Copies copies) {
373 int numCopies = copies.getValue();
374 return (numCopies > 0 && numCopies < MAXCOPIES);
375 }
376
377 private boolean isSupportedMedia(MediaSizeName msn) {
378 for (int i=0; i<mediaSizes.length; i++) {
379 if (msn.equals(mediaSizes[i])) {
380 return true;
381 }
382 }
383 return false;
384 }
385
386 public DocPrintJob createPrintJob() {
387 SecurityManager security = System.getSecurityManager();
388 if (security != null) {
389 security.checkPrintJobAccess();
390 }
391 return new UnixPrintJob(this);
392 }
393
394 private PrintServiceAttributeSet getDynamicAttributes() {
395 if (UnixPrintServiceLookup.isSysV()) {
396 return getSysVServiceAttributes();
397 } else {
398 return getBSDServiceAttributes();
399 }
400 }
401
402 public PrintServiceAttributeSet getUpdatedAttributes() {
403 PrintServiceAttributeSet currSet = getDynamicAttributes();
404 if (lastSet == null) {
405 lastSet = currSet;
406 return AttributeSetUtilities.unmodifiableView(currSet);
407 } else {
408 PrintServiceAttributeSet updates =
409 new HashPrintServiceAttributeSet();
410 Attribute []attrs = currSet.toArray();
411 Attribute attr;
412 for (int i=0; i<attrs.length; i++) {
413 attr = attrs[i];
414 if (!lastSet.containsValue(attr)) {
415 updates.add(attr);
416 }
417 }
418 lastSet = currSet;
419 return AttributeSetUtilities.unmodifiableView(updates);
420 }
421 }
422
423 public void wakeNotifier() {
424 synchronized (this) {
425 if (notifier != null) {
426 notifier.wake();
427 }
428 }
429 }
430
431 public void addPrintServiceAttributeListener(
432 PrintServiceAttributeListener listener) {
433 synchronized (this) {
434 if (listener == null) {
435 return;
436 }
437 if (notifier == null) {
438 notifier = new ServiceNotifier(this);
439 }
440 notifier.addListener(listener);
441 }
442 }
443
444 public void removePrintServiceAttributeListener(
445 PrintServiceAttributeListener listener) {
446 synchronized (this) {
447 if (listener == null || notifier == null ) {
448 return;
449 }
450 notifier.removeListener(listener);
451 if (notifier.isEmpty()) {
452 notifier.stopNotifier();
453 notifier = null;
454 }
455 }
456 }
457
458 public <T extends PrintServiceAttribute>
459 T getAttribute(Class<T> category)
460 {
461 if (category == null) {
462 throw new NullPointerException("category");
463 }
464 if (!(PrintServiceAttribute.class.isAssignableFrom(category))) {
465 throw new IllegalArgumentException("Not a PrintServiceAttribute");
466 }
467
468 if (category == PrinterName.class) {
469 return (T)getPrinterName();
470 } else if (category == PrinterState.class) {
471 return (T)getPrinterState();
472 } else if (category == PrinterStateReasons.class) {
473 return (T)getPrinterStateReasons();
474 } else if (category == QueuedJobCount.class) {
475 return (T)getQueuedJobCount();
476 } else if (category == PrinterIsAcceptingJobs.class) {
477 return (T)getPrinterIsAcceptingJobs();
478 } else {
479 return null;
480 }
481 }
482
483 public PrintServiceAttributeSet getAttributes() {
484 PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();
485 attrs.add(getPrinterName());
486 attrs.add(getPrinterIsAcceptingJobs());
487 PrinterState prnState = getPrinterState();
488 if (prnState != null) {
489 attrs.add(prnState);
490 }
491 PrinterStateReasons prnStateReasons = getPrinterStateReasons();
492 if (prnStateReasons != null) {
493 attrs.add(prnStateReasons);
494 }
495 attrs.add(getQueuedJobCount());
496 return AttributeSetUtilities.unmodifiableView(attrs);
497 }
498
499 private void initSupportedDocFlavors() {
500 String hostEnc = DocFlavor.hostEncoding.toLowerCase(Locale.ENGLISH);
501 if (!hostEnc.equals("utf-8") && !hostEnc.equals("utf-16") &&
502 !hostEnc.equals("utf-16be") && !hostEnc.equals("utf-16le") &&
503 !hostEnc.equals("us-ascii")) {
504
505 int len = supportedDocFlavorsInit.length;
506 DocFlavor[] flavors =
507 new DocFlavor[len + supportedHostDocFlavors.length];
508 // copy host encoding flavors
509 System.arraycopy(supportedHostDocFlavors, 0, flavors,
510 len, supportedHostDocFlavors.length);
511 System.arraycopy(supportedDocFlavorsInit, 0, flavors, 0, len);
512
513 supportedDocFlavors = flavors;
514 } else {
515 supportedDocFlavors = supportedDocFlavorsInit;
516 }
517 }
518
519 public DocFlavor[] getSupportedDocFlavors() {
520 if (supportedDocFlavors == null) {
521 initSupportedDocFlavors();
522 }
523 int len = supportedDocFlavors.length;
524 DocFlavor[] flavors = new DocFlavor[len];
525 System.arraycopy(supportedDocFlavors, 0, flavors, 0, len);
526
527 return flavors;
528 }
529
530 public boolean isDocFlavorSupported(DocFlavor flavor) {
531 if (supportedDocFlavors == null) {
532 initSupportedDocFlavors();
533 }
534 for (int f=0; f<supportedDocFlavors.length; f++) {
535 if (flavor.equals(supportedDocFlavors[f])) {
536 return true;
537 }
538 }
539 return false;
540 }
541
542 public Class[] getSupportedAttributeCategories() {
543 int totalCats = otherAttrCats.length;
544 Class [] cats = new Class[totalCats];
545 System.arraycopy(otherAttrCats, 0, cats, 0, otherAttrCats.length);
546 return cats;
547 }
548
549 public boolean
550 isAttributeCategorySupported(Class<? extends Attribute> category)
551 {
552 if (category == null) {
553 throw new NullPointerException("null category");
554 }
555 if (!(Attribute.class.isAssignableFrom(category))) {
556 throw new IllegalArgumentException(category +
557 " is not an Attribute");
558 }
559
560 for (int i=0;i<otherAttrCats.length;i++) {
561 if (category == otherAttrCats[i]) {
562 return true;
563 }
564 }
565 return false;
566 }
567
568 /* return defaults for all attributes for which there is a default
569 * value
570 */
571 public Object
572 getDefaultAttributeValue(Class<? extends Attribute> category)
573 {
574 if (category == null) {
575 throw new NullPointerException("null category");
576 }
577 if (!Attribute.class.isAssignableFrom(category)) {
578 throw new IllegalArgumentException(category +
579 " is not an Attribute");
580 }
581
582 if (!isAttributeCategorySupported(category)) {
583 return null;
584 }
585
586 if (category == Copies.class) {
587 return new Copies(1);
588 } else if (category == Chromaticity.class) {
589 return Chromaticity.COLOR;
590 } else if (category == Destination.class) {
591 try {
592 return new Destination((new File("out.ps")).toURI());
593 } catch (SecurityException se) {
594 try {
595 return new Destination(new URI("file:out.ps"));
596 } catch (URISyntaxException e) {
597 return null;
598 }
599 }
600 } else if (category == Fidelity.class) {
601 return Fidelity.FIDELITY_FALSE;
602 } else if (category == JobName.class) {
603 return new JobName("Java Printing", null);
604 } else if (category == JobSheets.class) {
605 return JobSheets.STANDARD;
606 } else if (category == Media.class) {
607 String defaultCountry = Locale.getDefault().getCountry();
608 if (defaultCountry != null &&
609 (defaultCountry.equals("") ||
610 defaultCountry.equals(Locale.US.getCountry()) ||
611 defaultCountry.equals(Locale.CANADA.getCountry()))) {
612 return MediaSizeName.NA_LETTER;
613 } else {
614 return MediaSizeName.ISO_A4;
615 }
616 } else if (category == MediaPrintableArea.class) {
617 String defaultCountry = Locale.getDefault().getCountry();
618 float iw, ih;
619 if (defaultCountry != null &&
620 (defaultCountry.equals("") ||
621 defaultCountry.equals(Locale.US.getCountry()) ||
622 defaultCountry.equals(Locale.CANADA.getCountry()))) {
623 iw = MediaSize.NA.LETTER.getX(Size2DSyntax.INCH) - 0.5f;
624 ih = MediaSize.NA.LETTER.getY(Size2DSyntax.INCH) - 0.5f;
625 } else {
626 iw = MediaSize.ISO.A4.getX(Size2DSyntax.INCH) - 0.5f;
627 ih = MediaSize.ISO.A4.getY(Size2DSyntax.INCH) - 0.5f;
628 }
629 return new MediaPrintableArea(0.25f, 0.25f, iw, ih,
630 MediaPrintableArea.INCH);
631 } else if (category == OrientationRequested.class) {
632 return OrientationRequested.PORTRAIT;
633 } else if (category == PageRanges.class) {
634 return new PageRanges(1, Integer.MAX_VALUE);
635 } else if (category == RequestingUserName.class) {
636 String userName = "";
637 try {
638 userName = System.getProperty("user.name", "");
639 } catch (SecurityException se) {
640 }
641 return new RequestingUserName(userName, null);
642 } else if (category == SheetCollate.class) {
643 return SheetCollate.UNCOLLATED;
644 } else if (category == Sides.class) {
645 return Sides.ONE_SIDED;
646 } else
647 return null;
648 }
649
650
651 private boolean isAutoSense(DocFlavor flavor) {
652 if (flavor.equals(DocFlavor.BYTE_ARRAY.AUTOSENSE) ||
653 flavor.equals(DocFlavor.INPUT_STREAM.AUTOSENSE) ||
654 flavor.equals(DocFlavor.URL.AUTOSENSE)) {
655 return true;
656 }
657 else {
658 return false;
659 }
660 }
661
662 public Object
663 getSupportedAttributeValues(Class<? extends Attribute> category,
664 DocFlavor flavor,
665 AttributeSet attributes)
666 {
667
668 if (category == null) {
669 throw new NullPointerException("null category");
670 }
671 if (!Attribute.class.isAssignableFrom(category)) {
672 throw new IllegalArgumentException(category +
673 " does not implement Attribute");
674 }
675 if (flavor != null) {
676 if (!isDocFlavorSupported(flavor)) {
677 throw new IllegalArgumentException(flavor +
678 " is an unsupported flavor");
679 } else if (isAutoSense(flavor)) {
680 return null;
681 }
682 }
683
684 if (!isAttributeCategorySupported(category)) {
685 return null;
686 }
687
688 if (category == Chromaticity.class) {
689 if (flavor == null ||
690 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
691 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
692 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
693 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
694 flavor.equals(DocFlavor.URL.GIF) ||
695 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
696 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
697 flavor.equals(DocFlavor.URL.JPEG) ||
698 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
699 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
700 flavor.equals(DocFlavor.URL.PNG)) {
701
702 Chromaticity[]arr = new Chromaticity[1];
703 arr[0] = Chromaticity.COLOR;
704 return (arr);
705 } else {
706 return null;
707 }
708 } else if (category == Destination.class) {
709 try {
710 return new Destination((new File("out.ps")).toURI());
711 } catch (SecurityException se) {
712 try {
713 return new Destination(new URI("file:out.ps"));
714 } catch (URISyntaxException e) {
715 return null;
716 }
717 }
718 } else if (category == JobName.class) {
719 return new JobName("Java Printing", null);
720 } else if (category == JobSheets.class) {
721 JobSheets arr[] = new JobSheets[2];
722 arr[0] = JobSheets.NONE;
723 arr[1] = JobSheets.STANDARD;
724 return arr;
725 } else if (category == RequestingUserName.class) {
726 String userName = "";
727 try {
728 userName = System.getProperty("user.name", "");
729 } catch (SecurityException se) {
730 }
731 return new RequestingUserName(userName, null);
732 } else if (category == OrientationRequested.class) {
733 if (flavor == null ||
734 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
735 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
736 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
737 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
738 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
739 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
740 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
741 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
742 flavor.equals(DocFlavor.URL.GIF) ||
743 flavor.equals(DocFlavor.URL.JPEG) ||
744 flavor.equals(DocFlavor.URL.PNG)) {
745 OrientationRequested []arr = new OrientationRequested[3];
746 arr[0] = OrientationRequested.PORTRAIT;
747 arr[1] = OrientationRequested.LANDSCAPE;
748 arr[2] = OrientationRequested.REVERSE_LANDSCAPE;
749 return arr;
750 } else {
751 return null;
752 }
753 } else if ((category == Copies.class) ||
754 (category == CopiesSupported.class)) {
755 return new CopiesSupported(1, MAXCOPIES);
756 } else if (category == Media.class) {
757 Media []arr = new Media[mediaSizes.length];
758 System.arraycopy(mediaSizes, 0, arr, 0, mediaSizes.length);
759 return arr;
760 } else if (category == Fidelity.class) {
761 Fidelity []arr = new Fidelity[2];
762 arr[0] = Fidelity.FIDELITY_FALSE;
763 arr[1] = Fidelity.FIDELITY_TRUE;
764 return arr;
765 } else if (category == MediaPrintableArea.class) {
766 /* The code below implements the behaviour that if no Media or
767 * MediaSize attribute is specified, return an array of
768 * MediaPrintableArea, one for each supported Media.
769 * If a MediaSize is specified, return a MPA consistent for that,
770 * and if a Media is specified locate its MediaSize and return
771 * its MPA, and if none is found, return an MPA for the default
772 * Media for this service.
773 */
774 if (attributes == null) {
775 return getAllPrintableAreas();
776 }
777 MediaSize mediaSize = (MediaSize)attributes.get(MediaSize.class);
778 Media media = (Media)attributes.get(Media.class);
779 MediaPrintableArea []arr = new MediaPrintableArea[1];
780 if (mediaSize == null) {
781 if (media instanceof MediaSizeName) {
782 MediaSizeName msn = (MediaSizeName)media;
783 mediaSize = MediaSize.getMediaSizeForName(msn);
784 if (mediaSize == null) {
785 /* try to get a size from the default media */
786 media = (Media)getDefaultAttributeValue(Media.class);
787 if (media instanceof MediaSizeName) {
788 msn = (MediaSizeName)media;
789 mediaSize = MediaSize.getMediaSizeForName(msn);
790 }
791 if (mediaSize == null) {
792 /* shouldn't happen, return a default */
793 arr[0] = new MediaPrintableArea(0.25f, 0.25f,
794 8f, 10.5f,
795 MediaSize.INCH);
796 return arr;
797 }
798 }
799 } else {
800 return getAllPrintableAreas();
801 }
802 }
803 /* If reach here MediaSize is non-null */
804 assert mediaSize != null;
805 arr[0] = new MediaPrintableArea(0.25f, 0.25f,
806 mediaSize.getX(MediaSize.INCH)-0.5f,
807 mediaSize.getY(MediaSize.INCH)-0.5f,
808 MediaSize.INCH);
809 return arr;
810 } else if (category == PageRanges.class) {
811 if (flavor == null ||
812 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
813 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
814 PageRanges []arr = new PageRanges[1];
815 arr[0] = new PageRanges(1, Integer.MAX_VALUE);
816 return arr;
817 } else {
818 return null;
819 }
820 } else if (category == SheetCollate.class) {
821 if (flavor == null ||
822 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
823 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
824 SheetCollate []arr = new SheetCollate[2];
825 arr[0] = SheetCollate.UNCOLLATED;
826 arr[1] = SheetCollate.COLLATED;
827 return arr;
828 } else {
829 return null;
830 }
831 } else if (category == Sides.class) {
832 if (flavor == null ||
833 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
834 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {
835 Sides []arr = new Sides[3];
836 arr[0] = Sides.ONE_SIDED;
837 arr[1] = Sides.TWO_SIDED_LONG_EDGE;
838 arr[2] = Sides.TWO_SIDED_SHORT_EDGE;
839 return arr;
840 } else {
841 return null;
842 }
843 } else {
844 return null;
845 }
846 }
847
848 private static MediaPrintableArea[] mpas = null;
849 private MediaPrintableArea[] getAllPrintableAreas() {
850
851 if (mpas == null) {
852 Media[] media = (Media[])getSupportedAttributeValues(Media.class,
853 null, null);
854 mpas = new MediaPrintableArea[media.length];
855 for (int i=0; i< mpas.length; i++) {
856 if (media[i] instanceof MediaSizeName) {
857 MediaSizeName msn = (MediaSizeName)media[i];
858 MediaSize mediaSize = MediaSize.getMediaSizeForName(msn);
859 if (mediaSize == null) {
860 mpas[i] = (MediaPrintableArea)
861 getDefaultAttributeValue(MediaPrintableArea.class);
862 } else {
863 mpas[i] = new MediaPrintableArea(0.25f, 0.25f,
864 mediaSize.getX(MediaSize.INCH)-0.5f,
865 mediaSize.getY(MediaSize.INCH)-0.5f,
866 MediaSize.INCH);
867 }
868 }
869 }
870 }
871 MediaPrintableArea[] mpasCopy = new MediaPrintableArea[mpas.length];
872 System.arraycopy(mpas, 0, mpasCopy, 0, mpas.length);
873 return mpasCopy;
874 }
875
876 /* Is this one of the flavors that this service explicitly
877 * generates postscript for, and so can control how it is rendered?
878 */
879 private boolean isServiceFormattedFlavor(DocFlavor flavor) {
880 return
881 flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
882 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||
883 flavor.equals(DocFlavor.BYTE_ARRAY.GIF) ||
884 flavor.equals(DocFlavor.INPUT_STREAM.GIF) ||
885 flavor.equals(DocFlavor.URL.GIF) ||
886 flavor.equals(DocFlavor.BYTE_ARRAY.JPEG) ||
887 flavor.equals(DocFlavor.INPUT_STREAM.JPEG) ||
888 flavor.equals(DocFlavor.URL.JPEG) ||
889 flavor.equals(DocFlavor.BYTE_ARRAY.PNG) ||
890 flavor.equals(DocFlavor.INPUT_STREAM.PNG) ||
891 flavor.equals(DocFlavor.URL.PNG);
892 }
893
894 public boolean isAttributeValueSupported(Attribute attr,
895 DocFlavor flavor,
896 AttributeSet attributes) {
897 if (attr == null) {
898 throw new NullPointerException("null attribute");
899 }
900 if (flavor != null) {
901 if (!isDocFlavorSupported(flavor)) {
902 throw new IllegalArgumentException(flavor +
903 " is an unsupported flavor");
904 } else if (isAutoSense(flavor)) {
905 return false;
906 }
907 }
908 Class category = attr.getCategory();
909 if (!isAttributeCategorySupported(category)) {
910 return false;
911 }
912 else if (attr.getCategory() == Chromaticity.class) {
913 if (flavor == null || isServiceFormattedFlavor(flavor)) {
914 return attr == Chromaticity.COLOR;
915 } else {
916 return false;
917 }
918 }
919 else if (attr.getCategory() == Copies.class) {
920 return
921 (flavor == null || isServiceFormattedFlavor(flavor)) &&
922 isSupportedCopies((Copies)attr);
923 } else if (attr.getCategory() == Destination.class) {
924 URI uri = ((Destination)attr).getURI();
925 if ("file".equals(uri.getScheme()) &&
926 !(uri.getSchemeSpecificPart().equals(""))) {
927 return true;
928 } else {
929 return false;
930 }
931 } else if (attr.getCategory() == Media.class) {
932 if (attr instanceof MediaSizeName) {
933 return isSupportedMedia((MediaSizeName)attr);
934 } else {
935 return false;
936 }
937 } else if (attr.getCategory() == OrientationRequested.class) {
938 if (attr == OrientationRequested.REVERSE_PORTRAIT ||
939 (flavor != null) &&
940 !isServiceFormattedFlavor(flavor)) {
941 return false;
942 }
943 } else if (attr.getCategory() == PageRanges.class) {
944 if (flavor != null &&
945 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
946 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
947 return false;
948 }
949 } else if (attr.getCategory() == SheetCollate.class) {
950 if (flavor != null &&
951 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
952 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
953 return false;
954 }
955 } else if (attr.getCategory() == Sides.class) {
956 if (flavor != null &&
957 !(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||
958 flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {
959 return false;
960 }
961 }
962 return true;
963 }
964
965 public AttributeSet getUnsupportedAttributes(DocFlavor flavor,
966 AttributeSet attributes) {
967
968 if (flavor != null && !isDocFlavorSupported(flavor)) {
969 throw new IllegalArgumentException("flavor " + flavor +
970 "is not supported");
971 }
972
973 if (attributes == null) {
974 return null;
975 }
976
977 Attribute attr;
978 AttributeSet unsupp = new HashAttributeSet();
979 Attribute []attrs = attributes.toArray();
980 for (int i=0; i<attrs.length; i++) {
981 try {
982 attr = attrs[i];
983 if (!isAttributeCategorySupported(attr.getCategory())) {
984 unsupp.add(attr);
985 } else if (!isAttributeValueSupported(attr, flavor,
986 attributes)) {
987 unsupp.add(attr);
988 }
989 } catch (ClassCastException e) {
990 }
991 }
992 if (unsupp.isEmpty()) {
993 return null;
994 } else {
995 return unsupp;
996 }
997 }
998
999 public ServiceUIFactory getServiceUIFactory() {
1000 return null;
1001 }
1002
1003 public String toString() {
1004 return "Unix Printer : " + getName();
1005 }
1006
1007 public boolean equals(Object obj) {
1008 return (obj == this ||
1009 (obj instanceof UnixPrintService &&
1010 ((UnixPrintService)obj).getName().equals(getName())));
1011 }
1012
1013 public int hashCode() {
1014 return this.getClass().hashCode()+getName().hashCode();
1015 }
1016
1017 public boolean usesClass(Class c) {
1018 return (c == sun.print.PSPrinterJob.class);
1019 }
1020
1021}