externalized JNI bindings

This commit is contained in:
Sebastian Stenzel
2016-08-30 17:19:45 +02:00
parent dc58ba434a
commit e0ae50378f
9 changed files with 37 additions and 114 deletions

View File

@@ -17,16 +17,17 @@ public final class LazyInitializer {
* @return The initialized value
*/
public static <T> T initializeLazily(AtomicReference<T> reference, Supplier<T> factory) {
final T existingInstance = reference.get();
if (existingInstance != null) {
return existingInstance;
final T existing = reference.get();
if (existing != null) {
return existing;
} else {
final T newInstance = factory.get();
if (reference.compareAndSet(null, newInstance)) {
return newInstance;
} else {
return reference.get();
}
return reference.updateAndGet(currentValue -> {
if (currentValue == null) {
return factory.get();
} else {
return currentValue;
}
});
}
}

View File

@@ -54,6 +54,11 @@
<groupId>org.cryptomator</groupId>
<artifactId>frontend-webdav</artifactId>
</dependency>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>jni</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<!-- EasyBind -->
<dependency>

View File

@@ -13,8 +13,8 @@ import java.util.concurrent.ExecutorService;
import javax.inject.Singleton;
import org.cryptomator.jni.MacFunctions;
import org.cryptomator.ui.controllers.MainController;
import org.cryptomator.ui.jni.MacFunctions;
import org.cryptomator.ui.settings.Localization;
import org.cryptomator.ui.util.AsyncTaskService;
import org.cryptomator.ui.util.DeferredCloser;
@@ -38,4 +38,5 @@ interface CryptomatorComponent {
ExitUtil exitUtil();
Optional<MacFunctions> nativeMacFunctions();
}
}

View File

@@ -8,6 +8,7 @@
*******************************************************************************/
package org.cryptomator.ui;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -19,7 +20,8 @@ import org.cryptomator.crypto.engine.impl.CryptoEngineModule;
import org.cryptomator.frontend.FrontendFactory;
import org.cryptomator.frontend.webdav.WebDavModule;
import org.cryptomator.frontend.webdav.WebDavServer;
import org.cryptomator.ui.jni.JniModule;
import org.cryptomator.jni.JniModule;
import org.cryptomator.jni.MacFunctions;
import org.cryptomator.ui.model.VaultObjectMapperProvider;
import org.cryptomator.ui.settings.Settings;
import org.cryptomator.ui.settings.SettingsProvider;
@@ -34,7 +36,7 @@ import dagger.Provides;
import javafx.application.Application;
import javafx.stage.Stage;
@Module(includes = {CryptoEngineModule.class, CommonsModule.class, WebDavModule.class, JniModule.class})
@Module(includes = {CryptoEngineModule.class, CommonsModule.class, WebDavModule.class})
class CryptomatorModule {
private static final Logger LOG = LoggerFactory.getLogger(CryptomatorModule.class);
@@ -100,4 +102,10 @@ class CryptomatorModule {
return closer.closeLater(webDavServer, WebDavServer::stop).get().orElseThrow(IllegalStateException::new);
}
@Provides
@Singleton
Optional<MacFunctions> provideMacFunctions() {
return JniModule.macFunctions();
}
}

View File

@@ -33,8 +33,9 @@ import javax.script.ScriptException;
import javax.swing.SwingUtilities;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.ui.jni.JniException;
import org.cryptomator.ui.jni.MacFunctions;
import org.cryptomator.jni.JniException;
import org.cryptomator.jni.MacApplicationUiState;
import org.cryptomator.jni.MacFunctions;
import org.cryptomator.ui.settings.Localization;
import org.cryptomator.ui.settings.Settings;
import org.slf4j.Logger;
@@ -93,7 +94,7 @@ class ExitUtil {
if (Platform.isImplicitExit()) {
exitCommand.run();
} else {
macFunctions.ifPresent(JniException.ignore(MacFunctions::transformToAgentApplication));
macFunctions.map(MacFunctions::uiState).ifPresent(JniException.ignore(MacApplicationUiState::transformToAgentApplication));
mainWindow.close();
this.showTrayNotification(trayIcon);
}
@@ -195,7 +196,7 @@ class ExitUtil {
private void restoreFromTray(ActionEvent event) {
Platform.runLater(() -> {
macFunctions.ifPresent(JniException.ignore(MacFunctions::transformToForegroundApplication));
macFunctions.map(MacFunctions::uiState).ifPresent(JniException.ignore(MacApplicationUiState::transformToForegroundApplication));
mainWindow.show();
mainWindow.requestFocus();
});

View File

@@ -15,9 +15,10 @@ import java.nio.file.Path;
import java.util.concurrent.ExecutionException;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.jni.JniException;
import org.cryptomator.jni.MacApplicationUiState;
import org.cryptomator.jni.MacFunctions;
import org.cryptomator.ui.controllers.MainController;
import org.cryptomator.ui.jni.JniException;
import org.cryptomator.ui.jni.MacFunctions;
import org.cryptomator.ui.util.ActiveWindowStyleSupport;
import org.cryptomator.ui.util.DeferredCloser;
import org.cryptomator.ui.util.SingleInstanceManager;
@@ -69,7 +70,7 @@ public class MainApplication extends Application {
}
// show window and start observing its focus:
comp.nativeMacFunctions().ifPresent(JniException.ignore(MacFunctions::transformToForegroundApplication));
comp.nativeMacFunctions().map(MacFunctions::uiState).ifPresent(JniException.ignore(MacApplicationUiState::transformToForegroundApplication));
primaryStage.show();
ActiveWindowStyleSupport.startObservingFocus(primaryStage);
comp.exitUtil().initExitHandler(this::quit);

View File

@@ -1,24 +0,0 @@
package org.cryptomator.ui.jni;
import java.util.function.Consumer;
/**
* Thrown to indicate that a JNI call didn't succeed, i.e. returned an unexpected return value.
*/
public class JniException extends RuntimeException {
protected JniException(String message) {
super(message);
}
public static <T> Consumer<T> ignore(Consumer<T> consumer) {
return value -> {
try {
consumer.accept(value);
} catch (RuntimeException e) {
// no-op
}
};
}
}

View File

@@ -1,33 +0,0 @@
package org.cryptomator.ui.jni;
import java.util.Optional;
import javax.inject.Singleton;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dagger.Module;
import dagger.Provides;
@Module
public class JniModule {
private static final Logger LOG = LoggerFactory.getLogger(JniModule.class);
@Provides
@Singleton
Optional<MacFunctions> provideMacFunctions(MacFunctions macFunctions) {
if (SystemUtils.IS_OS_MAC) {
try {
System.loadLibrary("MacFunctions");
return Optional.of(macFunctions);
} catch (UnsatisfiedLinkError e) {
LOG.error("Could not load JNI lib from path {}", System.getProperty("java.library.path"));
}
}
return Optional.empty();
}
}

View File

@@ -1,37 +0,0 @@
package org.cryptomator.ui.jni;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class MacFunctions {
@Inject
MacFunctions() {
}
/**
* Makes the current application a foreground application, which appears in the Dock and the Application Switcher.
*/
public void transformToForegroundApplication() {
int errorCode = transformToForegroundApplication0();
if (errorCode != 0) {
throw new JniException("Failed to make app a foreground app. Error code " + errorCode);
}
}
private native int transformToForegroundApplication0();
/**
* Makes the current application an agent app. Agent apps do not appear in the Dock or in the Force Quit window.
*/
public void transformToAgentApplication() {
int errorCode = transformToAgentApplication0();
if (errorCode != 0) {
throw new JniException("Failed to make app an agent app. Error code " + errorCode);
}
}
private native int transformToAgentApplication0();
}