ExperimentWorkbenchLauncher.java

package org.hammer;

import java.awt.Desktop;
import java.awt.EventQueue;
import java.io.File;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hammer.audio.experiment.document.ExperimentDocumentService;
import org.hammer.audio.pluginhost.PluginManager;
import org.hammer.audio.pluginhost.PluginRegistry;
import org.hammer.audio.ui.theme.UiTheme;

/**
 * Launches the experiment-aware desktop with portable document preview and normalization actions.
 */
public final class ExperimentWorkbenchLauncher {

  private static final Logger LOGGER =
      Logger.getLogger(ExperimentWorkbenchLauncher.class.getName());

  private ExperimentWorkbenchLauncher() {
    // application entry point
  }

  /** Start the Swing workbench on the event-dispatch thread. */
  public static void main(String[] args) {
    EventQueue.invokeLater(
        () -> {
          try {
            UiTheme.installDarkTheme();
            PluginRegistry plugins = new PluginManager().loadPlugins();
            ExperimentAudioAnalyseFrame frame = new ExperimentAudioAnalyseFrame();
            ExperimentDocumentService documentService =
                new ExperimentDocumentService(plugins.plugins());
            ExperimentDocumentSwingActions documentActions =
                new ExperimentDocumentSwingActions(frame, documentService);
            documentActions.install();
            installDesktopOpenFileHandler(documentActions::inspect);
            frame.setVisible(true);
            inspectStartupArguments(args, documentActions::inspect);
          } catch (RuntimeException exception) {
            LOGGER.log(Level.SEVERE, "Failed to start experiment desktop workbench", exception);
          }
        });
  }

  /** Send non-blank startup file arguments through the same safe document-preview action. */
  static void inspectStartupArguments(String[] args, Consumer<Path> inspector) {
    Objects.requireNonNull(args, "args");
    Objects.requireNonNull(inspector, "inspector");
    for (String argument : args) {
      if (argument == null || argument.isBlank()) {
        continue;
      }
      try {
        inspector.accept(Path.of(argument));
      } catch (InvalidPathException exception) {
        LOGGER.log(Level.WARNING, "Ignoring invalid experiment document path argument", exception);
      }
    }
  }

  /**
   * Register already-running application open-file events when the desktop platform supports them.
   */
  static void installDesktopOpenFileHandler(Consumer<Path> inspector) {
    Objects.requireNonNull(inspector, "inspector");
    try {
      if (!Desktop.isDesktopSupported()) {
        return;
      }
      Desktop desktop = Desktop.getDesktop();
      if (!desktop.isSupported(Desktop.Action.APP_OPEN_FILE)) {
        return;
      }
      desktop.setOpenFileHandler(
          event ->
              event.getFiles().stream()
                  .map(File::toPath)
                  .forEach(path -> inspectOnEventThread(path, inspector)));
    } catch (SecurityException | UnsupportedOperationException exception) {
      LOGGER.log(Level.FINE, "Desktop open-file integration is unavailable", exception);
    }
  }

  private static void inspectOnEventThread(Path source, Consumer<Path> inspector) {
    if (EventQueue.isDispatchThread()) {
      inspector.accept(source);
    } else {
      EventQueue.invokeLater(() -> inspector.accept(source));
    }
  }
}