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