8221412: lookupPrintServices() does not always update the list of Windows remote printers
authoraivanov
Thu, 28 Mar 2019 14:52:41 +0000
changeset 54400 31c35004f300
parent 54399 b10e1f4f8b69
child 54401 3a217bbdd3a2
8221412: lookupPrintServices() does not always update the list of Windows remote printers Reviewed-by: prr, serb
src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java
src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp
--- a/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java	Thu Mar 28 13:49:27 2019 +0530
+++ b/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java	Thu Mar 28 14:52:41 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,14 +25,8 @@
 
 package sun.print;
 
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.IOException;
+import java.security.AccessController;
 import java.util.ArrayList;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
 import javax.print.DocFlavor;
 import javax.print.MultiDocPrintService;
 import javax.print.PrintService;
@@ -81,8 +75,9 @@
 
         if (refreshTimeStr != null) {
             try {
-                minRefreshTime = (Integer.valueOf(refreshTimeStr)).intValue();
+                minRefreshTime = Integer.parseInt(refreshTimeStr);
             } catch (NumberFormatException e) {
+                // ignore
             }
             if (minRefreshTime < DEFAULT_MINREFRESH) {
                 minRefreshTime = DEFAULT_MINREFRESH;
@@ -139,7 +134,7 @@
             if (pollServices) {
                 // start the remote printer listener thread
                 Thread remThr = new Thread(null, new RemotePrinterChangeListener(),
-                                        "RemotePrinterListener", 0, false);
+                                           "RemotePrinterListener", 0, false);
                 remThr.setDaemon(true);
                 remThr.start();
             }
@@ -358,6 +353,7 @@
         }
         return defaultPrintService;
     }
+
     class PrinterChangeListener implements Runnable {
         long chgObj;
         PrinterChangeListener() {
@@ -387,10 +383,10 @@
     /* 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
+       Alternatively, Windows provides a way through 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
+       The Windows WMI offers an async and sync method to read through 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.
@@ -398,18 +394,17 @@
        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
+       Hence an alternative mechanism is chosen 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 String[] prevRemotePrinters = null;
+        private String[] prevRemotePrinters;
 
         RemotePrinterChangeListener() {
-            prevRemotePrinters = getRemotePrintersNames();
         }
 
-        boolean doCompare(String[] str1, String[] str2) {
+        private boolean doCompare(String[] str1, String[] str2) {
             if (str1 == null && str2 == null) {
                 return false;
             } else if (str1 == null || str2 == null) {
@@ -419,8 +414,8 @@
             if (str1.length != str2.length) {
                 return true;
             } else {
-                for (int i = 0;i < str1.length;i++) {
-                    for (int j = 0;j < str2.length;j++) {
+                for (int i = 0; i < str1.length; i++) {
+                    for (int j = 0; j < str2.length; j++) {
                         // skip if both are nulls
                         if (str1[i] == null && str2[j] == null) {
                             continue;
@@ -445,27 +440,26 @@
 
         @Override
         public void run() {
-            while (true) {
-                if (prevRemotePrinters != null && prevRemotePrinters.length > 0) {
-                    String[] currentRemotePrinters = getRemotePrintersNames();
-                    if (doCompare(prevRemotePrinters, currentRemotePrinters)) {
+            // Init the list of remote printers
+            prevRemotePrinters = getRemotePrintersNames();
 
-                        // updated the printers data
-                        // printers list now contains both local and network printer data
-                        refreshServices();
-
-                        // store the current data for next comparison
-                        prevRemotePrinters = currentRemotePrinters;
-                    }
-                } else {
-                    prevRemotePrinters = getRemotePrintersNames();
-                }
-
+            while (true) {
                 try {
                     Thread.sleep(minRefreshTime * 1000);
                 } catch (InterruptedException e) {
                     break;
                 }
+
+                String[] currentRemotePrinters = getRemotePrintersNames();
+                if (doCompare(prevRemotePrinters, currentRemotePrinters)) {
+                    // The list of remote printers got updated,
+                    // so update the cached list printers which
+                    // includes both local and network printers
+                    refreshServices();
+
+                    // store the current data for next comparison
+                    prevRemotePrinters = currentRemotePrinters;
+                }
             }
         }
     }
--- a/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp	Thu Mar 28 13:49:27 2019 +0530
+++ b/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp	Thu Mar 28 14:52:41 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -118,10 +118,7 @@
 }
 
 
-JNIEXPORT jobjectArray JNICALL
-Java_sun_print_PrintServiceLookupProvider_getAllPrinterNames(JNIEnv *env,
-                                                          jobject peer)
-{
+static jobjectArray getPrinterNames(JNIEnv *env, DWORD flags) {
     TRY;
 
     DWORD cbNeeded = 0;
@@ -136,10 +133,10 @@
     jobjectArray nameArray;
 
     try {
-        ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
+        ::EnumPrinters(flags,
                        NULL, 4, NULL, 0, &cbNeeded, &cReturned);
         pPrinterEnum = new BYTE[cbNeeded];
-        ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
+        ::EnumPrinters(flags,
                        NULL, 4, pPrinterEnum, cbNeeded, &cbNeeded,
                        &cReturned);
 
@@ -174,6 +171,20 @@
     CATCH_BAD_ALLOC_RET(NULL);
 }
 
+JNIEXPORT jobjectArray JNICALL
+Java_sun_print_PrintServiceLookupProvider_getAllPrinterNames(JNIEnv *env,
+                                                             jobject peer)
+{
+    return getPrinterNames(env, PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS);
+}
+
+JNIEXPORT jobjectArray JNICALL
+Java_sun_print_PrintServiceLookupProvider_getRemotePrintersNames(JNIEnv *env,
+                                                                 jobject peer)
+{
+    return getPrinterNames(env, PRINTER_ENUM_CONNECTIONS);
+}
+
 
 JNIEXPORT jlong JNICALL
 Java_sun_print_PrintServiceLookupProvider_notifyFirstPrinterChange(JNIEnv *env,
@@ -232,82 +243,6 @@
     }
 }
 
-JNIEXPORT jobjectArray JNICALL
-Java_sun_print_PrintServiceLookupProvider_getRemotePrintersNames(JNIEnv *env,
-                                                           jobject peer)
-{
-    TRY;
-
-    int remotePrintersCount = 0;
-    DWORD cbNeeded = 0;
-    DWORD cReturned = 0;
-    LPBYTE pPrinterEnum = NULL;
-    LPBYTE pNetworkPrinterLoc = NULL;
-
-    jstring utf_str;
-    jclass clazz = env->FindClass("java/lang/String");
-    if (clazz == NULL) {
-        return NULL;
-    }
-    jobjectArray nameArray = NULL;
-
-    try {
-        ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
-                       NULL, 4, NULL, 0, &cbNeeded, &cReturned);
-        pPrinterEnum = new BYTE[cbNeeded];
-        pNetworkPrinterLoc = new BYTE[cbNeeded/sizeof(PRINTER_INFO_4)];
-        ::EnumPrinters(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
-                       NULL, 4, pPrinterEnum, cbNeeded, &cbNeeded,
-                       &cReturned);
-
-        if (cReturned > 0) {
-            for (DWORD i = 0; i < cReturned; i++) {
-                PRINTER_INFO_4 *info4 = (PRINTER_INFO_4 *) (pPrinterEnum + i * sizeof(PRINTER_INFO_4));
-
-                // Store the network printers indexes
-                if (info4->Attributes & PRINTER_ATTRIBUTE_NETWORK) {
-                    pNetworkPrinterLoc[remotePrintersCount++] = i;
-                }
-            }
-
-            // return remote printers only if the list contains it.
-            if (remotePrintersCount > 0) {
-                // Allocate space only for the network type printers
-                nameArray = env->NewObjectArray(remotePrintersCount, clazz, NULL);
-                if (nameArray == NULL) {
-                    throw std::bad_alloc();
-                }
-            }
-        }
-
-        // Loop thro' network printers list only
-        for (int i = 0; i < remotePrintersCount; i++) {
-            PRINTER_INFO_4 *info4 = (PRINTER_INFO_4 *)
-                (pPrinterEnum + pNetworkPrinterLoc[i] * sizeof(PRINTER_INFO_4));
-            utf_str = JNU_NewStringPlatform(env, info4->pPrinterName);
-            if (utf_str == NULL) {
-                throw std::bad_alloc();
-            }
-            env->SetObjectArrayElement(nameArray, i, utf_str);
-            env->DeleteLocalRef(utf_str);
-        }
-    } catch (std::bad_alloc&) {
-        delete [] pPrinterEnum;
-        delete [] pNetworkPrinterLoc;
-        throw;
-    }
-
-    delete [] pPrinterEnum;
-    delete [] pNetworkPrinterLoc;
-
-    if (nameArray != NULL) {
-      return nameArray;
-    } else {
-      return env->NewObjectArray(0, clazz, NULL);
-    }
-
-    CATCH_BAD_ALLOC_RET(NULL);
-}
 
 JNIEXPORT jfloatArray JNICALL
 Java_sun_print_Win32PrintService_getMediaPrintableArea(JNIEnv *env,