diff --git a/src/main/jastadd/Coordinator.jrag b/src/main/jastadd/Coordinator.jrag index 1f9a8a201da38baff7948e4bb9466e3f9669f02a..c7bd041e509f7c978000959462da2dd67f9251c4 100644 --- a/src/main/jastadd/Coordinator.jrag +++ b/src/main/jastadd/Coordinator.jrag @@ -49,10 +49,10 @@ aspect Manipulation { return Collections.emptySet(); } for (String service : services) { - resolveComponentByDockerComposeName(service).ifPresentOrElse( - comp -> result.add(comp), - () -> System.err.println("Could not resolve docker component for '" + service + "'!") - ); + Component resolvedComponent = resolveComponentByDockerComposeName(service); + if (!resolvedComponent.handleFailedComponentResolving("Service", () -> "resolving docker compose")) { + result.add(resolvedComponent); + } } return result; } @@ -137,6 +137,9 @@ aspect Navigation { syn MqttReportStrategy ReportStrategy.asMqttReportStrategy() = null; eq MqttReportStrategy.asMqttReportStrategy() = this; + + syn boolean Component.isUnknownComponent() = false; + eq UnknownComponent.isUnknownComponent() = true; } aspect Printing { @@ -222,31 +225,65 @@ aspect Printing { } aspect Resolving { - syn Optional<Component> Coordinator.resolveComponent(String name) { + public enum ResolvingFailedStrategy { + IGNORE, + WARNING, + EXIT + } + + public static ResolvingFailedStrategy Coordinator.RESOLVING_FAILED_STRATEGY = ResolvingFailedStrategy.EXIT; + + syn nta Component Coordinator.unknownComponent(String id) = new UnknownComponent().setName(id); + + syn Component Coordinator.resolveComponent(String name) { for (Component comp : getComponentList()) { if (comp.getName().equals(name)) { - return Optional.of(comp); + return comp; } } - return Optional.empty(); + return unknownComponent(name); } - syn Optional<Component> Coordinator.resolveComponentByDockerComposeName(String dockerComposeName) { + syn Component Coordinator.resolveComponentByDockerComposeName(String dockerComposeName) { for (Component comp : getComponentList()) { if (comp.getStartStrategy().isDockerComposeStartStrategy() && comp.getStartStrategy().asDockerComposeStartStrategy().getName().equals(dockerComposeName)) { - return Optional.of(comp); + return comp; } } - return Optional.empty(); + return unknownComponent(dockerComposeName); } refine RefResolverStubs eq ParsedPrecedenceRelation.resolvePredecessorByToken(String id, int position) { - return coordinator().resolveComponent(id).orElseThrow(() -> new RuntimeException("Predecessor '" + id + "' not found in " + this.prettyPrint() + "!")); + return coordinator().resolveComponent(id); } refine RefResolverStubs eq ParsedPrecedenceRelation.resolveSuccessorByToken(String id, int position) { - return coordinator().resolveComponent(id).orElseThrow(() -> new RuntimeException("Successor '" + id + "' not found in " + this.prettyPrint() + "!")); + return coordinator().resolveComponent(id); + } + + /** + * Handles component resolving based on the current strategy. + * If the component is an unknownComponent, decide based on RESOLVING_FAILED_STRATEGY what to do. + * Either do nothing (IGNORE), print a message (WARNING), or throw a RuntimeException (EXIT). + * @return false if a real component was resolved, true if this is an unknown component + */ + public boolean Component.handleFailedComponentResolving(String kind, java.util.function.Supplier<String> context) { + return false; + } + @Override + public boolean UnknownComponent.handleFailedComponentResolving(String kind, java.util.function.Supplier<String> context) { + String message = kind + " '" + getName() + "' not found in " + context.get() + "!"; + switch (Coordinator.RESOLVING_FAILED_STRATEGY) { + case IGNORE: + break; + case WARNING: + System.err.println(message); + break; + case EXIT: + throw new RuntimeException(message); + } + return true; } } diff --git a/src/main/jastadd/Coordinator.parser b/src/main/jastadd/Coordinator.parser index a1bb3f64f4db8a49c5d95284effd3b03c609a72f..1b5e9d8f5dd5fe9e489d4e9882e29c46aad4be7f 100644 --- a/src/main/jastadd/Coordinator.parser +++ b/src/main/jastadd/Coordinator.parser @@ -13,7 +13,9 @@ import java.util.HashMap; private void replaceRelations(Coordinator o) { for (ParsedPrecedenceRelation rel : o.getParsedPrecedenceRelationList()) { for (Component pred : rel.getPredecessorList()) { + if (pred.handleFailedComponentResolving("Predecessor", () -> rel.prettyPrint())) { continue; } for (Component succ : rel.getSuccessorList()) { + if (succ.handleFailedComponentResolving("Successor", () -> rel.prettyPrint())) { continue; } pred.addSuccessor(succ); } } diff --git a/src/main/jastadd/Coordinator.relast b/src/main/jastadd/Coordinator.relast index 11abd3738d7b0b8732d2ea632edee9308925a0fa..3eb491c327cfa7f3268e7a88d33a4326724126fb 100644 --- a/src/main/jastadd/Coordinator.relast +++ b/src/main/jastadd/Coordinator.relast @@ -15,3 +15,6 @@ AutoSetStatus ::= <Status:String> <DelayInSeconds:int> ; ParsedPrecedenceRelation ; rel ParsedPrecedenceRelation.Predecessor* -> Component ; rel ParsedPrecedenceRelation.Successor* -> Component ; + +// Parser-only +UnknownComponent : Component ; diff --git a/src/main/java/de/tudresden/inf/st/coordinator/MainCoordinator.java b/src/main/java/de/tudresden/inf/st/coordinator/MainCoordinator.java index 7ccd1f6085742164b91ab4a3fcfeb345c3a70650..c3923ebf881340bd90371fdb948bb76045e677a5 100644 --- a/src/main/java/de/tudresden/inf/st/coordinator/MainCoordinator.java +++ b/src/main/java/de/tudresden/inf/st/coordinator/MainCoordinator.java @@ -1,10 +1,7 @@ package de.tudresden.inf.st.coordinator; import beaver.Parser; -import de.tudresden.inf.st.coordinator.ast.Component; -import de.tudresden.inf.st.coordinator.ast.Coordinator; -import de.tudresden.inf.st.coordinator.ast.MqttHandler; -import de.tudresden.inf.st.coordinator.ast.MqttReportStrategy; +import de.tudresden.inf.st.coordinator.ast.*; import de.tudresden.inf.st.coordinator.parser.CoordinatorParser; import de.tudresden.inf.st.coordinator.scanner.CoordinatorScanner; import picocli.CommandLine; @@ -45,17 +42,23 @@ public class MainCoordinator implements Callable<Integer> { @Option(names = { "--mqtt-host"}, description = "MQTT host to control this coordinator") String mqttHost = "localhost"; + @Option(names = { "-r", "--resolvingFailedStrategy"}, description = "Action if resolving of component fails, do nothing (IGNORE), print a message (WARNING), or throw a RuntimeException (EXIT)") + ResolvingFailedStrategy resolvingFailedStrategy = ResolvingFailedStrategy.EXIT; + @Parameters(description = "Coordinator config file to use") File configFile; public static void main(String[] args) { - int exitCode = new CommandLine(new MainCoordinator()).execute(args); + int exitCode = new CommandLine(new MainCoordinator()) + .setCaseInsensitiveEnumValuesAllowed(true) + .execute(args); System.exit(exitCode); } @Override public Integer call() throws Exception { Coordinator.DRY_RUN = dryRun; + Coordinator.RESOLVING_FAILED_STRATEGY = resolvingFailedStrategy; parsedBuild(); return start(); }