< prev index next >

src/windows/classes/sun/print/PrintServiceLookupProvider.java

Print this page
rev 13663 : 8222108: Reduce minRefreshTime for updating remote printer list on Windows
Reviewed-by: prr, serb


  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 


 377     }
 378 
 379     /* Windows provides *PrinterChangeNotification* functions that provides
 380        information about printer status changes of the local printers but not
 381        network printers.
 382        Alternatively, Windows provides a way through which one can get the
 383        network printer status changes by using WMI, RegistryKeyChange combination,
 384        which is a slightly complex mechanism.
 385        The Windows WMI offers an async and sync method to read through registry
 386        via the WQL query. The async method is considered dangerous as it leaves
 387        open a channel until we close it. But the async method has the advantage of
 388        being notified of a change in registry by calling callback without polling for it.
 389        The sync method uses the polling mechanism to notify.
 390        RegistryValueChange cannot be used in combination with WMI to get registry
 391        value change notification because of an error that may be generated because the
 392        scope of the query would be too big to handle(at times).
 393        Hence an alternative mechanism is chosen via the EnumPrinters by polling for the
 394        count of printer status changes(add\remove) and based on it update the printers
 395        list.
 396     */
 397     class RemotePrinterChangeListener extends Thread {
 398         private String[] prevRemotePrinters;
 399 
 400         RemotePrinterChangeListener() {
 401             prevRemotePrinters = getRemotePrintersNames();
 402         }
 403 
 404         private boolean doCompare(String[] str1, String[] str2) {
 405             if (str1 == null && str2 == null) {
 406                 return false;
 407             } else if (str1 == null || str2 == null) {
 408                 return true;
 409             }
 410 
 411             if (str1.length != str2.length) {
 412                 return true;
 413             } else {
 414                 for (int i = 0; i < str1.length; i++) {
 415                     for (int j = 0; j < str2.length; j++) {
 416                         // skip if both are nulls
 417                         if (str1[i] == null && str2[j] == null) {
 418                             continue;
 419                         }
 420 
 421                         // return true if there is a 'difference' but
 422                         // no need to access the individual string
 423                         if (str1[i] == null || str2[j] == null) {
 424                             return true;
 425                         }
 426 
 427                         // do comparison only if they are non-nulls
 428                         if (!str1[i].equals(str2[j])) {
 429                             return true;
 430                         }
 431                     }
 432                 }
 433             }
 434 
 435             return false;
 436         }
 437 
 438         @Override
 439         public void run() {
 440             // Init the list of remote printers
 441             prevRemotePrinters = getRemotePrintersNames();



 442 
 443             while (true) {
 444                 try {
 445                     Thread.sleep(minRefreshTime * 1000);
 446                 } catch (InterruptedException e) {
 447                     break;
 448                 }
 449 
 450                 String[] currentRemotePrinters = getRemotePrintersNames();
 451                 if (doCompare(prevRemotePrinters, currentRemotePrinters)) {



 452                     // The list of remote printers got updated,
 453                     // so update the cached list printers which
 454                     // includes both local and network printers
 455                     refreshServices();
 456 
 457                     // store the current data for next comparison
 458                     prevRemotePrinters = currentRemotePrinters;
 459                 }
 460             }
 461         }
 462     }
 463 
 464     private native String getDefaultPrinterName();
 465     private native String[] getAllPrinterNames();
 466     private native long notifyFirstPrinterChange(String printer);
 467     private native void notifyClosePrinterChange(long chgObj);
 468     private native int notifyPrinterChange(long chgObj);
 469     private native String[] getRemotePrintersNames();
 470 }


  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 


 379     }
 380 
 381     /* Windows provides *PrinterChangeNotification* functions that provides
 382        information about printer status changes of the local printers but not
 383        network printers.
 384        Alternatively, Windows provides a way through which one can get the
 385        network printer status changes by using WMI, RegistryKeyChange combination,
 386        which is a slightly complex mechanism.
 387        The Windows WMI offers an async and sync method to read through registry
 388        via the WQL query. The async method is considered dangerous as it leaves
 389        open a channel until we close it. But the async method has the advantage of
 390        being notified of a change in registry by calling callback without polling for it.
 391        The sync method uses the polling mechanism to notify.
 392        RegistryValueChange cannot be used in combination with WMI to get registry
 393        value change notification because of an error that may be generated because the
 394        scope of the query would be too big to handle(at times).
 395        Hence an alternative mechanism is chosen via the EnumPrinters by polling for the
 396        count of printer status changes(add\remove) and based on it update the printers
 397        list.
 398     */
 399     class RemotePrinterChangeListener extends Thread implements Comparator<String>{
 400         private String[] prevRemotePrinters;
 401 
 402         RemotePrinterChangeListener() {
 403             prevRemotePrinters = getRemotePrintersNames();
 404         }
 405 
 406         @Override
 407         public int compare(String o1, String o2) {
 408             return ((o1 == null)
 409                     ? ((o2 == null) ? 0 : 1)
 410                     : ((o2 == null) ? -1 : o1.compareTo(o2)));



























 411         }
 412 
 413         @Override
 414         public void run() {
 415             // Init the list of remote printers
 416             String[] prevRemotePrinters = getRemotePrintersNames();
 417             if (prevRemotePrinters != null) {
 418                 Arrays.sort(prevRemotePrinters, this);
 419             }
 420 
 421             while (true) {
 422                 try {
 423                     Thread.sleep(refreshTime * 1000);
 424                 } catch (InterruptedException e) {
 425                     break;
 426                 }
 427 
 428                 String[] currentRemotePrinters = getRemotePrintersNames();
 429                 if (currentRemotePrinters != null) {
 430                     Arrays.sort(currentRemotePrinters, this);
 431                 }
 432                 if (!Arrays.equals(prevRemotePrinters, currentRemotePrinters)) {
 433                     // The list of remote printers got updated,
 434                     // so update the cached list printers which
 435                     // includes both local and network printers
 436                     refreshServices();
 437 
 438                     // store the current data for next comparison
 439                     prevRemotePrinters = currentRemotePrinters;
 440                 }
 441             }
 442         }
 443     }
 444 
 445     private native String getDefaultPrinterName();
 446     private native String[] getAllPrinterNames();
 447     private native long notifyFirstPrinterChange(String printer);
 448     private native void notifyClosePrinterChange(long chgObj);
 449     private native int notifyPrinterChange(long chgObj);
 450     private native String[] getRemotePrintersNames();
 451 }
< prev index next >