SpringBootMigrationAdapterTransformer.java
package io.vanillabp.integration.config;
import static io.vanillabp.integration.config.SpringBootMigrationAdapterProperties.PREFIX;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import io.vanillabp.integration.modules.WorkflowModuleProperties;
import lombok.Builder;
@Builder(toBuilder = true)
public class SpringBootMigrationAdapterTransformer {
private SpringBootMigrationAdapterProperties properties;
private List<String> adaptersLoaded;
private List<String> workflowModulesLoaded;
public MigrationAdapterProperties getAndValidatePropertiesConfigured() {
final var result = new MigrationAdapterProperties();
final var adaptersConfigured = getAndValidateAdaptersConfigured();
result.setAdapters(adaptersConfigured);
final var prioritizedAdaptersConfigured = getAndValidatePrioritizedAdaptersConfigured(
adaptersConfigured);
result.setPrioritizedAdapters(prioritizedAdaptersConfigured);
final var workflowModulesConfigured = getAndValidateWorkflowModulesConfigured();
result.setWorkflowModules(workflowModulesConfigured);
result.validateProperties(adaptersLoaded, workflowModulesLoaded);
return result;
}
private Map<String, WorkflowModuleAdapterProperties> getAndValidateWorkflowModulesConfigured() {
if (workflowModulesLoaded.isEmpty()) {
throw new IllegalStateException(
"No workflow-modules found in classpath! Add dependencies providing static beans of type '%s'."
.formatted(WorkflowModuleProperties.class));
}
final var result = properties
.getWorkflowModules()
.entrySet()
.stream()
.map(config -> Map.entry(
config.getKey(),
(WorkflowModuleAdapterProperties) WorkflowModuleAdapterProperties
.builder()
.workflowModuleId(config.getKey())
.workflows(Map.of()) // TODO fill workflows
.adapters(config
.getValue()
.getAdapters()
.entrySet()
.stream()
.map(adapter -> Map.entry(
adapter.getKey(),
AdapterConfiguration
.builder()
.resourcesLocation(adapter.getValue().getResourcesLocation())
.build()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))
.build()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
if (result.isEmpty()) {
final var missingConfigSections = workflowModulesLoaded
.stream()
.map(module -> "%s.workflow-modules.%s".formatted(PREFIX, module))
.collect(Collectors.joining("', '"));
throw new IllegalStateException(
"No workflow-modules configured! Add properties sections '%s'.".formatted(missingConfigSections));
}
// check for unknown adapters
final var unknownModules = result
.keySet()
.stream()
.filter(workflowModuleAdapterProperties -> !workflowModulesLoaded.contains(workflowModuleAdapterProperties))
.map(workflowModuleAdapterProperties -> "%s.workflow-modules.%s".formatted(PREFIX,
workflowModuleAdapterProperties))
.collect(Collectors.joining("\n, "));
if (!unknownModules.isEmpty()) {
throw new IllegalStateException(
"""
Properties '%s.workflow-modules.*' must contain VanillaBP workflow modules available in classpath!
These workflow modules are unknown:
%s
Available workflow modules currently loaded in classpath: '%s'."""
.formatted(PREFIX, unknownModules, String.join("', '", workflowModulesLoaded)));
}
return result;
}
private Map<String, String> getAndValidateAdaptersConfigured() {
if (adaptersLoaded.isEmpty()) {
throw new IllegalStateException(
"No adapters found in classpath! Add dependencies providing VanillaBP adapters.");
}
// build result map (key = adapter name, value = adapter type)
final var result = properties
.getAdapters()
.entrySet()
.stream()
.map(config -> Map.entry(config.getKey(),
Optional.ofNullable(config.getValue().getType()).orElse(config.getKey())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
if (result.isEmpty()) {
final var missingConfigSections = adaptersLoaded
.stream()
.map(adapter -> "%s.adapters.%s".formatted(PREFIX, adapter))
.collect(Collectors.joining("\n"));
throw new IllegalStateException(
"""
No adapters configured! Add properties sections
%s"""
.formatted(missingConfigSections));
}
// check for unknown adapters
final var unknownAdapters = result
.entrySet()
.stream()
.filter(adapter -> !adaptersLoaded.contains(adapter.getValue()))
.map(adapter -> "'%s' found in '%s.adapters.%s.type'".formatted(adapter.getValue(), PREFIX, adapter.getKey()))
.collect(Collectors.joining(", "));
if (!unknownAdapters.isEmpty()) {
throw new IllegalStateException(
"""
Properties '%s.adapters.*.type' must contain VanillaBP adapters available in classpath!
These adapters are unknown: %s.
Available adapter types currently loaded in classpath: '%s'."""
.formatted(PREFIX, unknownAdapters, String.join("', '", adaptersLoaded)));
}
return result;
}
private List<String> getAndValidatePrioritizedAdaptersConfigured(
final Map<String, String> adapters) {
// It is OK to skip property vanillabp.prioritized-adapters in case
// only one adapter is configured:
if (properties.getPrioritizedAdapters().isEmpty() && (adapters.size() == 1)) {
return adapters.keySet().stream().toList();
}
// if more than one adapter is configured then the
// property vanillabp.prioritized-adapters has to list each adapter
// configured:
final var adapterNamesConfigured = String.join(", ", adapters.keySet());
if (properties.getPrioritizedAdapters()
.isEmpty() || (adapters.size() != properties.getPrioritizedAdapters().size())) {
throw new IllegalStateException(
"""
The property '%s.prioritized-adapters' must list all the adapters configured in '%s.adapters.*' to define the order in which adapters are addressed to find workflows running.
These are: %s."""
.formatted(PREFIX, PREFIX, adapterNamesConfigured));
}
final var unknownAdapters = properties
.getPrioritizedAdapters()
.stream()
.filter(adapter -> !adapterNamesConfigured.contains(adapter))
.collect(Collectors.joining(", "));
if (!unknownAdapters.isEmpty()) {
throw new IllegalStateException(
"The property '%s.prioritized-adapters' lists these adapters for which no properties '%s.adapters.*' were found: %s!"
.formatted(PREFIX, PREFIX, unknownAdapters));
}
return properties.getPrioritizedAdapters();
}
}