sshtools / two-slices

Simple library for desktop notifications from Java on Windows, Mac OS X and Linux.
Apache License 2.0
36 stars 2 forks source link

[mac] Provider com.sshtools.twoslices.impl.SWTToaster$Service not found #3

Open avently opened 5 months ago

avently commented 5 months ago

Hello. One of users has this exception on Mac arm64 on version 0.9.3. No such exception happened in 0.9.0-SNAPSHOT:

java.util.ServiceConfigurationError: com.sshtools.twoslices.ToasterService: Provider com.sshtools.twoslices.impl.SWTToaster$Service not found
    at java.base/java.util.ServiceLoader.fail(Unknown Source)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.nextProviderClass(Unknown Source)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(Unknown Source)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(Unknown Source)
    at java.base/java.util.ServiceLoader$2.hasNext(Unknown Source)
    at java.base/java.util.ServiceLoader$3.hasNext(Unknown Source)
    at com.sshtools.twoslices.ToasterFactory$ServicesToasterFactory.toaster(ToasterFactory.java:56)
    at com.sshtools.twoslices.ToastBuilder.toast(ToastBuilder.java:513)
    at chat.simplex.common.model.NtfManager.displayNotificationViaLib(NtfManager.desktop.kt:113)
    at chat.simplex.common.model.NtfManager.displayNotification(NtfManager.desktop.kt:87)
    at chat.simplex.common.platform.AppCommon_desktopKt$initApp$1.displayNotification(AppCommon.desktop.kt:21)
    at chat.simplex.common.platform.NtfManager.displayNotification$default(NtfManager.kt:99)
    at chat.simplex.common.platform.NtfManager.notifyContactConnected(NtfManager.kt:20)
    at chat.simplex.common.model.ChatController.processReceivedMsg(SimpleXAPI.kt:1711)
    at chat.simplex.common.model.ChatController.access$processReceivedMsg(SimpleXAPI.kt:349)
    at chat.simplex.common.model.ChatController$startReceiver$1$finishedWithoutTimeout$1.invokeSuspend(SimpleXAPI.kt:483)
    at chat.simplex.common.model.ChatController$startReceiver$1$finishedWithoutTimeout$1.invoke(SimpleXAPI.kt)
    at chat.simplex.common.model.ChatController$startReceiver$1$finishedWithoutTimeout$1.invoke(SimpleXAPI.kt)
    at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturnIgnoreTimeout(Undispatched.kt:72)
    at kotlinx.coroutines.TimeoutKt.setupTimeout(Timeout.kt:148)
    at kotlinx.coroutines.TimeoutKt.withTimeoutOrNull(Timeout.kt:104)
    at chat.simplex.common.model.ChatController$startReceiver$1.invokeSuspend(SimpleXAPI.kt:482)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:28)
    at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:99)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
    at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:111)
    at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:99)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:585)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:802)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:706)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:693)

Do you have any idea why it happens?

madukan commented 4 months ago

I confirm this is a problem in Mac.

Simplest code example as follows:

import com.sshtools.twoslices.Toast;
import com.sshtools.twoslices.ToastType;

Toast.toast(ToastType.INFO, "Information", "Here is some information you cannot do without.");

Error that was experienced:

Exception in thread "main" java.lang.IllegalStateException: java.util.ServiceConfigurationError: com.sshtools.twoslices.ToasterService: Provider com.sshtools.twoslices.impl.SWTToaster$Service not found
    at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:825)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:344)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343)
    at com.maduranga.commander.CommanderApplication.main(CommanderApplication.java:10)
Caused by: java.util.ServiceConfigurationError: com.sshtools.twoslices.ToasterService: Provider com.sshtools.twoslices.impl.SWTToaster$Service not found
    at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:593)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.nextProviderClass(ServiceLoader.java:1219)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1228)
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1273)
    at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1309)
    at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1393)
    at com.sshtools.twoslices.ToasterFactory$ServicesToasterFactory.toaster(ToasterFactory.java:56)
    at com.sshtools.twoslices.ToastBuilder.toast(ToastBuilder.java:513)
    at com.sshtools.twoslices.Toast.toast(Toast.java:70)
    at com.maduranga.commander.fileops.Finder.find(Finder.java:65)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.springframework.shell.command.invocation.InvocableShellMethod.doInvoke(InvocableShellMethod.java:306)
    at org.springframework.shell.command.invocation.InvocableShellMethod.invoke(InvocableShellMethod.java:232)
    at org.springframework.shell.command.CommandExecution$DefaultCommandExecution.evaluate(CommandExecution.java:227)
    at org.springframework.shell.Shell.evaluate(Shell.java:248)
    at org.springframework.shell.Shell.run(Shell.java:159)
    at org.springframework.shell.jline.InteractiveShellRunner.run(InteractiveShellRunner.java:73)
    at org.springframework.shell.DefaultShellApplicationRunner.run(DefaultShellApplicationRunner.java:65)
    at org.springframework.boot.SpringApplication.lambda$callRunner$4(SpringApplication.java:786)
    at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:83)
    at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60)
    at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:88)
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798)
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:786)
    at org.springframework.boot.SpringApplication.lambda$callRunners$3(SpringApplication.java:774)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
    at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:774)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:341)

Dependancy:

        <dependency>
            <groupId>com.sshtools</groupId>
            <artifactId>two-slices</artifactId>
            <version>0.9.3</version>
        </dependency>

Have you already found any solutions or is there anything the users may be doing wrong here?

brett-smith commented 2 months ago

This happened because SWT support was moved to a separate module two-slices-swt in order to make it possible for two-slices to be fully JPMS compliant. SWT itself is utterly incompatible with JPMS due to its module naming scheme.

If your application is just a simple classpath based application, all you should need to do is add ...

<dependency>
    <groupId>com.sshtools</groupId>
    <artifactId>two-slices-swt</artifactId>
    <version>0.9.3</version>
</dependency>

I had made a mistake a left the service definition in the wrong module, but I think the only bad effects of this would be the less than helpful error above. This has been fixed for 0.9.4-SNAPSHOT.

madukan commented 2 months ago

In MacOS Sonoma 14.5, issue still happening. I suspect if the ScriptEngine is still used this way in new versions, and if that's the case for this error. When this error comes the Notifications don't work as well.

ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider apple.applescript.AppleScriptEngineFactory not found
ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider apple.applescript.AppleScriptEngineFactory not found
ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider apple.applescript.AppleScriptEngineFactory not found
2024-07-10T07:21:09.481+10:00  INFO 273 --- [NotificationsTester] [           main] .s.b.a.l.ConditionEvaluationReportLogger : 

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-07-10T07:21:09.490+10:00 ERROR 273 --- [NotificationsTester] [           main] o.s.boot.SpringApplication               : Application run failed

java.util.ServiceConfigurationError: com.sshtools.twoslices.ToasterService: Provider com.sshtools.twoslices.impl.SWTToaster$Service not found
    at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:593) ~[na:na]
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.nextProviderClass(ServiceLoader.java:1219) ~[na:na]
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNextService(ServiceLoader.java:1228) ~[na:na]
    at java.base/java.util.ServiceLoader$LazyClassPathLookupIterator.hasNext(ServiceLoader.java:1273) ~[na:na]
brett-smith commented 2 months ago

Hrm. Ok, I'll release 0.9.4 now, see how you get on with that. It should be on Maven central in the next hour.

madukan commented 2 months ago

0.9.4 works! Nice work!

Following error is printed in the console, however I get the notification on MacOS 14.5 without other issues.

ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider apple.applescript.AppleScriptEngineFactory not found
ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory: Provider apple.applescript.AppleScriptEngineFactory not found

Output/Notification:

image

Dependancy:

        <dependency>
            <groupId>com.sshtools</groupId>
            <artifactId>two-slices-swt</artifactId>
            <version>0.9.4</version>
        </dependency>

Code:

import com.sshtools.twoslices.Toast;
import com.sshtools.twoslices.ToastType;

Toast.toast(ToastType.INFO, "Information", "Here is some information you cannot do without.");
brett-smith commented 2 months ago

Great, thanks for reporting back. 0.9.4 contained a "fix" for that error message, but of course it won't work if you are actually on a Mac. The problem is it's trying to look for Growl support, when really with modern Java + Mac OS it's never going to find it.

I think I'll probably just drop the scripted Growl support.

FYI, the screenshot you have posted looks like it is NotificationCenterToaster or OsXToaster, so you will not need that SWT module. That suggestion was only a (failed) work around for the bug in 0.9.3 anyway.

In the meantime, setting a specific toaster yourself when on Mac should stop the error.

ToasterSettings settings = new ToasterSettings();

// Pick one of ...
//   com.sshtools.twoslices.impl.OsXToaster (works out of box - probably the one your are using)
//   com.sshtools.twoslices.impl.NotificationCenterToaster (requires JNA on classpath, special permissions)
//   com.sshtools.twoslices.swt.SWTToaster (requires SWT two-slices module and SWT itself on classpath)
//   com.sshtools.twoslices.impl.JavaFXToaster (requires JavaFX on classpath)
//  com.sshtools.twoslices.impl.AWTToaster (works out of box, if java.desktop is available)
if(System.getProperty("os.name").toLowerCase().contains("mac os")) {
    settings.setPreferredToasterClassName("com.sshtools.twoslices.impl.OsXToaster");
}

ToasterFactory.setSettings(settings);