8221412: lookupPrintServices() does not always update the list of Windows remote printers
Reviewed-by: prr, serb
--- 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,