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