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