Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delay on adding/removing printers for qz.printers().find() #393

Closed
majoncas opened this issue Dec 7, 2018 · 9 comments

Comments

Projects
None yet
4 participants
@majoncas
Copy link

commented Dec 7, 2018

I figured out the problem in our application then I tried to reproduce the problem on your demo page on your website so I can proof that this is not an implementation problem.

On my MAC, I add a new printer, then I click on "Disconnect" and after I click on "Connect" to force a new QZ connection. I click on "Find all printers" button and my newly added printer is not visible. I need to do the same thing a lot of time before being able to see it in the list returned by QZ. I can reproduce the same scenario when I delete the printer it takes a lot of tries before my deleted printer becomes unlisted. Is there any caching on QZ side which prevent displaying up to date information regarding available printers list ?

Thank you for your hep.

@tresf

This comment has been minimized.

Copy link
Contributor

commented Dec 7, 2018

Is there any caching on QZ side which prevent displaying up to date information regarding available printers list ?

No, we get this information from CUPS which -- especially on macOS -- is not realtime. I recommend you have the printers configured before starting QZ Tray and restarting between changes.

@majoncas

This comment has been minimized.

Copy link
Author

commented Dec 7, 2018

I just realized that as a workaround, closing the QZ Tray application and restart it would fix the issue but I would not expect as a user to do such operation in order to make this work. The API should send me accurate informations.

@tresf

This comment has been minimized.

Copy link
Contributor

commented Dec 7, 2018

The API should send me accurate informations.

We use standard Java APIs, the issue is not with our product.

@majoncas

This comment has been minimized.

Copy link
Author

commented Dec 10, 2018

It's ok then. I just wanted to check with you guy if this was really "as designed" . Thank you for your confirmation

@majoncas majoncas closed this Dec 10, 2018

@CindyLulu

This comment has been minimized.

Copy link

commented May 10, 2019

@majoncas , I have the same issue too, add below code into the first line of PrintServiceMatcher getPrintServices function can help resolve this issue:
AppContext.getAppContext().put(PrintServiceLookup.class.getDeclaredClasses()[0], null);

@tresf

This comment has been minimized.

Copy link
Contributor

commented May 10, 2019

Reopening to see if we can improve this logic.

@tresf tresf reopened this May 10, 2019

@klabarge

This comment has been minimized.

Copy link
Member

commented May 25, 2019

@CindyLulu, thanks for providing this!

I've added
AppContext.getAppContext().put(PrintServiceLookup.class.getDeclaredClasses()[0], null); to the below line and it indeed speeds up the printer listing in CUPS.

When a printer is added or removed, the first call to qz.printers.find reflects the changes (without any refreshing) 👍

PrintService[] printers = PrintServiceLookup.lookupPrintServices(null, null);

I'll commit this into our code, and it will make into the 2.0.10 release

@klabarge klabarge closed this in 023843e May 25, 2019

@tresf

This comment has been minimized.

Copy link
Contributor

commented May 31, 2019

Turns out the solution in 023843e uses a proprietary internal API and may be removed from future Java versions. We need to file an upstream bug with AdoptOpenJDK11 to patch this in the JDK so that we don't get bit by it down the road.

Developers: If IntelliJ complains package sun.awt does not exist, see the workaround here: https://stackoverflow.com/a/56388149/3196753

@tresf

This comment has been minimized.

Copy link
Contributor

commented May 31, 2019

If Java removed the sun.awt API, a potential solution is to use Java reflection to try to set this property...

/**
 * Updates printer listing in CUPS immediately
 */
public static void forcePrintersRefresh() {
    try {
        Class appContextClass = Class.forName("sun.awt.AppContext");
        Method getAppContextMethod = appContextClass.getMethod("getAppContext");
        Object appContextInstance = getAppContextMethod.invoke(appContextClass);
        Method putMethod = appContextInstance.getClass().getMethod("put", Object.class, Object.class);
        putMethod.invoke(appContextInstance, PrintServiceLookup.class.getDeclaredClasses()[0], null);
        AppContext.getAppContext().put(PrintServiceLookup.class.getDeclaredClasses()[0], null);
    } catch (Throwable t) {
        // Catches JDK9+ "InaccessibleObjectException"
    }
}

The downside to this approach is that the JDK9+ warns:

- WARNING: An illegal reflective access operation has occurred
- WARNING: Illegal reflective access to method sun.awt.AppContext.getAppContext()
- WARNING: Please consider reporting this to the maintainers
- WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
- WARNING: All illegal access operations will be denied in a future release

Testing the code with --illegal-access=deny actually shows no warnings because the InaccessibleObjectException is swallowed by the Throwable despite it being a JDK9+ class.

For now, we can keep this proprietary call, but I'll ask @klabarge to file a bug report upstream so that we can get it fixed properly and (eventually) remove the workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.