As the title says, I would like to refresh the printers that are registered in the settings of the computer while my Java application is running.
Normally, I can use PrinterJob.lookupPrintServices()
to get the printers. However, these are only refreshed when restarting the application. I've read something on that lookupPrintServices() should be done in a new thread in order to get the printers. This however did not work, the list of printers remains the same. The following link shows that this problem should have been fixed in Java 5.0, am I doing something wrong?
Any help is much appreciated!
EDIT Added MWE.
public class MTPrinterTest extends Thread {
public static void main(String[] args) {
MTPrinterTest t1 = new MTPrinterTest();
t1.start();
try {
System.in.read();
} catch (Exception e){}
MTPrinterTest t2 = new MTPrinterTest();
t2.start();
}
public void run() {
PrinterJob printerJob;
PrintService[] printServices;
printerJob = PrinterJob.getPrinterJob();
printServices = printerJob.lookupPrintServices();
System.out.println("Number of servies found: " + printServices.length);
for (int i =0; i< printServices.length; i++)
System.out.println("--> Available Printer " + i + ": " + printServices[i]);
printerJob.printDialog();
}
}
I'm not sure what you were expecting. Here's the output for my Windows Vista laptop running Java 7.
Printer services don't change every 5 minutes, even on a shared network.
Updated based on the comment:
Your Java application will have to have to be stopped and started to get the updated list of printers.
I guess I don't understand your environment. In the places I've worked, all of the printers have been defined on the network long before we ever wrote any code. Printer changes were rarely (i mean once a year) made.
I have encountered the same problem before and after multiple tests, it seems like the printer list is snapshotted at the start of the Java application and can't be refreshed after that using java's
lookupPrintServices()
.What I did to solve that problem is call directly the Winspool API using JNA. If you intend to do so, the Winspool API is well documented by Microsoft : Winspool API documentation
Also, I described a part of my solution to a problem I had a few month ago in this question, it might help you understand JNA and the Winspool API.
There is no need to restart the application in order to refresh the list of print services.
Here I found the solution:
Basically, the static class
PrintServiceLookup.Services
maintains the list of print services. So, if you remove this class from theAppContext
, you forcePrintServiceLookup
to create a new instance again. Thus, the list of print services gets refreshed.A quick workaround is for CUPS-based systems is:
Warning, this has the side-effect of gradually slowing down calls (e.g.
80ms
) toPrintServiceLookup.lookupPrintServices(...)
.Specifically:
Property
sun.java2d.print.polling
set totrue
:<1ms
to callPrintServiceLookup.lookupPrintServices(...)
Property
sun.java2d.print.polling
set tofalse
:80ms
to callPrintServiceLookup.lookupPrintServices(...)
Although 80ms is a very short amount of time for most UI, in a high-load scenario this can affect performance.
Furthemore, this
80ms
gradually increases over time. For example, 100,000 calls toPrintServiceLookup.lookupPrintServices(...)
gradually increases the delay from80ms
to1,000ms
. Long-running programs may experience a noticeable delay.That said, this delay is still prefered over the
AppContext
workaround, especially on CUPS systems (Linux, Mac). TheAppContext
provided in other solutions introduces JVM threading issues that eventually cause2,000ms
delays, and at times up to200,000ms
delays (reference: https://github.com/qzind/tray/issues/479)Detailed bug report: https://github.com/AdoptOpenJDK/openjdk-build/issues/1212