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.security.AccessController; 29 import java.util.ArrayList; 30 import javax.print.DocFlavor; 31 import javax.print.MultiDocPrintService; 32 import javax.print.PrintService; 33 import javax.print.PrintServiceLookup; 34 import javax.print.attribute.Attribute; 35 import javax.print.attribute.AttributeSet; 36 import javax.print.attribute.HashPrintRequestAttributeSet; 37 import javax.print.attribute.HashPrintServiceAttributeSet; 38 import javax.print.attribute.PrintRequestAttribute; 39 import javax.print.attribute.PrintRequestAttributeSet; 40 import javax.print.attribute.PrintServiceAttribute; 41 import javax.print.attribute.PrintServiceAttributeSet; 42 import javax.print.attribute.standard.PrinterName; 43 44 public class PrintServiceLookupProvider extends PrintServiceLookup { 45 46 private String defaultPrinter; 47 private PrintService defaultPrintService; 48 private String[] printers; /* excludes the default printer */ 49 private PrintService[] printServices; /* includes the default printer */ 50 private static boolean pollServices = true; 51 private static final int DEFAULT_MINREFRESH = 240; // 4 minutes 52 private static int minRefreshTime = DEFAULT_MINREFRESH; 53 54 static { 55 /* The system property "sun.java2d.print.polling" 56 * can be used to force the printing code to poll or not poll 57 * for PrintServices. 58 */ 59 String pollStr = java.security.AccessController.doPrivileged( 60 new sun.security.action.GetPropertyAction("sun.java2d.print.polling")); 61 62 if (pollStr != null) { 63 if (pollStr.equalsIgnoreCase("false")) { 64 pollServices = false; 65 } 66 } 67 68 /* The system property "sun.java2d.print.minRefreshTime" 69 * can be used to specify minimum refresh time (in seconds) 70 * for polling PrintServices. The default is 240. 71 */ 72 String refreshTimeStr = java.security.AccessController.doPrivileged( 73 new sun.security.action.GetPropertyAction( 74 "sun.java2d.print.minRefreshTime")); 75 76 if (refreshTimeStr != null) { 77 try { 78 minRefreshTime = Integer.parseInt(refreshTimeStr); 79 } catch (NumberFormatException e) { 80 // ignore 81 } 82 if (minRefreshTime < DEFAULT_MINREFRESH) { 83 minRefreshTime = DEFAULT_MINREFRESH; 84 } 85 } 86 87 java.security.AccessController.doPrivileged( 88 new java.security.PrivilegedAction<Void>() { 89 public Void run() { 90 System.loadLibrary("awt"); 91 return null; 92 } 93 }); 94 } 95 96 /* The singleton win32 print lookup service. 97 * Code that is aware of this field and wants to use it must first 98 * see if its null, and if so instantiate it by calling a method such as 99 * javax.print.PrintServiceLookup.defaultPrintService() so that the 100 * same instance is stored there. 101 */ 102 private static PrintServiceLookupProvider win32PrintLUS; 103 104 /* Think carefully before calling this. Preferably don't call it. */ 105 public static PrintServiceLookupProvider getWin32PrintLUS() { 106 if (win32PrintLUS == null) { 107 /* This call is internally synchronized. 108 * When it returns an instance of this class will have 109 * been instantiated - else there's a JDK internal error. 110 */ 111 PrintServiceLookup.lookupDefaultPrintService(); 112 } 113 return win32PrintLUS; 114 } 115 381 } 382 383 /* Windows provides *PrinterChangeNotification* functions that provides 384 information about printer status changes of the local printers but not 385 network printers. 386 Alternatively, Windows provides a way through which one can get the 387 network printer status changes by using WMI, RegistryKeyChange combination, 388 which is a slightly complex mechanism. 389 The Windows WMI offers an async and sync method to read through registry 390 via the WQL query. The async method is considered dangerous as it leaves 391 open a channel until we close it. But the async method has the advantage of 392 being notified of a change in registry by calling callback without polling for it. 393 The sync method uses the polling mechanism to notify. 394 RegistryValueChange cannot be used in combination with WMI to get registry 395 value change notification because of an error that may be generated because the 396 scope of the query would be too big to handle(at times). 397 Hence an alternative mechanism is chosen via the EnumPrinters by polling for the 398 count of printer status changes(add\remove) and based on it update the printers 399 list. 400 */ 401 class RemotePrinterChangeListener implements Runnable { 402 private String[] prevRemotePrinters; 403 404 RemotePrinterChangeListener() { 405 } 406 407 private boolean doCompare(String[] str1, String[] str2) { 408 if (str1 == null && str2 == null) { 409 return false; 410 } else if (str1 == null || str2 == null) { 411 return true; 412 } 413 414 if (str1.length != str2.length) { 415 return true; 416 } else { 417 for (int i = 0; i < str1.length; i++) { 418 for (int j = 0; j < str2.length; j++) { 419 // skip if both are nulls 420 if (str1[i] == null && str2[j] == null) { 421 continue; 422 } 423 424 // return true if there is a 'difference' but 425 // no need to access the individual string 426 if (str1[i] == null || str2[j] == null) { 427 return true; 428 } 429 430 // do comparison only if they are non-nulls 431 if (!str1[i].equals(str2[j])) { 432 return true; 433 } 434 } 435 } 436 } 437 438 return false; 439 } 440 441 @Override 442 public void run() { 443 // Init the list of remote printers 444 prevRemotePrinters = getRemotePrintersNames(); 445 446 while (true) { 447 try { 448 Thread.sleep(minRefreshTime * 1000); 449 } catch (InterruptedException e) { 450 break; 451 } 452 453 String[] currentRemotePrinters = getRemotePrintersNames(); 454 if (doCompare(prevRemotePrinters, currentRemotePrinters)) { 455 // The list of remote printers got updated, 456 // so update the cached list printers which 457 // includes both local and network printers 458 refreshServices(); 459 460 // store the current data for next comparison 461 prevRemotePrinters = currentRemotePrinters; 462 } 463 } 464 } 465 } 466 467 private native String getDefaultPrinterName(); 468 private native String[] getAllPrinterNames(); 469 private native long notifyFirstPrinterChange(String printer); 470 private native void notifyClosePrinterChange(long chgObj); 471 private native int notifyPrinterChange(long chgObj); 472 private native String[] getRemotePrintersNames(); 473 } | 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.security.AccessController; 29 import java.util.ArrayList; 30 import java.util.Arrays; 31 import java.util.Comparator; 32 import javax.print.DocFlavor; 33 import javax.print.MultiDocPrintService; 34 import javax.print.PrintService; 35 import javax.print.PrintServiceLookup; 36 import javax.print.attribute.Attribute; 37 import javax.print.attribute.AttributeSet; 38 import javax.print.attribute.HashPrintRequestAttributeSet; 39 import javax.print.attribute.HashPrintServiceAttributeSet; 40 import javax.print.attribute.PrintRequestAttribute; 41 import javax.print.attribute.PrintRequestAttributeSet; 42 import javax.print.attribute.PrintServiceAttribute; 43 import javax.print.attribute.PrintServiceAttributeSet; 44 import javax.print.attribute.standard.PrinterName; 45 46 public class PrintServiceLookupProvider extends PrintServiceLookup { 47 48 private String defaultPrinter; 49 private PrintService defaultPrintService; 50 private String[] printers; /* excludes the default printer */ 51 private PrintService[] printServices; /* includes the default printer */ 52 53 private static final int DEFAULT_REFRESH_TIME = 240; // 4 minutes 54 private static final int MINIMUM_REFRESH_TIME = 120; // 2 minutes 55 private static final boolean pollServices; 56 private static final int refreshTime; 57 58 static { 59 /* The system property "sun.java2d.print.polling" 60 * can be used to force the printing code to poll or not poll 61 * for PrintServices. 62 */ 63 String pollStr = java.security.AccessController.doPrivileged( 64 new sun.security.action.GetPropertyAction("sun.java2d.print.polling")); 65 pollServices = !("false".equalsIgnoreCase(pollStr)); 66 67 /* The system property "sun.java2d.print.minRefreshTime" 68 * can be used to specify minimum refresh time (in seconds) 69 * for polling PrintServices. The default is 240. 70 */ 71 String refreshTimeStr = java.security.AccessController.doPrivileged( 72 new sun.security.action.GetPropertyAction( 73 "sun.java2d.print.minRefreshTime")); 74 refreshTime = (refreshTimeStr != null) 75 ? getRefreshTime(refreshTimeStr) 76 : DEFAULT_REFRESH_TIME; 77 78 java.security.AccessController.doPrivileged( 79 new java.security.PrivilegedAction<Void>() { 80 public Void run() { 81 System.loadLibrary("awt"); 82 return null; 83 } 84 }); 85 } 86 87 private static int getRefreshTime(final String refreshTimeStr) { 88 try { 89 int minRefreshTime = Integer.parseInt(refreshTimeStr); 90 return (minRefreshTime < MINIMUM_REFRESH_TIME) 91 ? MINIMUM_REFRESH_TIME 92 : minRefreshTime; 93 } catch (NumberFormatException e) { 94 return DEFAULT_REFRESH_TIME; 95 } 96 } 97 98 /* The singleton win32 print lookup service. 99 * Code that is aware of this field and wants to use it must first 100 * see if its null, and if so instantiate it by calling a method such as 101 * javax.print.PrintServiceLookup.defaultPrintService() so that the 102 * same instance is stored there. 103 */ 104 private static PrintServiceLookupProvider win32PrintLUS; 105 106 /* Think carefully before calling this. Preferably don't call it. */ 107 public static PrintServiceLookupProvider getWin32PrintLUS() { 108 if (win32PrintLUS == null) { 109 /* This call is internally synchronized. 110 * When it returns an instance of this class will have 111 * been instantiated - else there's a JDK internal error. 112 */ 113 PrintServiceLookup.lookupDefaultPrintService(); 114 } 115 return win32PrintLUS; 116 } 117 383 } 384 385 /* Windows provides *PrinterChangeNotification* functions that provides 386 information about printer status changes of the local printers but not 387 network printers. 388 Alternatively, Windows provides a way through which one can get the 389 network printer status changes by using WMI, RegistryKeyChange combination, 390 which is a slightly complex mechanism. 391 The Windows WMI offers an async and sync method to read through registry 392 via the WQL query. The async method is considered dangerous as it leaves 393 open a channel until we close it. But the async method has the advantage of 394 being notified of a change in registry by calling callback without polling for it. 395 The sync method uses the polling mechanism to notify. 396 RegistryValueChange cannot be used in combination with WMI to get registry 397 value change notification because of an error that may be generated because the 398 scope of the query would be too big to handle(at times). 399 Hence an alternative mechanism is chosen via the EnumPrinters by polling for the 400 count of printer status changes(add\remove) and based on it update the printers 401 list. 402 */ 403 class RemotePrinterChangeListener implements Comparator<String>, Runnable { 404 405 RemotePrinterChangeListener() { 406 } 407 408 @Override 409 public int compare(String o1, String o2) { 410 return ((o1 == null) 411 ? ((o2 == null) ? 0 : 1) 412 : ((o2 == null) ? -1 : o1.compareTo(o2))); 413 } 414 415 @Override 416 public void run() { 417 // Init the list of remote printers 418 String[] prevRemotePrinters = getRemotePrintersNames(); 419 if (prevRemotePrinters != null) { 420 Arrays.sort(prevRemotePrinters, this); 421 } 422 423 while (true) { 424 try { 425 Thread.sleep(refreshTime * 1000); 426 } catch (InterruptedException e) { 427 break; 428 } 429 430 String[] currentRemotePrinters = getRemotePrintersNames(); 431 if (currentRemotePrinters != null) { 432 Arrays.sort(currentRemotePrinters, this); 433 } 434 if (!Arrays.equals(prevRemotePrinters, currentRemotePrinters)) { 435 // The list of remote printers got updated, 436 // so update the cached list printers which 437 // includes both local and network printers 438 refreshServices(); 439 440 // store the current data for next comparison 441 prevRemotePrinters = currentRemotePrinters; 442 } 443 } 444 } 445 } 446 447 private native String getDefaultPrinterName(); 448 private native String[] getAllPrinterNames(); 449 private native long notifyFirstPrinterChange(String printer); 450 private native void notifyClosePrinterChange(long chgObj); 451 private native int notifyPrinterChange(long chgObj); 452 private native String[] getRemotePrintersNames(); 453 } |