mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-17 02:01:27 +00:00
@@ -5,74 +5,107 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.cryptomator.launcher;
|
package org.cryptomator.launcher;
|
||||||
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Platform;
|
||||||
import javafx.stage.Stage;
|
|
||||||
import org.apache.commons.lang3.SystemUtils;
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.cryptomator.ui.controllers.MainController;
|
import org.cryptomator.logging.DebugMode;
|
||||||
|
import org.cryptomator.logging.LoggerConfiguration;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
public class Cryptomator {
|
public class Cryptomator {
|
||||||
|
|
||||||
private static final Logger LOG;
|
// DaggerCryptomatorComponent gets generated by Dagger.
|
||||||
private static final CryptomatorComponent CRYPTOMATOR_COMPONENT;
|
// Run Maven and include target/generated-sources/annotations in your IDE.
|
||||||
|
private static final CryptomatorComponent CRYPTOMATOR_COMPONENT = DaggerCryptomatorComponent.create();
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(Cryptomator.class);
|
||||||
|
|
||||||
static {
|
private final LoggerConfiguration logConfig;
|
||||||
// DaggerCryptomatorComponent gets generated by Dagger.
|
private final DebugMode debugMode;
|
||||||
// Run Maven and include target/generated-sources/annotations in your IDE.
|
private final IpcFactory ipcFactory;
|
||||||
CRYPTOMATOR_COMPONENT = DaggerCryptomatorComponent.create();
|
private final Optional<String> applicationVersion;
|
||||||
CRYPTOMATOR_COMPONENT.initLogging().run();
|
private final CountDownLatch shutdownLatch;
|
||||||
LOG = LoggerFactory.getLogger(Cryptomator.class);
|
|
||||||
|
@Inject
|
||||||
|
Cryptomator(LoggerConfiguration logConfig, DebugMode debugMode, IpcFactory ipcFactory, @Named("applicationVersion") Optional<String> applicationVersion, @Named("shutdownLatch") CountDownLatch shutdownLatch) {
|
||||||
|
this.logConfig = logConfig;
|
||||||
|
this.debugMode = debugMode;
|
||||||
|
this.ipcFactory = ipcFactory;
|
||||||
|
this.applicationVersion = applicationVersion;
|
||||||
|
this.shutdownLatch = shutdownLatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
LOG.info("Starting Cryptomator {} on {} {} ({})", CRYPTOMATOR_COMPONENT.applicationVersion().orElse("SNAPSHOT"), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
|
int exitCode = CRYPTOMATOR_COMPONENT.application().run(args);
|
||||||
|
System.exit(exitCode); // end remaining non-daemon threads.
|
||||||
try (IpcFactory.IpcEndpoint endpoint = CRYPTOMATOR_COMPONENT.ipcFactory().create()) {
|
|
||||||
endpoint.getRemote().handleLaunchArgs(args); // if we are the server, getRemote() returns self.
|
|
||||||
if (endpoint.isConnectedToRemote()) {
|
|
||||||
LOG.info("Found running application instance. Shutting down.");
|
|
||||||
} else {
|
|
||||||
CRYPTOMATOR_COMPONENT.debugMode().initialize();
|
|
||||||
CleanShutdownPerformer.registerShutdownHook();
|
|
||||||
Application.launch(MainApp.class, args);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.error("Failed to initiate inter-process communication.", e);
|
|
||||||
System.exit(2);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
LOG.error("Error during startup", e);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
System.exit(0); // end remaining non-daemon threads.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need a separate FX Application class, until we can use the module system. See https://stackoverflow.com/q/54756176/4014509
|
/**
|
||||||
public static class MainApp extends Application {
|
* Main entry point of the application launcher.
|
||||||
|
* @param args The arguments passed to this program via {@link #main(String[])}.
|
||||||
|
* @return Nonzero exit code in case of an error.
|
||||||
|
*/
|
||||||
|
private int run(String[] args) {
|
||||||
|
logConfig.init();
|
||||||
|
LOG.info("Starting Cryptomator {} on {} {} ({})", applicationVersion.orElse("SNAPSHOT"), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
|
||||||
|
|
||||||
@Override
|
if (sendArgsToRunningInstance(args)) {
|
||||||
public void start(Stage primaryStage) {
|
LOG.info("Found running application instance. Shutting down...");
|
||||||
LOG.info("JavaFX application started.");
|
return 0;
|
||||||
primaryStage.setMinWidth(652.0);
|
|
||||||
primaryStage.setMinHeight(440.0);
|
|
||||||
|
|
||||||
FxApplicationComponent fxApplicationComponent = CRYPTOMATOR_COMPONENT.fxApplicationComponent() //
|
|
||||||
.fxApplication(this) //
|
|
||||||
.mainWindow(primaryStage) //
|
|
||||||
.build();
|
|
||||||
|
|
||||||
MainController mainCtrl = fxApplicationComponent.fxmlLoader().load("/fxml/main.fxml");
|
|
||||||
mainCtrl.initStage(primaryStage);
|
|
||||||
primaryStage.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
try {
|
||||||
public void stop() {
|
runGuiApplication();
|
||||||
LOG.info("JavaFX application stopped.");
|
LOG.info("Shutting down...");
|
||||||
|
return 0;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOG.error("Terminating due to error", e);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to create an IPC connection to a running Cryptomator instance and sends it the given args.
|
||||||
|
* If no external process could be reached, the args will be handled by the loopback IPC endpoint.
|
||||||
|
*
|
||||||
|
* @param args Arguments to send to the instance (if possible)
|
||||||
|
* @return <code>true</code> if a different process could be reached, <code>false</code> otherwise.
|
||||||
|
*/
|
||||||
|
private boolean sendArgsToRunningInstance(String[] args) {
|
||||||
|
try (IpcFactory.IpcEndpoint endpoint = ipcFactory.create()) {
|
||||||
|
endpoint.getRemote().handleLaunchArgs(args); // if we are the server, getRemote() returns self.
|
||||||
|
return endpoint.isConnectedToRemote();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Failed to initiate inter-process communication.", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Launches the JavaFX application and waits until shutdown is requested.
|
||||||
|
*
|
||||||
|
* @implNote This method blocks until {@link #shutdownLatch} reached zero.
|
||||||
|
*/
|
||||||
|
private void runGuiApplication() {
|
||||||
|
try {
|
||||||
|
debugMode.initialize();
|
||||||
|
CleanShutdownPerformer.registerShutdownHook();
|
||||||
|
Platform.startup(() -> {
|
||||||
|
assert Platform.isFxApplicationThread();
|
||||||
|
FxApplication app = CRYPTOMATOR_COMPONENT.fxApplicationComponent().application();
|
||||||
|
app.start();
|
||||||
|
});
|
||||||
|
shutdownLatch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,16 +14,8 @@ import java.util.Optional;
|
|||||||
@Component(modules = {CryptomatorModule.class, CommonsModule.class, LoggerModule.class})
|
@Component(modules = {CryptomatorModule.class, CommonsModule.class, LoggerModule.class})
|
||||||
public interface CryptomatorComponent {
|
public interface CryptomatorComponent {
|
||||||
|
|
||||||
@Named("initLogging")
|
Cryptomator application();
|
||||||
Runnable initLogging();
|
|
||||||
|
|
||||||
DebugMode debugMode();
|
FxApplicationComponent fxApplicationComponent();
|
||||||
|
|
||||||
IpcFactory ipcFactory();
|
|
||||||
|
|
||||||
@Named("applicationVersion")
|
|
||||||
Optional<String> applicationVersion();
|
|
||||||
|
|
||||||
FxApplicationComponent.Builder fxApplicationComponent();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,27 +11,35 @@ import javax.inject.Singleton;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
class CryptomatorModule {
|
class CryptomatorModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
Settings provideSettings(SettingsProvider settingsProvider) {
|
@Named("shutdownLatch")
|
||||||
|
static CountDownLatch provideShutdownLatch() {
|
||||||
|
return new CountDownLatch(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
static Settings provideSettings(SettingsProvider settingsProvider) {
|
||||||
return settingsProvider.get();
|
return settingsProvider.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("launchEventQueue")
|
@Named("launchEventQueue")
|
||||||
BlockingQueue<AppLaunchEvent> provideFileOpenRequests() {
|
static BlockingQueue<AppLaunchEvent> provideFileOpenRequests() {
|
||||||
return new ArrayBlockingQueue<>(10);
|
return new ArrayBlockingQueue<>(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("applicationVersion")
|
@Named("applicationVersion")
|
||||||
Optional<String> provideApplicationVersion() {
|
static Optional<String> provideApplicationVersion() {
|
||||||
return Optional.ofNullable(Cryptomator.class.getPackage().getImplementationVersion());
|
return Optional.ofNullable(Cryptomator.class.getPackage().getImplementationVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.cryptomator.launcher;
|
|||||||
|
|
||||||
import java.awt.Desktop;
|
import java.awt.Desktop;
|
||||||
import java.awt.desktop.OpenFilesEvent;
|
import java.awt.desktop.OpenFilesEvent;
|
||||||
|
import java.awt.desktop.QuitStrategy;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.FileSystem;
|
import java.nio.file.FileSystem;
|
||||||
import java.nio.file.FileSystems;
|
import java.nio.file.FileSystems;
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package org.cryptomator.launcher;
|
||||||
|
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import org.cryptomator.common.FxApplicationScoped;
|
||||||
|
import org.cryptomator.ui.controllers.MainController;
|
||||||
|
import org.cryptomator.ui.controllers.ViewControllerLoader;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
|
||||||
|
@FxApplicationScoped
|
||||||
|
public class FxApplication extends Application {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(FxApplication.class);
|
||||||
|
|
||||||
|
private final Stage primaryStage;
|
||||||
|
private final ViewControllerLoader fxmlLoader;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
FxApplication(@Named("mainWindow") Stage primaryStage, ViewControllerLoader fxmlLoader) {
|
||||||
|
this.primaryStage = primaryStage;
|
||||||
|
this.fxmlLoader = fxmlLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
LOG.info("Starting GUI...");
|
||||||
|
start(primaryStage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage primaryStage) {
|
||||||
|
MainController mainCtrl = fxmlLoader.load("/fxml/main.fxml");
|
||||||
|
mainCtrl.initStage(primaryStage);
|
||||||
|
primaryStage.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,33 +5,13 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.cryptomator.launcher;
|
package org.cryptomator.launcher;
|
||||||
|
|
||||||
import dagger.BindsInstance;
|
|
||||||
import dagger.Subcomponent;
|
import dagger.Subcomponent;
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.stage.Stage;
|
|
||||||
import org.cryptomator.common.FxApplicationScoped;
|
import org.cryptomator.common.FxApplicationScoped;
|
||||||
import org.cryptomator.logging.DebugMode;
|
|
||||||
import org.cryptomator.ui.controllers.ViewControllerLoader;
|
|
||||||
|
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
@FxApplicationScoped
|
@FxApplicationScoped
|
||||||
@Subcomponent(modules = FxApplicationModule.class)
|
@Subcomponent(modules = FxApplicationModule.class)
|
||||||
interface FxApplicationComponent {
|
interface FxApplicationComponent {
|
||||||
|
|
||||||
ViewControllerLoader fxmlLoader();
|
FxApplication application();
|
||||||
|
|
||||||
@Subcomponent.Builder
|
|
||||||
interface Builder {
|
|
||||||
|
|
||||||
@BindsInstance
|
|
||||||
Builder fxApplication(Application application);
|
|
||||||
|
|
||||||
@BindsInstance
|
|
||||||
Builder mainWindow(@Named("mainWindow") Stage mainWindow);
|
|
||||||
|
|
||||||
FxApplicationComponent build();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,12 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.cryptomator.launcher;
|
package org.cryptomator.launcher;
|
||||||
|
|
||||||
|
import dagger.Binds;
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.stage.Stage;
|
||||||
import org.cryptomator.common.FxApplicationScoped;
|
import org.cryptomator.common.FxApplicationScoped;
|
||||||
import org.cryptomator.ui.UiModule;
|
import org.cryptomator.ui.UiModule;
|
||||||
|
|
||||||
@@ -14,13 +18,28 @@ import javax.inject.Named;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@Module(includes = {UiModule.class})
|
@Module(includes = {UiModule.class})
|
||||||
class FxApplicationModule {
|
abstract class FxApplicationModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@FxApplicationScoped
|
@FxApplicationScoped
|
||||||
@Named("shutdownTaskScheduler")
|
@Named("shutdownTaskScheduler")
|
||||||
Consumer<Runnable> provideShutdownTaskScheduler() {
|
static Consumer<Runnable> provideShutdownTaskScheduler() {
|
||||||
return CleanShutdownPerformer::scheduleShutdownTask;
|
return CleanShutdownPerformer::scheduleShutdownTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@FxApplicationScoped
|
||||||
|
@Named("mainWindow")
|
||||||
|
static Stage providePrimaryStage() {
|
||||||
|
Stage stage = new Stage();
|
||||||
|
stage.setMinWidth(652.0);
|
||||||
|
stage.setMinHeight(440.0);
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@FxApplicationScoped
|
||||||
|
abstract Application bindApplication(FxApplication application);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package org.cryptomator.logging;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
import ch.qos.logback.classic.LoggerContext;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.Appender;
|
||||||
|
import ch.qos.logback.core.hook.DelayingShutdownHook;
|
||||||
|
import ch.qos.logback.core.util.Duration;
|
||||||
|
import org.cryptomator.common.Environment;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class LoggerConfiguration {
|
||||||
|
|
||||||
|
private static final double SHUTDOWN_DELAY_MS = 100;
|
||||||
|
|
||||||
|
private final LoggerContext context;
|
||||||
|
private final Environment environment;
|
||||||
|
private final Appender<ILoggingEvent> stdout;
|
||||||
|
private final Appender<ILoggingEvent> upgrade;
|
||||||
|
private final Appender<ILoggingEvent> file;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
LoggerConfiguration(LoggerContext context, //
|
||||||
|
Environment environment, //
|
||||||
|
@Named("stdoutAppender") Appender<ILoggingEvent> stdout, //
|
||||||
|
@Named("upgradeAppender") Appender<ILoggingEvent> upgrade, //
|
||||||
|
@Named("fileAppender") Appender<ILoggingEvent> file) {
|
||||||
|
this.context = context;
|
||||||
|
this.environment = environment;
|
||||||
|
this.stdout = stdout;
|
||||||
|
this.upgrade = upgrade;
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
if (environment.useCustomLogbackConfig()) {
|
||||||
|
Logger root = context.getLogger(Logger.ROOT_LOGGER_NAME);
|
||||||
|
root.info("Using external logback configuration file.");
|
||||||
|
} else {
|
||||||
|
context.reset();
|
||||||
|
|
||||||
|
// configure loggers:
|
||||||
|
for (Map.Entry<String, Level> loglevel : LoggerModule.DEFAULT_LOG_LEVELS.entrySet()) {
|
||||||
|
Logger logger = context.getLogger(loglevel.getKey());
|
||||||
|
logger.setLevel(loglevel.getValue());
|
||||||
|
logger.setAdditive(false);
|
||||||
|
logger.addAppender(stdout);
|
||||||
|
logger.addAppender(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure upgrade logger:
|
||||||
|
Logger upgrades = context.getLogger("org.cryptomator.ui.model.upgrade");
|
||||||
|
upgrades.setLevel(Level.DEBUG);
|
||||||
|
upgrades.addAppender(stdout);
|
||||||
|
upgrades.addAppender(upgrade);
|
||||||
|
upgrades.setAdditive(false);
|
||||||
|
|
||||||
|
// add shutdown hook
|
||||||
|
DelayingShutdownHook shutdownHook = new DelayingShutdownHook();
|
||||||
|
shutdownHook.setContext(context);
|
||||||
|
shutdownHook.setDelay(Duration.buildByMilliseconds(SHUTDOWN_DELAY_MS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -32,7 +32,6 @@ public class LoggerModule {
|
|||||||
private static final String LOGFILE_ROLLING_PATTERN = "cryptomator%i.log";
|
private static final String LOGFILE_ROLLING_PATTERN = "cryptomator%i.log";
|
||||||
private static final int LOGFILE_ROLLING_MIN = 1;
|
private static final int LOGFILE_ROLLING_MIN = 1;
|
||||||
private static final int LOGFILE_ROLLING_MAX = 9;
|
private static final int LOGFILE_ROLLING_MAX = 9;
|
||||||
private static final double SHUTDOWN_DELAY_MS = 100;
|
|
||||||
private static final String LOG_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n";
|
private static final String LOG_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n";
|
||||||
static final Map<String, Level> DEFAULT_LOG_LEVELS = Map.of( //
|
static final Map<String, Level> DEFAULT_LOG_LEVELS = Map.of( //
|
||||||
Logger.ROOT_LOGGER_NAME, Level.INFO, //
|
Logger.ROOT_LOGGER_NAME, Level.INFO, //
|
||||||
@@ -45,7 +44,7 @@ public class LoggerModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
LoggerContext provideLoggerContext() {
|
static LoggerContext provideLoggerContext() {
|
||||||
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
|
ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
|
||||||
if (loggerFactory instanceof LoggerContext) {
|
if (loggerFactory instanceof LoggerContext) {
|
||||||
return (LoggerContext) loggerFactory;
|
return (LoggerContext) loggerFactory;
|
||||||
@@ -56,7 +55,7 @@ public class LoggerModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
PatternLayoutEncoder provideLayoutEncoder(LoggerContext context) {
|
static PatternLayoutEncoder provideLayoutEncoder(LoggerContext context) {
|
||||||
PatternLayoutEncoder ple = new PatternLayoutEncoder();
|
PatternLayoutEncoder ple = new PatternLayoutEncoder();
|
||||||
ple.setPattern(LOG_PATTERN);
|
ple.setPattern(LOG_PATTERN);
|
||||||
ple.setContext(context);
|
ple.setContext(context);
|
||||||
@@ -67,7 +66,7 @@ public class LoggerModule {
|
|||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("stdoutAppender")
|
@Named("stdoutAppender")
|
||||||
Appender<ILoggingEvent> provideStdoutAppender(LoggerContext context, PatternLayoutEncoder encoder) {
|
static Appender<ILoggingEvent> provideStdoutAppender(LoggerContext context, PatternLayoutEncoder encoder) {
|
||||||
ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
|
ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
|
||||||
appender.setContext(context);
|
appender.setContext(context);
|
||||||
appender.setEncoder(encoder);
|
appender.setEncoder(encoder);
|
||||||
@@ -78,7 +77,7 @@ public class LoggerModule {
|
|||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("fileAppender")
|
@Named("fileAppender")
|
||||||
Appender<ILoggingEvent> provideFileAppender(LoggerContext context, PatternLayoutEncoder encoder, Environment environment) {
|
static Appender<ILoggingEvent> provideFileAppender(LoggerContext context, PatternLayoutEncoder encoder, Environment environment) {
|
||||||
if (environment.getLogDir().isPresent()) {
|
if (environment.getLogDir().isPresent()) {
|
||||||
Path logDir = environment.getLogDir().get();
|
Path logDir = environment.getLogDir().get();
|
||||||
RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
|
RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
|
||||||
@@ -109,7 +108,7 @@ public class LoggerModule {
|
|||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("upgradeAppender")
|
@Named("upgradeAppender")
|
||||||
Appender<ILoggingEvent> provideUpgradeAppender(LoggerContext context, PatternLayoutEncoder encoder, Environment environment) {
|
static Appender<ILoggingEvent> provideUpgradeAppender(LoggerContext context, PatternLayoutEncoder encoder, Environment environment) {
|
||||||
if (environment.getLogDir().isPresent()) {
|
if (environment.getLogDir().isPresent()) {
|
||||||
FileAppender<ILoggingEvent> appender = new FileAppender<>();
|
FileAppender<ILoggingEvent> appender = new FileAppender<>();
|
||||||
appender.setFile(environment.getLogDir().get().resolve(UPGRADE_FILENAME).toString());
|
appender.setFile(environment.getLogDir().get().resolve(UPGRADE_FILENAME).toString());
|
||||||
@@ -124,46 +123,5 @@ public class LoggerModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
@Named("initLogging")
|
|
||||||
Runnable provideLogbackInitializer(LoggerContext context, //
|
|
||||||
Environment environment, //
|
|
||||||
@Named("stdoutAppender") Appender<ILoggingEvent> stdout, //
|
|
||||||
@Named("upgradeAppender") Appender<ILoggingEvent> upgrade, //
|
|
||||||
@Named("fileAppender") Appender<ILoggingEvent> file) {
|
|
||||||
if (environment.useCustomLogbackConfig()) {
|
|
||||||
return () -> {
|
|
||||||
Logger root = context.getLogger(Logger.ROOT_LOGGER_NAME);
|
|
||||||
root.info("Using external logback configuration file.");
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return () -> {
|
|
||||||
context.reset();
|
|
||||||
|
|
||||||
// configure loggers:
|
|
||||||
for (Map.Entry<String, Level> loglevel : DEFAULT_LOG_LEVELS.entrySet()) {
|
|
||||||
Logger logger = context.getLogger(loglevel.getKey());
|
|
||||||
logger.setLevel(loglevel.getValue());
|
|
||||||
logger.setAdditive(false);
|
|
||||||
logger.addAppender(stdout);
|
|
||||||
logger.addAppender(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure upgrade logger:
|
|
||||||
Logger upgrades = context.getLogger("org.cryptomator.ui.model.upgrade");
|
|
||||||
upgrades.setLevel(Level.DEBUG);
|
|
||||||
upgrades.addAppender(stdout);
|
|
||||||
upgrades.addAppender(upgrade);
|
|
||||||
upgrades.setAdditive(false);
|
|
||||||
|
|
||||||
// add shutdown hook
|
|
||||||
DelayingShutdownHook shutdownHook = new DelayingShutdownHook();
|
|
||||||
shutdownHook.setContext(context);
|
|
||||||
shutdownHook.setDelay(Duration.buildByMilliseconds(SHUTDOWN_DELAY_MS));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@@ -99,6 +100,7 @@ public class MainController implements ViewController {
|
|||||||
private final ViewControllerLoader viewControllerLoader;
|
private final ViewControllerLoader viewControllerLoader;
|
||||||
private final ObjectProperty<ViewController> activeController = new SimpleObjectProperty<>();
|
private final ObjectProperty<ViewController> activeController = new SimpleObjectProperty<>();
|
||||||
private final ObservableList<Vault> vaults;
|
private final ObservableList<Vault> vaults;
|
||||||
|
private final CountDownLatch shutdownLatch;
|
||||||
private final BooleanBinding areAllVaultsLocked;
|
private final BooleanBinding areAllVaultsLocked;
|
||||||
private final ObjectProperty<Vault> selectedVault = new SimpleObjectProperty<>();
|
private final ObjectProperty<Vault> selectedVault = new SimpleObjectProperty<>();
|
||||||
private final ObjectExpression<Vault.State> selectedVaultState = ObjectExpression.objectExpression(EasyBind.select(selectedVault).selectObject(Vault::stateProperty));
|
private final ObjectExpression<Vault.State> selectedVaultState = ObjectExpression.objectExpression(EasyBind.select(selectedVault).selectObject(Vault::stateProperty));
|
||||||
@@ -112,7 +114,7 @@ public class MainController implements ViewController {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public MainController(@Named("mainWindow") Stage mainWindow, ExecutorService executorService, @Named("launchEventQueue") BlockingQueue<AppLaunchEvent> launchEventQueue, ExitUtil exitUtil, Localization localization,
|
public MainController(@Named("mainWindow") Stage mainWindow, ExecutorService executorService, @Named("launchEventQueue") BlockingQueue<AppLaunchEvent> launchEventQueue, ExitUtil exitUtil, Localization localization,
|
||||||
VaultFactory vaultFactoy, ViewControllerLoader viewControllerLoader, UpgradeStrategies upgradeStrategies, VaultList vaults, AutoUnlocker autoUnlocker) {
|
VaultFactory vaultFactoy, ViewControllerLoader viewControllerLoader, UpgradeStrategies upgradeStrategies, VaultList vaults, AutoUnlocker autoUnlocker, @Named("shutdownLatch") CountDownLatch shutdownLatch) {
|
||||||
this.mainWindow = mainWindow;
|
this.mainWindow = mainWindow;
|
||||||
this.executorService = executorService;
|
this.executorService = executorService;
|
||||||
this.launchEventQueue = launchEventQueue;
|
this.launchEventQueue = launchEventQueue;
|
||||||
@@ -121,6 +123,7 @@ public class MainController implements ViewController {
|
|||||||
this.vaultFactoy = vaultFactoy;
|
this.vaultFactoy = vaultFactoy;
|
||||||
this.viewControllerLoader = viewControllerLoader;
|
this.viewControllerLoader = viewControllerLoader;
|
||||||
this.vaults = vaults;
|
this.vaults = vaults;
|
||||||
|
this.shutdownLatch = shutdownLatch;
|
||||||
|
|
||||||
// derived bindings:
|
// derived bindings:
|
||||||
this.isShowingSettings = Bindings.equal(SettingsController.class, EasyBind.monadic(activeController).map(ViewController::getClass));
|
this.isShowingSettings = Bindings.equal(SettingsController.class, EasyBind.monadic(activeController).map(ViewController::getClass));
|
||||||
@@ -231,13 +234,13 @@ public class MainController implements ViewController {
|
|||||||
if (tryAgainButtonType.equals(btnType)) {
|
if (tryAgainButtonType.equals(btnType)) {
|
||||||
gracefulShutdown();
|
gracefulShutdown();
|
||||||
} else if (forceShutdownButtonType.equals(btnType)) {
|
} else if (forceShutdownButtonType.equals(btnType)) {
|
||||||
Platform.runLater(Platform::exit);
|
shutdownLatch.countDown();
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Platform.runLater(Platform::exit);
|
shutdownLatch.countDown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.cryptomator.ui.controls;
|
package org.cryptomator.ui.controls;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.embed.swing.JFXPanel;
|
import javafx.embed.swing.JFXPanel;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.Assumptions;
|
import org.junit.jupiter.api.Assumptions;
|
||||||
@@ -22,10 +23,7 @@ class SecPasswordFieldTest {
|
|||||||
static void initJavaFx() throws InterruptedException {
|
static void initJavaFx() throws InterruptedException {
|
||||||
Assumptions.assumeFalse(GraphicsEnvironment.isHeadless());
|
Assumptions.assumeFalse(GraphicsEnvironment.isHeadless());
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
SwingUtilities.invokeLater(() -> {
|
Platform.startup(latch::countDown);
|
||||||
new JFXPanel(); // initializes JavaFX environment
|
|
||||||
latch.countDown();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!latch.await(5L, TimeUnit.SECONDS)) {
|
if (!latch.await(5L, TimeUnit.SECONDS)) {
|
||||||
throw new ExceptionInInitializerError();
|
throw new ExceptionInInitializerError();
|
||||||
|
|||||||
Reference in New Issue
Block a user