--- old/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java 2018-06-22 00:25:01.958152200 +0530 +++ new/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java 2018-06-22 00:25:00.360141900 +0530 @@ -96,11 +96,17 @@ if (osName != null && osName.startsWith("Windows 98")) { return; } - // start the printer listener thread + // start the local printer listener thread Thread thr = new Thread(null, new PrinterChangeListener(), "PrinterListener", 0, false); thr.setDaemon(true); thr.start(); + + // start the remote printer listener thread + Thread remThr = new Thread(null, new RemotePrinterChangeListener(), + "RemotePrinterListener", 0, false); + remThr.setDaemon(true); + remThr.start(); } /* else condition ought to never happen! */ } @@ -316,7 +322,6 @@ } return defaultPrintService; } - class PrinterChangeListener implements Runnable { long chgObj; PrinterChangeListener() { @@ -341,6 +346,71 @@ } } } + } + + /* Windows provides *PrinterChangeNotification* functions that provides + information about printer status changes of the local printers but not + network printers. + Alternatively, Windows provides a way thro' which one can get the + network printer status changes by using WMI, RegistryKeyChange combination, + which is a slightly complex mechanism. + The Windows WMI offers an async and sync method to read thro' registry + via the WQL query. The async method is considered dangerous as it leaves + open a channel until we close it. But the async method has the advantage of + being notified of a change in registry by calling callback without polling for it. + The sync method uses the polling mechanism to notify. + RegistryValueChange cannot be used in combination with WMI to get registry + value change notification because of an error that may be generated because the + scope of the query would be too big to handle(at times). + Hence an alternative mechanism is choosen via the EnumPrinters by polling for the + count of printer status changes(add\remove) and based on it update the printers + list. + */ + class RemotePrinterChangeListener implements Runnable { + private static final long DELAY = 1000 * 60 * 4; // 4 min pooling + private String[] prevRemotePrinters; + + RemotePrinterChangeListener() { + prevRemotePrinters = GetRemotePrintersNames(); + } + + boolean doCompare(String[] str1, String[] str2) { + if(str1.length != str2.length) { + return true; + } else { + for(int i = 0;i < str1.length;i++) { + for(int j = 0;j < str2.length;j++) { + if(!str1[i].equals(str2[j])) { + return true; + } + } + } + } + + return false; + } + + @Override + public void run() { + while(true) { + String[] currentRemotePrinters = GetRemotePrintersNames(); + if(doCompare(prevRemotePrinters, currentRemotePrinters)) { + + // updated the printers data + // printers list now contains both local and network printer data + refreshServices(); + + // store the current data for next comparison + prevRemotePrinters = currentRemotePrinters; + } + + try { + Thread.sleep(DELAY); + } catch (InterruptedException e) { + break; + } + } + } } private native String getDefaultPrinterName(); @@ -348,4 +418,5 @@ private native long notifyFirstPrinterChange(String printer); private native void notifyClosePrinterChange(long chgObj); private native int notifyPrinterChange(long chgObj); + private native String[] GetRemotePrintersNames(); }