1 /* 2 * Copyright (c) 2000, 2012, 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.BufferedReader; 29 import java.io.FileInputStream; 30 import java.io.InputStream; 31 import java.io.InputStreamReader; 32 import java.io.IOException; 33 import java.util.ArrayList; 34 import java.util.Vector; 35 import java.security.AccessController; 36 import java.security.PrivilegedActionException; 37 import java.security.PrivilegedExceptionAction; 38 import javax.print.DocFlavor; 39 import javax.print.MultiDocPrintService; 40 import javax.print.PrintService; 41 import javax.print.PrintServiceLookup; 42 import javax.print.attribute.Attribute; 43 import javax.print.attribute.AttributeSet; 44 import javax.print.attribute.HashPrintRequestAttributeSet; 45 import javax.print.attribute.HashPrintServiceAttributeSet; 46 import javax.print.attribute.PrintRequestAttribute; 47 import javax.print.attribute.PrintRequestAttributeSet; 48 import javax.print.attribute.PrintServiceAttribute; 49 import javax.print.attribute.PrintServiceAttributeSet; 50 import javax.print.attribute.standard.PrinterName; 51 import java.io.File; 52 import java.io.FileReader; 53 import java.net.URL; 54 55 /* 56 * Remind: This class uses solaris commands. We also need a linux 57 * version 58 */ 59 public class UnixPrintServiceLookup extends PrintServiceLookup 60 implements BackgroundServiceLookup, Runnable { 61 62 /* Remind: the current implementation is static, as its assumed 63 * its preferable to minimise creation of PrintService instances. 64 * Later we should add logic to add/remove services on the fly which 65 * will take a hit of needing to regather the list of services. 66 */ 67 private String defaultPrinter; 68 private PrintService defaultPrintService; 69 private PrintService[] printServices; /* includes the default printer */ 70 private Vector lookupListeners = null; 71 private static String debugPrefix = "UnixPrintServiceLookup>> "; 72 private static boolean pollServices = true; 73 private static final int DEFAULT_MINREFRESH = 120; // 2 minutes 74 private static int minRefreshTime = DEFAULT_MINREFRESH; 75 76 77 static String osname; 78 79 static { 80 /* The system property "sun.java2d.print.polling" 81 * can be used to force the printing code to poll or not poll 82 * for PrintServices. 83 */ 84 String pollStr = java.security.AccessController.doPrivileged( 85 new sun.security.action.GetPropertyAction("sun.java2d.print.polling")); 86 87 if (pollStr != null) { 88 if (pollStr.equalsIgnoreCase("true")) { 89 pollServices = true; 90 } else if (pollStr.equalsIgnoreCase("false")) { 91 pollServices = false; 92 } 93 } 94 95 /* The system property "sun.java2d.print.minRefreshTime" 96 * can be used to specify minimum refresh time (in seconds) 97 * for polling PrintServices. The default is 120. 98 */ 99 String refreshTimeStr = java.security.AccessController.doPrivileged( 100 new sun.security.action.GetPropertyAction( 101 "sun.java2d.print.minRefreshTime")); 102 103 if (refreshTimeStr != null) { 104 try { 105 minRefreshTime = (new Integer(refreshTimeStr)).intValue(); 106 } catch (NumberFormatException e) { 107 } 108 if (minRefreshTime < DEFAULT_MINREFRESH) { 109 minRefreshTime = DEFAULT_MINREFRESH; 110 } 111 } 112 113 osname = java.security.AccessController.doPrivileged( 114 new sun.security.action.GetPropertyAction("os.name")); 115 } 116 117 static boolean isSysV() { 118 return osname.equals("SunOS"); 119 } 120 121 static boolean isBSD() { 122 return (osname.equals("Linux") || 123 osname.contains("OS X")); 124 } 125 126 static final int UNINITIALIZED = -1; 127 static final int BSD_LPD = 0; 128 static final int BSD_LPD_NG = 1; 129 130 static int cmdIndex = UNINITIALIZED; 131 132 String[] lpcFirstCom = { 133 "/usr/sbin/lpc status | grep : | sed -ne '1,1 s/://p'", 134 "/usr/sbin/lpc status | grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}'" 135 }; 136 137 String[] lpcAllCom = { 138 "/usr/sbin/lpc status all | grep : | sed -e 's/://'", 139 "/usr/sbin/lpc status all | grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}' | sort" 140 }; 141 142 String[] lpcNameCom = { 143 "| grep : | sed -ne 's/://p'", 144 "| grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}'" 145 }; 146 147 148 static int getBSDCommandIndex() { 149 String command = "/usr/sbin/lpc status all"; 150 String[] names = execCmd(command); 151 152 if ((names == null) || (names.length == 0)) { 153 return BSD_LPD_NG; 154 } 155 156 for (int i=0; i<names.length; i++) { 157 if (names[i].indexOf('@') != -1) { 158 return BSD_LPD_NG; 159 } 160 } 161 162 return BSD_LPD; 163 } 164 165 166 public UnixPrintServiceLookup() { 167 // start the printer listener thread 168 if (pollServices) { 169 PrinterChangeListener thr = new PrinterChangeListener(); 170 thr.setDaemon(true); 171 thr.start(); 172 IPPPrintService.debug_println(debugPrefix+"polling turned on"); 173 } 174 } 175 176 /* Want the PrintService which is default print service to have 177 * equality of reference with the equivalent in list of print services 178 * This isn't required by the API and there's a risk doing this will 179 * lead people to assume its guaranteed. 180 */ 181 public synchronized PrintService[] getPrintServices() { 182 SecurityManager security = System.getSecurityManager(); 183 if (security != null) { 184 security.checkPrintJobAccess(); 185 } 186 187 if (printServices == null || !pollServices) { 188 refreshServices(); 189 } 190 if (printServices == null) { 191 return new PrintService[0]; 192 } else { 193 return printServices; 194 } 195 } 196 197 198 // refreshes "printServices" 199 public synchronized void refreshServices() { 200 /* excludes the default printer */ 201 String[] printers = null; // array of printer names 202 String[] printerURIs = null; //array of printer URIs 203 204 getDefaultPrintService(); 205 if (CUPSPrinter.isCupsRunning()) { 206 printerURIs = CUPSPrinter.getAllPrinters(); 207 if ((printerURIs != null) && (printerURIs.length > 0)) { 208 printers = new String[printerURIs.length]; 209 for (int i=0; i<printerURIs.length; i++) { 210 int lastIndex = printerURIs[i].lastIndexOf("/"); 211 printers[i] = printerURIs[i].substring(lastIndex+1); 212 } 213 } 214 } else { 215 if (isSysV()) { 216 printers = getAllPrinterNamesSysV(); 217 } else { //BSD 218 printers = getAllPrinterNamesBSD(); 219 } 220 } 221 222 if (printers == null) { 223 if (defaultPrintService != null) { 224 printServices = new PrintService[1]; 225 printServices[0] = defaultPrintService; 226 } else { 227 printServices = null; 228 } 229 return; 230 } 231 232 ArrayList printerList = new ArrayList(); 233 int defaultIndex = -1; 234 for (int p=0; p<printers.length; p++) { 235 if (printers[p] == null) { 236 continue; 237 } 238 if ((defaultPrintService != null) 239 && printers[p].equals(defaultPrintService.getName())) { 240 printerList.add(defaultPrintService); 241 defaultIndex = printerList.size() - 1; 242 } else { 243 if (printServices == null) { 244 IPPPrintService.debug_println(debugPrefix+ 245 "total# of printers = "+printers.length); 246 247 if (CUPSPrinter.isCupsRunning()) { 248 try { 249 printerList.add(new IPPPrintService(printers[p], 250 printerURIs[p], 251 true)); 252 } catch (Exception e) { 253 IPPPrintService.debug_println(debugPrefix+ 254 " getAllPrinters Exception "+ 255 e); 256 257 } 258 } else { 259 printerList.add(new UnixPrintService(printers[p])); 260 } 261 } else { 262 int j; 263 for (j=0; j<printServices.length; j++) { 264 if ((printServices[j] != null) && 265 (printers[p].equals(printServices[j].getName()))) { 266 printerList.add(printServices[j]); 267 printServices[j] = null; 268 break; 269 } 270 } 271 272 if (j == printServices.length) { // not found? 273 if (CUPSPrinter.isCupsRunning()) { 274 try { 275 printerList.add(new IPPPrintService( 276 printers[p], 277 printerURIs[p], 278 true)); 279 } catch (Exception e) { 280 IPPPrintService.debug_println(debugPrefix+ 281 " getAllPrinters Exception "+ 282 e); 283 284 } 285 } else { 286 printerList.add(new UnixPrintService(printers[p])); 287 } 288 } 289 } 290 } 291 } 292 293 // Look for deleted services and invalidate these 294 if (printServices != null) { 295 for (int j=0; j < printServices.length; j++) { 296 if ((printServices[j] instanceof UnixPrintService) && 297 (!printServices[j].equals(defaultPrintService))) { 298 ((UnixPrintService)printServices[j]).invalidateService(); 299 } 300 } 301 } 302 303 //if defaultService is not found in printerList 304 if (defaultIndex == -1 && defaultPrintService != null) { 305 //add default to the list 306 printerList.add(defaultPrintService); 307 defaultIndex = printerList.size() - 1; 308 } 309 310 printServices = (PrintService[])printerList.toArray( 311 new PrintService[] {}); 312 313 // swap default with the first in the list 314 if (defaultIndex > 0) { 315 PrintService saveService = printServices[0]; 316 printServices[0] = printServices[defaultIndex]; 317 printServices[defaultIndex] = saveService; 318 } 319 } 320 321 private boolean matchesAttributes(PrintService service, 322 PrintServiceAttributeSet attributes) { 323 324 Attribute [] attrs = attributes.toArray(); 325 Attribute serviceAttr; 326 for (int i=0; i<attrs.length; i++) { 327 serviceAttr 328 = service.getAttribute((Class<PrintServiceAttribute>)attrs[i].getCategory()); 329 if (serviceAttr == null || !serviceAttr.equals(attrs[i])) { 330 return false; 331 } 332 } 333 return true; 334 } 335 336 /* This checks for validity of the printer name before passing as 337 * parameter to a shell command. 338 */ 339 private boolean checkPrinterName(String s) { 340 char c; 341 342 for (int i=0; i < s.length(); i++) { 343 c = s.charAt(i); 344 if (Character.isLetterOrDigit(c) || 345 c == '-' || c == '_' || c == '.' || c == '/') { 346 continue; 347 } else { 348 return false; 349 } 350 } 351 return true; 352 } 353 354 /* On a network with many (hundreds) of network printers, it 355 * can save several seconds if you know all you want is a particular 356 * printer, to ask for that printer rather than retrieving all printers. 357 */ 358 private PrintService getServiceByName(PrinterName nameAttr) { 359 String name = nameAttr.getValue(); 360 PrintService printer = null; 361 if (name == null || name.equals("") || !checkPrinterName(name)) { 362 return null; 363 } 364 if (isSysV()) { 365 printer = getNamedPrinterNameSysV(name); 366 } else { 367 printer = getNamedPrinterNameBSD(name); 368 } 369 return printer; 370 } 371 372 private PrintService[] 373 getPrintServices(PrintServiceAttributeSet serviceSet) { 374 375 if (serviceSet == null || serviceSet.isEmpty()) { 376 return getPrintServices(); 377 } 378 379 /* Typically expect that if a service attribute is specified that 380 * its a printer name and there ought to be only one match. 381 * Directly retrieve that service and confirm 382 * that it meets the other requirements. 383 * If printer name isn't mentioned then go a slow path checking 384 * all printers if they meet the reqiremements. 385 */ 386 PrintService[] services; 387 PrinterName name = (PrinterName)serviceSet.get(PrinterName.class); 388 PrintService defService; 389 if (name != null && (defService = getDefaultPrintService()) != null) { 390 /* To avoid execing a unix command see if the client is asking 391 * for the default printer by name, since we already have that 392 * initialised. 393 */ 394 395 PrinterName defName = 396 (PrinterName)defService.getAttribute(PrinterName.class); 397 398 if (defName != null && name.equals(defName)) { 399 if (matchesAttributes(defService, serviceSet)) { 400 services = new PrintService[1]; 401 services[0] = defService; 402 return services; 403 } else { 404 return new PrintService[0]; 405 } 406 } else { 407 /* Its not the default service */ 408 PrintService service = getServiceByName(name); 409 if (service != null && 410 matchesAttributes(service, serviceSet)) { 411 services = new PrintService[1]; 412 services[0] = service; 413 return services; 414 } else { 415 return new PrintService[0]; 416 } 417 } 418 } else { 419 /* specified service attributes don't include a name.*/ 420 Vector matchedServices = new Vector(); 421 services = getPrintServices(); 422 for (int i = 0; i< services.length; i++) { 423 if (matchesAttributes(services[i], serviceSet)) { 424 matchedServices.add(services[i]); 425 } 426 } 427 services = new PrintService[matchedServices.size()]; 428 for (int i = 0; i< services.length; i++) { 429 services[i] = (PrintService)matchedServices.elementAt(i); 430 } 431 return services; 432 } 433 } 434 435 /* 436 * If service attributes are specified then there must be additional 437 * filtering. 438 */ 439 public PrintService[] getPrintServices(DocFlavor flavor, 440 AttributeSet attributes) { 441 SecurityManager security = System.getSecurityManager(); 442 if (security != null) { 443 security.checkPrintJobAccess(); 444 } 445 PrintRequestAttributeSet requestSet = null; 446 PrintServiceAttributeSet serviceSet = null; 447 448 if (attributes != null && !attributes.isEmpty()) { 449 450 requestSet = new HashPrintRequestAttributeSet(); 451 serviceSet = new HashPrintServiceAttributeSet(); 452 453 Attribute[] attrs = attributes.toArray(); 454 for (int i=0; i<attrs.length; i++) { 455 if (attrs[i] instanceof PrintRequestAttribute) { 456 requestSet.add(attrs[i]); 457 } else if (attrs[i] instanceof PrintServiceAttribute) { 458 serviceSet.add(attrs[i]); 459 } 460 } 461 } 462 463 PrintService[] services = getPrintServices(serviceSet); 464 if (services.length == 0) { 465 return services; 466 } 467 468 if (CUPSPrinter.isCupsRunning()) { 469 ArrayList matchingServices = new ArrayList(); 470 for (int i=0; i<services.length; i++) { 471 try { 472 if (services[i]. 473 getUnsupportedAttributes(flavor, requestSet) == null) { 474 matchingServices.add(services[i]); 475 } 476 } catch (IllegalArgumentException e) { 477 } 478 } 479 services = new PrintService[matchingServices.size()]; 480 return (PrintService[])matchingServices.toArray(services); 481 482 } else { 483 // We only need to compare 1 PrintService because all 484 // UnixPrintServices are the same anyway. We will not use 485 // default PrintService because it might be null. 486 PrintService service = services[0]; 487 if ((flavor == null || 488 service.isDocFlavorSupported(flavor)) && 489 service.getUnsupportedAttributes(flavor, requestSet) == null) 490 { 491 return services; 492 } else { 493 return new PrintService[0]; 494 } 495 } 496 } 497 498 /* 499 * return empty array as don't support multi docs 500 */ 501 public MultiDocPrintService[] 502 getMultiDocPrintServices(DocFlavor[] flavors, 503 AttributeSet attributes) { 504 SecurityManager security = System.getSecurityManager(); 505 if (security != null) { 506 security.checkPrintJobAccess(); 507 } 508 return new MultiDocPrintService[0]; 509 } 510 511 512 public synchronized PrintService getDefaultPrintService() { 513 SecurityManager security = System.getSecurityManager(); 514 if (security != null) { 515 security.checkPrintJobAccess(); 516 } 517 518 // clear defaultPrintService 519 defaultPrintService = null; 520 521 IPPPrintService.debug_println("isRunning ? "+ 522 (CUPSPrinter.isCupsRunning())); 523 if (CUPSPrinter.isCupsRunning()) { 524 defaultPrinter = CUPSPrinter.getDefaultPrinter(); 525 } else { 526 if (isSysV()) { 527 defaultPrinter = getDefaultPrinterNameSysV(); 528 } else { 529 defaultPrinter = getDefaultPrinterNameBSD(); 530 } 531 } 532 if (defaultPrinter == null) { 533 return null; 534 } 535 defaultPrintService = null; 536 if (printServices != null) { 537 for (int j=0; j<printServices.length; j++) { 538 if (defaultPrinter.equals(printServices[j].getName())) { 539 defaultPrintService = printServices[j]; 540 break; 541 } 542 } 543 } 544 if (defaultPrintService == null) { 545 if (CUPSPrinter.isCupsRunning()) { 546 try { 547 PrintService defaultPS = 548 new IPPPrintService(defaultPrinter, 549 new URL("http://"+ 550 CUPSPrinter.getServer()+":"+ 551 CUPSPrinter.getPort()+"/"+ 552 defaultPrinter)); 553 defaultPrintService = defaultPS; 554 } catch (Exception e) { 555 } 556 } else { 557 defaultPrintService = new UnixPrintService(defaultPrinter); 558 } 559 } 560 561 return defaultPrintService; 562 } 563 564 public synchronized void 565 getServicesInbackground(BackgroundLookupListener listener) { 566 if (printServices != null) { 567 listener.notifyServices(printServices); 568 } else { 569 if (lookupListeners == null) { 570 lookupListeners = new Vector(); 571 lookupListeners.add(listener); 572 Thread lookupThread = new Thread(this); 573 lookupThread.start(); 574 } else { 575 lookupListeners.add(listener); 576 } 577 } 578 } 579 580 /* This method isn't used in most cases because we rely on code in 581 * javax.print.PrintServiceLookup. This is needed just for the cases 582 * where those interfaces are by-passed. 583 */ 584 private PrintService[] copyOf(PrintService[] inArr) { 585 if (inArr == null || inArr.length == 0) { 586 return inArr; 587 } else { 588 PrintService []outArr = new PrintService[inArr.length]; 589 System.arraycopy(inArr, 0, outArr, 0, inArr.length); 590 return outArr; 591 } 592 } 593 594 public void run() { 595 PrintService[] services = getPrintServices(); 596 synchronized (this) { 597 BackgroundLookupListener listener; 598 for (int i=0; i<lookupListeners.size(); i++) { 599 listener = 600 (BackgroundLookupListener)lookupListeners.elementAt(i); 601 listener.notifyServices(copyOf(services)); 602 } 603 lookupListeners = null; 604 } 605 } 606 607 private String getDefaultPrinterNameBSD() { 608 if (cmdIndex == UNINITIALIZED) { 609 cmdIndex = getBSDCommandIndex(); 610 } 611 String[] names = execCmd(lpcFirstCom[cmdIndex]); 612 if (names == null || names.length == 0) { 613 return null; 614 } 615 616 if ((cmdIndex==BSD_LPD_NG) && 617 (names[0].startsWith("missingprinter"))) { 618 return null; 619 } 620 return names[0]; 621 } 622 623 private PrintService getNamedPrinterNameBSD(String name) { 624 if (cmdIndex == UNINITIALIZED) { 625 cmdIndex = getBSDCommandIndex(); 626 } 627 String command = "/usr/sbin/lpc status " + name + lpcNameCom[cmdIndex]; 628 String[] result = execCmd(command); 629 630 if (result == null || !(result[0].equals(name))) { 631 return null; 632 } 633 return new UnixPrintService(name); 634 } 635 636 private String[] getAllPrinterNamesBSD() { 637 if (cmdIndex == UNINITIALIZED) { 638 cmdIndex = getBSDCommandIndex(); 639 } 640 String[] names = execCmd(lpcAllCom[cmdIndex]); 641 if (names == null || names.length == 0) { 642 return null; 643 } 644 return names; 645 } 646 647 private String getDefaultPrinterNameSysV() { 648 String defaultPrinter = "lp"; 649 String command = "/usr/bin/lpstat -d"; 650 651 String [] names = execCmd(command); 652 if (names == null || names.length == 0) { 653 return defaultPrinter; 654 } else { 655 int index = names[0].indexOf(":"); 656 if (index == -1 || (names[0].length() <= index+1)) { 657 return null; 658 } else { 659 String name = names[0].substring(index+1).trim(); 660 if (name.length() == 0) { 661 return null; 662 } else { 663 return name; 664 } 665 } 666 } 667 } 668 669 private PrintService getNamedPrinterNameSysV(String name) { 670 671 String command = "/usr/bin/lpstat -v " + name; 672 String []result = execCmd(command); 673 674 if (result == null || result[0].indexOf("unknown printer") > 0) { 675 return null; 676 } else { 677 return new UnixPrintService(name); 678 } 679 } 680 681 private String[] getAllPrinterNamesSysV() { 682 String defaultPrinter = "lp"; 683 String command = "/usr/bin/lpstat -v|/usr/bin/expand|/usr/bin/cut -f3 -d' ' |/usr/bin/cut -f1 -d':' | /usr/bin/sort"; 684 685 String [] names = execCmd(command); 686 ArrayList printerNames = new ArrayList(); 687 for (int i=0; i < names.length; i++) { 688 if (!names[i].equals("_default") && 689 !names[i].equals(defaultPrinter) && 690 !names[i].equals("")) { 691 printerNames.add(names[i]); 692 } 693 } 694 return (String[])printerNames.toArray(new String[printerNames.size()]); 695 } 696 697 static String[] execCmd(final String command) { 698 ArrayList results = null; 699 try { 700 final String[] cmd = new String[3]; 701 if (isSysV()) { 702 cmd[0] = "/usr/bin/sh"; 703 cmd[1] = "-c"; 704 cmd[2] = "env LC_ALL=C " + command; 705 } else { 706 cmd[0] = "/bin/sh"; 707 cmd[1] = "-c"; 708 cmd[2] = "LC_ALL=C " + command; 709 } 710 711 results = (ArrayList)AccessController.doPrivileged( 712 new PrivilegedExceptionAction() { 713 public Object run() throws IOException { 714 715 Process proc; 716 BufferedReader bufferedReader = null; 717 File f = File.createTempFile("prn","xc"); 718 cmd[2] = cmd[2]+">"+f.getAbsolutePath(); 719 720 proc = Runtime.getRuntime().exec(cmd); 721 try { 722 boolean done = false; // in case of interrupt. 723 while (!done) { 724 try { 725 proc.waitFor(); 726 done = true; 727 } catch (InterruptedException e) { 728 } 729 } 730 731 if (proc.exitValue() == 0) { 732 FileReader reader = new FileReader(f); 733 bufferedReader = new BufferedReader(reader); 734 String line; 735 ArrayList results = new ArrayList(); 736 while ((line = bufferedReader.readLine()) 737 != null) { 738 results.add(line); 739 } 740 return results; 741 } 742 } finally { 743 f.delete(); 744 // promptly close all streams. 745 if (bufferedReader != null) { 746 bufferedReader.close(); 747 } 748 proc.getInputStream().close(); 749 proc.getErrorStream().close(); 750 proc.getOutputStream().close(); 751 } 752 return null; 753 } 754 }); 755 } catch (PrivilegedActionException e) { 756 } 757 if (results == null) { 758 return new String[0]; 759 } else { 760 return (String[])results.toArray(new String[results.size()]); 761 } 762 } 763 764 private class PrinterChangeListener extends Thread { 765 766 public void run() { 767 int refreshSecs; 768 while (true) { 769 try { 770 refreshServices(); 771 } catch (Exception se) { 772 IPPPrintService.debug_println(debugPrefix+"Exception in refresh thread."); 773 break; 774 } 775 776 if ((printServices != null) && 777 (printServices.length > minRefreshTime)) { 778 // compute new refresh time 1 printer = 1 sec 779 refreshSecs = printServices.length; 780 } else { 781 refreshSecs = minRefreshTime; 782 } 783 try { 784 sleep(refreshSecs * 1000); 785 } catch (InterruptedException e) { 786 break; 787 } 788 } 789 } 790 } 791 }