WorkbenchConfiguration.java
package org.hammer.audio.app;
import java.util.List;
import org.hammer.audio.experiment.document.ExperimentDocumentService;
import org.hammer.audio.experiment.document.workspace.ExperimentDocumentWorkspaceService;
import org.hammer.audio.pluginhost.PluginManager;
import org.hammer.audio.pluginhost.PluginRegistry;
import org.hammer.audio.workflow.Edge;
import org.hammer.audio.workflow.Node;
import org.hammer.audio.workflow.Workflow;
import org.hammer.audio.workflow.WorkflowOperationLog;
import org.hammer.audio.workflow.WorkflowValidator;
import org.hammer.audio.workflow.catalog.ExperimentNodeCatalog;
import org.hammer.audio.workflow.collaboration.WorkflowSessionEventHub;
import org.hammer.audio.workflow.collaboration.WorkflowSessionRegistry;
import org.hammer.audio.workflow.collaboration.store.WorkflowSessionStateStore;
import org.hammer.audio.workflow.editor.WorkflowEditorService;
import org.hammer.audio.workflow.store.VersionedWorkflowStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Spring configuration for the workflow workbench.
*
* <p>Provides workflow editing and collaboration application services and consumes the optional
* {@link VersionedWorkflowStore} selected by {@link WorkflowPersistenceConfiguration}. Also
* registers a filesystem resource handler when {@code workbench.static.dir} is configured;
* otherwise the built-in classpath UI at {@code /workbench-ui/} is served.
*/
@Configuration
public class WorkbenchConfiguration implements WebMvcConfigurer {
@Value("${workbench.static.dir:}")
private String staticDir;
/** Creates the single-user workflow editor service and injects the optional store. */
@Bean
public WorkflowEditorService workflowEditorService(
ObjectProvider<VersionedWorkflowStore> storeProvider) {
WorkflowOperationLog log = new WorkflowOperationLog(seedWorkflow());
WorkflowValidator validator = new WorkflowValidator();
return new WorkflowEditorService(log, validator, storeProvider.getIfAvailable());
}
/** Discovers the installed trusted plugins exactly once for the workbench application. */
@Bean
public PluginRegistry pluginRegistry() {
return new PluginManager().loadPlugins();
}
/** Creates the shared safe experiment-document service from the installed plugin registry. */
@Bean
public ExperimentDocumentService experimentDocumentService(PluginRegistry pluginRegistry) {
return new ExperimentDocumentService(pluginRegistry.plugins());
}
/** Coordinates confirmed document application with editor and collaboration state. */
@Bean
public ExperimentDocumentWorkspaceService experimentDocumentWorkspaceService(
ExperimentDocumentService documentService,
WorkflowEditorService editorService,
WorkflowSessionRegistry sessionRegistry) {
return new ExperimentDocumentWorkspaceService(documentService, editorService, sessionRegistry);
}
/** Creates the bounded transport-neutral collaboration event hub. */
@Bean
public WorkflowSessionEventHub workflowSessionEventHub() {
return new WorkflowSessionEventHub();
}
/**
* Creates the collaboration-session application service and hydrates durable sessions when the
* Hibernate persistence mode contributes a state store.
*/
@Bean
public WorkflowSessionRegistry workflowSessionRegistry(
WorkflowSessionEventHub eventHub,
ObjectProvider<WorkflowSessionStateStore> stateStoreProvider) {
return new WorkflowSessionRegistry(eventHub, stateStoreProvider.getIfAvailable());
}
/** Registers a filesystem resource handler when configured. */
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (staticDir != null && !staticDir.isBlank()) {
String location = staticDir.endsWith("/") ? "file:" + staticDir : "file:" + staticDir + "/";
registry.addResourceHandler("/**").addResourceLocations(location);
}
}
/** Returns the deterministic seed workflow for the workbench. */
static Workflow seedWorkflow() {
Node inputNode = ExperimentNodeCatalog.syntheticSignalGenerator("seed.input");
Node gainNode = ExperimentNodeCatalog.gain("seed.gain");
Node outputNode = ExperimentNodeCatalog.localization("seed.output");
Edge inputToGain =
new Edge("seed.edge.in-to-gain", "seed.input", "signal-out", "seed.gain", "audio-in");
Edge gainToOutput =
new Edge("seed.edge.gain-to-out", "seed.gain", "audio-out", "seed.output", "audio-in");
return new Workflow(
"seed.workflow",
"Input -> Gain -> Output",
List.of(inputNode, gainNode, outputNode),
List.of(inputToGain, gainToOutput));
}
}