diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/FileOpenRequestHandler.java b/main/launcher/src/main/java/org/cryptomator/launcher/FileOpenRequestHandler.java index 97306d231..3a0ac97c9 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/FileOpenRequestHandler.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/FileOpenRequestHandler.java @@ -13,7 +13,6 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.concurrent.BlockingQueue; -import org.apache.commons.lang3.SystemUtils; import org.cryptomator.ui.util.EawtApplicationWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,13 +24,11 @@ class FileOpenRequestHandler { public FileOpenRequestHandler(BlockingQueue fileOpenRequests) { this.fileOpenRequests = fileOpenRequests; - if (SystemUtils.IS_OS_MAC_OSX) { - EawtApplicationWrapper.getApplication().ifPresent(app -> { - app.setOpenFileHandler(files -> { - files.stream().map(File::toPath).forEach(fileOpenRequests::add); - }); + EawtApplicationWrapper.getApplication().ifPresent(app -> { + app.setOpenFileHandler(files -> { + files.stream().map(File::toPath).forEach(fileOpenRequests::add); }); - } + }); } public void handleLaunchArgs(String[] args) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/EawtApplicationWrapper.java b/main/ui/src/main/java/org/cryptomator/ui/util/EawtApplicationWrapper.java index 8c260fe6f..3c524e418 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/EawtApplicationWrapper.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/EawtApplicationWrapper.java @@ -12,7 +12,10 @@ import java.lang.reflect.Proxy; import java.util.List; import java.util.Optional; import java.util.function.Consumer; +import java.util.function.Function; +import org.apache.commons.lang3.SystemUtils; +import org.cryptomator.common.SupplierThrowingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,7 +34,13 @@ public class EawtApplicationWrapper { this.application = applicationClass.getMethod("getApplication").invoke(null); } + /** + * @return A wrapper for com.apple.ewat.Application if the current OS is macOS and the class is available in this JVM. + */ public static Optional getApplication() { + if (!SystemUtils.IS_OS_MAC_OSX) { + return Optional.empty(); + } try { return Optional.of(new EawtApplicationWrapper()); } catch (ReflectiveOperationException e) { @@ -50,15 +59,12 @@ public class EawtApplicationWrapper { try { Class openFilesEventClass = Class.forName("com.apple.eawt.AppEvent$OpenFilesEvent"); Method getFiles = openFilesEventClass.getMethod("getFiles"); - setOpenFileHandler(newMethodSpecificInvocationHandler("openFiles", args -> { - try { - Object openFilesEvent = args[0]; - @SuppressWarnings("unchecked") - List files = (List) getFiles.invoke(openFilesEvent); - handler.accept(files); - } catch (ReflectiveOperationException e) { - LOG.error("Error invoking openFileHandler.", e); - } + setOpenFileHandler(methodSpecificInvocationHandler("openFiles", args -> { + Object openFilesEvent = args[0]; + assert openFilesEventClass.isInstance(openFilesEvent); + @SuppressWarnings("unchecked") + List files = (List) uncheckedReflectiveOperation(() -> getFiles.invoke(openFilesEvent)); + handler.accept(files); return null; })); } catch (ReflectiveOperationException e) { @@ -75,7 +81,7 @@ public class EawtApplicationWrapper { public void setPreferencesHandler(Runnable handler) { try { - setPreferencesHandler(newMethodSpecificInvocationHandler("handlePreferences", args -> { + setPreferencesHandler(methodSpecificInvocationHandler("handlePreferences", args -> { handler.run(); return null; })); @@ -84,22 +90,38 @@ public class EawtApplicationWrapper { } } - @FunctionalInterface - private static interface MethodSpecificInvocationHandler { - Object invoke(Object[] args); - } - - private static InvocationHandler newMethodSpecificInvocationHandler(String methodName, MethodSpecificInvocationHandler handler) { + private static InvocationHandler methodSpecificInvocationHandler(String methodName, Function handler) { return new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals(methodName)) { - return handler.invoke(args); + return handler.apply(args); } else { - return null; + throw new UnsupportedOperationException("Unexpected invocation " + method.getName() + ", expected " + methodName); } } }; } + /** + * Wraps {@link ReflectiveOperationException}s as {@link UncheckedReflectiveOperationException}. + * + * @param operation Invokation throwing an ReflectiveOperationException + * @return Result returned by operation + * @throws UncheckedReflectiveOperationException in case operation throws an ReflectiveOperationException. + */ + private static T uncheckedReflectiveOperation(SupplierThrowingException operation) throws UncheckedReflectiveOperationException { + try { + return operation.get(); + } catch (ReflectiveOperationException e) { + throw new UncheckedReflectiveOperationException(e); + } + } + + private static class UncheckedReflectiveOperationException extends RuntimeException { + public UncheckedReflectiveOperationException(ReflectiveOperationException cause) { + super(cause); + } + } + }