From ca6eaa0fbd721ccbc947478bb935a9b3a2c4f07c Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Mon, 5 Aug 2024 17:42:51 -0700 Subject: [PATCH 01/17] Add "Stateless Aerie" Module Co-authored-by: Ryan Goetz --- settings.gradle | 4 + stateless-aerie/build.gradle | 85 +++++++++++++++++++ .../gov/nasa/jpl/aerie/stateless/Main.java | 5 ++ 3 files changed, 94 insertions(+) create mode 100644 stateless-aerie/build.gradle create mode 100644 stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java diff --git a/settings.gradle b/settings.gradle index e8d8c7311b..195ce9efe9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,6 +27,9 @@ include 'sequencing-server' include 'constraints' include 'scheduler-driver' +// Stateless Mode +include 'stateless-aerie' + // Testing include 'db-tests' include 'e2e-tests' @@ -38,3 +41,4 @@ include 'examples:config-with-defaults' include 'examples:config-without-defaults' include 'examples:minimal-mission-model' include 'examples:streamline-demo' +include 'stateless-aerie' diff --git a/stateless-aerie/build.gradle b/stateless-aerie/build.gradle new file mode 100644 index 0000000000..368cb73e72 --- /dev/null +++ b/stateless-aerie/build.gradle @@ -0,0 +1,85 @@ +plugins { + id 'java-library' + id 'maven-publish' + id 'jacoco' + id 'application' +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + + withJavadocJar() + withSourcesJar() +} + +jar { + dependsOn(':parsing-utilities:jar') + dependsOn(':merlin-sdk:jar') + dependsOn(':merlin-driver:jar') + dependsOn(':constraints:jar') + + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + manifest { + attributes('Main-Class': 'gov.nasa.jpl.aerie.stateless.Main') + } + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } +} + +test { + useJUnitPlatform { + includeEngines 'junit-jupiter' + } + testLogging { + exceptionFormat = 'full' + } +} + +jacocoTestReport { + dependsOn test + reports { + xml.required = true + } +} + +// Link references to standard Java classes to the official Java 11 documentation. +javadoc.options.links 'https://docs.oracle.com/en/java/javase/11/docs/api/' +javadoc.options.links 'https://commons.apache.org/proper/commons-lang/javadocs/api-3.9/' +javadoc.options.addStringOption('Xdoclint:none', '-quiet') + +dependencies { + implementation project(':merlin-server') + implementation project(':merlin-driver') + implementation project(':parsing-utilities') + implementation 'commons-cli:commons-cli:1.8.0' + + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' + + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + +publishing { + publications { + library(MavenPublication) { + version = findProperty('publishing.version') + from components.java + } + } + + publishing { + repositories { + maven { + name = findProperty("publishing.name") + url = findProperty("publishing.url") + credentials { + username = System.getenv(findProperty("publishing.usernameEnvironmentVariable")) + password = System.getenv(findProperty("publishing.passwordEnvironmentVariable")) + } + } + } + } +} diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java new file mode 100644 index 0000000000..20547303a2 --- /dev/null +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java @@ -0,0 +1,5 @@ +package gov.nasa.jpl.aerie.stateless; + +public class Main { + public static void main(String[] args) {} +} From 62579439cf7bcbea77e4963e74ae854148c9485e Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Mon, 5 Aug 2024 17:44:46 -0700 Subject: [PATCH 02/17] Add Parser for CLI inputs - Add new Plan Constructor with Sim Config Co-authored-by: Ryan Goetz --- .../jpl/aerie/merlin/server/models/Plan.java | 15 ++ .../gov/nasa/jpl/aerie/stateless/Main.java | 194 +++++++++++++++++- .../jpl/aerie/stateless/PlanJsonParser.java | 167 +++++++++++++++ 3 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java index 2406dd8b69..bf2ab8e2b0 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java @@ -73,6 +73,21 @@ public Plan( this.simulationEndTimestamp = simulationEndTimestamp; } + public Plan( + String name, + Timestamp startTimestamp, + Timestamp endTimestamp, + Map activityDirectives, + Map simulationConfig) { + this.name = name; + this.startTimestamp = startTimestamp; + this.endTimestamp = endTimestamp; + this.activityDirectives = activityDirectives; + this.configuration = simulationConfig; + this.simulationStartTimestamp = startTimestamp; + this.simulationEndTimestamp = endTimestamp; + } + @Override public boolean equals(final Object object) { if (!(object instanceof final Plan other)) { diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java index 20547303a2..69454696ef 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java @@ -1,5 +1,197 @@ package gov.nasa.jpl.aerie.stateless; +import gov.nasa.jpl.aerie.merlin.driver.MissionModel; +import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; +import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.merlin.server.models.Plan; + +import java.nio.file.Path; +import java.util.Optional; + +import org.apache.commons.cli.*; + public class Main { - public static void main(String[] args) {} + private static final String VERSION = "v2.16.0"; + private static final String FOOTER = "\nStateless Aerie "+VERSION; + + private static final Option HELP_OPTION = new Option("h", "help", false, "display this message and exit"); + + private sealed interface Arguments { + record SimulationArguments ( + MissionModel missionModel, + Plan plan, + boolean verbose, + Optional outputFilePath, + long extentUpdatePeriod + ) implements Arguments {} + } + + public static void main(String[] args) { + if(args.length == 0) { + displayTopLevelHelp(); + return; + } + + final var command = args[0]; + + switch (command.toLowerCase()) { + case "simulate": { + simulate(parseSimulationArgs(args)); + break; + } + case "-h": + case "--help": + default: + displayTopLevelHelp(); + break; + } + } + + private static Arguments.SimulationArguments parseSimulationArgs(String[] args) { + final Path modelJarPath; + final Path planJsonPath; + final Optional configJsonPath; + final boolean verbose; + final Optional outputFilePath; + final long extentUpdatePeriod; + + // Parse the command line arguments + final Options simulationOptions = createSimulationOptions(); + try { + checkForHelp(args, simulationOptions, "simulate", "Simulate a plan using the specified model and configuration"); + + final CommandLineParser parser = new DefaultParser(); + final CommandLine cmd = parser.parse(simulationOptions, args); + + modelJarPath = cmd.getParsedOptionValue('m'); + planJsonPath = cmd.getParsedOptionValue('p'); + verbose = cmd.hasOption("verbose"); + // Parser sets unused fields to 'null' + configJsonPath = cmd.getParsedOptionValue('s', Optional.empty()); + outputFilePath = cmd.getParsedOptionValue('f', Optional.empty()); + extentUpdatePeriod = cmd.getParsedOptionValue('i', 500L); + } catch (ParseException e) { + simulationOptions.addOption(HELP_OPTION); + new HelpFormatter().printHelp( + "stateless-aerie simulate", + "Simulate a plan using the specified model and configuration", + simulationOptions, + FOOTER, + true); + System.exit(2); + // The below is included as java doesn't recognize System.exit() as stopping the method, + // which causes compilation methods when trying to use the values assigned above + throw new RuntimeException(e); + } + + // Parse the plan and simulation config files into a Plan object + if (verbose) { System.out.println("Parsing plan "+planJsonPath+"..."); } + final var plan = PlanJsonParser.parsePlan(planJsonPath); + configJsonPath.ifPresent(path -> { + if (verbose) { System.out.println("Parsing simulation configuration "+path+"..."); } + PlanJsonParser.parseSimulationConfiguration(path, plan); + }); + + // Load the mission model + try { + if (verbose) { System.out.println("Loading mission model "+modelJarPath+"..."); } + final var model = MissionModelLoader.loadMissionModel( + plan.simulationStartTimestamp.toInstant(), + SerializedValue.of(plan.configuration), + modelJarPath, + modelJarPath.getFileName().toString(), + "" + ); + + return new Arguments.SimulationArguments<>(model, plan, verbose, outputFilePath, extentUpdatePeriod); + } catch (MissionModelLoader.MissionModelLoadException | MissionModelLoader.MissionModelInstantiationException e) { + throw new RuntimeException("Error while loading mission model: "+modelJarPath, e); + } + } + + private static void simulate(Arguments.SimulationArguments simArgs) { + System.out.println("Simulating Plan..."); + } + + /** + * Display top-level help for the application + */ + private static void displayTopLevelHelp() { + System.out.printf( + """ + usage: stateless-aerie COMMAND [ARGS]... + + Available commands: + - simulate: Simulate a plan using the specified model and configuration + %s + %n""", FOOTER); + } + + /** + * Build the parser options for the "simulate" command. + */ + private static Options createSimulationOptions() { + // Required Args + final Option modelPath = new Option("m", "model", true, "path to model jar"); + modelPath.setRequired(true); + modelPath.setConverter(Path::of); + + final Option planPath = new Option("p", "plan", true, "path to plan json"); + planPath.setRequired(true); + planPath.setConverter(Path::of); + + // Optional Path Args + final Option simConfigPath = new Option("s", "sim_config", true, "path to simulation configuration json"); + simConfigPath.setRequired(false); + simConfigPath.setConverter(s -> Optional.of(Path.of(s))); + + final Option outputFile = new Option("f", "file", true, "output file path"); + outputFile.setRequired(false); + outputFile.setConverter(f -> Optional.of(Path.of(f))); + + // Other Optional Args + final Option verbose = new Option("v", "verbose", false, "verbosity of simulation"); + + final Option extentUpdateFrequency = new Option("i", "update_interval", true, "minimum interval that simulation extent updates are posted, in milliseconds" ); + extentUpdateFrequency.setRequired(false); + extentUpdateFrequency.setConverter(Long::parseLong); + + final Options simulationOptions = new Options(); + simulationOptions.addOption(verbose); + simulationOptions.addOption(modelPath); + simulationOptions.addOption(planPath); + simulationOptions.addOption(simConfigPath); + simulationOptions.addOption(outputFile); + simulationOptions.addOption(extentUpdateFrequency); + return simulationOptions; + } + + /** + * Check if the "help" option was passed for a given command + * and, if so, print the command's help message and exit the program with status code 0. + * Checked independently to avoid required args for the command causing parsing issues. + * @param args the args passed into the commandline. + * @param subCommandOptions the parser options normally used to parse this command. + * @param subcommand the name of the subcommand (ie "simulate"). + * @param subcommandDescription the description of what the subcommand does. + */ + private static void checkForHelp( + String[] args, + Options subCommandOptions, + String subcommand, + String subcommandDescription + ) throws ParseException { + for(final var opt : args) { + if (opt.equals("-h") || opt.equals("--help")) { + subCommandOptions.addOption(HELP_OPTION); + new HelpFormatter().printHelp( + "stateless-aerie " + subcommand, + subcommandDescription, + subCommandOptions, + FOOTER, + true); + System.exit(0); + } + } + } } diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java new file mode 100644 index 0000000000..de0b4f3e88 --- /dev/null +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java @@ -0,0 +1,167 @@ +package gov.nasa.jpl.aerie.stateless; + +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.merlin.server.models.Plan; +import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; + +import static gov.nasa.jpl.aerie.merlin.server.remotes.postgres.PostgresParsers.activityArgumentsP; +import static gov.nasa.jpl.aerie.merlin.server.remotes.postgres.PostgresParsers.pgTimestampP; +import static gov.nasa.jpl.aerie.merlin.server.remotes.postgres.PostgresParsers.simulationArgumentsP; + +import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; + +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; +import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonObject; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Class to parse a plan.json file. + */ +public class PlanJsonParser { + + private PlanJsonParser() {} + + /** + * Parses a plan.json file that has been exported by the Aerie Gateway. + */ + public static Plan parsePlan(final Path filePath) { + try (final var fileReader = new FileReader(filePath.toString())) { + final var parser = Json.createParser(fileReader); + parser.next(); + final var planObject = parser.getObject(); + + final var name = planObject.getString("name"); + final var duration = parseDuration(planObject.getString("duration")); + final Timestamp startTime = pgTimestampP.parse(planObject.get("start_time")).getSuccessOrThrow(); + final Timestamp endTime = startTime.plusMicros(duration.in(Duration.MICROSECOND)); + + final var activityDirectives = parseActivities(planObject.getJsonArray("activities")); + final var simulationConfig = parseSimulationConfiguration(planObject.getJsonObject("simulation_arguments")); + + return new Plan(name, startTime, endTime, activityDirectives, simulationConfig); + } catch (final FileNotFoundException e) { + throw new RuntimeException("Specified plan JSON file does not exist: " + filePath); + } catch (final Exception e) { + throw new RuntimeException("Error while reading plan JSON file: " + filePath, e); + } + } + + /** + * Parse an array of JSON activities into a map of ActivityDirectives + * + * @param activities the json array directives to be parsed + */ + private static Map parseActivities(final JsonArray activities) { + final var activitiesMap = new HashMap(activities.size()); + + activities.forEach(v -> { + final var a = v.asJsonObject(); + + final var id = new ActivityDirectiveId(a.getInt("id")); + final var startOffset = parseDuration(a.getString("start_offset")); + final var type = a.getString("type"); + final var anchoredToStart = a.getBoolean("anchored_to_start"); + final var anchorId = a.isNull("anchor_id") ? null : new ActivityDirectiveId(a.getInt("anchor_id")); + final var arguments = activityArgumentsP.parse(a.getJsonObject("arguments")).getSuccessOrThrow(); + + activitiesMap.put( + id, + new ActivityDirective( + startOffset, + type, + arguments, + anchorId, + anchoredToStart + )); + }); + + return activitiesMap; + } + + /** + * Parses the simulation configuration from a jsonObject into a Map + * + * @param simConfig the JsonObject containing the simulation configuration + * @return A map containing the parsed simulation configuration + **/ + private static Map parseSimulationConfiguration(final JsonObject simConfig) { + // Return if we don't have any simConfigs + if (simConfig.isEmpty()) + return Map.of(); + return simulationArgumentsP.parse(simConfig).getSuccessOrThrow(); + } + + + /** + * Parses a Simulation Configuration JSON file and updates the given plan accordingly. + * + * Schema for a Simulation Configuration: + * { + * version: "2" + * simulation_start_time: string (PG Timestamp) + * simulation_end_time: string (PG Timestamp) + * arguments: json object + * } + * + * @param filePath path to the config file + * @param plan plan object to be updated + */ + public static void parseSimulationConfiguration(final Path filePath, final Plan plan) { + try (final var fileReader = new FileReader(filePath.toString())) { + final var parser = Json.createParser(fileReader); + parser.next(); + final var configObject = parser.getObject(); + + final var simStartTime = pgTimestampP.parse(configObject.get("simulation_start_time")).getSuccessOrThrow(); + final var simEndTime = pgTimestampP.parse(configObject.get("simulation_end_time")).getSuccessOrThrow(); + final var config = PlanJsonParser.parseSimulationConfiguration(configObject.getJsonObject("arguments")); + + plan.configuration.putAll(config); + plan.simulationStartTimestamp = simStartTime; + plan.simulationEndTimestamp = simEndTime; + + } catch (final FileNotFoundException e) { + throw new RuntimeException("Specified simulation configuration JSON file does not exist: " + filePath); + } catch (final Exception e) { + throw new RuntimeException("Error while reading simulation configuration JSON file: " + filePath, e); + } + } + + private static Duration parseDuration(final String duration) { + final var regexp = "(\\d{2,}):(\\d{2}):(\\d{2})(\\.\\d{1,6})?"; + + final Pattern pattern = Pattern.compile(regexp, Pattern.MULTILINE); + final Matcher matcher = pattern.matcher(duration); + + if (!matcher.matches()) { /// Unit test for this matcher.results().count() != 1 + throw new IllegalArgumentException("Duration has incorrect format. Expected format HH:MM:SS. Provided duration: " + + duration); + } + final var hours = Duration.of(Integer.parseInt(matcher.group(1)),Duration.HOURS); + final var minutes = Duration.of(Integer.parseInt(matcher.group(2)),Duration.MINUTES); + final var seconds = Duration.of(Integer.parseInt(matcher.group(3)),Duration.SECONDS); + final var microsecondString = Optional.ofNullable(matcher.group(4)); + var micros = Duration.ZERO; + + if (microsecondString.isPresent()){ + var subSecond = microsecondString.get().substring(1); + if (subSecond.length() < 6){ + // append the missing zeros. + subSecond=subSecond+"0".repeat(6-subSecond.length()); + } + micros = Duration.of(Integer.parseInt(subSecond), Duration.MICROSECONDS); + } + return micros.plus(seconds).plus(minutes).plus(hours); + } +} From 869badfec7938919431abbab7c39c88bc8ac0c8d Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Thu, 1 Aug 2024 14:05:31 -0700 Subject: [PATCH 03/17] Extract ParseDuration to Duration class - Make Duration.isEqualTo null-safe --- .../aerie/merlin/protocol/types/Duration.java | 36 +++++++++++++++++-- .../jpl/aerie/stateless/PlanJsonParser.java | 34 ++---------------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/merlin-sdk/src/main/java/gov/nasa/jpl/aerie/merlin/protocol/types/Duration.java b/merlin-sdk/src/main/java/gov/nasa/jpl/aerie/merlin/protocol/types/Duration.java index 561e8eb71e..3915f6ead6 100644 --- a/merlin-sdk/src/main/java/gov/nasa/jpl/aerie/merlin/protocol/types/Duration.java +++ b/merlin-sdk/src/main/java/gov/nasa/jpl/aerie/merlin/protocol/types/Duration.java @@ -2,6 +2,9 @@ import java.util.Collections; import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * A signed measure of the temporal distance between two instants. @@ -165,6 +168,34 @@ public static Duration of(final long quantity, final Duration unit) { return unit.times(quantity); } + /** Construct a duration from a string representation. Only accepts input in the format HH:MM:SS.ssssss */ + public static Duration fromString(final String duration) { + final var regexp = "(\\d{2,}):(\\d{2}):(\\d{2})(\\.\\d{1,6})?"; + + final Pattern pattern = Pattern.compile(regexp, Pattern.MULTILINE); + final Matcher matcher = pattern.matcher(duration); + + if (!matcher.matches()) { /// Unit test for this matcher.results().count() != 1 + throw new IllegalArgumentException("Duration has incorrect format. Expected format HH:MM:SS. Provided duration: " + + duration); + } + final var hours = Duration.of(Integer.parseInt(matcher.group(1)),Duration.HOURS); + final var minutes = Duration.of(Integer.parseInt(matcher.group(2)),Duration.MINUTES); + final var seconds = Duration.of(Integer.parseInt(matcher.group(3)),Duration.SECONDS); + final var microsecondString = Optional.ofNullable(matcher.group(4)); + var micros = Duration.ZERO; + + if (microsecondString.isPresent()){ + var subSecond = microsecondString.get().substring(1); + if (subSecond.length() < 6){ + // append the missing zeros. + subSecond=subSecond+"0".repeat(6-subSecond.length()); + } + micros = Duration.of(Integer.parseInt(subSecond), Duration.MICROSECONDS); + } + return micros.plus(seconds).plus(minutes).plus(hours); + } + /** * Construct a duration as a multiple of some unit. * @@ -504,6 +535,7 @@ public boolean isZero() { } public boolean isEqualTo(final Duration other) { + if(other == null) return false; return this.durationInMicroseconds == other.durationInMicroseconds; } @@ -511,9 +543,7 @@ public boolean isEqualTo(final Duration other) { @Override @Deprecated public boolean equals(final Object o) { - if (!(o instanceof Duration)) return false; - final var other = (Duration)o; - + if (!(o instanceof final Duration other)) return false; return this.isEqualTo(other); } diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java index de0b4f3e88..f2644e9aa6 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java @@ -21,9 +21,6 @@ import java.nio.file.Path; import java.util.HashMap; import java.util.Map; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Class to parse a plan.json file. @@ -42,7 +39,7 @@ public static Plan parsePlan(final Path filePath) { final var planObject = parser.getObject(); final var name = planObject.getString("name"); - final var duration = parseDuration(planObject.getString("duration")); + final var duration = Duration.fromString(planObject.getString("duration")); final Timestamp startTime = pgTimestampP.parse(planObject.get("start_time")).getSuccessOrThrow(); final Timestamp endTime = startTime.plusMicros(duration.in(Duration.MICROSECOND)); @@ -69,7 +66,7 @@ private static Map parseActivities(final final var a = v.asJsonObject(); final var id = new ActivityDirectiveId(a.getInt("id")); - final var startOffset = parseDuration(a.getString("start_offset")); + final var startOffset = Duration.fromString(a.getString("start_offset")); final var type = a.getString("type"); final var anchoredToStart = a.getBoolean("anchored_to_start"); final var anchorId = a.isNull("anchor_id") ? null : new ActivityDirectiveId(a.getInt("anchor_id")); @@ -137,31 +134,4 @@ public static void parseSimulationConfiguration(final Path filePath, final Plan throw new RuntimeException("Error while reading simulation configuration JSON file: " + filePath, e); } } - - private static Duration parseDuration(final String duration) { - final var regexp = "(\\d{2,}):(\\d{2}):(\\d{2})(\\.\\d{1,6})?"; - - final Pattern pattern = Pattern.compile(regexp, Pattern.MULTILINE); - final Matcher matcher = pattern.matcher(duration); - - if (!matcher.matches()) { /// Unit test for this matcher.results().count() != 1 - throw new IllegalArgumentException("Duration has incorrect format. Expected format HH:MM:SS. Provided duration: " - + duration); - } - final var hours = Duration.of(Integer.parseInt(matcher.group(1)),Duration.HOURS); - final var minutes = Duration.of(Integer.parseInt(matcher.group(2)),Duration.MINUTES); - final var seconds = Duration.of(Integer.parseInt(matcher.group(3)),Duration.SECONDS); - final var microsecondString = Optional.ofNullable(matcher.group(4)); - var micros = Duration.ZERO; - - if (microsecondString.isPresent()){ - var subSecond = microsecondString.get().substring(1); - if (subSecond.length() < 6){ - // append the missing zeros. - subSecond=subSecond+"0".repeat(6-subSecond.length()); - } - micros = Duration.of(Integer.parseInt(subSecond), Duration.MICROSECONDS); - } - return micros.plus(seconds).plus(minutes).plus(hours); - } } From 2c8d52e67075d374f76ef57e4f3d377b4fb35337 Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Mon, 5 Aug 2024 17:45:19 -0700 Subject: [PATCH 04/17] Create Simulation Utilities Co-authored-by: Ryan Goetz --- .../simulation/CanceledListener.java | 15 ++++++ .../simulation/SimulationExtentConsumer.java | 50 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/CanceledListener.java create mode 100644 stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationExtentConsumer.java diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/CanceledListener.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/CanceledListener.java new file mode 100644 index 0000000000..02a9f095d1 --- /dev/null +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/CanceledListener.java @@ -0,0 +1,15 @@ +package gov.nasa.jpl.aerie.stateless.simulation; + +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; + +public class CanceledListener implements Supplier { + private final AtomicBoolean canceled = new AtomicBoolean(false); + + public void cancel() { canceled.set(true); } + + @Override + public Boolean get() { + return canceled.get(); + } +} diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationExtentConsumer.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationExtentConsumer.java new file mode 100644 index 0000000000..8f879e61a3 --- /dev/null +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationExtentConsumer.java @@ -0,0 +1,50 @@ +package gov.nasa.jpl.aerie.stateless.simulation; + +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.function.Consumer; + +public class SimulationExtentConsumer implements Consumer, AutoCloseable { + private Duration lastAcceptedDuration = Duration.ZERO; + private Duration lastReportedDuration = null; + private final Timer printTimer; + + /** + * Create a new SimulationExtentConsumer that prints the simulation time with a minimum frequency. + * @param periodMillis The minimum gap between simulation extent updates, in milliseconds. + */ + public SimulationExtentConsumer(final long periodMillis) { + printTimer = new Timer(); + printTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + // Only print if simulation time has progressed. + if(!lastAcceptedDuration.isEqualTo(lastReportedDuration)) { + System.out.println("Current simulation time: " + lastAcceptedDuration); + lastReportedDuration = lastAcceptedDuration; + } + } + }, periodMillis, periodMillis); + } + + /** + * Create a new SimulationExtentConsumer that consumes but does not print the simulation time. + */ + public SimulationExtentConsumer() { + printTimer = new Timer(); + } + + @Override + public void accept(final Duration duration) { + lastAcceptedDuration = duration; + } + + public Duration getLastAcceptedDuration() { return lastAcceptedDuration; } + + @Override + public void close() { + printTimer.cancel(); + } +} From f2ee091e6f5d0309343f48c6d0dab3711b9e6631 Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Mon, 5 Aug 2024 17:45:48 -0700 Subject: [PATCH 05/17] Create Simulation Results Writer Co-authored-by: Ryan Goetz --- .../gov/nasa/jpl/aerie/stateless/Main.java | 67 ++- .../simulation/SimulationResultsWriter.java | 431 ++++++++++++++++++ 2 files changed, 497 insertions(+), 1 deletion(-) create mode 100644 stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java index 69454696ef..6cfedf74a5 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java @@ -1,15 +1,27 @@ package gov.nasa.jpl.aerie.stateless; +import gov.nasa.jpl.aerie.stateless.simulation.CanceledListener; +import gov.nasa.jpl.aerie.stateless.simulation.SimulationExtentConsumer; +import gov.nasa.jpl.aerie.stateless.simulation.SimulationResultsWriter; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; +import gov.nasa.jpl.aerie.merlin.driver.SimulationDriver; +import gov.nasa.jpl.aerie.merlin.driver.SimulationException; +import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; +import gov.nasa.jpl.aerie.merlin.driver.resources.InMemorySimulationResourceManager; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.server.models.Plan; import java.nio.file.Path; +import java.util.Map; import java.util.Optional; import org.apache.commons.cli.*; +import javax.json.Json; +import javax.json.stream.JsonGenerator; + public class Main { private static final String VERSION = "v2.16.0"; private static final String FOOTER = "\nStateless Aerie "+VERSION; @@ -110,7 +122,60 @@ private static Arguments.SimulationArguments parseSimulationArgs(String[] arg } private static void simulate(Arguments.SimulationArguments simArgs) { - System.out.println("Simulating Plan..."); + if (simArgs.verbose()) { System.out.println("Simulating Plan..."); } + + // TODO: Update this to a streaming manager streaming to temp files + // this will impact how results are written + final InMemorySimulationResourceManager rmgr = new InMemorySimulationResourceManager(); + final var canceledListener = new CanceledListener(); + final var extentConsumer = simArgs.verbose? new SimulationExtentConsumer(simArgs.extentUpdatePeriod) : new SimulationExtentConsumer(); + + final var planDuration = Duration.of(simArgs.plan.startTimestamp.microsUntil(simArgs.plan.endTimestamp), + Duration.MICROSECOND); + final var simulationDuration = Duration.of(simArgs.plan.simulationStartTimestamp.microsUntil(simArgs.plan.simulationEndTimestamp), + Duration.MICROSECOND); + + try { + final SimulationResults results = SimulationDriver.simulate( + simArgs.missionModel, + simArgs.plan.activityDirectives, + simArgs.plan.simulationStartTimestamp.toInstant(), + simulationDuration, + simArgs.plan.startTimestamp.toInstant(), + planDuration, + canceledListener, + extentConsumer, + rmgr); + + final var resultsWriter = new SimulationResultsWriter(results, simArgs.plan); + + simArgs.outputFilePath().ifPresentOrElse( + p -> resultsWriter.writeResults(canceledListener, p, extentConsumer), + () -> resultsWriter.writeResults(canceledListener, extentConsumer) + ); + } catch (SimulationException ex) { + final var dataBuilder = Json.createObjectBuilder() + .add("elapsedTime", SimulationException.formatDuration(ex.elapsedTime)) + .add("utcTimeDoy", SimulationException.formatInstant(ex.instant)); + ex.directiveId.ifPresent(directiveId -> dataBuilder.add("executingDirectiveId", directiveId.id())); + ex.activityType.ifPresent(activityType -> dataBuilder.add("executingActivityType", activityType)); + ex.activityStackTrace.ifPresent(activityStackTrace -> dataBuilder.add("activityStackTrace", activityStackTrace)); + + final var exception = Json.createObjectBuilder() + .add("type", "SIMULATION_EXCEPTION") + .add("message", ex.cause.getMessage()) + .add("data", dataBuilder) + .add("trace", ex.cause.toString()) + .build(); + + final Map config = Map.of(JsonGenerator.PRETTY_PRINTING, ""); + try(final var jsonWriter = Json.createWriterFactory(config).createWriter(System.err)) { + jsonWriter.writeObject(exception); + } + System.exit(1); + } finally { + extentConsumer.close(); + } } /** diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java new file mode 100644 index 0000000000..abd1a43183 --- /dev/null +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java @@ -0,0 +1,431 @@ +package gov.nasa.jpl.aerie.stateless.simulation; + +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; +import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; +import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; +import gov.nasa.jpl.aerie.merlin.driver.UnfinishedActivity; +import gov.nasa.jpl.aerie.merlin.driver.engine.EventRecord; +import gov.nasa.jpl.aerie.merlin.driver.resources.ResourceProfile; +import gov.nasa.jpl.aerie.merlin.driver.timeline.EventGraph; +import gov.nasa.jpl.aerie.merlin.protocol.types.RealDynamics; +import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; +import gov.nasa.jpl.aerie.merlin.server.models.Plan; + +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonValue; +import javax.json.stream.JsonGenerator; +import java.io.FileWriter; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.file.Path; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Map; +import java.util.concurrent.RecursiveTask; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.merlin.server.remotes.postgres.EventGraphFlattener; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.lang3.tuple.Triple; + +import static gov.nasa.jpl.aerie.merlin.driver.json.SerializedValueJsonParser.serializedValueP; +import static gov.nasa.jpl.aerie.merlin.driver.json.ValueSchemaJsonParser.valueSchemaP; +import static gov.nasa.jpl.aerie.merlin.server.http.ProfileParsers.realDynamicsP; +import static gov.nasa.jpl.aerie.merlin.server.remotes.postgres.PostgresParsers.activityArgumentsP; +import static gov.nasa.jpl.aerie.merlin.server.remotes.postgres.PostgresParsers.simulationArgumentsP; + + +public class SimulationResultsWriter { + private final static double SCHEMA_VERSION = 1; + + // Write JSONs with Pretty Printing + private final static Map config = Map.of(JsonGenerator.PRETTY_PRINTING, ""); + + private final RecursiveTask profilesTask; + private final RecursiveTask eventsTask; + private final RecursiveTask spansTask; + private final RecursiveTask simConfigTask; + + private final Plan plan; + + public SimulationResultsWriter(SimulationResults results, Plan plan) { + this.plan = plan; + this.profilesTask = new RecursiveTask<>() { + @Override + protected JsonObject compute() { + return buildProfiles(results.realProfiles, results.discreteProfiles); + } + }; + this.eventsTask = new RecursiveTask<>() { + @Override + protected JsonObject compute() { + return buildEvents(results.events,results.topics); + } + }; + this.spansTask = new RecursiveTask<>() { + @Override + protected JsonObject compute() { + return buildSpans(results.simulatedActivities,results.unfinishedActivities, plan.simulationStartTimestamp); + } + }; + this.simConfigTask = new RecursiveTask<>() { + @Override + protected JsonObject compute() { + return buildSimConfig(plan); + } + }; + } + + private void forkSubTasks() { + // Fork tasks to build subjsons in parallel + profilesTask.fork(); + eventsTask.fork(); + spansTask.fork(); + simConfigTask.fork(); + } + + public void writeResults(CanceledListener canceledListener, SimulationExtentConsumer consumer) { + final var stringWriter = new StringWriter(); + try(final var resultsJsonGenerator = Json.createGeneratorFactory(config).createGenerator(stringWriter)) { + forkSubTasks(); + + // Output the starting information + writeOpening(resultsJsonGenerator, canceledListener.get(), consumer); + print(resultsJsonGenerator, stringWriter); + + // Join the forked tasks + resultsJsonGenerator.write("simulationConfiguration", simConfigTask.join()); + print(resultsJsonGenerator, stringWriter); + + resultsJsonGenerator.write("profiles", profilesTask.join()); + print(resultsJsonGenerator, stringWriter); + + resultsJsonGenerator.write("spans", spansTask.join()); + print(resultsJsonGenerator, stringWriter); + + resultsJsonGenerator.write("events", eventsTask.join()); + resultsJsonGenerator.writeEnd(); + print(resultsJsonGenerator, stringWriter); + } + } + + public void writeResults(CanceledListener canceledListener, Path outputFilePath, SimulationExtentConsumer consumer) { + final var stringWriter = new StringWriter(); + try(final var resultsJsonGenerator = Json.createGeneratorFactory(config).createGenerator(stringWriter); + final var fileWriter = new FileWriter(outputFilePath.toFile())) + { + forkSubTasks(); + + // Output the starting information + writeOpening(resultsJsonGenerator, canceledListener.get(), consumer); + printFile(resultsJsonGenerator, stringWriter, fileWriter); + + // Join the forked tasks + resultsJsonGenerator.write("simulationConfiguration", simConfigTask.join()); + printFile(resultsJsonGenerator, stringWriter, fileWriter); + + resultsJsonGenerator.write("profiles", profilesTask.join()); + printFile(resultsJsonGenerator, stringWriter, fileWriter); + + resultsJsonGenerator.write("spans", spansTask.join()); + printFile(resultsJsonGenerator, stringWriter, fileWriter); + + resultsJsonGenerator.write("events", eventsTask.join()); + resultsJsonGenerator.writeEnd(); + printFile(resultsJsonGenerator, stringWriter, fileWriter); + + fileWriter.flush(); + System.out.println("Results written to "+outputFilePath); + } catch (IOException e) { + throw new RuntimeException("Unable to write to file: "+outputFilePath, e); + } + } + + private void print(JsonGenerator resultsGenerator, StringWriter stringWriter) { + resultsGenerator.flush(); + System.out.print(stringWriter.toString().trim()); + // StringWriter.flush() does nothing, so we must clear the underlying buffer manually + stringWriter.getBuffer().setLength(0); + stringWriter.getBuffer().trimToSize(); // deallocates used buffer memory + } + + private void printFile(JsonGenerator resultsGenerator, StringWriter stringWriter, FileWriter fileWriter) + throws IOException { + resultsGenerator.flush(); + fileWriter.write(stringWriter.toString().trim()); + // StringWriter.flush() does nothing, so we must clear the underlying buffer manually + stringWriter.getBuffer().setLength(0); + stringWriter.getBuffer().trimToSize(); // deallocates used buffer memory + } + + private void writeOpening(JsonGenerator resultsGenerator, boolean canceled, SimulationExtentConsumer consumer) { + final Timestamp simEndTime = plan.simulationStartTimestamp + .plusMicros(consumer.getLastAcceptedDuration().in(Duration.MICROSECOND)); + + resultsGenerator.writeStartObject(); + resultsGenerator.write("version", SCHEMA_VERSION); + resultsGenerator.write("simulationStartTime", plan.simulationStartTimestamp.toString()); + resultsGenerator.write("simulationEndTime", simEndTime.toString()); + + if (canceled) { resultsGenerator.write("canceled", JsonValue.TRUE); } + else { resultsGenerator.write("canceled", JsonValue.FALSE); } + } + + private JsonObject buildProfiles( + final Map> realProfiles, + final Map> discreteProfiles + ) { + final var realProfileBuilder = Json.createArrayBuilder(); + final var discreteProfileBuilder = Json.createArrayBuilder(); + + for(final var e : realProfiles.entrySet()) { + final var name = e.getKey(); + final var profile = e.getValue(); + + // Precompute segments + final var segmentsBuilder = Json.createArrayBuilder(); + profile.segments().forEach(s -> segmentsBuilder.add(Json.createObjectBuilder() + .add("extent", s.extent().toString()) + .add("dynamics", realDynamicsP.unparse(s.dynamics())))); + + final var profileBuilder = Json.createObjectBuilder() + .add("name", name) + .add("schema", valueSchemaP.unparse(profile.schema())) + .add("segments", segmentsBuilder); + + // Append to the array builder + realProfileBuilder.add(profileBuilder); + } + + for(final var e : discreteProfiles.entrySet()) { + final var name = e.getKey(); + final var profile = e.getValue(); + + // Precompute segments + final var segmentsBuilder = Json.createArrayBuilder(); + profile.segments().forEach(s -> segmentsBuilder.add(Json.createObjectBuilder() + .add("extent", s.extent().toString()) + .add("dynamics", serializedValueP.unparse(s.dynamics())))); + + final var profileBuilder = Json.createObjectBuilder() + .add("name",name) + .add("schema", valueSchemaP.unparse(profile.schema())) + .add("segments", segmentsBuilder); + + // Append to the array builder + discreteProfileBuilder.add(profileBuilder); + } + + return Json.createObjectBuilder() + .add("realProfiles", realProfileBuilder) + .add("discreteProfiles", discreteProfileBuilder) + .build(); + } + + private JsonObject buildSpans( + final Map simulatedActivities, + final Map unfinishedActivities, + final Timestamp simStartTime + ) { + final var simulatedActivitiesBuilder = Json.createArrayBuilder(); + final var unfinishedActivitiesBuilder = Json.createArrayBuilder(); + + for(final var e : simulatedActivities.entrySet()) { + final var id = e.getKey(); + final var act = e.getValue(); + + // Precompute complicated fields + final var childIdsBuilder = Json.createArrayBuilder(); + act.childIds().forEach(ci -> childIdsBuilder.add(ci.id())); + + final var startOffset = Duration.of(simStartTime.microsUntil(new Timestamp(act.start())), Duration.MICROSECOND).toString(); + final var endTime = act.start().plus(act.duration().in(Duration.MICROSECOND), ChronoUnit.MICROS).toString(); + + // Build activity's builder + final var actBuilder = Json.createObjectBuilder().add("id", id.id()); + + act.directiveId().ifPresentOrElse(did -> actBuilder.add("directiveId", did.id()), + () -> actBuilder.add("directiveId", JsonValue.NULL)); + if(act.parentId() != null) { actBuilder.add("parentId", act.parentId().id()); } + else { actBuilder.add("parentId", JsonValue.NULL); } + + actBuilder.add("childIds", childIdsBuilder) + .add("type", act.type()) + .add("startOffset", startOffset) + .add("duration", act.duration().toString()) + .add("attributes", serializedValueP.unparse(act.computedAttributes())) + .add("arguments", activityArgumentsP.unparse(act.arguments())) + .add("startTime", act.start().toString()) + .add("endTime", endTime); + + // Append to the array builder + simulatedActivitiesBuilder.add(actBuilder); + } + + for(final var e : unfinishedActivities.entrySet()) { + final var id = e.getKey(); + final var act = e.getValue(); + + // Precompute complicated fields + final var childIdsBuilder = Json.createArrayBuilder(); + act.childIds().forEach(ci -> childIdsBuilder.add(ci.id())); + + final var startOffset = Duration.of(simStartTime.microsUntil(new Timestamp(act.start())), Duration.MICROSECOND).toString(); + + // Build activity's builder + final var actBuilder = Json.createObjectBuilder().add("id", id.id()); + + act.directiveId().ifPresentOrElse(did -> actBuilder.add("directiveId", did.id()), + () -> actBuilder.add("directiveId", JsonValue.NULL)); + if(act.parentId() != null) { actBuilder.add("parentId", act.parentId().id()); } + else { actBuilder.add("parentId", JsonValue.NULL); } + + actBuilder.add("childIds", childIdsBuilder) + .add("type", act.type()) + .add("startOffset", startOffset) + .add("arguments", activityArgumentsP.unparse(act.arguments())) + .add("startTime", act.start().toString()); + + // Append to the array builder + unfinishedActivitiesBuilder.add(actBuilder); + } + + return Json.createObjectBuilder() + .add("simulatedActivities", simulatedActivitiesBuilder) + .add("unfinishedActivities", unfinishedActivitiesBuilder) + .build(); + } + + private JsonObject buildEvents(final Map>> events, final List> topics ) { + final var eventArrayBuilder = Json.createArrayBuilder(); + + for (final var eventPoint : events.entrySet()) { + final var realTime = eventPoint.getKey(); + final var transactions = eventPoint.getValue(); + + for (int transactionIndex = 0; transactionIndex < transactions.size(); transactionIndex++) { + final var eventGraph = transactions.get(transactionIndex); + final var flattenedEventGraph = EventGraphFlattener.flatten(eventGraph); + + for (final Pair entry : flattenedEventGraph) { + final EventRecord event = entry.getRight(); + final var eventBuilder = Json.createObjectBuilder() + .add("causalTime",entry.getLeft()) + .add("realTime",realTime.toString()) + .add("transactionIndex",transactionIndex) + .add("value", serializedValueP.unparse(event.value())); + + //grab the topic from the event's topic id + topics.stream() + .filter(topic -> topic.getLeft() == event.topicId()) + .findFirst() + .ifPresent(topic -> eventBuilder.add("topic", Json.createObjectBuilder() + .add("name",topic.getMiddle()) + .add("valueSchema", valueSchemaP.unparse(topic.getRight())))); + + // optional span id + event.spanId().ifPresentOrElse(spanId -> eventBuilder.add("spanId", spanId), + () -> eventBuilder.add("spanId", JsonValue.NULL)); + eventArrayBuilder.add(eventBuilder); + } + } + } + + return Json.createObjectBuilder() + .add("event",eventArrayBuilder.build()) + .build(); + } + + private JsonObject buildSimConfig(final Plan plan) { + return Json.createObjectBuilder() + .add("startTime", plan.simulationStartTimestamp.toString()) + .add("endTime",plan.simulationEndTimestamp.toString()) + .add("arguments", simulationArgumentsP.unparse(plan.configuration)) + .build(); + } + +} + +/* +Json Schema for Sim results: + +{ +version: 1.0 +simulationStartTime: Timestamp (2024-07-01T00:00:00Z) +simulationEndTime: Timestamp // When the simulation stopped +canceled: boolean + +simulationConfiguration: { + startTime: Timestamp + endTime: Timestamp + arguments: {} +} + +profiles: { + realProfiles: [ + { + name: string + schema: ValueSchema + segments: [ + extent: Duration + dynamics: {}//arbitrary value based on schema + ] + } + ], + discreteProfiles: [ + { + name: string + schema: ValueSchema + segments: [ + extent: Duration + dynamics: {}//arbitrary value based on schema + ] + } + ] +} + +spans: { + simulatedActivities: [ + { + id: int + directiveId: int | null + parentId: int | null + childIds: [int] + type: String + startOffset: Duration + duration: Duration + attributes: {} + arguments: {} + startTime: Timestamp + endTime: Timestamp + } + ], + unfinishedActivities: [ + { + id: int + directiveId: int | null + parentId: int | null + childIds: [int] + type: string + startOffset: Duration + arguments: {} + startTime: Timestamp + } + ] +} + +events: { + causalTime : string, + realTime : Timestamp, + transactionIndex : int, + value : {}, + topic: { + name : string + valueSchema : {} + } + spanId: int, +} +} + */ From ee60bc47fc46f5671fc4547d1768c17dcec1a4f3 Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Mon, 5 Aug 2024 18:02:21 -0700 Subject: [PATCH 06/17] Cancel Support --- .../gov/nasa/jpl/aerie/stateless/Main.java | 83 +++++++++++++++---- 1 file changed, 69 insertions(+), 14 deletions(-) diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java index 6cfedf74a5..0ae85780e0 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java @@ -16,6 +16,10 @@ import java.nio.file.Path; import java.util.Map; import java.util.Optional; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import org.apache.commons.cli.*; @@ -135,8 +139,12 @@ private static void simulate(Arguments.SimulationArguments simArgs) { final var simulationDuration = Duration.of(simArgs.plan.simulationStartTimestamp.microsUntil(simArgs.plan.simulationEndTimestamp), Duration.MICROSECOND); - try { - final SimulationResults results = SimulationDriver.simulate( + // Cancel support + Thread shutdownHook = null; + final var resultsThread = new Callable() { + @Override + public SimulationResults call() { + return SimulationDriver.simulate( simArgs.missionModel, simArgs.plan.activityDirectives, simArgs.plan.simulationStartTimestamp.toInstant(), @@ -146,15 +154,66 @@ private static void simulate(Arguments.SimulationArguments simArgs) { canceledListener, extentConsumer, rmgr); + } + }; + + try(final var exec = Executors.newSingleThreadExecutor()) { + final Future f = exec.submit(resultsThread); + + shutdownHook = new Thread(() -> { + canceledListener.cancel(); + try { + final var results = f.get(); + + if (simArgs.verbose()) { System.out.println("Writing Results..."); } + final var resultsWriter = new SimulationResultsWriter(results, simArgs.plan); + + simArgs.outputFilePath().ifPresentOrElse( + p -> resultsWriter.writeResults(canceledListener, p, extentConsumer), + () -> resultsWriter.writeResults(canceledListener, extentConsumer) + ); + + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + }); + + // Surround awaiting sim results in a thread to output partial results during SIGINT + Runtime.getRuntime().addShutdownHook(shutdownHook); + final var results = f.get(); + if(!canceledListener.get()) { + // Avoid two threads writing to the output file at the same time + Runtime.getRuntime().removeShutdownHook(shutdownHook); + + if (simArgs.verbose()) { System.out.println("Writing Results..."); } + final var resultsWriter = new SimulationResultsWriter(results, simArgs.plan); + simArgs.outputFilePath().ifPresentOrElse( + p -> resultsWriter.writeResults(canceledListener, p, extentConsumer), + () -> resultsWriter.writeResults(canceledListener, extentConsumer) + ); + } + } catch (ExecutionException e) { + if(e.getCause() instanceof SimulationException se) { + writeSimulationException(se); + System.exit(1); + } + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } catch (IllegalStateException ise) { + // If this is the message, it must've come from Runtime.getRuntime().removeShutdownHook and can be safely ignored + if(!ise.getMessage().contains("Shutdown in progress")) throw ise; + } finally { + extentConsumer.close(); + // Try-catch wrapping in case this is executed while the shutdown hook is running. + try { + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } catch (IllegalStateException ise) {} + } + } - final var resultsWriter = new SimulationResultsWriter(results, simArgs.plan); - - simArgs.outputFilePath().ifPresentOrElse( - p -> resultsWriter.writeResults(canceledListener, p, extentConsumer), - () -> resultsWriter.writeResults(canceledListener, extentConsumer) - ); - } catch (SimulationException ex) { - final var dataBuilder = Json.createObjectBuilder() + private static void writeSimulationException(SimulationException ex) { + final var dataBuilder = Json.createObjectBuilder() .add("elapsedTime", SimulationException.formatDuration(ex.elapsedTime)) .add("utcTimeDoy", SimulationException.formatInstant(ex.instant)); ex.directiveId.ifPresent(directiveId -> dataBuilder.add("executingDirectiveId", directiveId.id())); @@ -172,10 +231,6 @@ private static void simulate(Arguments.SimulationArguments simArgs) { try(final var jsonWriter = Json.createWriterFactory(config).createWriter(System.err)) { jsonWriter.writeObject(exception); } - System.exit(1); - } finally { - extentConsumer.close(); - } } /** From 9d7bdf74af776395c8f8c2ee75aeb2224520cd3a Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Mon, 5 Aug 2024 16:33:03 -0700 Subject: [PATCH 07/17] Write Resources to temporary files - Remove Extent in favor of SimResults.duration Co-authored-by: Ryan Goetz --- .../gov/nasa/jpl/aerie/stateless/Main.java | 20 +- .../simulation/ResourceFileStreamer.java | 98 ++++++++++ .../simulation/SimulationResultsWriter.java | 177 ++++++++++++++++-- 3 files changed, 274 insertions(+), 21 deletions(-) create mode 100644 stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java index 0ae85780e0..f4ebf0a01c 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java @@ -1,6 +1,8 @@ package gov.nasa.jpl.aerie.stateless; +import gov.nasa.jpl.aerie.merlin.driver.resources.StreamingSimulationResourceManager; import gov.nasa.jpl.aerie.stateless.simulation.CanceledListener; +import gov.nasa.jpl.aerie.stateless.simulation.ResourceFileStreamer; import gov.nasa.jpl.aerie.stateless.simulation.SimulationExtentConsumer; import gov.nasa.jpl.aerie.stateless.simulation.SimulationResultsWriter; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; @@ -8,7 +10,6 @@ import gov.nasa.jpl.aerie.merlin.driver.SimulationDriver; import gov.nasa.jpl.aerie.merlin.driver.SimulationException; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; -import gov.nasa.jpl.aerie.merlin.driver.resources.InMemorySimulationResourceManager; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.server.models.Plan; @@ -128,9 +129,8 @@ private static Arguments.SimulationArguments parseSimulationArgs(String[] arg private static void simulate(Arguments.SimulationArguments simArgs) { if (simArgs.verbose()) { System.out.println("Simulating Plan..."); } - // TODO: Update this to a streaming manager streaming to temp files - // this will impact how results are written - final InMemorySimulationResourceManager rmgr = new InMemorySimulationResourceManager(); + final var rfs = new ResourceFileStreamer(); + final var rmgr = new StreamingSimulationResourceManager(rfs); final var canceledListener = new CanceledListener(); final var extentConsumer = simArgs.verbose? new SimulationExtentConsumer(simArgs.extentUpdatePeriod) : new SimulationExtentConsumer(); @@ -166,11 +166,11 @@ public SimulationResults call() { final var results = f.get(); if (simArgs.verbose()) { System.out.println("Writing Results..."); } - final var resultsWriter = new SimulationResultsWriter(results, simArgs.plan); + final var resultsWriter = new SimulationResultsWriter(results, simArgs.plan, rfs); simArgs.outputFilePath().ifPresentOrElse( - p -> resultsWriter.writeResults(canceledListener, p, extentConsumer), - () -> resultsWriter.writeResults(canceledListener, extentConsumer) + p -> resultsWriter.writeResults(canceledListener, p), + () -> resultsWriter.writeResults(canceledListener) ); } catch (InterruptedException | ExecutionException e) { @@ -186,10 +186,10 @@ public SimulationResults call() { Runtime.getRuntime().removeShutdownHook(shutdownHook); if (simArgs.verbose()) { System.out.println("Writing Results..."); } - final var resultsWriter = new SimulationResultsWriter(results, simArgs.plan); + final var resultsWriter = new SimulationResultsWriter(results, simArgs.plan, rfs); simArgs.outputFilePath().ifPresentOrElse( - p -> resultsWriter.writeResults(canceledListener, p, extentConsumer), - () -> resultsWriter.writeResults(canceledListener, extentConsumer) + p -> resultsWriter.writeResults(canceledListener, p), + () -> resultsWriter.writeResults(canceledListener) ); } } catch (ExecutionException e) { diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java new file mode 100644 index 0000000000..9e26575fd0 --- /dev/null +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java @@ -0,0 +1,98 @@ +package gov.nasa.jpl.aerie.stateless.simulation; + +import gov.nasa.jpl.aerie.merlin.driver.resources.ResourceProfiles; + +import javax.json.Json; +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.UUID; +import java.util.function.Consumer; + +import static gov.nasa.jpl.aerie.merlin.driver.json.SerializedValueJsonParser.serializedValueP; +import static gov.nasa.jpl.aerie.merlin.server.http.ProfileParsers.realDynamicsP; + +/** + * A consumer that writes resource segments to the file system. + */ +public class ResourceFileStreamer implements Consumer { + private final UUID uuid; + private final HashMap fileNames; + + public ResourceFileStreamer() { + uuid = UUID.randomUUID(); + fileNames = new HashMap<>(); + } + + /* + Forbidden Characters for File Names: + Assuming no nonprintable characters are used, as resource names are already visualized in the UI + + Forbidden on Windows (Linux and Mac use a subset): + < (less than) + > (greater than) + : (colon - sometimes works, but is actually NTFS Alternate Data Streams) + " (double quote) + / (forward slash) + \ (backslash) + | (vertical bar or pipe) + ? (question mark) + * (asterisk) + + Forbidden for Being Potentially Problematic: + . (period) (windows doesn't allow trailing '.', file extension signifier) + , (comma) + + (plus) + & (ampersand) + ' (single quote) + ' ' (space) + */ + private static final char[] EXCLUSION = {'<', '>', ':', '"', '\\', '/', '|', '?', '*', '.', ',', '+', '&', '\'', ' '}; + + @Override + public void accept(final ResourceProfiles resourceProfile) { + for(final var r : resourceProfile.realProfiles().entrySet()) { + final var name = getFileName(r.getKey()); + try (final var fileWriter = new FileWriter(name, true)) { + for(final var segment : r.getValue().segments()) { + final var s = Json.createObjectBuilder() + .add("extent", segment.extent().toString()) + .add("dynamics", realDynamicsP.unparse(segment.dynamics())) + .build(); + fileWriter.write(s.toString()+"\n"); + } + fileWriter.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + for(final var d : resourceProfile.discreteProfiles().entrySet()) { + final var name = getFileName(d.getKey()); + try (final var fileWriter = new FileWriter(name, true)) { + for(final var segment : d.getValue().segments()) { + final var s = Json.createObjectBuilder() + .add("extent", segment.extent().toString()) + .add("dynamics", serializedValueP.unparse(segment.dynamics())) + .build(); + fileWriter.write(s.toString()+"\n"); + } + fileWriter.flush(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + /** + * Converts a resource's name into a legal file name and saves it in its cache of filenames. + */ + public String getFileName(String resourceName) { + if(fileNames.containsKey(resourceName)) return fileNames.get(resourceName); + + final var fileName = System.getProperty("java.io.tmpdir") + resourceName.replaceAll("[" + String.valueOf(EXCLUSION) + "]", "_") + uuid.toString()+".rsc"; + fileNames.put(resourceName, fileName); + return fileName; + } + +} diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java index abd1a43183..d6732ada38 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java @@ -14,11 +14,14 @@ import javax.json.Json; import javax.json.JsonObject; +import javax.json.JsonReader; import javax.json.JsonValue; import javax.json.stream.JsonGenerator; import java.io.FileWriter; import java.io.IOException; +import java.io.StringReader; import java.io.StringWriter; +import java.nio.file.Files; import java.nio.file.Path; import java.time.temporal.ChronoUnit; import java.util.List; @@ -49,9 +52,57 @@ public class SimulationResultsWriter { private final RecursiveTask simConfigTask; private final Plan plan; + private final Duration extent; + + /** + * Creates a SimulationResultsWriter that will write SimulationResults generated + * using a StreamingResourceManager using the provided ResourceFileStreamer. + * @param results The SimulationResults to be written + * @param plan The Plan simulated + * @param rfs The ResourceFileStreamer used during the simulation + */ + public SimulationResultsWriter(SimulationResults results, Plan plan, ResourceFileStreamer rfs) { + this.plan = plan; + this.extent = results.duration; + this.profilesTask = new RecursiveTask<>() { + @Override + protected JsonObject compute() { + try { + return buildProfiles(results.realProfiles, results.discreteProfiles, rfs); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }; + this.eventsTask = new RecursiveTask<>() { + @Override + protected JsonObject compute() { + return buildEvents(results.events,results.topics); + } + }; + this.spansTask = new RecursiveTask<>() { + @Override + protected JsonObject compute() { + return buildSpans(results.simulatedActivities,results.unfinishedActivities, plan.simulationStartTimestamp); + } + }; + this.simConfigTask = new RecursiveTask<>() { + @Override + protected JsonObject compute() { + return buildSimConfig(plan); + } + }; + } + /** + * Create a SimulationResultsWriter that will write SimulationResults generated + * using an InMemorySimulationResourceManager. + * @param results The SimulationResults to be written + * @param plan The plan simulated + */ public SimulationResultsWriter(SimulationResults results, Plan plan) { this.plan = plan; + this.extent = results.duration; this.profilesTask = new RecursiveTask<>() { @Override protected JsonObject compute() { @@ -78,21 +129,26 @@ protected JsonObject compute() { }; } + /** Fork tasks to build subjsons in parallel **/ private void forkSubTasks() { - // Fork tasks to build subjsons in parallel profilesTask.fork(); eventsTask.fork(); spansTask.fork(); simConfigTask.fork(); } - public void writeResults(CanceledListener canceledListener, SimulationExtentConsumer consumer) { + /** + * Write the formatted SimulationResult JSON to System.out + * @param canceledListener The CanceledListener used during simulation. + * Used to determine if the results represent a canceled simulation. + */ + public void writeResults(CanceledListener canceledListener) { final var stringWriter = new StringWriter(); try(final var resultsJsonGenerator = Json.createGeneratorFactory(config).createGenerator(stringWriter)) { forkSubTasks(); // Output the starting information - writeOpening(resultsJsonGenerator, canceledListener.get(), consumer); + writeOpening(resultsJsonGenerator, canceledListener.get()); print(resultsJsonGenerator, stringWriter); // Join the forked tasks @@ -111,7 +167,13 @@ public void writeResults(CanceledListener canceledListener, SimulationExtentCons } } - public void writeResults(CanceledListener canceledListener, Path outputFilePath, SimulationExtentConsumer consumer) { + /** + * Write the formatted SimulationResult JSON to the specified file. + * @param canceledListener The CanceledListener used during simulation. + * Used to determine if the results represent a canceled simulation. + * @param outputFilePath The file path to write results to. + */ + public void writeResults(CanceledListener canceledListener, Path outputFilePath) { final var stringWriter = new StringWriter(); try(final var resultsJsonGenerator = Json.createGeneratorFactory(config).createGenerator(stringWriter); final var fileWriter = new FileWriter(outputFilePath.toFile())) @@ -119,7 +181,7 @@ public void writeResults(CanceledListener canceledListener, Path outputFilePath, forkSubTasks(); // Output the starting information - writeOpening(resultsJsonGenerator, canceledListener.get(), consumer); + writeOpening(resultsJsonGenerator, canceledListener.get()); printFile(resultsJsonGenerator, stringWriter, fileWriter); // Join the forked tasks @@ -143,6 +205,7 @@ public void writeResults(CanceledListener canceledListener, Path outputFilePath, } } + /** Helper method that handles buffer management for printing to System.out */ private void print(JsonGenerator resultsGenerator, StringWriter stringWriter) { resultsGenerator.flush(); System.out.print(stringWriter.toString().trim()); @@ -151,6 +214,7 @@ private void print(JsonGenerator resultsGenerator, StringWriter stringWriter) { stringWriter.getBuffer().trimToSize(); // deallocates used buffer memory } + /** Helper method that handles buffer management for writing to a file */ private void printFile(JsonGenerator resultsGenerator, StringWriter stringWriter, FileWriter fileWriter) throws IOException { resultsGenerator.flush(); @@ -160,9 +224,9 @@ private void printFile(JsonGenerator resultsGenerator, StringWriter stringWriter stringWriter.getBuffer().trimToSize(); // deallocates used buffer memory } - private void writeOpening(JsonGenerator resultsGenerator, boolean canceled, SimulationExtentConsumer consumer) { - final Timestamp simEndTime = plan.simulationStartTimestamp - .plusMicros(consumer.getLastAcceptedDuration().in(Duration.MICROSECOND)); + /** Write the beginning and top-level fields of the results JSON */ + private void writeOpening(JsonGenerator resultsGenerator, boolean canceled) { + final Timestamp simEndTime = plan.simulationStartTimestamp.plusMicros(extent.in(Duration.MICROSECOND)); resultsGenerator.writeStartObject(); resultsGenerator.write("version", SCHEMA_VERSION); @@ -173,6 +237,7 @@ private void writeOpening(JsonGenerator resultsGenerator, boolean canceled, Simu else { resultsGenerator.write("canceled", JsonValue.FALSE); } } + /** Build up a JSON Object containing the resource profiles. */ private JsonObject buildProfiles( final Map> realProfiles, final Map> discreteProfiles @@ -180,7 +245,7 @@ private JsonObject buildProfiles( final var realProfileBuilder = Json.createArrayBuilder(); final var discreteProfileBuilder = Json.createArrayBuilder(); - for(final var e : realProfiles.entrySet()) { + for (final var e : realProfiles.entrySet()) { final var name = e.getKey(); final var profile = e.getValue(); @@ -199,16 +264,103 @@ private JsonObject buildProfiles( realProfileBuilder.add(profileBuilder); } - for(final var e : discreteProfiles.entrySet()) { + for (final var e : discreteProfiles.entrySet()) { final var name = e.getKey(); final var profile = e.getValue(); - // Precompute segments + // Precompute segments final var segmentsBuilder = Json.createArrayBuilder(); profile.segments().forEach(s -> segmentsBuilder.add(Json.createObjectBuilder() .add("extent", s.extent().toString()) .add("dynamics", serializedValueP.unparse(s.dynamics())))); + final var profileBuilder = Json.createObjectBuilder() + .add("name", name) + .add("schema", valueSchemaP.unparse(profile.schema())) + .add("segments", segmentsBuilder); + + // Append to the array builder + discreteProfileBuilder.add(profileBuilder); + } + + return Json.createObjectBuilder() + .add("realProfiles", realProfileBuilder) + .add("discreteProfiles", discreteProfileBuilder) + .build(); + } + + /** + * Build up a JSON Object containing the resource profiles. + * Prioritizes getting profile segments from ResourceFileStreamer, + * using the Maps as fallbacks should a resource file be missing. + */ + private JsonObject buildProfiles( + final Map> realProfiles, + final Map> discreteProfiles, + final ResourceFileStreamer rfs + ) throws IOException + { + final var realProfileBuilder = Json.createArrayBuilder(); + final var discreteProfileBuilder = Json.createArrayBuilder(); + + for(final var e : realProfiles.entrySet()) { + final var name = e.getKey(); + final var profile = e.getValue(); + final var filepath = Path.of(rfs.getFileName(name)); + + // Precompute segments + final var segmentsBuilder = Json.createArrayBuilder(); + + try (final var stream = Files.lines(filepath)) { + stream.forEach(s -> { + if (!s.isBlank()) { + try (final JsonReader jr = Json.createReader(new StringReader(s))) { + segmentsBuilder.add(jr.readObject()); + } + } + }); + } + + // If somehow the file didn't exist and didn't except above, use the resources in the rmgr + if(!Files.deleteIfExists(filepath)){ + profile.segments().forEach(s -> segmentsBuilder.add(Json.createObjectBuilder() + .add("extent", s.extent().toString()) + .add("dynamics", realDynamicsP.unparse(s.dynamics())))); + } + + final var profileBuilder = Json.createObjectBuilder() + .add("name", name) + .add("schema", valueSchemaP.unparse(profile.schema())) + .add("segments", segmentsBuilder); + + // Append to the array builder + realProfileBuilder.add(profileBuilder); + } + + for(final var e : discreteProfiles.entrySet()) { + final var name = e.getKey(); + final var profile = e.getValue(); + final var filepath = Path.of(rfs.getFileName(name)); + + // Precompute segments + final var segmentsBuilder = Json.createArrayBuilder(); + try (final var stream = Files.lines(filepath)) { + stream.forEach(s -> { + if (!s.isBlank()) { + try (final JsonReader jr = Json.createReader(new StringReader(s))) { + segmentsBuilder.add(jr.readObject()); + } + } + }); + } + + // If somehow the file didn't exist and didn't except above, use the resources in the rmgr + if(!Files.deleteIfExists(filepath)){ + profile.segments().forEach(s -> segmentsBuilder.add(Json.createObjectBuilder() + .add("extent", s.extent().toString()) + .add("dynamics", serializedValueP.unparse(s.dynamics())))); + } + final var profileBuilder = Json.createObjectBuilder() .add("name",name) .add("schema", valueSchemaP.unparse(profile.schema())) @@ -224,6 +376,7 @@ private JsonObject buildProfiles( .build(); } + /** Build up a JSON Object containing the activity spans. */ private JsonObject buildSpans( final Map simulatedActivities, final Map unfinishedActivities, @@ -298,6 +451,7 @@ private JsonObject buildSpans( .build(); } + /** Build up a JSON Object containing the simulation events. */ private JsonObject buildEvents(final Map>> events, final List> topics ) { final var eventArrayBuilder = Json.createArrayBuilder(); @@ -338,6 +492,7 @@ private JsonObject buildEvents(final Map> .build(); } + /** Build up a JSON Object containing the simulation configuration. */ private JsonObject buildSimConfig(final Plan plan) { return Json.createObjectBuilder() .add("startTime", plan.simulationStartTimestamp.toString()) From c69d9e0496bedb6d557a8b3f9b8ff3d310d331d2 Mon Sep 17 00:00:00 2001 From: Ryan Goetz Date: Tue, 6 Aug 2024 09:40:29 -1000 Subject: [PATCH 08/17] Added a unit test for parsing a duration string. --- .../aerie/merlin/protocol/types/Duration.java | 14 +++++---- .../merlin/protocol/types/DurationTest.java | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/merlin-sdk/src/main/java/gov/nasa/jpl/aerie/merlin/protocol/types/Duration.java b/merlin-sdk/src/main/java/gov/nasa/jpl/aerie/merlin/protocol/types/Duration.java index 3915f6ead6..42e7a90fca 100644 --- a/merlin-sdk/src/main/java/gov/nasa/jpl/aerie/merlin/protocol/types/Duration.java +++ b/merlin-sdk/src/main/java/gov/nasa/jpl/aerie/merlin/protocol/types/Duration.java @@ -170,7 +170,7 @@ public static Duration of(final long quantity, final Duration unit) { /** Construct a duration from a string representation. Only accepts input in the format HH:MM:SS.ssssss */ public static Duration fromString(final String duration) { - final var regexp = "(\\d{2,}):(\\d{2}):(\\d{2})(\\.\\d{1,6})?"; + final var regexp = "([+-]?)(\\d{2,}):(\\d{2}):(\\d{2})(\\.\\d{1,6})?"; final Pattern pattern = Pattern.compile(regexp, Pattern.MULTILINE); final Matcher matcher = pattern.matcher(duration); @@ -179,10 +179,11 @@ public static Duration fromString(final String duration) { throw new IllegalArgumentException("Duration has incorrect format. Expected format HH:MM:SS. Provided duration: " + duration); } - final var hours = Duration.of(Integer.parseInt(matcher.group(1)),Duration.HOURS); - final var minutes = Duration.of(Integer.parseInt(matcher.group(2)),Duration.MINUTES); - final var seconds = Duration.of(Integer.parseInt(matcher.group(3)),Duration.SECONDS); - final var microsecondString = Optional.ofNullable(matcher.group(4)); + final var sign = Optional.ofNullable(matcher.group(1)); + final var hours = Duration.of(Integer.parseInt(matcher.group(2)),Duration.HOURS); + final var minutes = Duration.of(Integer.parseInt(matcher.group(3)),Duration.MINUTES); + final var seconds = Duration.of(Integer.parseInt(matcher.group(4)),Duration.SECONDS); + final var microsecondString = Optional.ofNullable(matcher.group(5)); var micros = Duration.ZERO; if (microsecondString.isPresent()){ @@ -193,7 +194,8 @@ public static Duration fromString(final String duration) { } micros = Duration.of(Integer.parseInt(subSecond), Duration.MICROSECONDS); } - return micros.plus(seconds).plus(minutes).plus(hours); + + return micros.plus(seconds).plus(minutes).plus(hours).times(sign.isPresent() && sign.get().equals("-") ? -1 : 1); } /** diff --git a/merlin-sdk/src/test/java/gov/nasa/jpl/aerie/merlin/protocol/types/DurationTest.java b/merlin-sdk/src/test/java/gov/nasa/jpl/aerie/merlin/protocol/types/DurationTest.java index 79e60ab97a..30c140544a 100644 --- a/merlin-sdk/src/test/java/gov/nasa/jpl/aerie/merlin/protocol/types/DurationTest.java +++ b/merlin-sdk/src/test/java/gov/nasa/jpl/aerie/merlin/protocol/types/DurationTest.java @@ -10,6 +10,7 @@ import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.roundNearest; import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.roundUpward; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public final class DurationTest { @Test @@ -45,4 +46,34 @@ public void testSaturation() { assertEquals(Duration.MIN_VALUE.saturatingPlus(Duration.of(-1, SECONDS)), Duration.MIN_VALUE); assertEquals(Duration.MIN_VALUE.plus(Duration.SECOND).saturatingPlus(Duration.of(-2, SECONDS)), Duration.MIN_VALUE); } + + @Test + public void parseDurationFromString(){ + // Test positive duration + assertEquals(Duration.of(3, Duration.HOURS).plus(Duration.of(2, Duration.MINUTES).plus(Duration.of(3, Duration.SECONDS).plus(Duration.of(4, Duration.MICROSECONDS)))), + Duration.fromString("03:02:03.000004")); + // Test negative duration + assertEquals(Duration.of(-1, Duration.HOURS).plus(Duration.of(-2, Duration.MINUTES).plus(Duration.of(-3, Duration.SECONDS).plus(Duration.of(-4, Duration.MICROSECONDS)))), + Duration.fromString("-01:02:03.000004")); + // Test duration with no subseconds + assertEquals(Duration.of(1, Duration.HOURS).plus(Duration.of(2, Duration.MINUTES).plus(Duration.of(3, Duration.SECONDS))), + Duration.fromString("01:02:03")); + // Test duration with trailing zeros in subseconds + assertEquals(Duration.of(1, Duration.HOURS).plus(Duration.of(2, Duration.MINUTES).plus(Duration.of(3, Duration.SECONDS).plus(Duration.of(4, Duration.MICROSECONDS)))), + Duration.fromString("01:02:03.000004")); + // Test duration with leading hours + assertEquals(Duration.of(1234, Duration.HOURS).plus(Duration.of(12, Duration.MINUTES).plus(Duration.of(0, Duration.SECONDS).plus(Duration.of(123456, Duration.MICROSECONDS)))), + Duration.fromString("1234:12:00.123456")); + // Test unbalanced duration + assertEquals(Duration.of(1, Duration.HOURS).plus(Duration.of(0, Duration.MINUTES).plus(Duration.of(0, Duration.SECONDS))), + Duration.fromString("+00:60:00")); + + assertThrows(IllegalArgumentException.class, () -> Duration.fromString("+20:00")); + // invalid input + assertThrows(IllegalArgumentException.class,() -> Duration.fromString("3:2:03")); + // Test positive duration + assertThrows(IllegalArgumentException.class, () -> Duration.fromString("a1:023.1234567")); + assertThrows(IllegalArgumentException.class, () -> Duration.fromString("-01:02:03.12345678901")); + + } } From a8b69db32fc63dcb5fb2033f1eab53db9f082e4b Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Wed, 7 Aug 2024 15:37:02 -0700 Subject: [PATCH 09/17] Create method for plan duration --- .../java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java | 5 +++++ .../jpl/aerie/merlin/server/services/ConstraintAction.java | 2 +- .../jpl/aerie/merlin/server/services/SimulationAgent.java | 5 +---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java index bf2ab8e2b0..62d20501a4 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java @@ -2,6 +2,7 @@ import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import java.util.HashMap; @@ -88,6 +89,10 @@ public Plan( this.simulationEndTimestamp = endTimestamp; } + public Duration duration() { + return Duration.of(startTimestamp.microsUntil(endTimestamp), Duration.MICROSECOND); + } + @Override public boolean equals(final Object object) { if (!(object instanceof final Plan other)) { diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintAction.java index 38105f4684..8198c93726 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintAction.java @@ -75,7 +75,7 @@ public Map> getViolations(final PlanId planId, final Opt final var simDuration = resultsHandle$ .map(SimulationResultsHandle::duration) .orElse(Duration.of( - plan.startTimestamp.toInstant().until(plan.endTimestamp.toInstant(), ChronoUnit.MICROS), + plan.simulationStartTimestamp.toInstant().until(plan.simulationEndTimestamp.toInstant(), ChronoUnit.MICROS), Duration.MICROSECONDS)); final var simOffset = Duration.of( plan.startTimestamp.toInstant().until(simStartTime, ChronoUnit.MICROS), diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java index b999b3e541..375b197bad 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java @@ -50,9 +50,6 @@ public void simulate( return; } - final var planDuration = Duration.of( - plan.startTimestamp.toInstant().until(plan.endTimestamp.toInstant(), ChronoUnit.MICROS), - Duration.MICROSECONDS); final var simDuration = Duration.of( plan.simulationStartTimestamp.toInstant().until(plan.simulationEndTimestamp.toInstant(), ChronoUnit.MICROS), Duration.MICROSECONDS); @@ -85,7 +82,7 @@ public void simulate( plan.simulationStartTimestamp.toInstant(), simDuration, plan.startTimestamp.toInstant(), - planDuration, + plan.duration(), plan.activityDirectives, plan.configuration), extentListener::updateValue, From 9bb77507918222bbf5033e4e4b0a9c465196e62d Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Wed, 7 Aug 2024 15:34:06 -0700 Subject: [PATCH 10/17] Extract sim code into SimulationUtility Library --- .../aerie/banananation/SimulationUtility.java | 14 +- .../gov/nasa/jpl/aerie/stateless/Main.java | 96 +++------- .../simulation/SimulationUtility.java | 178 ++++++++++++++++++ 3 files changed, 210 insertions(+), 78 deletions(-) create mode 100644 stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationUtility.java diff --git a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java index 65adba4bc1..83651c76e3 100644 --- a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java +++ b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java @@ -3,6 +3,7 @@ import gov.nasa.jpl.aerie.banananation.generated.GeneratedModelType; import gov.nasa.jpl.aerie.merlin.driver.*; import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import gov.nasa.jpl.aerie.merlin.protocol.model.ModelType; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import org.apache.commons.lang3.tuple.Pair; @@ -12,20 +13,15 @@ import java.util.Map; public final class SimulationUtility { - private static MissionModel makeMissionModel(final MissionModelBuilder builder, final Instant planStart, final Configuration config) { - final var factory = new GeneratedModelType(); - final var registry = DirectiveTypeRegistry.extract(factory); - // TODO: [AERIE-1516] Teardown the model to release any system resources (e.g. threads). - final var model = factory.instantiate(planStart, config, builder); - return builder.build(model, registry); - } - public static SimulationResults simulate(final Map schedule, final Duration simulationDuration) { final var dataPath = Path.of(SimulationUtility.class.getResource("data/lorem_ipsum.txt").getPath()); final var config = new Configuration(Configuration.DEFAULT_PLANT_COUNT, Configuration.DEFAULT_PRODUCER, dataPath, Configuration.DEFAULT_INITIAL_CONDITIONS); final var startTime = Instant.now(); - final var missionModel = makeMissionModel(new MissionModelBuilder(), Instant.EPOCH, config); + final var missionModel = gov.nasa.jpl.aerie.stateless.simulation.SimulationUtility.instantiateMissionModel( + new GeneratedModelType(), + Instant.EPOCH, + config); return SimulationDriver.simulate( missionModel, diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java index f4ebf0a01c..54cbeca1ff 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java @@ -1,27 +1,20 @@ package gov.nasa.jpl.aerie.stateless; -import gov.nasa.jpl.aerie.merlin.driver.resources.StreamingSimulationResourceManager; import gov.nasa.jpl.aerie.stateless.simulation.CanceledListener; import gov.nasa.jpl.aerie.stateless.simulation.ResourceFileStreamer; import gov.nasa.jpl.aerie.stateless.simulation.SimulationExtentConsumer; import gov.nasa.jpl.aerie.stateless.simulation.SimulationResultsWriter; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; -import gov.nasa.jpl.aerie.merlin.driver.SimulationDriver; import gov.nasa.jpl.aerie.merlin.driver.SimulationException; -import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; -import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.server.models.Plan; import java.nio.file.Path; import java.util.Map; import java.util.Optional; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import gov.nasa.jpl.aerie.stateless.simulation.SimulationUtility; import org.apache.commons.cli.*; import javax.json.Json; @@ -112,12 +105,10 @@ private static Arguments.SimulationArguments parseSimulationArgs(String[] arg // Load the mission model try { if (verbose) { System.out.println("Loading mission model "+modelJarPath+"..."); } - final var model = MissionModelLoader.loadMissionModel( - plan.simulationStartTimestamp.toInstant(), - SerializedValue.of(plan.configuration), + final var model = SimulationUtility.instantiateMissionModel( modelJarPath, - modelJarPath.getFileName().toString(), - "" + plan.simulationStartTimestamp.toInstant(), + plan.configuration ); return new Arguments.SimulationArguments<>(model, plan, verbose, outputFilePath, extentUpdatePeriod); @@ -129,41 +120,27 @@ private static Arguments.SimulationArguments parseSimulationArgs(String[] arg private static void simulate(Arguments.SimulationArguments simArgs) { if (simArgs.verbose()) { System.out.println("Simulating Plan..."); } + Thread shutdownHook = null; final var rfs = new ResourceFileStreamer(); - final var rmgr = new StreamingSimulationResourceManager(rfs); final var canceledListener = new CanceledListener(); - final var extentConsumer = simArgs.verbose? new SimulationExtentConsumer(simArgs.extentUpdatePeriod) : new SimulationExtentConsumer(); - - final var planDuration = Duration.of(simArgs.plan.startTimestamp.microsUntil(simArgs.plan.endTimestamp), - Duration.MICROSECOND); - final var simulationDuration = Duration.of(simArgs.plan.simulationStartTimestamp.microsUntil(simArgs.plan.simulationEndTimestamp), - Duration.MICROSECOND); // Cancel support - Thread shutdownHook = null; - final var resultsThread = new Callable() { - @Override - public SimulationResults call() { - return SimulationDriver.simulate( - simArgs.missionModel, - simArgs.plan.activityDirectives, - simArgs.plan.simulationStartTimestamp.toInstant(), - simulationDuration, - simArgs.plan.startTimestamp.toInstant(), - planDuration, + try (final var extentConsumer = simArgs.verbose + ? new SimulationExtentConsumer(simArgs.extentUpdatePeriod) + : new SimulationExtentConsumer(); + final var simUtil = new SimulationUtility(rfs) + ) { + final var resultsFuture = simUtil.simulate( + simArgs.missionModel(), + simArgs.plan(), canceledListener, - extentConsumer, - rmgr); - } - }; - - try(final var exec = Executors.newSingleThreadExecutor()) { - final Future f = exec.submit(resultsThread); + extentConsumer + ); shutdownHook = new Thread(() -> { canceledListener.cancel(); try { - final var results = f.get(); + final var results = resultsFuture.get(); if (simArgs.verbose()) { System.out.println("Writing Results..."); } final var resultsWriter = new SimulationResultsWriter(results, simArgs.plan, rfs); @@ -180,8 +157,8 @@ public SimulationResults call() { // Surround awaiting sim results in a thread to output partial results during SIGINT Runtime.getRuntime().addShutdownHook(shutdownHook); - final var results = f.get(); - if(!canceledListener.get()) { + final var results = resultsFuture.get(); + if (!canceledListener.get()) { // Avoid two threads writing to the output file at the same time Runtime.getRuntime().removeShutdownHook(shutdownHook); @@ -193,8 +170,12 @@ public SimulationResults call() { ); } } catch (ExecutionException e) { - if(e.getCause() instanceof SimulationException se) { - writeSimulationException(se); + if (e.getCause() instanceof SimulationException se) { + // Write Formatted Sim Exception to std.err + final Map config = Map.of(JsonGenerator.PRETTY_PRINTING, ""); + try(final var jsonWriter = Json.createWriterFactory(config).createWriter(System.err)) { + jsonWriter.writeObject(SimulationUtility.formatSimulationException(se)); + } System.exit(1); } throw new RuntimeException(e); @@ -202,37 +183,14 @@ public SimulationResults call() { throw new RuntimeException(e); } catch (IllegalStateException ise) { // If this is the message, it must've come from Runtime.getRuntime().removeShutdownHook and can be safely ignored - if(!ise.getMessage().contains("Shutdown in progress")) throw ise; + if (!ise.getMessage().contains("Shutdown in progress")) throw ise; } finally { - extentConsumer.close(); // Try-catch wrapping in case this is executed while the shutdown hook is running. - try { - Runtime.getRuntime().removeShutdownHook(shutdownHook); - } catch (IllegalStateException ise) {} + try { Runtime.getRuntime().removeShutdownHook(shutdownHook); } + catch (IllegalStateException ise) {} } } - private static void writeSimulationException(SimulationException ex) { - final var dataBuilder = Json.createObjectBuilder() - .add("elapsedTime", SimulationException.formatDuration(ex.elapsedTime)) - .add("utcTimeDoy", SimulationException.formatInstant(ex.instant)); - ex.directiveId.ifPresent(directiveId -> dataBuilder.add("executingDirectiveId", directiveId.id())); - ex.activityType.ifPresent(activityType -> dataBuilder.add("executingActivityType", activityType)); - ex.activityStackTrace.ifPresent(activityStackTrace -> dataBuilder.add("activityStackTrace", activityStackTrace)); - - final var exception = Json.createObjectBuilder() - .add("type", "SIMULATION_EXCEPTION") - .add("message", ex.cause.getMessage()) - .add("data", dataBuilder) - .add("trace", ex.cause.toString()) - .build(); - - final Map config = Map.of(JsonGenerator.PRETTY_PRINTING, ""); - try(final var jsonWriter = Json.createWriterFactory(config).createWriter(System.err)) { - jsonWriter.writeObject(exception); - } - } - /** * Display top-level help for the application */ diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationUtility.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationUtility.java new file mode 100644 index 0000000000..ff7e761779 --- /dev/null +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationUtility.java @@ -0,0 +1,178 @@ +package gov.nasa.jpl.aerie.stateless.simulation; + +import gov.nasa.jpl.aerie.merlin.driver.DirectiveTypeRegistry; +import gov.nasa.jpl.aerie.merlin.driver.MissionModel; +import gov.nasa.jpl.aerie.merlin.driver.MissionModelBuilder; +import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; +import gov.nasa.jpl.aerie.merlin.driver.SimulationDriver; +import gov.nasa.jpl.aerie.merlin.driver.SimulationException; +import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; +import gov.nasa.jpl.aerie.merlin.driver.resources.InMemorySimulationResourceManager; +import gov.nasa.jpl.aerie.merlin.driver.resources.ResourceProfiles; +import gov.nasa.jpl.aerie.merlin.driver.resources.SimulationResourceManager; +import gov.nasa.jpl.aerie.merlin.driver.resources.StreamingSimulationResourceManager; +import gov.nasa.jpl.aerie.merlin.protocol.model.ModelType; +import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.merlin.server.models.Plan; + +import javax.json.Json; +import javax.json.JsonObject; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Path; +import java.time.Instant; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class SimulationUtility implements AutoCloseable { + private final ExecutorService exec; + private final SimulationResourceManager rmgr; + + /** + * Create a new SimulationUtility that manages resources using an InMemorySimulationResourceManager. + */ + public SimulationUtility() { + this.exec = Executors.newSingleThreadExecutor(); + rmgr = new InMemorySimulationResourceManager(); + } + + /** + * Create a new SimulationUtility that manages resources using a StreamingSimulationResourceManager. + * @param resourceStreamer a Consumer defining how the ResourceManager will stream resources. + */ + public SimulationUtility(Consumer resourceStreamer) { + this.exec = Executors.newSingleThreadExecutor(); + rmgr = new StreamingSimulationResourceManager(resourceStreamer); + } + + /** + * Load and instantiate a Mission Model from a JAR on the file system. + * + * @param modelJarPath Path to the JAR + * @param simulationStartTime The time the loaded model expects to be simulated starting at. + * Necessary to correctly instantiate internal resources. + * @param modelConfiguration The configuration to be used while instantiating the model. + * Expected contents defined by the Model's Configuration. + * @return An instantiated MissionModel + * @throws MissionModelLoader.MissionModelLoadException If there is an issue while loading the JAR, + * such as the JAR not existing at the specified path. + * @throws MissionModelLoader.MissionModelInstantiationException If there is an issue while instantiating the Model, + * such as a invalid configuration or simulationStartTime. + */ + public static MissionModel instantiateMissionModel( + Path modelJarPath, + Instant simulationStartTime, + Map modelConfiguration + ) throws MissionModelLoader.MissionModelLoadException, MissionModelLoader.MissionModelInstantiationException { + return MissionModelLoader.loadMissionModel( + simulationStartTime, + SerializedValue.of(modelConfiguration), + modelJarPath, + modelJarPath.getFileName().toString(), + "" + ); + } + + /** + * Instantiate a Mission Model using the generated Java code + * + * @param modelType An instance of the GeneratedModelType class created for the mission model by the merlin processor + * @param simulationStartTime The time the loaded model expects to be simulated starting at. + * Necessary to correctly instantiate internal resources. + * @param modelConfiguration The configuration to be used while instantiating the mission model. + * @return An instantiated MissionModel + * @param The mission model's Configuration class, as defined by the @WithConfiguration tag within its package-info.java + * @param The mission model's Model class, as defined by the @MissionModel tag within its package-info.java + */ + public static MissionModel instantiateMissionModel( + ModelType modelType, + Instant simulationStartTime, + Config modelConfiguration + ) { + final var modelBuilder = new MissionModelBuilder(); + final var registry = DirectiveTypeRegistry.extract(modelType); + + // TODO: [AERIE-1516] Teardown the model to release any system resources (e.g. threads). + final var model = modelType.instantiate(simulationStartTime, modelConfiguration, modelBuilder); + return modelBuilder.build(model, registry); + } + + /** + * Simulate a plan. Simulation will not be cancelable. + * @param model The mission model to be used during simulation + * @param plan The plan to simulate. Contains the simulation configuration + * @return A Future to get the SimulationResults + */ + public Future simulate(MissionModel model, Plan plan) { + return simulate(model, plan, () -> false, d -> {}); + } + + /** + * Simulate a plan + * @param model The mission model to be used during simulation + * @param plan The plan to simulate. Contains the simulation configuration + * @param canceledListener A boolean supplier to permit canceling of the simulation + * @param extentConsumer A duration consumer to receive updates on how much time has elapsed within the simulation + * @return A Future to get the SimulationResults + */ + public Future simulate( + MissionModel model, + Plan plan, + Supplier canceledListener, + Consumer extentConsumer + ) { + final var simulationDuration = Duration.of(plan.simulationStartTimestamp + .microsUntil(plan.simulationEndTimestamp), Duration.MICROSECOND); + final var resultsThread = new Callable() { + @Override + public SimulationResults call() { + return SimulationDriver.simulate( + model, + plan.activityDirectives, + plan.simulationStartTimestamp.toInstant(), + simulationDuration, + plan.startTimestamp.toInstant(), + plan.duration(), + canceledListener, + extentConsumer, + rmgr); + } + }; + + return exec.submit(resultsThread); + } + + /** + * Format a SimulationException into a JSON object. + */ + public static JsonObject formatSimulationException(SimulationException ex) { + final var dataBuilder = Json.createObjectBuilder() + .add("elapsedTime", SimulationException.formatDuration(ex.elapsedTime)) + .add("utcTimeDoy", SimulationException.formatInstant(ex.instant)); + ex.directiveId.ifPresent(directiveId -> dataBuilder.add("executingDirectiveId", directiveId.id())); + ex.activityType.ifPresent(activityType -> dataBuilder.add("executingActivityType", activityType)); + ex.activityStackTrace.ifPresent(activityStackTrace -> dataBuilder.add("activityStackTrace", activityStackTrace)); + + final var sw = new StringWriter(); + ex.cause.printStackTrace(new PrintWriter(sw, true)); + final var stackTrace = sw.toString(); + + return Json.createObjectBuilder() + .add("type", "SIMULATION_EXCEPTION") + .add("message", ex.cause.getMessage()) + .add("data", dataBuilder) + .add("trace", stackTrace) + .build(); + } + + @Override + public void close() { + exec.close(); + } +} From f1fc1bf09aaffa6a692ccd02e3d59478488a9441 Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Tue, 6 Aug 2024 08:12:48 -0700 Subject: [PATCH 11/17] Create way to block System.exit() in Unit Tests - Uses deprecated SecurityManager -- see comment on class for more details - Created as the CLI calls `System.exit()` under certain conditions (such as displaying help text for a subcommand). This allows those conditions to be tested. --- stateless-aerie/build.gradle | 2 + .../utils/BlockExitSecurityManager.java | 69 +++++++++++++++++++ .../jpl/aerie/stateless/utils/SystemExit.java | 10 +++ 3 files changed, 81 insertions(+) create mode 100644 stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/utils/BlockExitSecurityManager.java create mode 100644 stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/utils/SystemExit.java diff --git a/stateless-aerie/build.gradle b/stateless-aerie/build.gradle index 368cb73e72..870e81cc64 100644 --- a/stateless-aerie/build.gradle +++ b/stateless-aerie/build.gradle @@ -37,6 +37,8 @@ test { testLogging { exceptionFormat = 'full' } + // Allow security manager so it can be overridden with mock for unit tests + systemProperty("java.security.manager", "allow") } jacocoTestReport { diff --git a/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/utils/BlockExitSecurityManager.java b/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/utils/BlockExitSecurityManager.java new file mode 100644 index 0000000000..f311f30da2 --- /dev/null +++ b/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/utils/BlockExitSecurityManager.java @@ -0,0 +1,69 @@ +package gov.nasa.jpl.aerie.stateless.utils; + +import java.security.Permission; + +/** + * A SecurityManager that throws an exception when System.exit() is called instead of stopping the JVM. + */ +/* + SecurityManager is set to be deprecated by JEP 411 (https://openjdk.org/jeps/411) + However, our usage falls into the niche that currently has no followup: + - Evaluate whether new APIs or mechanisms are needed to address specific narrow use cases + for which the Security Manager has been employed, such as blocking System::exit. + Relevant open JDK ticket: https://bugs.openjdk.org/browse/JDK-8199704 + Once that ticket is closed, this class can be updated to use the new API +*/ +@SuppressWarnings("removal") +public class BlockExitSecurityManager extends SecurityManager { + private static SecurityManager originalSecurityManager; + private static boolean installed = false; + + private BlockExitSecurityManager(){} + + /** + * Set a BlockExitSecurityManager as the current Security Manager, if it is not already in use. + */ + public static void install() { + if(installed) { + throw new IllegalStateException("BlockExitSecurityManager is already in use."); + } + + installed = true; + originalSecurityManager = System.getSecurityManager(); + System.setSecurityManager(new BlockExitSecurityManager()); + } + + /** + * If a BlockExitSecurityManager is the current Security Manager, + * restore the security manager it replaced as the current manager. + * + * Note that this method cannot detect if a new SecurityManager was installed between calling `install` and `uninstall`. + */ + public static void uninstall() { + if(!installed) { + throw new IllegalStateException("BlockExitSecurityManager is not in use."); + } + + installed = false; + System.setSecurityManager(originalSecurityManager); + } + + /** + * Block system exit and instead throw as an exception with the specified status code + */ + @Override + public void checkExit(final int statusCode) { + throw new SystemExit(statusCode); + } + + /** + * Defer permission checks to the original security manager, if it exists. + * Without this override, the JVM hangs during "BlockExitSecurityManager::uninstall" + */ + @Override + public void checkPermission(Permission perm) { + if(originalSecurityManager != null) { + originalSecurityManager.checkPermission(perm); + } + } +} diff --git a/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/utils/SystemExit.java b/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/utils/SystemExit.java new file mode 100644 index 0000000000..65d582738e --- /dev/null +++ b/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/utils/SystemExit.java @@ -0,0 +1,10 @@ +package gov.nasa.jpl.aerie.stateless.utils; + +public class SystemExit extends RuntimeException { + private final int statusCode; + + public SystemExit(int statusCode) { + this.statusCode = statusCode; + } + public int getStatusCode() { return statusCode; } +} From 10c67145571586f2ba0a250762f44a2075b70643 Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Tue, 6 Aug 2024 08:13:20 -0700 Subject: [PATCH 12/17] Create CLI Args Tests --- stateless-aerie/build.gradle | 1 + .../jpl/aerie/stateless/CLIArgumentsTest.java | 302 ++++++ .../resources/exceptionFooConfiguration.json | 8 + .../src/test/resources/simpleFooPlan.json | 40 + .../test/resources/simpleFooPlanResults.json | 909 ++++++++++++++++++ .../test/resources/subsetFooPlanResults.json | 559 +++++++++++ .../temporalSubsetFooConfiguration.json | 6 + 7 files changed, 1825 insertions(+) create mode 100644 stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/CLIArgumentsTest.java create mode 100644 stateless-aerie/src/test/resources/exceptionFooConfiguration.json create mode 100644 stateless-aerie/src/test/resources/simpleFooPlan.json create mode 100644 stateless-aerie/src/test/resources/simpleFooPlanResults.json create mode 100644 stateless-aerie/src/test/resources/subsetFooPlanResults.json create mode 100644 stateless-aerie/src/test/resources/temporalSubsetFooConfiguration.json diff --git a/stateless-aerie/build.gradle b/stateless-aerie/build.gradle index 870e81cc64..6c2cee6416 100644 --- a/stateless-aerie/build.gradle +++ b/stateless-aerie/build.gradle @@ -60,6 +60,7 @@ dependencies { implementation 'commons-cli:commons-cli:1.8.0' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' + testRuntimeOnly(project(':examples:foo-missionmodel')) testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/CLIArgumentsTest.java b/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/CLIArgumentsTest.java new file mode 100644 index 0000000000..b043aa7657 --- /dev/null +++ b/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/CLIArgumentsTest.java @@ -0,0 +1,302 @@ +package gov.nasa.jpl.aerie.stateless; + +import gov.nasa.jpl.aerie.stateless.utils.BlockExitSecurityManager; +import gov.nasa.jpl.aerie.stateless.utils.SystemExit; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import javax.json.Json; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintStream; +import java.io.StringReader; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class CLIArgumentsTest { + private ByteArrayOutputStream out; + private ByteArrayOutputStream err; + private PrintStream outputStream; + private PrintStream errorStream; + + @BeforeEach + void beforeEach() { + // Redirect System streams to buffers that can be examined + out = new ByteArrayOutputStream(); + err = new ByteArrayOutputStream(); + outputStream = new PrintStream(out); + errorStream = new PrintStream(err); + + System.setOut(outputStream); + System.setErr(errorStream); + } + + @AfterEach + void afterEach() { + outputStream.close(); + errorStream.close(); + } + + /** + * Top level help text only displays if: + * - the first argument is '-h' or '--help' + * - no arguments are passed + * - a nonexistent subcommand is passed + */ + @Test + void topLevelHelp() { + final String helpString = + """ + usage: stateless-aerie COMMAND [ARGS]... + + Available commands: + - simulate: Simulate a plan using the specified model and configuration + + Stateless Aerie v"""; + + final var validArgs = new String[][]{{"-h"}, {"--help"}, {}, {"fakeCommand"}, + {"-h", "simulate"}, {"--help", "simulate"}, + {"-h", "--help"}, {"--help", "-h"}}; + for(final var args : validArgs) { + Main.main(args); + outputStream.flush(); + assertTrue(out.toString().contains(helpString)); + assertTrue(err.toString().isBlank()); + out.reset(); + err.reset(); + } + + // '-h' or '--help' as the second argument does not display the top-level help string + final var otherArgs = new String[][]{{"simulate", "-h"}, {"simulate", "--help"}}; + BlockExitSecurityManager.install(); + for(final var args : otherArgs) { + final var sysExit = assertThrows(SystemExit.class, () -> Main.main(args)); + assertEquals(0, sysExit.getStatusCode()); + + outputStream.flush(); + assertFalse(out.toString().contains(helpString)); + assertTrue(err.toString().isBlank()); + out.reset(); + err.reset(); + } + BlockExitSecurityManager.uninstall(); + } + + @Nested + public class SimulationArguments { + /** + * Subcommand help message appears if the '-h' or '--help' flag is passed after the subcommand, + * regardless of presence of other arguments or position. + */ + @Test + void simulationHelp() { + final var helpString = + """ + usage: stateless-aerie simulate [-f ] [-h] [-i ] -m -p + [-s ] [-v] + Simulate a plan using the specified model and configuration + -f,--file output file path + -h,--help display this message and exit + -i,--update_interval minimum interval that simulation extent + updates are posted, in milliseconds + -m,--model path to model jar + -p,--plan path to plan json + -s,--sim_config path to simulation configuration json + -v,--verbose verbosity of simulation + + Stateless Aerie v"""; + + final var helpArgs = new String[][] {{"simulate", "-h"}, {"simulate", "--help"}, + {"simulate", "-p", "foo plan.json", "-h"}, + {"simulate", "-i", "1000", "--help"}}; + + BlockExitSecurityManager.install(); + for (final var args : helpArgs) { + final var sysExit = assertThrows(SystemExit.class, () -> Main.main(args)); + assertEquals(0, sysExit.getStatusCode()); + + outputStream.flush(); + assertTrue(out.toString().contains(helpString)); + assertTrue(err.toString().isBlank()); + out.reset(); + err.reset(); + } + BlockExitSecurityManager.uninstall(); + } + + /** An exception is thrown if simulation is run for a plan that doesn't exist or cannot be parsed. */ + @Test + void badPlan() { + final var missingFileError = assertThrows(RuntimeException.class, + () -> Main.main(new String[]{ + "simulate", + "-m", "../examples/foo-missionmodel/build/libs/foo-missionmodel.jar", + "-p", "src/test/resources/fake_plan.json"})); + assertEquals("Specified plan JSON file does not exist: src/test/resources/fake_plan.json", + missingFileError.getMessage()); + + final var badFileError = assertThrows(RuntimeException.class, + () -> Main.main(new String[]{ + "simulate", + "-m", "../examples/foo-missionmodel/build/libs/foo-missionmodel.jar", + "-p", "../examples/foo-missionmodel/build/libs/foo-missionmodel.jar"})); + assertEquals("Error while reading plan JSON file: ../examples/foo-missionmodel/build/libs/foo-missionmodel.jar", + badFileError.getMessage()); + } + + /** An exception is thrown if simulation is run using a model that doesn't exist or cannot be parsed. */ + @Test + void badModel() { + final var missingFileError = assertThrows(RuntimeException.class, + () -> Main.main(new String[]{ + "simulate", + "-m", "fake-mission-model.jar", + "-p", "src/test/resources/simpleFooPlan.json"})); + assertEquals("Error while loading mission model: fake-mission-model.jar", + missingFileError.getMessage()); + + final var badFileError = assertThrows(RuntimeException.class, + () -> Main.main(new String[]{ + "simulate", + "-m", "src/test/resources/simpleFooPlan.json", + "-p", "src/test/resources/simpleFooPlan.json"})); + assertEquals("Error while loading mission model: src/test/resources/simpleFooPlan.json", + badFileError.getMessage()); + } + + /** An exception is thrown if simulation is run using a sim config that doesn't exist or cannot be parsed. */ + @Test + void badSimConfig() { + final var missingFileError = assertThrows(RuntimeException.class, + () -> Main.main(new String[]{ + "simulate", + "-m", "../examples/foo-missionmodel/build/libs/foo-missionmodel.jar", + "-p", "src/test/resources/simpleFooPlan.json", + "-s", "src/test/resources/fake_config.json"})); + assertEquals("Specified simulation configuration JSON file does not exist: src/test/resources/fake_config.json", + missingFileError.getMessage()); + + final var badFileError = assertThrows(RuntimeException.class, + () -> Main.main(new String[]{ + "simulate", + "-m", "../examples/foo-missionmodel/build/libs/foo-missionmodel.jar", + "-p", "src/test/resources/simpleFooPlan.json", + "-s", "src/test/resources/simpleFooPlan.json"})); + assertEquals("Error while reading simulation configuration JSON file: src/test/resources/simpleFooPlan.json", + badFileError.getMessage()); + } + + /** When verbose is on, progress is reported prior to simulation results. */ + @Test + void verboseOn() throws IOException { + Main.main(new String[]{"simulate", + "-m", "../examples/foo-missionmodel/build/libs/foo-missionmodel.jar", + "-p", "src/test/resources/simpleFooPlan.json", + // Extent interval cranked way up to guarantee no extent is printed (5000s) + "-i", "5000000000", + "--verbose"}); + outputStream.flush(); + try(final var reader = new BufferedReader(new FileReader("src/test/resources/simpleFooPlanResults.json"))) { + final var fileLines = reader.lines().toList(); + final var output = out.toString(); + assertEquals(fileLines.size() + 4, output.split("\n").length); + + int truncateIndex = 0; + for(int i = 0; i < 4; ++i) { + truncateIndex = output.indexOf("\n", truncateIndex + 1); + } + + final var introLines = """ + Parsing plan src/test/resources/simpleFooPlan.json... + Loading mission model ../examples/foo-missionmodel/build/libs/foo-missionmodel.jar... + Simulating Plan... + Writing Results..."""; + + assertEquals(introLines, output.substring(0, truncateIndex)); + + try(final var fileReader = Json.createReader(new FileReader("src/test/resources/simpleFooPlanResults.json")); + final var outputReader = Json.createReader(new StringReader(output.substring(truncateIndex)))) { + final var fileJson = fileReader.readObject(); + final var outputJson = outputReader.readObject(); + assertEquals(fileJson, outputJson); + } + } + } + + /** When verbose is off, only simulation results are output. */ + @Test + void verboseOff() throws IOException { + Main.main(new String[]{"simulate", + "-m", "../examples/foo-missionmodel/build/libs/foo-missionmodel.jar", + "-p", "src/test/resources/simpleFooPlan.json"}); + outputStream.flush(); + + try(final var fileReader = Json.createReader(new FileReader("src/test/resources/simpleFooPlanResults.json")); + final var outputReader = Json.createReader(new StringReader(out.toString()))) { + final var fileJson = fileReader.readObject(); + final var outputJson = outputReader.readObject(); + assertEquals(fileJson, outputJson); + } + } + + /** Sim config bounds take precedence over plan bounds */ + @Test + void simConfigTemporalSubset() throws FileNotFoundException { + Main.main(new String[] {"simulate", + "-m", "../examples/foo-missionmodel/build/libs/foo-missionmodel.jar", + "-p", "src/test/resources/simpleFooPlan.json", + "-s", "src/test/resources/temporalSubsetFooConfiguration.json"}); + try(final var fileReader = Json.createReader(new FileReader("src/test/resources/subsetFooPlanResults.json")); + final var outputReader = Json.createReader(new StringReader(out.toString()))) { + final var fileJson = fileReader.readObject(); + final var outputJson = outputReader.readObject(); + assertEquals(fileJson, outputJson); + } + } + + /** + * Sim exceptions are given as a well-formatted JSON. + * Also tests that sim config arguments are applied to simulation. + */ + @Test + void simException() { + BlockExitSecurityManager.install(); + final var sysExit = assertThrows(SystemExit.class, + () -> Main.main(new String[]{ + "simulate", + "-m", "../examples/foo-missionmodel/build/libs/foo-missionmodel.jar", + "-p", "src/test/resources/simpleFooPlan.json", + "-s", "src/test/resources/exceptionFooConfiguration.json",})); + assertEquals(1, sysExit.getStatusCode()); + BlockExitSecurityManager.uninstall(); + + assertTrue(out.toString().isBlank()); + assertFalse(err.toString().isBlank()); + + try(final var errorReader = Json.createReader(new StringReader(err.toString()))) { + final var errorJson = errorReader.readObject(); + final var dataObject = Json.createObjectBuilder() + .add("elapsedTime", "01:00:00.000000") + .add( "utcTimeDoy", "2024-183T01:00:00") + .build(); + + assertEquals(4, errorJson.keySet().size()); + assertTrue(errorJson.keySet().containsAll(List.of("type", "message", "data", "trace"))); + + assertEquals("SIMULATION_EXCEPTION", errorJson.getString("type")); + assertEquals("Daemon task exception raised.", errorJson.getString("message")); + assertEquals(dataObject, errorJson.getJsonObject("data")); + assertTrue(errorJson.getString("trace").startsWith("java.lang.RuntimeException: Daemon task exception raised.")); + } + } + } +} diff --git a/stateless-aerie/src/test/resources/exceptionFooConfiguration.json b/stateless-aerie/src/test/resources/exceptionFooConfiguration.json new file mode 100644 index 0000000000..027612abaa --- /dev/null +++ b/stateless-aerie/src/test/resources/exceptionFooConfiguration.json @@ -0,0 +1,8 @@ +{ + "version": "2", + "simulation_start_time": "2024-07-01T00:00:00+00:00", + "simulation_end_time": "2024-07-02T00:00:00+00:00", + "arguments": { + "raiseException": true + } +} diff --git a/stateless-aerie/src/test/resources/simpleFooPlan.json b/stateless-aerie/src/test/resources/simpleFooPlan.json new file mode 100644 index 0000000000..400fa25cf8 --- /dev/null +++ b/stateless-aerie/src/test/resources/simpleFooPlan.json @@ -0,0 +1,40 @@ +{ + "activities": [ + { + "anchor_id": null, + "anchored_to_start": true, + "arguments": { + "duration": { + "amountInMicroseconds": 2000000 + } + }, + "id": 4, + "metadata": {}, + "name": "BasicFooActivity", + "start_offset": "02:27:15.059", + "tags": [], + "type": "BasicFooActivity" + }, + { + "anchor_id": null, + "anchored_to_start": true, + "arguments": { + "minutesElapsed": 700, + "spawnDelay": 1 + }, + "id": 5, + "metadata": {}, + "name": "DaemonCheckerSpawner", + "start_offset": "11:39:55.219", + "tags": [], + "type": "DaemonCheckerSpawner" + } + ], + "duration": "24:00:00", + "id": 3, + "model_id": 4, + "name": "foo plan", + "simulation_arguments": {}, + "start_time": "2024-07-01T00:00:00+00:00", + "tags": [] +} diff --git a/stateless-aerie/src/test/resources/simpleFooPlanResults.json b/stateless-aerie/src/test/resources/simpleFooPlanResults.json new file mode 100644 index 0000000000..07fd5cfd89 --- /dev/null +++ b/stateless-aerie/src/test/resources/simpleFooPlanResults.json @@ -0,0 +1,909 @@ +{ + "version": 1.0, + "simulationStartTime": "2024-183T00:00:00", + "simulationEndTime": "2024-184T00:00:00", + "canceled": false, + "simulationConfiguration": { + "startTime": "2024-183T00:00:00", + "endTime": "2024-184T00:00:00", + "arguments": { + } + }, + "profiles": { + "realProfiles": [ + { + "name": "/utcClock", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 1000.0 + } + } + ] + }, + { + "name": "/simple_data/b/volume", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 5.0 + } + } + ] + }, + { + "name": "/simple_data/a/volume", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 10.0 + } + } + ] + }, + { + "name": "/sink/rate", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 0.5, + "rate": 0.0 + } + } + ] + }, + { + "name": "/source/rate", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 1.0, + "rate": 0.0 + } + } + ] + }, + { + "name": "/sink", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 0.5 + } + } + ] + }, + { + "name": "/simple_data/a/rate", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 10.0, + "rate": 0.0 + } + } + ] + }, + { + "name": "/batterySoC", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 100.0, + "rate": 0.5 + } + } + ] + }, + { + "name": "/simple_data/b/rate", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 5.0, + "rate": 0.0 + } + } + ] + }, + { + "name": "/data/rate", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 42.0, + "rate": 0.0 + } + } + ] + }, + { + "name": "/data", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 42.0 + } + } + ] + }, + { + "name": "/simple_data/total_volume", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 15.0 + } + } + ] + }, + { + "name": "/source", + "schema": { + "type": "struct", + "items": { + "rate": { + "type": "real" + }, + "initial": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": { + "initial": 100.0, + "rate": 1.0 + } + } + ] + } + ], + "discreteProfiles": [ + { + "name": "/foo", + "schema": { + "type": "real" + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": 21.0 + } + ] + }, + { + "name": "/foo/conflicted", + "schema": { + "type": "boolean" + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": false + } + ] + }, + { + "name": "/counter", + "schema": { + "type": "int" + }, + "segments": [ + { + "extent": "+00:16:40.000000", + "dynamics": 0 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 1 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 2 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 3 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 4 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 5 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 6 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 7 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 8 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 9 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 10 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 11 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 12 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 13 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 14 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 15 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 16 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 17 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 18 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 19 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 20 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 21 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 22 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 23 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 24 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 25 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 26 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 27 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 28 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 29 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 30 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 31 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 32 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 33 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 34 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 35 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 36 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 37 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 38 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 39 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 40 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 41 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 42 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 43 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 44 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 45 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 46 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 47 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 48 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 49 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 50 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 51 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 52 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 53 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 54 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 55 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 56 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 57 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 58 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 59 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 60 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 61 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 62 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 63 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 64 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 65 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 66 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 67 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 68 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 69 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 70 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 71 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 72 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 73 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 74 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 75 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 76 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 77 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 78 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 79 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 80 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 81 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 82 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 83 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 84 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 85 + }, + { + "extent": "+00:06:40.000000", + "dynamics": 86 + } + ] + }, + { + "name": "/activitiesExecuted", + "schema": { + "type": "int" + }, + "segments": [ + { + "extent": "+02:27:17.059000", + "dynamics": 0 + }, + { + "extent": "+21:32:42.941000", + "dynamics": 1 + } + ] + }, + { + "name": "/foo/starting_after_unix_epoch", + "schema": { + "type": "boolean" + }, + "segments": [ + { + "extent": "+24:00:00.000000", + "dynamics": true + } + ] + } + ] + }, + "spans": { + "simulatedActivities": [ + { + "id": 1, + "directiveId": null, + "parentId": 5, + "childIds": [ + ], + "type": "DaemonCheckerActivity", + "startOffset": "+11:40:55.219000", + "duration": "+00:00:00.000000", + "attributes": { + }, + "arguments": { + "minutesElapsed": 700 + }, + "startTime": "2024-07-01T11:40:55.219Z", + "endTime": "2024-07-01T11:40:55.219Z" + }, + { + "id": 4, + "directiveId": 4, + "parentId": null, + "childIds": [ + ], + "type": "BasicFooActivity", + "startOffset": "+02:27:15.059000", + "duration": "+00:00:02.000000", + "attributes": { + }, + "arguments": { + "duration": { + "amountInMicroseconds": 2000000 + } + }, + "startTime": "2024-07-01T02:27:15.059Z", + "endTime": "2024-07-01T02:27:17.059Z" + }, + { + "id": 5, + "directiveId": 5, + "parentId": null, + "childIds": [ + 1 + ], + "type": "DaemonCheckerSpawner", + "startOffset": "+11:39:55.219000", + "duration": "+00:01:00.000000", + "attributes": { + }, + "arguments": { + "minutesElapsed": 700, + "spawnDelay": 1 + }, + "startTime": "2024-07-01T11:39:55.219Z", + "endTime": "2024-07-01T11:40:55.219Z" + } + ], + "unfinishedActivities": [ + ] + }, + "events": { + "event": [ + { + "causalTime": ".1", + "realTime": "+02:27:15.059000", + "transactionIndex": 0, + "value": { + "duration": { + "amountInMicroseconds": 2000000 + } + }, + "topic": { + "name": "ActivityType.Input.BasicFooActivity", + "valueSchema": { + "type": "struct", + "items": { + "duration": { + "type": "struct", + "items": { + "amountInMicroseconds": { + "type": "int" + } + } + } + } + } + }, + "spanId": 4 + }, + { + "causalTime": ".1", + "realTime": "+02:27:17.059000", + "transactionIndex": 0, + "value": { + }, + "topic": { + "name": "ActivityType.Output.BasicFooActivity", + "valueSchema": { + "type": "struct", + "items": { + } + } + }, + "spanId": 4 + }, + { + "causalTime": ".1", + "realTime": "+11:39:55.219000", + "transactionIndex": 0, + "value": { + "minutesElapsed": 700, + "spawnDelay": 1 + }, + "topic": { + "name": "ActivityType.Input.DaemonCheckerSpawner", + "valueSchema": { + "type": "struct", + "items": { + "minutesElapsed": { + "type": "int" + }, + "spawnDelay": { + "type": "int" + } + } + } + }, + "spanId": 5 + }, + { + "causalTime": ".1", + "realTime": "+11:40:55.219000", + "transactionIndex": 0, + "value": { + "minutesElapsed": 700 + }, + "topic": { + "name": "ActivityType.Input.DaemonCheckerActivity", + "valueSchema": { + "type": "struct", + "items": { + "minutesElapsed": { + "type": "int" + } + } + } + }, + "spanId": 1 + }, + { + "causalTime": ".2", + "realTime": "+11:40:55.219000", + "transactionIndex": 0, + "value": { + }, + "topic": { + "name": "ActivityType.Output.DaemonCheckerActivity", + "valueSchema": { + "type": "struct", + "items": { + } + } + }, + "spanId": 1 + }, + { + "causalTime": ".1", + "realTime": "+11:40:55.219000", + "transactionIndex": 1, + "value": { + }, + "topic": { + "name": "ActivityType.Output.DaemonCheckerSpawner", + "valueSchema": { + "type": "struct", + "items": { + } + } + }, + "spanId": 5 + } + ] + } +} \ No newline at end of file diff --git a/stateless-aerie/src/test/resources/subsetFooPlanResults.json b/stateless-aerie/src/test/resources/subsetFooPlanResults.json new file mode 100644 index 0000000000..98a8346d75 --- /dev/null +++ b/stateless-aerie/src/test/resources/subsetFooPlanResults.json @@ -0,0 +1,559 @@ +{ + "version": 1.0, + "simulationStartTime": "2024-183T12:00:00", + "simulationEndTime": "2024-184T00:00:00", + "canceled": false, + "simulationConfiguration": { + "startTime": "2024-183T12:00:00", + "endTime": "2024-184T00:00:00", + "arguments": { + } + }, + "profiles": { + "realProfiles": [ + { + "name": "/utcClock", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 1000.0 + } + } + ] + }, + { + "name": "/simple_data/b/volume", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 5.0 + } + } + ] + }, + { + "name": "/simple_data/a/volume", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 10.0 + } + } + ] + }, + { + "name": "/sink/rate", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 0.5, + "rate": 0.0 + } + } + ] + }, + { + "name": "/source/rate", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 1.0, + "rate": 0.0 + } + } + ] + }, + { + "name": "/sink", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 0.5 + } + } + ] + }, + { + "name": "/simple_data/a/rate", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 10.0, + "rate": 0.0 + } + } + ] + }, + { + "name": "/batterySoC", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 100.0, + "rate": 0.5 + } + } + ] + }, + { + "name": "/simple_data/b/rate", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 5.0, + "rate": 0.0 + } + } + ] + }, + { + "name": "/data/rate", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 42.0, + "rate": 0.0 + } + } + ] + }, + { + "name": "/data", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 42.0 + } + } + ] + }, + { + "name": "/simple_data/total_volume", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 0.0, + "rate": 15.0 + } + } + ] + }, + { + "name": "/source", + "schema": { + "type": "struct", + "items": { + "initial": { + "type": "real" + }, + "rate": { + "type": "real" + } + } + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": { + "initial": 100.0, + "rate": 1.0 + } + } + ] + } + ], + "discreteProfiles": [ + { + "name": "/foo", + "schema": { + "type": "real" + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": 21.0 + } + ] + }, + { + "name": "/foo/conflicted", + "schema": { + "type": "boolean" + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": false + } + ] + }, + { + "name": "/counter", + "schema": { + "type": "int" + }, + "segments": [ + { + "extent": "+00:16:40.000000", + "dynamics": 0 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 1 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 2 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 3 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 4 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 5 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 6 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 7 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 8 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 9 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 10 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 11 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 12 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 13 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 14 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 15 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 16 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 17 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 18 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 19 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 20 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 21 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 22 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 23 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 24 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 25 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 26 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 27 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 28 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 29 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 30 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 31 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 32 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 33 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 34 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 35 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 36 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 37 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 38 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 39 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 40 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 41 + }, + { + "extent": "+00:16:40.000000", + "dynamics": 42 + }, + { + "extent": "+00:03:20.000000", + "dynamics": 43 + } + ] + }, + { + "name": "/activitiesExecuted", + "schema": { + "type": "int" + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": 0 + } + ] + }, + { + "name": "/foo/starting_after_unix_epoch", + "schema": { + "type": "boolean" + }, + "segments": [ + { + "extent": "+12:00:00.000000", + "dynamics": true + } + ] + } + ] + }, + "spans": { + "simulatedActivities": [ + ], + "unfinishedActivities": [ + ] + }, + "events": { + "event": [ + ] + } +} \ No newline at end of file diff --git a/stateless-aerie/src/test/resources/temporalSubsetFooConfiguration.json b/stateless-aerie/src/test/resources/temporalSubsetFooConfiguration.json new file mode 100644 index 0000000000..59bd59231e --- /dev/null +++ b/stateless-aerie/src/test/resources/temporalSubsetFooConfiguration.json @@ -0,0 +1,6 @@ +{ + "version": "2", + "simulation_start_time": "2024-07-01T12:00:00+00:00", + "simulation_end_time": "2024-07-02T00:00:00+00:00", + "arguments": {} +} From eb683d06c86d2b2b8821341343b0a201c9084cd1 Mon Sep 17 00:00:00 2001 From: Ryan Goetz Date: Thu, 15 Aug 2024 11:26:46 -1000 Subject: [PATCH 13/17] Added a filename generator test * Verify that the generated temporary filename conforms to file naming conventions and remove any invalid characters --- stateless-aerie/build.gradle | 1 + .../simulation/ResourceFileStreamer.java | 8 +++- .../stateless/FileNameGeneratorTest.java | 44 +++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/FileNameGeneratorTest.java diff --git a/stateless-aerie/build.gradle b/stateless-aerie/build.gradle index 6c2cee6416..3476d7d6f6 100644 --- a/stateless-aerie/build.gradle +++ b/stateless-aerie/build.gradle @@ -60,6 +60,7 @@ dependencies { implementation 'commons-cli:commons-cli:1.8.0' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.0' testRuntimeOnly(project(':examples:foo-missionmodel')) testRuntimeOnly 'org.junit.platform:junit-platform-launcher' diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java index 9e26575fd0..c7a12eddbf 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java @@ -5,6 +5,7 @@ import javax.json.Json; import java.io.FileWriter; import java.io.IOException; +import java.util.Arrays; import java.util.HashMap; import java.util.UUID; import java.util.function.Consumer; @@ -47,7 +48,7 @@ Forbidden on Windows (Linux and Mac use a subset): ' (single quote) ' ' (space) */ - private static final char[] EXCLUSION = {'<', '>', ':', '"', '\\', '/', '|', '?', '*', '.', ',', '+', '&', '\'', ' '}; + private static final String[] EXCLUSION = {"<", ">", ",", ":", "\"", "\\\\", "/", "|", "?", "*", ".","+", "&", "'"," "}; @Override public void accept(final ResourceProfiles resourceProfile) { @@ -89,8 +90,11 @@ public void accept(final ResourceProfiles resourceProfile) { */ public String getFileName(String resourceName) { if(fileNames.containsKey(resourceName)) return fileNames.get(resourceName); + // Create files in the temp directory, or the PWD if there is no set tmpdir + String dirname = System.getProperty("java.io.tmpdir", "."); + if(!dirname.endsWith("/")) dirname = dirname + "/"; // Append a Path deliminator if necessary - final var fileName = System.getProperty("java.io.tmpdir") + resourceName.replaceAll("[" + String.valueOf(EXCLUSION) + "]", "_") + uuid.toString()+".rsc"; + final var fileName = dirname + resourceName.replaceAll("[" + Arrays.toString(EXCLUSION) + "]", "_") + uuid.toString()+".rsc"; fileNames.put(resourceName, fileName); return fileName; } diff --git a/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/FileNameGeneratorTest.java b/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/FileNameGeneratorTest.java new file mode 100644 index 0000000000..6dde81de66 --- /dev/null +++ b/stateless-aerie/src/test/java/gov/nasa/jpl/aerie/stateless/FileNameGeneratorTest.java @@ -0,0 +1,44 @@ +package gov.nasa.jpl.aerie.stateless; + +import gov.nasa.jpl.aerie.orchestration.simulation.ResourceFileStreamer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.*; + +public class FileNameGeneratorTest { + + @ParameterizedTest + @ValueSource(chars = {'<', '>', ':', '"', '\\', '/', '|', '?', '*', '.', ',', '+', '&', '\'', ' '}) + public void testFileNameGenerationWithForbiddenChars(char c) { + final var resourceName = c+"This"+c+"name"+c+"has"+c+"forbidden"+c+"chars"; + final var expectedFileName = "_This_name_has_forbidden_chars"; + + assertTrue(new ResourceFileStreamer().getFileName(resourceName).contains(expectedFileName)); + + } + + @Test + public void testFileNameGenerationRandomForbiddenChars() { + final char[] forbiddenChars = {'<', '>', ':', '"', '\\', '/', '|', '?', '*', '.', ',', '+', '&', '\'', ' '}; + final var fileGenerator = new ResourceFileStreamer(); + + final var random = new Random(); + for (int i = 0; i < 1000; i++) { + final var resourceNameBuilder = new StringBuilder(); + final var expectedFileNameBuilder = new StringBuilder(); + + for (int w = 0; w < 5; w++) { // 5 words + final var randomChar = forbiddenChars[random.nextInt(forbiddenChars.length)]; + resourceNameBuilder.append(randomChar).append("hello").append(randomChar); + expectedFileNameBuilder.append("_").append("hello").append("_"); + } + resourceNameBuilder.append("world"); + expectedFileNameBuilder.append("world"); + + assertTrue(fileGenerator.getFileName(resourceNameBuilder.toString()).contains(expectedFileNameBuilder.toString())); + } + } +} From 758a8c2b491425a68634392f9509b9d059b882ad Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Thu, 8 Aug 2024 17:19:02 -0700 Subject: [PATCH 14/17] Extract Utility Libraries into new package --- orchestration-utils/build.gradle | 73 +++++++++++++++++++ .../aerie/orchestration}/PlanJsonParser.java | 2 +- .../simulation/CanceledListener.java | 2 +- .../simulation/ResourceFileStreamer.java | 2 +- .../simulation/SimulationExtentConsumer.java | 2 +- .../simulation/SimulationResultsWriter.java | 2 +- .../simulation/SimulationUtility.java | 7 +- settings.gradle | 1 + stateless-aerie/build.gradle | 5 +- .../gov/nasa/jpl/aerie/stateless/Main.java | 11 +-- 10 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 orchestration-utils/build.gradle rename {stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless => orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration}/PlanJsonParser.java (99%) rename {stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless => orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration}/simulation/CanceledListener.java (86%) rename {stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless => orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration}/simulation/ResourceFileStreamer.java (98%) rename {stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless => orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration}/simulation/SimulationExtentConsumer.java (96%) rename {stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless => orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration}/simulation/SimulationResultsWriter.java (99%) rename {stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless => orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration}/simulation/SimulationUtility.java (97%) diff --git a/orchestration-utils/build.gradle b/orchestration-utils/build.gradle new file mode 100644 index 0000000000..d8c785f80b --- /dev/null +++ b/orchestration-utils/build.gradle @@ -0,0 +1,73 @@ +plugins { + id 'java-library' + id 'maven-publish' + id 'jacoco' + id 'application' +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + + withJavadocJar() + withSourcesJar() +} + +test { + useJUnitPlatform { + includeEngines 'junit-jupiter' + } + testLogging { + exceptionFormat = 'full' + } + // Allow security manager so it can be overridden with mock for unit tests + systemProperty("java.security.manager", "allow") +} + +jacocoTestReport { + dependsOn test + reports { + xml.required = true + } +} + + +dependencies { + implementation project(':merlin-server') + implementation project(':merlin-driver') + implementation project(':parsing-utilities') + implementation 'commons-cli:commons-cli:1.8.0' + + testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' +} + + +// Link references to standard Java classes to the official Java 11 documentation. +javadoc.options.links 'https://docs.oracle.com/en/java/javase/11/docs/api/' +javadoc.options.links 'https://commons.apache.org/proper/commons-lang/javadocs/api-3.9/' +javadoc.options.addStringOption('Xdoclint:none', '-quiet') + + +publishing { + publications { + library(MavenPublication) { + version = findProperty('publishing.version') + from components.java + } + } + + publishing { + repositories { + maven { + name = findProperty("publishing.name") + url = findProperty("publishing.url") + credentials { + username = System.getenv(findProperty("publishing.usernameEnvironmentVariable")) + password = System.getenv(findProperty("publishing.passwordEnvironmentVariable")) + } + } + } + } +} diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java similarity index 99% rename from stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java rename to orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java index f2644e9aa6..db1074c4d1 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/PlanJsonParser.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java @@ -1,4 +1,4 @@ -package gov.nasa.jpl.aerie.stateless; +package gov.nasa.jpl.aerie.orchestration; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.server.models.Plan; diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/CanceledListener.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/CanceledListener.java similarity index 86% rename from stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/CanceledListener.java rename to orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/CanceledListener.java index 02a9f095d1..72bada00a6 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/CanceledListener.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/CanceledListener.java @@ -1,4 +1,4 @@ -package gov.nasa.jpl.aerie.stateless.simulation; +package gov.nasa.jpl.aerie.orchestration.simulation; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/ResourceFileStreamer.java similarity index 98% rename from stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java rename to orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/ResourceFileStreamer.java index c7a12eddbf..3c939079ee 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/ResourceFileStreamer.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/ResourceFileStreamer.java @@ -1,4 +1,4 @@ -package gov.nasa.jpl.aerie.stateless.simulation; +package gov.nasa.jpl.aerie.orchestration.simulation; import gov.nasa.jpl.aerie.merlin.driver.resources.ResourceProfiles; diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationExtentConsumer.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationExtentConsumer.java similarity index 96% rename from stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationExtentConsumer.java rename to orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationExtentConsumer.java index 8f879e61a3..b997b1444d 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationExtentConsumer.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationExtentConsumer.java @@ -1,4 +1,4 @@ -package gov.nasa.jpl.aerie.stateless.simulation; +package gov.nasa.jpl.aerie.orchestration.simulation; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java similarity index 99% rename from stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java rename to orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java index d6732ada38..79f87f4e27 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationResultsWriter.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java @@ -1,4 +1,4 @@ -package gov.nasa.jpl.aerie.stateless.simulation; +package gov.nasa.jpl.aerie.orchestration.simulation; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationUtility.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java similarity index 97% rename from stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationUtility.java rename to orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java index ff7e761779..2cf7a55913 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/simulation/SimulationUtility.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java @@ -1,4 +1,4 @@ -package gov.nasa.jpl.aerie.stateless.simulation; +package gov.nasa.jpl.aerie.orchestration.simulation; import gov.nasa.jpl.aerie.merlin.driver.DirectiveTypeRegistry; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; @@ -8,7 +8,6 @@ import gov.nasa.jpl.aerie.merlin.driver.SimulationException; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.driver.resources.InMemorySimulationResourceManager; -import gov.nasa.jpl.aerie.merlin.driver.resources.ResourceProfiles; import gov.nasa.jpl.aerie.merlin.driver.resources.SimulationResourceManager; import gov.nasa.jpl.aerie.merlin.driver.resources.StreamingSimulationResourceManager; import gov.nasa.jpl.aerie.merlin.protocol.model.ModelType; @@ -46,7 +45,7 @@ public SimulationUtility() { * Create a new SimulationUtility that manages resources using a StreamingSimulationResourceManager. * @param resourceStreamer a Consumer defining how the ResourceManager will stream resources. */ - public SimulationUtility(Consumer resourceStreamer) { + public SimulationUtility(ResourceFileStreamer resourceStreamer) { this.exec = Executors.newSingleThreadExecutor(); rmgr = new StreamingSimulationResourceManager(resourceStreamer); } @@ -137,7 +136,7 @@ public SimulationResults call() { plan.activityDirectives, plan.simulationStartTimestamp.toInstant(), simulationDuration, - plan.startTimestamp.toInstant(), + plan.planStartInstant(), plan.duration(), canceledListener, extentConsumer, diff --git a/settings.gradle b/settings.gradle index 195ce9efe9..ce6c145ad4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -42,3 +42,4 @@ include 'examples:config-without-defaults' include 'examples:minimal-mission-model' include 'examples:streamline-demo' include 'stateless-aerie' +include 'orchestration-utils' diff --git a/stateless-aerie/build.gradle b/stateless-aerie/build.gradle index 3476d7d6f6..2168fc812a 100644 --- a/stateless-aerie/build.gradle +++ b/stateless-aerie/build.gradle @@ -19,6 +19,7 @@ jar { dependsOn(':merlin-sdk:jar') dependsOn(':merlin-driver:jar') dependsOn(':constraints:jar') + dependsOn(':orchestration-utils:jar') duplicatesStrategy = DuplicatesStrategy.EXCLUDE @@ -54,9 +55,9 @@ javadoc.options.links 'https://commons.apache.org/proper/commons-lang/javadocs/a javadoc.options.addStringOption('Xdoclint:none', '-quiet') dependencies { - implementation project(':merlin-server') + implementation project(':orchestration-utils') implementation project(':merlin-driver') - implementation project(':parsing-utilities') + implementation project(':merlin-server') implementation 'commons-cli:commons-cli:1.8.0' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java index 54cbeca1ff..2fcc334cfc 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java @@ -1,9 +1,10 @@ package gov.nasa.jpl.aerie.stateless; -import gov.nasa.jpl.aerie.stateless.simulation.CanceledListener; -import gov.nasa.jpl.aerie.stateless.simulation.ResourceFileStreamer; -import gov.nasa.jpl.aerie.stateless.simulation.SimulationExtentConsumer; -import gov.nasa.jpl.aerie.stateless.simulation.SimulationResultsWriter; +import gov.nasa.jpl.aerie.orchestration.simulation.CanceledListener; +import gov.nasa.jpl.aerie.orchestration.PlanJsonParser; +import gov.nasa.jpl.aerie.orchestration.simulation.ResourceFileStreamer; +import gov.nasa.jpl.aerie.orchestration.simulation.SimulationExtentConsumer; +import gov.nasa.jpl.aerie.orchestration.simulation.SimulationResultsWriter; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; import gov.nasa.jpl.aerie.merlin.driver.SimulationException; @@ -14,7 +15,7 @@ import java.util.Optional; import java.util.concurrent.ExecutionException; -import gov.nasa.jpl.aerie.stateless.simulation.SimulationUtility; +import gov.nasa.jpl.aerie.orchestration.simulation.SimulationUtility; import org.apache.commons.cli.*; import javax.json.Json; From c74a3b845398a1b9027f3a3c397f864a0eb085e5 Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Thu, 8 Aug 2024 17:55:25 -0700 Subject: [PATCH 15/17] Use Plan in place of SimulationMessage With the changes made, a Plan now contains all of the information necessary to simulate. Additionally, since this class will be more relevant to external users via the Orchestration package, comment and privatize fields. Additionally, prevent the sim config and activity directive maps from being null. Co-authored-by: Ryan Goetz --- .../merlin/server/http/MerlinBindings.java | 4 +- .../server/mocks/InMemoryPlanRepository.java | 8 +- .../jpl/aerie/merlin/server/models/Plan.java | 145 ++++++++++++------ .../server/services/ConstraintAction.java | 12 +- .../services/CreateSimulationMessage.java | 32 ---- .../services/LocalMissionModelService.java | 22 +-- .../server/services/MissionModelService.java | 5 +- .../server/services/SimulationAgent.java | 18 +-- .../server/mocks/StubMissionModelService.java | 8 +- .../merlin/server/mocks/StubPlanService.java | 14 +- .../remotes/PlanRepositoryContractTest.java | 28 ++-- .../aerie/orchestration/PlanJsonParser.java | 2 +- .../simulation/SimulationResultsWriter.java | 2 +- .../simulation/SimulationUtility.java | 2 +- .../gov/nasa/jpl/aerie/stateless/Main.java | 2 +- 15 files changed, 151 insertions(+), 153 deletions(-) delete mode 100644 merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/CreateSimulationMessage.java diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinBindings.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinBindings.java index 9f82696a64..2300df6420 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinBindings.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinBindings.java @@ -328,10 +328,10 @@ private void validatePlan(final Context ctx) { final var planId = parseJson(ctx.body(), hasuraPlanActionP).input().planId(); final var plan = this.planService.getPlanForValidation(planId); - final var activities = plan.activityDirectives.entrySet().stream().collect(Collectors.toMap( + final var activities = plan.activityDirectives().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().serializedActivity())); - final var failures = this.missionModelService.validateActivityInstantiations(plan.missionModelId, activities); + final var failures = this.missionModelService.validateActivityInstantiations(plan.missionModelId(), activities); ctx.result(ResponseSerializers.serializeUnconstructableActivityFailures(failures).toString()); } catch (final InvalidJsonException ex) { diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/mocks/InMemoryPlanRepository.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/mocks/InMemoryPlanRepository.java index 8b58ae6518..fc84054035 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/mocks/InMemoryPlanRepository.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/mocks/InMemoryPlanRepository.java @@ -76,9 +76,7 @@ public InMemoryRevisionData getPlanRevisionData(final PlanId planId) throws NoSu public CreatedPlan storePlan(final Plan other) { final PlanId planId = new PlanId(this.nextPlanId++); final Plan plan = new Plan(other); - final List activityIds = - other.activityDirectives != null ? List.copyOf(plan.activityDirectives.keySet()) : List.of(); - if (other.activityDirectives == null) plan.activityDirectives = new HashMap<>(); + final List activityIds = List.copyOf(plan.activityDirectives().keySet()); this.plans.put(planId, Pair.of(0L, plan)); return new CreatedPlan(planId, activityIds); @@ -101,7 +99,7 @@ public ActivityDirectiveId createActivity(final PlanId planId, final ActivityDir final var revision = entry.getLeft() + 1; final ActivityDirectiveId activityId = new ActivityDirectiveId(this.nextActivityId++); - plan.activityDirectives.put(activityId, activity); + plan.activityDirectives().put(activityId, activity); this.plans.put(planId, Pair.of(revision, plan)); return activityId; @@ -114,7 +112,7 @@ public void deleteAllActivities(final PlanId planId) throws NoSuchPlanException final var plan = entry.getRight(); final var revision = entry.getLeft() + 1; - plan.activityDirectives.clear(); + plan.activityDirectives().clear(); this.plans.put(planId, Pair.of(revision, plan)); } diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java index 62d20501a4..35d4a8c82c 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java @@ -5,38 +5,27 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import java.time.Instant; import java.util.HashMap; import java.util.Map; import java.util.Objects; +/** + * A representation of a grounded plan. Contains the necessary information to be simulated. + */ public final class Plan { - public String name; - public MissionModelId missionModelId; - public Timestamp startTimestamp; - public Timestamp endTimestamp; - public Map activityDirectives; - public Map configuration = new HashMap<>(); + // Set-once fields + private final String name; + private final MissionModelId missionModelId; + private final Timestamp startTimestamp; + private final Timestamp endTimestamp; + private final Map activityDirectives; + private final Map configuration; + + // Simulation start and end times can be freely updated public Timestamp simulationStartTimestamp; public Timestamp simulationEndTimestamp; - public Plan() {} - - public Plan(final Plan other) { - this.name = other.name; - this.missionModelId = other.missionModelId; - this.startTimestamp = other.startTimestamp; - this.endTimestamp = other.endTimestamp; - this.simulationStartTimestamp = other.simulationStartTimestamp; - this.simulationEndTimestamp = other.simulationEndTimestamp; - - if (other.activityDirectives != null) { - this.activityDirectives = new HashMap<>(); - this.activityDirectives.putAll(other.activityDirectives); - } - - if (other.configuration != null) this.configuration = new HashMap<>(other.configuration); - } - public Plan( final String name, final MissionModelId missionModelId, @@ -44,14 +33,33 @@ public Plan( final Timestamp endTimestamp, final Map activityDirectives ) { - this.name = name; - this.missionModelId = missionModelId; - this.startTimestamp = startTimestamp; - this.endTimestamp = endTimestamp; - this.activityDirectives = (activityDirectives != null) ? Map.copyOf(activityDirectives) : null; - this.configuration = null; - this.simulationStartTimestamp = startTimestamp; - this.simulationEndTimestamp = endTimestamp; + this( + name, + missionModelId, + startTimestamp, + endTimestamp, + activityDirectives, + null, + startTimestamp, + endTimestamp); + } + + public Plan( + String name, + Timestamp startTimestamp, + Timestamp endTimestamp, + Map activityDirectives, + Map simulationConfig + ) { + this( + name, + null, + startTimestamp, + endTimestamp, + activityDirectives, + simulationConfig, + startTimestamp, + endTimestamp); } public Plan( @@ -68,31 +76,74 @@ public Plan( this.missionModelId = missionModelId; this.startTimestamp = startTimestamp; this.endTimestamp = endTimestamp; - this.activityDirectives = (activityDirectives != null) ? Map.copyOf(activityDirectives) : null; - if (configuration != null) this.configuration = new HashMap<>(configuration); + this.activityDirectives = (activityDirectives != null) ? new HashMap<>(activityDirectives) : new HashMap<>(); + this.configuration = (configuration != null) ? new HashMap<>(configuration) : new HashMap<>(); this.simulationStartTimestamp = simulationStartTimestamp; this.simulationEndTimestamp = simulationEndTimestamp; } - public Plan( - String name, - Timestamp startTimestamp, - Timestamp endTimestamp, - Map activityDirectives, - Map simulationConfig) { - this.name = name; - this.startTimestamp = startTimestamp; - this.endTimestamp = endTimestamp; - this.activityDirectives = activityDirectives; - this.configuration = simulationConfig; - this.simulationStartTimestamp = startTimestamp; - this.simulationEndTimestamp = endTimestamp; + public Plan(final Plan other) { + this.name = other.name; + this.missionModelId = other.missionModelId; + this.startTimestamp = other.startTimestamp; + this.endTimestamp = other.endTimestamp; + this.simulationStartTimestamp = other.simulationStartTimestamp; + this.simulationEndTimestamp = other.simulationEndTimestamp; + this.activityDirectives = new HashMap<>(other.activityDirectives); + this.configuration = new HashMap<>(other.configuration); } + /** + * Get the plan's name. + */ + public String name() {return name;} + + /** + * Get the id of the mission model this plan will work with. + */ + public MissionModelId missionModelId() {return missionModelId;} + + /** + * Get the start of the plan as an Instant. + */ + public Instant planStartInstant() {return startTimestamp.toInstant();} + + /** + * Get the duration of the plan. + */ public Duration duration() { return Duration.of(startTimestamp.microsUntil(endTimestamp), Duration.MICROSECOND); } + /** + * Get the map of grounded activity directives in this plan. + */ + public Map activityDirectives() {return activityDirectives;} + + /** + * Get the requested simulation configuration. + */ + public Map simulationConfiguration() {return configuration;} + + /** + * Get the requested simulation start time as an Instant. + */ + public Instant simulationStartInstant() {return simulationStartTimestamp.toInstant();} + + /** + * Get the requested simulation duration. + */ + public Duration simulationDuration() { + return Duration.of(simulationStartTimestamp.microsUntil(simulationEndTimestamp), Duration.MICROSECOND); + } + + /** + * Get the offset between the start time of the plan and the requested start time of simulation. + */ + public Duration simulationOffset() { + return Duration.of(startTimestamp.microsUntil(simulationStartTimestamp), Duration.MICROSECOND); + } + @Override public boolean equals(final Object object) { if (!(object instanceof final Plan other)) { diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintAction.java index 8198c93726..3b16377768 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintAction.java @@ -71,15 +71,11 @@ public Map> getViolations(final PlanId planId, final Opt if (!constraintCode.isEmpty()) { final var simStartTime = resultsHandle$ .map(gov.nasa.jpl.aerie.merlin.server.models.SimulationResultsHandle::startTime) - .orElse(plan.startTimestamp.toInstant()); + .orElse(plan.simulationStartInstant()); final var simDuration = resultsHandle$ .map(SimulationResultsHandle::duration) - .orElse(Duration.of( - plan.simulationStartTimestamp.toInstant().until(plan.simulationEndTimestamp.toInstant(), ChronoUnit.MICROS), - Duration.MICROSECONDS)); - final var simOffset = Duration.of( - plan.startTimestamp.toInstant().until(simStartTime, ChronoUnit.MICROS), - Duration.MICROSECONDS); + .orElse(plan.simulationDuration()); + final var simOffset = plan.simulationOffset(); final var activities = new ArrayList(); final var simulatedActivities = resultsHandle$ @@ -138,7 +134,7 @@ public Map> getViolations(final PlanId planId, final Opt final ConstraintsDSLCompilationService.ConstraintsDSLCompilationResult constraintCompilationResult; try { constraintCompilationResult = constraintsDSLCompilationService.compileConstraintsDSL( - plan.missionModelId, + plan.missionModelId(), Optional.of(planId), Optional.of(simDatasetId), constraint.definition() diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/CreateSimulationMessage.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/CreateSimulationMessage.java deleted file mode 100644 index ac6697fe58..0000000000 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/CreateSimulationMessage.java +++ /dev/null @@ -1,32 +0,0 @@ -package gov.nasa.jpl.aerie.merlin.server.services; - -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; -import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; - -import java.time.Instant; -import java.util.Map; -import java.util.Objects; - -public record CreateSimulationMessage( - MissionModelId missionModelId, - Instant simulationStartTime, - Duration simulationDuration, - Instant planStartTime, - Duration planDuration, - Map activityDirectives, - Map configuration -) -{ - public CreateSimulationMessage { - Objects.requireNonNull(missionModelId); - Objects.requireNonNull(simulationStartTime); - Objects.requireNonNull(simulationDuration); - Objects.requireNonNull(planStartTime); - Objects.requireNonNull(planDuration); - Objects.requireNonNull(activityDirectives); - Objects.requireNonNull(configuration); - } -} diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalMissionModelService.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalMissionModelService.java index 538fe398de..1d74324e2f 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalMissionModelService.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalMissionModelService.java @@ -7,7 +7,6 @@ import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; import gov.nasa.jpl.aerie.merlin.driver.SimulationDriver; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; -import gov.nasa.jpl.aerie.merlin.driver.engine.ProfileSegment; import gov.nasa.jpl.aerie.merlin.driver.resources.SimulationResourceManager; import gov.nasa.jpl.aerie.merlin.protocol.model.InputType.Parameter; import gov.nasa.jpl.aerie.merlin.protocol.model.InputType.ValidationNotice; @@ -20,6 +19,7 @@ import gov.nasa.jpl.aerie.merlin.server.models.ActivityType; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelJar; +import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.remotes.MissionModelRepository; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; @@ -280,19 +280,19 @@ public Map getModelEffectiveArguments(final MissionMode /** * Validate that a set of activity parameters conforms to the expectations of a named mission model. * - * @param message The parameters defining the simulation to perform. + * @param plan The plan to be simulated. Contains the parameters defining the simulation to perform. * @return A set of samples over the course of the simulation. * @throws NoSuchMissionModelException If no mission model is known by the given ID. */ @Override public SimulationResults runSimulation( - final CreateSimulationMessage message, + final Plan plan, final Consumer simulationExtentConsumer, final Supplier canceledListener, final SimulationResourceManager resourceManager) throws NoSuchMissionModelException { - final var config = message.configuration(); + final var config = plan.simulationConfiguration(); if (config.isEmpty()) { log.warn( "No mission model configuration defined for mission model. Simulations will receive an empty set of configuration arguments."); @@ -301,14 +301,14 @@ public SimulationResults runSimulation( // TODO: [AERIE-1516] Teardown the mission model after use to release any system resources (e.g. threads). return SimulationDriver.simulate( loadAndInstantiateMissionModel( - message.missionModelId(), - message.simulationStartTime(), + plan.missionModelId(), + plan.planStartInstant(), SerializedValue.of(config)), - message.activityDirectives(), - message.simulationStartTime(), - message.simulationDuration(), - message.planStartTime(), - message.planDuration(), + plan.activityDirectives(), + plan.simulationStartInstant(), + plan.simulationDuration(), + plan.planStartInstant(), + plan.duration(), canceledListener, simulationExtentConsumer, resourceManager); diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/MissionModelService.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/MissionModelService.java index 673c053b75..56a9f1870a 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/MissionModelService.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/MissionModelService.java @@ -4,7 +4,6 @@ import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; -import gov.nasa.jpl.aerie.merlin.driver.engine.ProfileSegment; import gov.nasa.jpl.aerie.merlin.driver.resources.SimulationResourceManager; import gov.nasa.jpl.aerie.merlin.protocol.model.InputType.Parameter; import gov.nasa.jpl.aerie.merlin.protocol.model.InputType.ValidationNotice; @@ -15,8 +14,8 @@ import gov.nasa.jpl.aerie.merlin.server.models.ActivityType; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelJar; +import gov.nasa.jpl.aerie.merlin.server.models.Plan; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -66,7 +65,7 @@ Map getModelEffectiveArguments(MissionModelId missionMo InstantiationException; SimulationResults runSimulation( - final CreateSimulationMessage message, + final Plan plan, final Consumer writer, final Supplier canceledListener, final SimulationResourceManager resourceManager diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java index 375b197bad..317825bf89 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java @@ -11,7 +11,6 @@ import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import javax.json.Json; -import java.time.temporal.ChronoUnit; import java.util.Map; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -50,16 +49,12 @@ public void simulate( return; } - final var simDuration = Duration.of( - plan.simulationStartTimestamp.toInstant().until(plan.simulationEndTimestamp.toInstant(), ChronoUnit.MICROS), - Duration.MICROSECONDS); - final SimulationResults results; try { // Validate plan activity construction final var failures = this.missionModelService.validateActivityInstantiations( - plan.missionModelId, - plan.activityDirectives.entrySet().stream().collect(Collectors.toMap( + plan.missionModelId(), + plan.activityDirectives().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().serializedActivity()))); @@ -77,14 +72,7 @@ public void simulate( simulationProgressPollPeriod) ) { results = this.missionModelService.runSimulation( - new CreateSimulationMessage( - plan.missionModelId, - plan.simulationStartTimestamp.toInstant(), - simDuration, - plan.startTimestamp.toInstant(), - plan.duration(), - plan.activityDirectives, - plan.configuration), + plan, extentListener::updateValue, canceledListener, resourceManager); diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubMissionModelService.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubMissionModelService.java index 93f28b5a9e..b68538420a 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubMissionModelService.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubMissionModelService.java @@ -12,7 +12,7 @@ import gov.nasa.jpl.aerie.merlin.server.models.ActivityType; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelJar; -import gov.nasa.jpl.aerie.merlin.server.services.CreateSimulationMessage; +import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.services.LocalMissionModelService; import gov.nasa.jpl.aerie.merlin.server.services.MissionModelService; @@ -195,13 +195,13 @@ public Map getModelEffectiveArguments( @Override public SimulationResults runSimulation( - final CreateSimulationMessage message, + final Plan plan, final Consumer simulationExtentConsumer, final Supplier canceledListener, final SimulationResourceManager resourceManager ) throws NoSuchMissionModelException { - if (!Objects.equals(message.missionModelId(), EXISTENT_MISSION_MODEL_ID)) { - throw new NoSuchMissionModelException(message.missionModelId()); + if (!Objects.equals(plan.missionModelId(), EXISTENT_MISSION_MODEL_ID)) { + throw new NoSuchMissionModelException(plan.missionModelId()); } return SUCCESSFUL_SIMULATION_RESULTS; diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubPlanService.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubPlanService.java index 8026660c38..580bcd5eaf 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubPlanService.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubPlanService.java @@ -18,6 +18,7 @@ import gov.nasa.jpl.aerie.merlin.server.services.RevisionData; import org.apache.commons.lang3.tuple.Pair; +import java.time.Instant; import java.util.List; import java.util.Map; import java.util.Objects; @@ -46,11 +47,7 @@ public MatchResult matches(final RevisionData other) { null, true ); - - EXISTENT_PLAN = new Plan(); - EXISTENT_PLAN.name = "existent"; - EXISTENT_PLAN.missionModelId = new MissionModelId(1); - EXISTENT_PLAN.activityDirectives = Map.of(EXISTENT_ACTIVITY_ID, EXISTENT_ACTIVITY); + EXISTENT_PLAN = new Plan("existent", new MissionModelId(1), new Timestamp(Instant.now()), new Timestamp(Instant.now()), Map.of(EXISTENT_ACTIVITY_ID, EXISTENT_ACTIVITY)); } @@ -81,7 +78,7 @@ public RevisionData getPlanRevisionData(final PlanId planId) throws NoSuchPlanEx @Override public Map getConstraintsForPlan(final PlanId planId) - { + throws NoSuchPlanException { return Map.of(); } @@ -91,6 +88,7 @@ public long addExternalDataset( final Optional simulationDatasetId, final Timestamp datasetStart, final ProfileSet profileSet) + throws NoSuchPlanException { return 0; } @@ -104,13 +102,13 @@ public void extendExternalDataset(final DatasetId datasetId, final ProfileSet pr public List> getExternalDatasets( final PlanId planId, final SimulationDatasetId simulationDatasetId - ) + ) throws NoSuchPlanException { return List.of(); } @Override - public Map getExternalResourceSchemas(final PlanId planId, final Optional simulationDatasetId) { + public Map getExternalResourceSchemas(final PlanId planId, final Optional simulationDatasetId) throws NoSuchPlanException { return Map.of("external resource", ValueSchema.BOOLEAN); } diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepositoryContractTest.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepositoryContractTest.java index 9404358dd8..e49a550042 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepositoryContractTest.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepositoryContractTest.java @@ -5,11 +5,14 @@ import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; import gov.nasa.jpl.aerie.merlin.server.mocks.InMemoryPlanRepository; import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; +import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.Plan; +import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.remotes.PlanRepository.CreatedPlan; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.time.Instant; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -31,14 +34,13 @@ public void testCanStorePlan() throws NoSuchPlanException { // GIVEN // WHEN - final Plan plan = new Plan(); - plan.name = "new-plan"; + final Plan plan = new Plan("new-plan", new MissionModelId(1), new Timestamp(Instant.now()), new Timestamp(Instant.now()), Map.of()); final CreatedPlan ids = this.planRepository.storePlan(plan); // THEN final Plan fetchedPlan = this.planRepository.getPlanForValidation(ids.planId()); - assertEquals("new-plan", fetchedPlan.name); + assertEquals("new-plan", fetchedPlan.name()); } @Test @@ -48,18 +50,16 @@ public void testCreatePlanWithActivity() throws NoSuchPlanException { // WHEN final ActivityDirective activity = new ActivityDirective(Duration.ZERO, "abc", Map.of("abc", SerializedValue.of(1)), null, true); - final Plan plan = new Plan(); - plan.name = "new-plan"; - plan.activityDirectives = Map.of(); + final Plan plan = new Plan("new-plan", new MissionModelId(1), new Timestamp(Instant.now()), new Timestamp(Instant.now()), Map.of()); final CreatedPlan ids = this.planRepository.storePlan(plan); this.planRepository.createActivity(ids.planId(), activity); // THEN final Plan fetchedPlan = this.planRepository.getPlanForValidation(ids.planId()); - assertEquals("new-plan", fetchedPlan.name); - assertEquals(1, fetchedPlan.activityDirectives.size()); - assertTrue(fetchedPlan.activityDirectives.containsValue(activity)); + assertEquals("new-plan", fetchedPlan.name()); + assertEquals(1, fetchedPlan.activityDirectives().size()); + assertTrue(fetchedPlan.activityDirectives().containsValue(activity)); } @Test @@ -69,10 +69,10 @@ public void testCreatePlanWithNullActivitiesList() // GIVEN // WHEN - final CreatedPlan ids = this.planRepository.storePlan(new Plan()); + final CreatedPlan ids = this.planRepository.storePlan(new Plan("new-plan", new MissionModelId(1), new Timestamp(Instant.now()), new Timestamp(Instant.now()), Map.of())); // THEN - final var directives = this.planRepository.getPlanForValidation(ids.planId()).activityDirectives; + final var directives = this.planRepository.getPlanForValidation(ids.planId()).activityDirectives(); assertNotNull(directives); assertTrue(directives.isEmpty()); } @@ -80,9 +80,9 @@ public void testCreatePlanWithNullActivitiesList() @Test public void testCanDeletePlan() throws NoSuchPlanException { // GIVEN - this.planRepository.storePlan(new Plan()); - final CreatedPlan ids = this.planRepository.storePlan(new Plan()); - this.planRepository.storePlan(new Plan()); + this.planRepository.storePlan(new Plan("new-plan", new MissionModelId(1), new Timestamp(Instant.now()), new Timestamp(Instant.now()), Map.of())); + final CreatedPlan ids = this.planRepository.storePlan(new Plan("new-plan", new MissionModelId(1), new Timestamp(Instant.now()), new Timestamp(Instant.now()), Map.of())); + this.planRepository.storePlan(new Plan("new-plan", new MissionModelId(1), new Timestamp(Instant.now()), new Timestamp(Instant.now()), Map.of())); assertEquals(3, this.planRepository.getAllPlans().size()); // WHEN diff --git a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java index db1074c4d1..9edc8adf42 100644 --- a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java @@ -124,7 +124,7 @@ public static void parseSimulationConfiguration(final Path filePath, final Plan final var simEndTime = pgTimestampP.parse(configObject.get("simulation_end_time")).getSuccessOrThrow(); final var config = PlanJsonParser.parseSimulationConfiguration(configObject.getJsonObject("arguments")); - plan.configuration.putAll(config); + plan.simulationConfiguration().putAll(config); plan.simulationStartTimestamp = simStartTime; plan.simulationEndTimestamp = simEndTime; diff --git a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java index 79f87f4e27..1efc87fb0d 100644 --- a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java @@ -497,7 +497,7 @@ private JsonObject buildSimConfig(final Plan plan) { return Json.createObjectBuilder() .add("startTime", plan.simulationStartTimestamp.toString()) .add("endTime",plan.simulationEndTimestamp.toString()) - .add("arguments", simulationArgumentsP.unparse(plan.configuration)) + .add("arguments", simulationArgumentsP.unparse(plan.simulationConfiguration())) .build(); } diff --git a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java index 2cf7a55913..2fa3eb39d3 100644 --- a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java @@ -133,7 +133,7 @@ public Future simulate( public SimulationResults call() { return SimulationDriver.simulate( model, - plan.activityDirectives, + plan.activityDirectives(), plan.simulationStartTimestamp.toInstant(), simulationDuration, plan.planStartInstant(), diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java index 2fcc334cfc..6fdc079d2d 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java @@ -109,7 +109,7 @@ private static Arguments.SimulationArguments parseSimulationArgs(String[] arg final var model = SimulationUtility.instantiateMissionModel( modelJarPath, plan.simulationStartTimestamp.toInstant(), - plan.configuration + plan.simulationConfiguration() ); return new Arguments.SimulationArguments<>(model, plan, verbose, outputFilePath, extentUpdatePeriod); From 6587e8409220bff9a59de3d91b5594b4faef1441 Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Tue, 13 Aug 2024 12:11:34 -0700 Subject: [PATCH 16/17] Extract common and relevant types into Type-Utils - reduces the codebase of the system users of orchestration-utils need to depend on - avoids code duplication --- constraints/build.gradle | 2 +- .../constraints/model/ActivityInstance.java | 3 +- .../gov/nasa/jpl/aerie/e2e/BindingsTests.java | 2 +- examples/banananation/build.gradle | 2 + .../banananation/ActivityInstanceTest.java | 2 +- .../gov/nasa/jpl/aerie/banananation/Main.java | 2 +- .../aerie/banananation/SimulationUtility.java | 5 +- examples/foo-missionmodel/build.gradle | 1 + .../FooSimulationDuplicationTest.java | 6 +-- .../foomissionmodel/SimulateMapSchedule.java | 6 +-- merlin-driver/build.gradle | 1 + .../aerie/merlin/driver/ActivityInstance.java | 1 + .../merlin/driver/CachedSimulationEngine.java | 2 + .../driver/CheckpointSimulationDriver.java | 2 + .../jpl/aerie/merlin/driver/MissionModel.java | 1 + .../aerie/merlin/driver/MissionModelId.java | 3 -- .../aerie/merlin/driver/SimulationDriver.java | 3 ++ .../driver/SimulationEngineConfiguration.java | 1 + .../merlin/driver/SimulationException.java | 2 + .../SimulationResultsComputerInputs.java | 3 +- .../merlin/driver/StartOffsetReducer.java | 2 + .../merlin/driver/UnfinishedActivity.java | 1 + .../merlin/driver/engine/DirectiveDetail.java | 5 +- .../driver/engine/SimulationEngine.java | 4 +- .../merlin/driver/AnchorSimulationTest.java | 3 ++ .../driver/SimulationDuplicationTest.java | 1 + .../driver/TemporalSubsetSimulationTests.java | 3 ++ merlin-server/build.gradle | 1 + .../merlin/server/http/HasuraParsers.java | 2 +- .../merlin/server/http/MerlinBindings.java | 2 +- .../merlin/server/http/MerlinParsers.java | 6 +-- .../server/http/ResponseSerializers.java | 2 +- .../server/mocks/InMemoryPlanRepository.java | 8 +-- .../ActivityDirectiveForValidation.java | 3 +- .../server/models/ActivityDirectiveId.java | 3 -- .../merlin/server/models/HasuraAction.java | 4 +- .../models/HasuraMissionModelEvent.java | 2 + .../remotes/MissionModelRepository.java | 2 +- .../merlin/server/remotes/PlanRepository.java | 6 +-- .../postgres/CreatePlanDatasetAction.java | 2 +- .../CreateSimulationDatasetAction.java | 2 +- .../remotes/postgres/GetAllPlansAction.java | 2 +- .../remotes/postgres/GetPlanAction.java | 2 +- .../remotes/postgres/GetSimulationAction.java | 2 +- .../postgres/GetSimulationDatasetAction.java | 2 +- .../GetSimulationDatasetByIdAction.java | 2 +- .../remotes/postgres/GetSpanRecords.java | 2 +- .../GetUnvalidatedDirectivesAction.java | 8 +-- .../InsertSimulationEventsAction.java | 2 +- .../LookupSimulationDatasetAction.java | 2 +- .../server/remotes/postgres/PlanRecord.java | 2 +- .../remotes/postgres/PostSpansAction.java | 3 +- .../PostgresMissionModelRepository.java | 2 +- .../remotes/postgres/PostgresParsers.java | 2 +- .../postgres/PostgresPlanRepository.java | 12 ++--- .../PostgresResultsCellRepository.java | 8 ++- .../remotes/postgres/PreparedStatements.java | 2 +- .../postgres/SimulationDatasetRecord.java | 3 +- .../remotes/postgres/SimulationRecord.java | 2 +- .../ConstraintsDSLCompilationService.java | 2 +- .../GenerateConstraintsLibAction.java | 2 +- .../services/LocalMissionModelService.java | 8 +-- .../server/services/LocalPlanService.java | 4 +- .../server/services/MissionModelService.java | 8 +-- .../merlin/server/services/PlanService.java | 4 +- .../server/services/SimulationAgent.java | 2 +- ...ypescriptCodeGenerationServiceAdapter.java | 2 +- .../merlin/server/http/MerlinParsersTest.java | 2 +- .../server/mocks/StubMissionModelService.java | 14 +++--- .../merlin/server/mocks/StubPlanService.java | 10 ++-- .../server/models/MissionModelTest.java | 2 +- .../remotes/PlanRepositoryContractTest.java | 8 +-- .../remotes/postgres/PostgresParsersTest.java | 2 +- ...ConstraintsDSLCompilationServiceTests.java | 2 +- .../TypescriptCodeGenerationServiceTest.java | 2 +- orchestration-utils/build.gradle | 1 + .../aerie/orchestration/PlanJsonParser.java | 9 ++-- .../simulation/SimulationResultsWriter.java | 6 +-- .../simulation/SimulationUtility.java | 2 +- scheduler-driver/build.gradle | 1 + .../aerie/scheduler/DirectiveIdGenerator.java | 2 +- .../MissingActivityTemplateConflict.java | 2 +- .../conflicts/MissingAssociationConflict.java | 2 +- .../scheduler/goals/CardinalityGoal.java | 2 +- .../scheduler/goals/CoexistenceGoal.java | 2 +- .../nasa/jpl/aerie/scheduler/goals/Goal.java | 4 -- .../jpl/aerie/scheduler/goals/OptionGoal.java | 3 -- .../nasa/jpl/aerie/scheduler/model/Plan.java | 2 +- .../aerie/scheduler/model/PlanInMemory.java | 2 +- .../jpl/aerie/scheduler/model/Problem.java | 2 - .../scheduler/model/SchedulePlanGrounder.java | 4 +- .../scheduler/model/SchedulingActivity.java | 4 +- .../CheckpointSimulationFacade.java | 6 +-- .../simulation/SimulationFacade.java | 4 +- .../simulation/SimulationFacadeUtils.java | 6 +-- .../scheduler/solver/PrioritySolver.java | 2 +- .../aerie/scheduler/FixedDurationTest.java | 2 +- .../scheduler/ParametricDurationTest.java | 2 +- .../aerie/scheduler/PrioritySolverTest.java | 2 +- .../scheduler/SchedulingGrounderTest.java | 2 +- .../aerie/scheduler/SimulationUtility.java | 2 +- .../jpl/aerie/scheduler/TestApplyWhen.java | 2 +- .../aerie/scheduler/TestPersistentAnchor.java | 4 +- .../simulation/AnchorSchedulerTest.java | 19 ++++--- .../CheckpointSimulationFacadeTest.java | 2 +- .../InMemoryCachedEngineStoreTest.java | 6 +-- scheduler-server/build.gradle | 1 + .../NoSuchActivityInstanceException.java | 2 +- .../NoSuchMissionModelException.java | 2 +- .../server/graphql/GraphQLParsers.java | 2 +- .../server/http/SchedulerParsers.java | 4 +- .../scheduler/server/models/HasuraAction.java | 2 + .../scheduler/server/models/MerlinPlan.java | 4 +- .../server/models/MissionModelId.java | 3 -- .../server/models/Specification.java | 1 + .../scheduler/server/models/Timestamp.java | 50 ------------------- .../postgres/GetCreatedActivitiesAction.java | 2 +- .../GetSatisfyingActivitiesAction.java | 2 +- .../postgres/GetSpecificationAction.java | 2 +- .../server/remotes/postgres/GoalBuilder.java | 2 +- .../InsertCreatedActivitiesAction.java | 2 +- .../InsertSatisfyingActivitiesAction.java | 2 +- .../remotes/postgres/PostgresParsers.java | 2 +- .../PostgresResultsCellRepository.java | 2 +- .../remotes/postgres/SpecificationRecord.java | 2 +- .../services/GenerateSchedulingLibAction.java | 2 +- .../GraphQLMerlinDatabaseService.java | 6 +-- .../services/MerlinDatabaseService.java | 4 +- .../server/services/ScheduleResults.java | 2 +- .../server/graphql/GraphQLParsersTest.java | 2 +- scheduler-worker/build.gradle | 1 + .../services/SynchronousSchedulerAgent.java | 4 +- .../services/MockMerlinDatabaseService.java | 6 +-- .../SchedulingDSLCompilationServiceTests.java | 24 +++------ .../services/SchedulingIntegrationTests.java | 24 ++++----- settings.gradle | 1 + stateless-aerie/build.gradle | 9 ++-- .../gov/nasa/jpl/aerie/stateless/Main.java | 2 +- type-utils/build.gradle | 23 +++++++++ .../jpl/aerie/types}/ActivityDirective.java | 2 +- .../jpl/aerie/types}/ActivityDirectiveId.java | 2 +- .../nasa/jpl/aerie/types}/MissionModelId.java | 2 +- .../java/gov/nasa/jpl/aerie/types}/Plan.java | 4 +- .../jpl/aerie/types}/SerializedActivity.java | 4 +- .../gov/nasa/jpl/aerie/types}/Timestamp.java | 2 +- 145 files changed, 278 insertions(+), 296 deletions(-) delete mode 100644 merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/MissionModelId.java delete mode 100644 merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/ActivityDirectiveId.java delete mode 100644 scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/MissionModelId.java delete mode 100644 scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/Timestamp.java create mode 100644 type-utils/build.gradle rename {merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver => type-utils/src/main/java/gov/nasa/jpl/aerie/types}/ActivityDirective.java (94%) rename {merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver => type-utils/src/main/java/gov/nasa/jpl/aerie/types}/ActivityDirectiveId.java (52%) rename {merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models => type-utils/src/main/java/gov/nasa/jpl/aerie/types}/MissionModelId.java (72%) rename {merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models => type-utils/src/main/java/gov/nasa/jpl/aerie/types}/Plan.java (97%) rename {merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver => type-utils/src/main/java/gov/nasa/jpl/aerie/types}/SerializedActivity.java (96%) rename {merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models => type-utils/src/main/java/gov/nasa/jpl/aerie/types}/Timestamp.java (96%) diff --git a/constraints/build.gradle b/constraints/build.gradle index 0bf3022b69..4d6eb916bb 100644 --- a/constraints/build.gradle +++ b/constraints/build.gradle @@ -30,8 +30,8 @@ repositories { dependencies { implementation project(':merlin-driver') - implementation project(':merlin-sdk') implementation project(':parsing-utilities') + implementation project(':type-utils') testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' diff --git a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/model/ActivityInstance.java b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/model/ActivityInstance.java index 96e9144dc3..8a3c8758c3 100644 --- a/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/model/ActivityInstance.java +++ b/constraints/src/main/java/gov/nasa/jpl/aerie/constraints/model/ActivityInstance.java @@ -1,12 +1,11 @@ package gov.nasa.jpl.aerie.constraints.model; import gov.nasa.jpl.aerie.constraints.time.Interval; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.util.Map; -import java.util.Objects; import java.util.Optional; public record ActivityInstance( diff --git a/e2e-tests/src/test/java/gov/nasa/jpl/aerie/e2e/BindingsTests.java b/e2e-tests/src/test/java/gov/nasa/jpl/aerie/e2e/BindingsTests.java index 4e3ae03126..222413bb40 100644 --- a/e2e-tests/src/test/java/gov/nasa/jpl/aerie/e2e/BindingsTests.java +++ b/e2e-tests/src/test/java/gov/nasa/jpl/aerie/e2e/BindingsTests.java @@ -1118,7 +1118,7 @@ void invalidModelId(){ assertEquals(200, response.status()); final var expectedBody = Json.createObjectBuilder() .add("status", "failure") - .add("reason", "No mission model exists with id `MissionModelId[id=-1]`") + .add("reason", "No mission model exists with id `-1`") .build(); assertEquals(expectedBody, getBody(response)); } diff --git a/examples/banananation/build.gradle b/examples/banananation/build.gradle index 19cdec5193..6de69cccb3 100644 --- a/examples/banananation/build.gradle +++ b/examples/banananation/build.gradle @@ -43,6 +43,8 @@ dependencies { implementation 'org.apache.commons:commons-lang3:3.13.0' testImplementation project(':merlin-framework-junit') + testImplementation project(':orchestration-utils') + testImplementation project(':type-utils') testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' diff --git a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/ActivityInstanceTest.java b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/ActivityInstanceTest.java index ec44be8cf9..717a92500c 100644 --- a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/ActivityInstanceTest.java +++ b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/ActivityInstanceTest.java @@ -1,12 +1,12 @@ package gov.nasa.jpl.aerie.banananation; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; import gov.nasa.jpl.aerie.merlin.driver.engine.SimulationEngine; import gov.nasa.jpl.aerie.merlin.driver.timeline.TemporalEventSource; import gov.nasa.jpl.aerie.merlin.protocol.driver.Topic; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.SerializedActivity; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; diff --git a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/Main.java b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/Main.java index 11148a57ff..63c86536bc 100644 --- a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/Main.java +++ b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/Main.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.banananation; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.SerializedActivity; import org.apache.commons.lang3.tuple.Pair; import java.util.Map; diff --git a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java index 83651c76e3..093b93fce7 100644 --- a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java +++ b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java @@ -2,9 +2,10 @@ import gov.nasa.jpl.aerie.banananation.generated.GeneratedModelType; import gov.nasa.jpl.aerie.merlin.driver.*; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.protocol.model.ModelType; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import org.apache.commons.lang3.tuple.Pair; import java.nio.file.Path; diff --git a/examples/foo-missionmodel/build.gradle b/examples/foo-missionmodel/build.gradle index 5e8bcd7354..f74026a8de 100644 --- a/examples/foo-missionmodel/build.gradle +++ b/examples/foo-missionmodel/build.gradle @@ -36,6 +36,7 @@ dependencies { implementation project(':merlin-framework') implementation project(':contrib') + implementation project(':type-utils') testImplementation project(':merlin-framework-junit') testImplementation 'org.assertj:assertj-core:3.24.2' diff --git a/examples/foo-missionmodel/src/test/java/gov/nasa/jpl/aerie/foomissionmodel/FooSimulationDuplicationTest.java b/examples/foo-missionmodel/src/test/java/gov/nasa/jpl/aerie/foomissionmodel/FooSimulationDuplicationTest.java index f183d23824..4da242a48e 100644 --- a/examples/foo-missionmodel/src/test/java/gov/nasa/jpl/aerie/foomissionmodel/FooSimulationDuplicationTest.java +++ b/examples/foo-missionmodel/src/test/java/gov/nasa/jpl/aerie/foomissionmodel/FooSimulationDuplicationTest.java @@ -1,21 +1,21 @@ package gov.nasa.jpl.aerie.foomissionmodel; import gov.nasa.jpl.aerie.foomissionmodel.generated.GeneratedModelType; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.CachedEngineStore; import gov.nasa.jpl.aerie.merlin.driver.CachedSimulationEngine; import gov.nasa.jpl.aerie.merlin.driver.CheckpointSimulationDriver; import gov.nasa.jpl.aerie.merlin.driver.DirectiveTypeRegistry; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; import gov.nasa.jpl.aerie.merlin.driver.MissionModelBuilder; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.driver.SimulationDriver; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.framework.ThreadedTask; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; diff --git a/examples/foo-missionmodel/src/test/java/gov/nasa/jpl/aerie/foomissionmodel/SimulateMapSchedule.java b/examples/foo-missionmodel/src/test/java/gov/nasa/jpl/aerie/foomissionmodel/SimulateMapSchedule.java index a5eafc5d2f..63f65609ed 100644 --- a/examples/foo-missionmodel/src/test/java/gov/nasa/jpl/aerie/foomissionmodel/SimulateMapSchedule.java +++ b/examples/foo-missionmodel/src/test/java/gov/nasa/jpl/aerie/foomissionmodel/SimulateMapSchedule.java @@ -2,11 +2,11 @@ import gov.nasa.jpl.aerie.foomissionmodel.generated.GeneratedModelType; import gov.nasa.jpl.aerie.merlin.driver.*; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.json.JsonEncoding; -import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import org.apache.commons.lang3.tuple.Pair; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import javax.json.Json; import java.time.Instant; diff --git a/merlin-driver/build.gradle b/merlin-driver/build.gradle index c6ad4e9c7d..a07b237cb7 100644 --- a/merlin-driver/build.gradle +++ b/merlin-driver/build.gradle @@ -39,6 +39,7 @@ dependencies { api project(':merlin-sdk') api 'org.glassfish:javax.json:1.1.4' + implementation project(':type-utils') implementation 'it.unimi.dsi:fastutil:8.5.12' implementation 'org.slf4j:slf4j-simple:2.0.7' diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityInstance.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityInstance.java index 48d1a0dc49..4fa9e27b24 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityInstance.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityInstance.java @@ -2,6 +2,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.time.Instant; import java.util.List; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/CachedSimulationEngine.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/CachedSimulationEngine.java index 2ce636965a..ae55cdddd6 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/CachedSimulationEngine.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/CachedSimulationEngine.java @@ -5,6 +5,8 @@ import gov.nasa.jpl.aerie.merlin.driver.resources.InMemorySimulationResourceManager; import gov.nasa.jpl.aerie.merlin.protocol.driver.Topic; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.time.Instant; import java.util.Map; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/CheckpointSimulationDriver.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/CheckpointSimulationDriver.java index 6f6d42cee8..4ec5787a90 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/CheckpointSimulationDriver.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/CheckpointSimulationDriver.java @@ -9,6 +9,8 @@ import gov.nasa.jpl.aerie.merlin.protocol.model.TaskFactory; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/MissionModel.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/MissionModel.java index fc9b477e34..8cbea7efbb 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/MissionModel.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/MissionModel.java @@ -11,6 +11,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException; import gov.nasa.jpl.aerie.merlin.protocol.types.TaskStatus; import gov.nasa.jpl.aerie.merlin.protocol.types.Unit; +import gov.nasa.jpl.aerie.types.SerializedActivity; import java.util.Collections; import java.util.List; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/MissionModelId.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/MissionModelId.java deleted file mode 100644 index 5f3d95bd8c..0000000000 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/MissionModelId.java +++ /dev/null @@ -1,3 +0,0 @@ -package gov.nasa.jpl.aerie.merlin.driver; - -public record MissionModelId(long id) {} diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationDriver.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationDriver.java index 29f7ea7dcf..ae6e4f1332 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationDriver.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationDriver.java @@ -10,6 +10,9 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException; import gov.nasa.jpl.aerie.merlin.protocol.types.Unit; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationEngineConfiguration.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationEngineConfiguration.java index 3f1f4e4294..bfef673b75 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationEngineConfiguration.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationEngineConfiguration.java @@ -1,6 +1,7 @@ package gov.nasa.jpl.aerie.merlin.driver; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.MissionModelId; import java.time.Instant; import java.util.Map; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationException.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationException.java index 87548c924e..d74cd39a89 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationException.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationException.java @@ -1,6 +1,8 @@ package gov.nasa.jpl.aerie.merlin.driver; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import java.time.Instant; import java.time.ZoneOffset; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationResultsComputerInputs.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationResultsComputerInputs.java index 6f34c1504f..50edc898fb 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationResultsComputerInputs.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SimulationResultsComputerInputs.java @@ -3,9 +3,8 @@ import gov.nasa.jpl.aerie.merlin.driver.engine.SimulationEngine; import gov.nasa.jpl.aerie.merlin.driver.engine.SpanId; import gov.nasa.jpl.aerie.merlin.driver.resources.SimulationResourceManager; -import gov.nasa.jpl.aerie.merlin.driver.timeline.TemporalEventSource; import gov.nasa.jpl.aerie.merlin.protocol.driver.Topic; -import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.time.Instant; import java.util.Map; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/StartOffsetReducer.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/StartOffsetReducer.java index 3611545ea9..c86f3cd35b 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/StartOffsetReducer.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/StartOffsetReducer.java @@ -1,6 +1,8 @@ package gov.nasa.jpl.aerie.merlin.driver; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/UnfinishedActivity.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/UnfinishedActivity.java index 7e87f20582..b6ef8f4a60 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/UnfinishedActivity.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/UnfinishedActivity.java @@ -1,6 +1,7 @@ package gov.nasa.jpl.aerie.merlin.driver; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.time.Instant; import java.util.List; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/DirectiveDetail.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/DirectiveDetail.java index ab2531069c..5a48ba83f4 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/DirectiveDetail.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/DirectiveDetail.java @@ -1,8 +1,7 @@ package gov.nasa.jpl.aerie.merlin.driver.engine; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; -import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.SerializedActivity; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.util.List; import java.util.Optional; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/SimulationEngine.java b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/SimulationEngine.java index d57945b7f9..f1000b8bdd 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/SimulationEngine.java +++ b/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/engine/SimulationEngine.java @@ -1,8 +1,6 @@ package gov.nasa.jpl.aerie.merlin.driver.engine; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.MissionModel.SerializableTopic; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.resources.SimulationResourceManager; @@ -28,6 +26,8 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.TaskStatus; import gov.nasa.jpl.aerie.merlin.protocol.types.Unit; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import org.apache.commons.lang3.mutable.Mutable; import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.mutable.MutableObject; diff --git a/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/AnchorSimulationTest.java b/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/AnchorSimulationTest.java index 976f9d4457..2e87d5e944 100644 --- a/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/AnchorSimulationTest.java +++ b/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/AnchorSimulationTest.java @@ -2,6 +2,9 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; diff --git a/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/SimulationDuplicationTest.java b/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/SimulationDuplicationTest.java index 24286636ab..abf7213e42 100644 --- a/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/SimulationDuplicationTest.java +++ b/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/SimulationDuplicationTest.java @@ -2,6 +2,7 @@ import gov.nasa.jpl.aerie.merlin.driver.resources.InMemorySimulationResourceManager; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/TemporalSubsetSimulationTests.java b/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/TemporalSubsetSimulationTests.java index 3df904ceee..cd67abdd32 100644 --- a/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/TemporalSubsetSimulationTests.java +++ b/merlin-driver/src/test/java/gov/nasa/jpl/aerie/merlin/driver/TemporalSubsetSimulationTests.java @@ -2,6 +2,9 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/merlin-server/build.gradle b/merlin-server/build.gradle index b9d145a482..8b8cb10212 100644 --- a/merlin-server/build.gradle +++ b/merlin-server/build.gradle @@ -79,6 +79,7 @@ application { } dependencies { + implementation project(':type-utils') implementation project(':merlin-driver') implementation project(':parsing-utilities') implementation project(':constraints') diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/HasuraParsers.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/HasuraParsers.java index ef0ab785ca..6d556d7cfe 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/HasuraParsers.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/HasuraParsers.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.merlin.server.http; import gov.nasa.jpl.aerie.json.JsonParser; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; +import gov.nasa.jpl.aerie.types.SerializedActivity; import gov.nasa.jpl.aerie.merlin.server.models.HasuraAction; import gov.nasa.jpl.aerie.merlin.server.models.HasuraMissionModelEvent; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinBindings.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinBindings.java index 2300df6420..2558cd3278 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinBindings.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinBindings.java @@ -2,7 +2,7 @@ import gov.nasa.jpl.aerie.constraints.InputMismatchException; import gov.nasa.jpl.aerie.json.JsonParser; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; +import gov.nasa.jpl.aerie.types.SerializedActivity; import gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException; import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanDatasetException; import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinParsers.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinParsers.java index 3b0e903e3b..12501047cf 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinParsers.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinParsers.java @@ -3,15 +3,15 @@ import gov.nasa.jpl.aerie.json.JsonParseResult; import gov.nasa.jpl.aerie.json.JsonParser; import gov.nasa.jpl.aerie.json.SchemaCache; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.SimulationFailure; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.server.models.DatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.services.UnexpectedSubtypeError; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.Timestamp; import javax.json.Json; import javax.json.JsonObject; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/ResponseSerializers.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/ResponseSerializers.java index 8e16964305..a32f70e568 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/ResponseSerializers.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/http/ResponseSerializers.java @@ -5,7 +5,6 @@ import gov.nasa.jpl.aerie.constraints.model.ConstraintResult; import gov.nasa.jpl.aerie.constraints.time.Interval; import gov.nasa.jpl.aerie.json.JsonParseResult.FailureReason; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; import gov.nasa.jpl.aerie.merlin.driver.UnfinishedActivity; import gov.nasa.jpl.aerie.merlin.driver.json.ValueSchemaJsonParser; @@ -27,6 +26,7 @@ import gov.nasa.jpl.aerie.merlin.server.services.MissionModelService.BulkEffectiveArgumentResponse; import gov.nasa.jpl.aerie.merlin.server.services.MissionModelService.BulkArgumentValidationResponse; import gov.nasa.jpl.aerie.merlin.server.services.UnexpectedSubtypeError; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.apache.commons.lang3.tuple.Pair; import javax.json.Json; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/mocks/InMemoryPlanRepository.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/mocks/InMemoryPlanRepository.java index fc84054035..56538dbecf 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/mocks/InMemoryPlanRepository.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/mocks/InMemoryPlanRepository.java @@ -1,18 +1,18 @@ package gov.nasa.jpl.aerie.merlin.server.mocks; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; import gov.nasa.jpl.aerie.merlin.server.models.Constraint; import gov.nasa.jpl.aerie.merlin.server.models.DatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import gov.nasa.jpl.aerie.merlin.server.models.ProfileSet; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.remotes.PlanRepository; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import java.util.HashMap; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/ActivityDirectiveForValidation.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/ActivityDirectiveForValidation.java index 6aefe8ca42..c293612460 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/ActivityDirectiveForValidation.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/ActivityDirectiveForValidation.java @@ -1,6 +1,7 @@ package gov.nasa.jpl.aerie.merlin.server.models; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import java.sql.Timestamp; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/ActivityDirectiveId.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/ActivityDirectiveId.java deleted file mode 100644 index 09d741c365..0000000000 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/ActivityDirectiveId.java +++ /dev/null @@ -1,3 +0,0 @@ -package gov.nasa.jpl.aerie.merlin.server.models; - -public record ActivityDirectiveId(long id) {} diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/HasuraAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/HasuraAction.java index 26a1f4fd17..1fcf8faba2 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/HasuraAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/HasuraAction.java @@ -1,7 +1,9 @@ package gov.nasa.jpl.aerie.merlin.server.models; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.Timestamp; import java.util.List; import java.util.Map; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/HasuraMissionModelEvent.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/HasuraMissionModelEvent.java index 9ba33e4c5e..9932d2145c 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/HasuraMissionModelEvent.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/HasuraMissionModelEvent.java @@ -1,3 +1,5 @@ package gov.nasa.jpl.aerie.merlin.server.models; +import gov.nasa.jpl.aerie.types.MissionModelId; + public record HasuraMissionModelEvent(MissionModelId missionModelId) { } diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/MissionModelRepository.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/MissionModelRepository.java index 9be6348e9e..cbe6e2d1b4 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/MissionModelRepository.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/MissionModelRepository.java @@ -4,9 +4,9 @@ import gov.nasa.jpl.aerie.merlin.protocol.model.Resource; import gov.nasa.jpl.aerie.merlin.server.models.ActivityDirectiveForValidation; import gov.nasa.jpl.aerie.merlin.server.models.ActivityType; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelJar; import gov.nasa.jpl.aerie.merlin.server.services.MissionModelService.BulkArgumentValidationResponse; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.apache.commons.lang3.tuple.Pair; import java.util.List; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepository.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepository.java index 7eabd94ffe..97aaab5a5b 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepository.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepository.java @@ -1,18 +1,18 @@ package gov.nasa.jpl.aerie.merlin.server.remotes; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanDatasetException; import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; import gov.nasa.jpl.aerie.merlin.server.models.Constraint; import gov.nasa.jpl.aerie.merlin.server.models.DatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import gov.nasa.jpl.aerie.merlin.server.models.ProfileSet; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.services.RevisionData; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import java.util.List; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/CreatePlanDatasetAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/CreatePlanDatasetAction.java index 2a8fbd3e73..76251987ad 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/CreatePlanDatasetAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/CreatePlanDatasetAction.java @@ -2,7 +2,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/CreateSimulationDatasetAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/CreateSimulationDatasetAction.java index 88003d00b3..aae2ea5f7f 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/CreateSimulationDatasetAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/CreateSimulationDatasetAction.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import gov.nasa.jpl.aerie.merlin.server.remotes.postgres.SimulationStateRecord.Status; import org.intellij.lang.annotations.Language; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetAllPlansAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetAllPlansAction.java index b3d7ebd123..5a5d6a129b 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetAllPlansAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetAllPlansAction.java @@ -1,6 +1,6 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetPlanAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetPlanAction.java index 900908249e..aa9213ca2a 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetPlanAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetPlanAction.java @@ -1,6 +1,6 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationAction.java index 1bc4a828ea..726e48923f 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationAction.java @@ -1,6 +1,6 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationDatasetAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationDatasetAction.java index f5071d8ba4..da16519746 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationDatasetAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationDatasetAction.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.remotes.postgres.SimulationStateRecord.Status; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationDatasetByIdAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationDatasetByIdAction.java index cd32f9f5e1..90c527fa8e 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationDatasetByIdAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSimulationDatasetByIdAction.java @@ -1,6 +1,6 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSpanRecords.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSpanRecords.java index 6b31e9821e..5b35e293c8 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSpanRecords.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetSpanRecords.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetUnvalidatedDirectivesAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetUnvalidatedDirectivesAction.java index 2f69e85c46..8971e8caf4 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetUnvalidatedDirectivesAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/GetUnvalidatedDirectivesAction.java @@ -1,9 +1,9 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import gov.nasa.jpl.aerie.merlin.server.models.ActivityDirectiveForValidation; -import gov.nasa.jpl.aerie.merlin.server.models.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import java.sql.Connection; @@ -26,7 +26,7 @@ public class GetUnvalidatedDirectivesAction implements AutoCloseable { join merlin.plan p on ad.plan_id = p.id where adv.status = 'pending'; - """; + """; private final PreparedStatement statement; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/InsertSimulationEventsAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/InsertSimulationEventsAction.java index 8ad0f1eb13..07bcdc8f0c 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/InsertSimulationEventsAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/InsertSimulationEventsAction.java @@ -3,7 +3,7 @@ import gov.nasa.jpl.aerie.merlin.driver.engine.EventRecord; import gov.nasa.jpl.aerie.merlin.driver.timeline.EventGraph; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import org.intellij.lang.annotations.Language; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/LookupSimulationDatasetAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/LookupSimulationDatasetAction.java index 6faf4162d0..fe63058a59 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/LookupSimulationDatasetAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/LookupSimulationDatasetAction.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.remotes.postgres.SimulationStateRecord.Status; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PlanRecord.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PlanRecord.java index 1da8c516c5..b7e7588ebf 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PlanRecord.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PlanRecord.java @@ -1,6 +1,6 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; public record PlanRecord( long id, diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostSpansAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostSpansAction.java index 11ec124c47..5c2307379a 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostSpansAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostSpansAction.java @@ -2,7 +2,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import java.sql.Connection; @@ -11,7 +11,6 @@ import java.sql.Statement; import java.sql.Types; import java.time.temporal.ChronoUnit; -import java.util.HashMap; import java.util.Map; import java.util.Optional; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresMissionModelRepository.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresMissionModelRepository.java index f2e9d9ffda..0d97d8ec82 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresMissionModelRepository.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresMissionModelRepository.java @@ -4,10 +4,10 @@ import gov.nasa.jpl.aerie.merlin.protocol.model.Resource; import gov.nasa.jpl.aerie.merlin.server.models.ActivityDirectiveForValidation; import gov.nasa.jpl.aerie.merlin.server.models.ActivityType; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelJar; import gov.nasa.jpl.aerie.merlin.server.remotes.MissionModelRepository; import gov.nasa.jpl.aerie.merlin.server.services.MissionModelService; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.apache.commons.lang3.tuple.Pair; import javax.sql.DataSource; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresParsers.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresParsers.java index bad5dc32fb..87cf3d3057 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresParsers.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresParsers.java @@ -7,8 +7,8 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.services.UnexpectedSubtypeError; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import org.postgresql.util.PGInterval; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresPlanRepository.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresPlanRepository.java index 9c7cf1862c..10a496fe4f 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresPlanRepository.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresPlanRepository.java @@ -1,7 +1,5 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; @@ -9,13 +7,15 @@ import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; import gov.nasa.jpl.aerie.merlin.server.models.Constraint; import gov.nasa.jpl.aerie.merlin.server.models.DatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import gov.nasa.jpl.aerie.merlin.server.models.ProfileSet; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.remotes.PlanRepository; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import javax.sql.DataSource; @@ -278,7 +278,7 @@ public List> getExternalDatasets( } @Override - public Map getExternalResourceSchemas(final PlanId planId, final Optional simulationDatasetId) throws NoSuchPlanException { + public Map getExternalResourceSchemas(final PlanId planId, final Optional simulationDatasetId) throws DatabaseException { try (final var connection = this.dataSource.getConnection()) { final var planDatasets = ProfileRepository.getPlanDatasetsForPlan(connection, planId, simulationDatasetId); final var result = new HashMap(); diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresResultsCellRepository.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresResultsCellRepository.java index e6d1c54b6c..39b7cd2f5e 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresResultsCellRepository.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresResultsCellRepository.java @@ -1,6 +1,5 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.SimulationException; @@ -19,8 +18,9 @@ import gov.nasa.jpl.aerie.merlin.server.models.ProfileSet; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; import gov.nasa.jpl.aerie.merlin.server.models.SimulationResultsHandle; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.remotes.ResultsCellRepository; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.slf4j.Logger; @@ -407,9 +407,7 @@ private static void postActivities( final Map unfinishedActivities, final Timestamp simulationStart ) throws SQLException { - try ( - final var postActivitiesAction = new PostSpansAction(connection); - ) { + try (final var postActivitiesAction = new PostSpansAction(connection)) { final var simulatedActivityRecords = simulatedActivities.entrySet().stream() .collect(Collectors.toMap( e -> e.getKey().id(), diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PreparedStatements.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PreparedStatements.java index 639561e6f5..135704b712 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PreparedStatements.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PreparedStatements.java @@ -5,8 +5,8 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.server.http.MerlinParsers; import gov.nasa.jpl.aerie.merlin.server.http.ResponseSerializers; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.services.MissionModelService; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import javax.json.Json; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/SimulationDatasetRecord.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/SimulationDatasetRecord.java index 6bdc107ebe..3c1f6d4158 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/SimulationDatasetRecord.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/SimulationDatasetRecord.java @@ -1,6 +1,7 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; + +import gov.nasa.jpl.aerie.types.Timestamp; public record SimulationDatasetRecord( long simulationId, diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/SimulationRecord.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/SimulationRecord.java index e209d44b86..a8a87babf9 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/SimulationRecord.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/SimulationRecord.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.merlin.server.remotes.postgres; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import java.util.Map; import java.util.Optional; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintsDSLCompilationService.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintsDSLCompilationService.java index f99a0f440c..2070154031 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintsDSLCompilationService.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintsDSLCompilationService.java @@ -8,9 +8,9 @@ import gov.nasa.jpl.aerie.merlin.server.http.InvalidJsonException; import gov.nasa.jpl.aerie.merlin.server.models.ConstraintsCompilationError; import gov.nasa.jpl.aerie.constraints.json.ConstraintParsers; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; +import gov.nasa.jpl.aerie.types.MissionModelId; import javax.json.Json; import javax.json.JsonObject; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/GenerateConstraintsLibAction.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/GenerateConstraintsLibAction.java index 7210b5f1c6..0eb357875d 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/GenerateConstraintsLibAction.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/GenerateConstraintsLibAction.java @@ -1,8 +1,8 @@ package gov.nasa.jpl.aerie.merlin.server.services; import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; +import gov.nasa.jpl.aerie.types.MissionModelId; import java.io.IOException; import java.nio.file.Files; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalMissionModelService.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalMissionModelService.java index 1d74324e2f..f2d4fa4658 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalMissionModelService.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalMissionModelService.java @@ -1,10 +1,12 @@ package gov.nasa.jpl.aerie.merlin.server.services; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.DirectiveTypeRegistry; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.SerializedActivity; import gov.nasa.jpl.aerie.merlin.driver.SimulationDriver; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.driver.resources.SimulationResourceManager; @@ -17,9 +19,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; import gov.nasa.jpl.aerie.merlin.server.models.ActivityDirectiveForValidation; import gov.nasa.jpl.aerie.merlin.server.models.ActivityType; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelJar; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.remotes.MissionModelRepository; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalPlanService.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalPlanService.java index e12c366e67..93bdf89134 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalPlanService.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/LocalPlanService.java @@ -6,12 +6,12 @@ import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; import gov.nasa.jpl.aerie.merlin.server.models.Constraint; import gov.nasa.jpl.aerie.merlin.server.models.DatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import gov.nasa.jpl.aerie.merlin.server.models.ProfileSet; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.remotes.PlanRepository; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import java.util.List; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/MissionModelService.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/MissionModelService.java index 56a9f1870a..cb3bda30e5 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/MissionModelService.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/MissionModelService.java @@ -1,8 +1,10 @@ package gov.nasa.jpl.aerie.merlin.server.services; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.SerializedActivity; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.driver.resources.SimulationResourceManager; import gov.nasa.jpl.aerie.merlin.protocol.model.InputType.Parameter; @@ -12,9 +14,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; import gov.nasa.jpl.aerie.merlin.server.models.ActivityType; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelJar; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import java.util.List; import java.util.Map; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/PlanService.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/PlanService.java index f70ce35c35..4bd652b3fe 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/PlanService.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/PlanService.java @@ -6,11 +6,11 @@ import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; import gov.nasa.jpl.aerie.merlin.server.models.Constraint; import gov.nasa.jpl.aerie.merlin.server.models.DatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import gov.nasa.jpl.aerie.merlin.server.models.ProfileSet; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import java.util.List; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java index 317825bf89..96556b223b 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/SimulationAgent.java @@ -7,8 +7,8 @@ import gov.nasa.jpl.aerie.merlin.server.ResultsProtocol; import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; import gov.nasa.jpl.aerie.merlin.server.http.ResponseSerializers; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; +import gov.nasa.jpl.aerie.types.Plan; import javax.json.Json; import java.util.Map; diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/TypescriptCodeGenerationServiceAdapter.java b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/TypescriptCodeGenerationServiceAdapter.java index 18bc66d273..98c02dfb80 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/TypescriptCodeGenerationServiceAdapter.java +++ b/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/services/TypescriptCodeGenerationServiceAdapter.java @@ -4,9 +4,9 @@ import gov.nasa.jpl.aerie.constraints.TypescriptCodeGenerationService; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; +import gov.nasa.jpl.aerie.types.MissionModelId; import java.util.HashMap; import java.util.Map; diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinParsersTest.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinParsersTest.java index 3c09fdb901..c2c594f04a 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinParsersTest.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/http/MerlinParsersTest.java @@ -4,7 +4,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.server.models.HasuraAction; import gov.nasa.jpl.aerie.merlin.server.models.HasuraMissionModelEvent; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.junit.jupiter.api.Test; import javax.json.Json; diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubMissionModelService.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubMissionModelService.java index b68538420a..391dea2529 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubMissionModelService.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubMissionModelService.java @@ -1,7 +1,9 @@ package gov.nasa.jpl.aerie.merlin.server.mocks; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.SerializedActivity; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.driver.resources.SimulationResourceManager; import gov.nasa.jpl.aerie.merlin.protocol.model.InputType.Parameter; @@ -10,9 +12,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; import gov.nasa.jpl.aerie.merlin.server.models.ActivityType; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.MissionModelJar; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.services.LocalMissionModelService; import gov.nasa.jpl.aerie.merlin.server.services.MissionModelService; @@ -208,11 +208,11 @@ public SimulationResults runSimulation( } @Override - public void refreshModelParameters(final MissionModelId missionModelId) throws NoSuchMissionModelException {} + public void refreshModelParameters(final MissionModelId missionModelId) {} @Override - public void refreshActivityTypes(final MissionModelId missionModelId) throws NoSuchMissionModelException {} + public void refreshActivityTypes(final MissionModelId missionModelId) {} @Override - public void refreshResourceTypes(final MissionModelId missionModelId) throws NoSuchMissionModelException {} + public void refreshResourceTypes(final MissionModelId missionModelId) {} } diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubPlanService.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubPlanService.java index 580bcd5eaf..2fd44de131 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubPlanService.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/mocks/StubPlanService.java @@ -1,21 +1,21 @@ package gov.nasa.jpl.aerie.merlin.server.mocks; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; import gov.nasa.jpl.aerie.merlin.server.models.Constraint; import gov.nasa.jpl.aerie.merlin.server.models.DatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; import gov.nasa.jpl.aerie.merlin.server.models.ProfileSet; import gov.nasa.jpl.aerie.merlin.server.models.SimulationDatasetId; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.services.PlanService; import gov.nasa.jpl.aerie.merlin.server.services.RevisionData; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import java.time.Instant; diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/models/MissionModelTest.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/models/MissionModelTest.java index d13b4532b3..3a03e9cdbc 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/models/MissionModelTest.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/models/MissionModelTest.java @@ -2,7 +2,7 @@ import gov.nasa.jpl.aerie.foomissionmodel.generated.GeneratedModelType; import gov.nasa.jpl.aerie.merlin.driver.DirectiveTypeRegistry; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; +import gov.nasa.jpl.aerie.types.SerializedActivity; import gov.nasa.jpl.aerie.merlin.protocol.model.InputType.Parameter; import gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepositoryContractTest.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepositoryContractTest.java index e49a550042..54718d4b5c 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepositoryContractTest.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/PlanRepositoryContractTest.java @@ -4,11 +4,11 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; import gov.nasa.jpl.aerie.merlin.server.mocks.InMemoryPlanRepository; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.remotes.PlanRepository.CreatedPlan; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.Timestamp; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresParsersTest.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresParsersTest.java index 08cde20175..aabbeb4cdb 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresParsersTest.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/remotes/postgres/PostgresParsersTest.java @@ -4,7 +4,7 @@ import static gov.nasa.jpl.aerie.merlin.server.remotes.postgres.PostgresParsers.pgTimestampP; import static org.junit.jupiter.api.Assertions.assertEquals; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.junit.jupiter.api.Test; public final class PostgresParsersTest { diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintsDSLCompilationServiceTests.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintsDSLCompilationServiceTests.java index 8b0276f15c..e4ae572a8d 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintsDSLCompilationServiceTests.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/services/ConstraintsDSLCompilationServiceTests.java @@ -52,8 +52,8 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.server.mocks.StubMissionModelService; import gov.nasa.jpl.aerie.merlin.server.mocks.StubPlanService; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/services/TypescriptCodeGenerationServiceTest.java b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/services/TypescriptCodeGenerationServiceTest.java index 33cfdaae2f..660d0cf143 100644 --- a/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/services/TypescriptCodeGenerationServiceTest.java +++ b/merlin-server/src/test/java/gov/nasa/jpl/aerie/merlin/server/services/TypescriptCodeGenerationServiceTest.java @@ -3,8 +3,8 @@ import gov.nasa.jpl.aerie.merlin.server.exceptions.NoSuchPlanException; import gov.nasa.jpl.aerie.merlin.server.mocks.StubMissionModelService; import gov.nasa.jpl.aerie.merlin.server.mocks.StubPlanService; -import gov.nasa.jpl.aerie.merlin.server.models.MissionModelId; import gov.nasa.jpl.aerie.merlin.server.models.PlanId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.junit.jupiter.api.Test; import java.util.Optional; diff --git a/orchestration-utils/build.gradle b/orchestration-utils/build.gradle index d8c785f80b..78f1a41230 100644 --- a/orchestration-utils/build.gradle +++ b/orchestration-utils/build.gradle @@ -37,6 +37,7 @@ dependencies { implementation project(':merlin-server') implementation project(':merlin-driver') implementation project(':parsing-utilities') + implementation project(':type-utils') implementation 'commons-cli:commons-cli:1.8.0' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' diff --git a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java index 9edc8adf42..25c1bb3158 100644 --- a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/PlanJsonParser.java @@ -1,8 +1,6 @@ package gov.nasa.jpl.aerie.orchestration; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import static gov.nasa.jpl.aerie.merlin.server.remotes.postgres.PostgresParsers.activityArgumentsP; import static gov.nasa.jpl.aerie.merlin.server.remotes.postgres.PostgresParsers.pgTimestampP; @@ -10,8 +8,11 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.Timestamp; + import javax.json.Json; import javax.json.JsonArray; import javax.json.JsonObject; diff --git a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java index 1efc87fb0d..9b4fab105b 100644 --- a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationResultsWriter.java @@ -10,7 +10,6 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.RealDynamics; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import javax.json.Json; import javax.json.JsonObject; @@ -28,8 +27,9 @@ import java.util.Map; import java.util.concurrent.RecursiveTask; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.merlin.server.models.Timestamp; import gov.nasa.jpl.aerie.merlin.server.remotes.postgres.EventGraphFlattener; +import gov.nasa.jpl.aerie.types.Plan; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; @@ -226,7 +226,7 @@ private void printFile(JsonGenerator resultsGenerator, StringWriter stringWriter /** Write the beginning and top-level fields of the results JSON */ private void writeOpening(JsonGenerator resultsGenerator, boolean canceled) { - final Timestamp simEndTime = plan.simulationStartTimestamp.plusMicros(extent.in(Duration.MICROSECOND)); + final var simEndTime = plan.simulationStartTimestamp.plusMicros(extent.in(Duration.MICROSECOND)); resultsGenerator.writeStartObject(); resultsGenerator.write("version", SCHEMA_VERSION); diff --git a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java index 2fa3eb39d3..153fca61e6 100644 --- a/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java +++ b/orchestration-utils/src/main/java/gov/nasa/jpl/aerie/orchestration/simulation/SimulationUtility.java @@ -13,7 +13,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.model.ModelType; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; +import gov.nasa.jpl.aerie.types.Plan; import javax.json.Json; import javax.json.JsonObject; diff --git a/scheduler-driver/build.gradle b/scheduler-driver/build.gradle index de8ee99f58..41c84dac59 100644 --- a/scheduler-driver/build.gradle +++ b/scheduler-driver/build.gradle @@ -37,6 +37,7 @@ dependencies { implementation 'org.slf4j:slf4j-simple:2.0.7' implementation 'org.apache.commons:commons-collections4:4.4' implementation project(':merlin-framework') + implementation project(':type-utils') testImplementation project(':merlin-framework-junit') testImplementation project(':constraints') diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/DirectiveIdGenerator.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/DirectiveIdGenerator.java index 4b69e3f82a..cf178f9651 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/DirectiveIdGenerator.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/DirectiveIdGenerator.java @@ -1,6 +1,6 @@ package gov.nasa.jpl.aerie.scheduler; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; public class DirectiveIdGenerator { private long counter; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityTemplateConflict.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityTemplateConflict.java index 823eb7f87b..b9de83ec9a 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityTemplateConflict.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingActivityTemplateConflict.java @@ -2,12 +2,12 @@ import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment; import gov.nasa.jpl.aerie.constraints.time.Windows; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; import gov.nasa.jpl.aerie.scheduler.goals.ActivityTemplateGoal; import gov.nasa.jpl.aerie.scheduler.goals.Goal; import gov.nasa.jpl.aerie.scheduler.solver.ScheduleAt; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.util.Optional; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingAssociationConflict.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingAssociationConflict.java index e1c7a6ef3c..a62f203551 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingAssociationConflict.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/conflicts/MissingAssociationConflict.java @@ -2,9 +2,9 @@ import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment; import gov.nasa.jpl.aerie.constraints.time.Windows; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; import gov.nasa.jpl.aerie.scheduler.goals.Goal; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.util.Collection; import java.util.Optional; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CardinalityGoal.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CardinalityGoal.java index 6363bf4c9e..25a5852055 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CardinalityGoal.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CardinalityGoal.java @@ -4,7 +4,6 @@ import gov.nasa.jpl.aerie.constraints.model.SimulationResults; import gov.nasa.jpl.aerie.constraints.time.Interval; import gov.nasa.jpl.aerie.constraints.time.Windows; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.Range; @@ -15,6 +14,7 @@ import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.solver.ScheduleAt; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CoexistenceGoal.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CoexistenceGoal.java index 18fc3f95f7..cf6c695231 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CoexistenceGoal.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/CoexistenceGoal.java @@ -7,7 +7,6 @@ import gov.nasa.jpl.aerie.constraints.time.Spans; import gov.nasa.jpl.aerie.constraints.time.Windows; import gov.nasa.jpl.aerie.constraints.tree.Expression; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.conflicts.Conflict; @@ -19,6 +18,7 @@ import gov.nasa.jpl.aerie.scheduler.model.PersistentTimeAnchor; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.solver.ScheduleAt; import java.util.ArrayList; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/Goal.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/Goal.java index 5fc75c9e2a..59db44d9da 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/Goal.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/Goal.java @@ -7,19 +7,15 @@ import gov.nasa.jpl.aerie.constraints.tree.And; import gov.nasa.jpl.aerie.constraints.tree.Expression; import gov.nasa.jpl.aerie.constraints.tree.WindowsWrapperExpression; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.conflicts.Conflict; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; -import org.apache.commons.collections4.BidiMap; import java.util.LinkedList; import java.util.List; import java.util.Set; -import java.util.Optional; /** * describes some criteria that is desired in the solution plans diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/OptionGoal.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/OptionGoal.java index be5d7c9912..3d9e2f23ec 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/OptionGoal.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/goals/OptionGoal.java @@ -2,18 +2,15 @@ import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment; import gov.nasa.jpl.aerie.constraints.model.SimulationResults; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; import gov.nasa.jpl.aerie.scheduler.conflicts.Conflict; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.solver.optimizers.Optimizer; -import org.apache.commons.collections4.BidiMap; import org.apache.commons.lang3.NotImplementedException; import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.Optional; public class OptionGoal extends Goal { diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Plan.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Plan.java index f4c2dec08f..b896bbdc40 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Plan.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Plan.java @@ -2,10 +2,10 @@ import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment; import gov.nasa.jpl.aerie.constraints.model.SimulationResults; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; import gov.nasa.jpl.aerie.scheduler.solver.Evaluation; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.util.Collection; import java.util.List; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/PlanInMemory.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/PlanInMemory.java index cc97ba5d0b..51b2ba5292 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/PlanInMemory.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/PlanInMemory.java @@ -2,10 +2,10 @@ import gov.nasa.jpl.aerie.constraints.model.EvaluationEnvironment; import gov.nasa.jpl.aerie.constraints.model.SimulationResults; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; import gov.nasa.jpl.aerie.scheduler.solver.Evaluation; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.util.ArrayList; import java.util.Collection; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Problem.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Problem.java index c046c6a295..1af4804706 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Problem.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/Problem.java @@ -2,7 +2,6 @@ import gov.nasa.jpl.aerie.constraints.model.DiscreteProfile; import gov.nasa.jpl.aerie.constraints.model.LinearProfile; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; @@ -11,7 +10,6 @@ import gov.nasa.jpl.aerie.scheduler.simulation.SimulationFacade; import gov.nasa.jpl.aerie.scheduler.simulation.SimulationData; import gov.nasa.jpl.aerie.scheduler.simulation.SimulationResultsConverter; -import org.apache.commons.collections4.BidiMap; import java.util.ArrayList; import java.util.Collection; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulePlanGrounder.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulePlanGrounder.java index 8da3da77ca..f2d87a2ad0 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulePlanGrounder.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulePlanGrounder.java @@ -2,10 +2,10 @@ import gov.nasa.jpl.aerie.constraints.model.ActivityInstance; import gov.nasa.jpl.aerie.constraints.time.Interval; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.StartOffsetReducer; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.apache.commons.lang3.tuple.Pair; import java.util.HashMap; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivity.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivity.java index b2e55bc2f9..114df90155 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivity.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/model/SchedulingActivity.java @@ -5,10 +5,10 @@ import gov.nasa.jpl.aerie.constraints.model.SimulationResults; import gov.nasa.jpl.aerie.constraints.time.Interval; import gov.nasa.jpl.aerie.constraints.tree.ProfileExpression; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.util.Comparator; import java.util.HashMap; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacade.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacade.java index a597106377..9a921a510b 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacade.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacade.java @@ -1,11 +1,8 @@ package gov.nasa.jpl.aerie.scheduler.simulation; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.CachedSimulationEngine; import gov.nasa.jpl.aerie.merlin.driver.CheckpointSimulationDriver; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.merlin.driver.SimulationResultsComputerInputs; import gov.nasa.jpl.aerie.merlin.framework.ThreadedTask; @@ -16,6 +13,9 @@ import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacade.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacade.java index 14c82a3671..051a4908de 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacade.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacade.java @@ -1,13 +1,13 @@ package gov.nasa.jpl.aerie.scheduler.simulation; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.SimulationResultsComputerInputs; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.SchedulingInterruptedException; import gov.nasa.jpl.aerie.scheduler.model.ActivityType; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.util.Collection; import java.util.HashSet; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacadeUtils.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacadeUtils.java index 69d510fd6a..772172fae5 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacadeUtils.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/simulation/SimulationFacadeUtils.java @@ -1,8 +1,5 @@ package gov.nasa.jpl.aerie.scheduler.simulation; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.SimulationResultsComputerInputs; @@ -14,6 +11,9 @@ import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/PrioritySolver.java b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/PrioritySolver.java index d5040493d0..de6564cb4a 100644 --- a/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/PrioritySolver.java +++ b/scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/solver/PrioritySolver.java @@ -6,7 +6,6 @@ import gov.nasa.jpl.aerie.constraints.time.Segment; import gov.nasa.jpl.aerie.constraints.time.Windows; import gov.nasa.jpl.aerie.constraints.tree.Expression; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.DurationType; import gov.nasa.jpl.aerie.merlin.protocol.types.InstantiationException; @@ -35,6 +34,7 @@ import gov.nasa.jpl.aerie.scheduler.simulation.SimulationData; import gov.nasa.jpl.aerie.scheduler.simulation.SimulationFacade; import gov.nasa.jpl.aerie.scheduler.solver.stn.TaskNetworkAdapter; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/FixedDurationTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/FixedDurationTest.java index 828b7ff81e..e3d5f57893 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/FixedDurationTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/FixedDurationTest.java @@ -5,7 +5,6 @@ import gov.nasa.jpl.aerie.constraints.tree.SpansFromWindows; import gov.nasa.jpl.aerie.constraints.tree.WindowsWrapperExpression; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; import gov.nasa.jpl.aerie.scheduler.constraints.timeexpressions.TimeExpressionRelative; @@ -16,6 +15,7 @@ import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.scheduler.simulation.CheckpointSimulationFacade; import gov.nasa.jpl.aerie.scheduler.solver.PrioritySolver; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/ParametricDurationTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/ParametricDurationTest.java index bcc1632f89..158a819e44 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/ParametricDurationTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/ParametricDurationTest.java @@ -4,7 +4,6 @@ import gov.nasa.jpl.aerie.constraints.time.Windows; import gov.nasa.jpl.aerie.constraints.tree.SpansFromWindows; import gov.nasa.jpl.aerie.constraints.tree.WindowsWrapperExpression; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.scheduler.simulation.InMemoryCachedEngineStore; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; @@ -17,6 +16,7 @@ import gov.nasa.jpl.aerie.scheduler.model.Problem; import gov.nasa.jpl.aerie.scheduler.simulation.CheckpointSimulationFacade; import gov.nasa.jpl.aerie.scheduler.solver.PrioritySolver; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/PrioritySolverTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/PrioritySolverTest.java index c5c6f82b7b..6272b58c81 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/PrioritySolverTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/PrioritySolverTest.java @@ -5,7 +5,6 @@ import gov.nasa.jpl.aerie.constraints.time.Windows; import gov.nasa.jpl.aerie.constraints.tree.WindowsWrapperExpression; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; import gov.nasa.jpl.aerie.scheduler.constraints.timeexpressions.TimeAnchor; @@ -24,6 +23,7 @@ import gov.nasa.jpl.aerie.scheduler.simulation.SimulationFacade; import gov.nasa.jpl.aerie.scheduler.solver.Evaluation; import gov.nasa.jpl.aerie.scheduler.solver.PrioritySolver; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.junit.jupiter.api.Test; import java.time.Instant; diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SchedulingGrounderTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SchedulingGrounderTest.java index d42f887caf..6d5e425ab4 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SchedulingGrounderTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SchedulingGrounderTest.java @@ -2,12 +2,12 @@ import gov.nasa.jpl.aerie.constraints.model.ActivityInstance; import gov.nasa.jpl.aerie.constraints.time.Interval; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.model.ActivityType; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.SchedulePlanGrounder; import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.junit.jupiter.api.Test; import java.util.List; diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SimulationUtility.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SimulationUtility.java index b2e03d19c6..20ed13e4d5 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SimulationUtility.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/SimulationUtility.java @@ -5,13 +5,13 @@ import gov.nasa.jpl.aerie.merlin.driver.DirectiveTypeRegistry; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; import gov.nasa.jpl.aerie.merlin.driver.MissionModelBuilder; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.Problem; import gov.nasa.jpl.aerie.scheduler.simulation.InMemoryCachedEngineStore; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.scheduler.simulation.CheckpointSimulationFacade; +import gov.nasa.jpl.aerie.types.MissionModelId; import java.nio.file.Path; import java.time.Instant; diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestApplyWhen.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestApplyWhen.java index 80e391c7c6..a3e0f4721f 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestApplyWhen.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestApplyWhen.java @@ -23,7 +23,6 @@ import gov.nasa.jpl.aerie.constraints.tree.SpansWrapperExpression; import gov.nasa.jpl.aerie.constraints.tree.ValueAt; import gov.nasa.jpl.aerie.constraints.tree.WindowsWrapperExpression; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.scheduler.constraints.activities.ActivityExpression; @@ -40,6 +39,7 @@ import gov.nasa.jpl.aerie.scheduler.simulation.InMemoryCachedEngineStore; import gov.nasa.jpl.aerie.scheduler.solver.PrioritySolver; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestPersistentAnchor.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestPersistentAnchor.java index c4ac77b15f..2e022cfa57 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestPersistentAnchor.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/TestPersistentAnchor.java @@ -10,8 +10,6 @@ import gov.nasa.jpl.aerie.constraints.tree.Expression; import gov.nasa.jpl.aerie.constraints.tree.ForEachActivitySpans; import gov.nasa.jpl.aerie.constraints.tree.WindowsWrapperExpression; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; @@ -23,6 +21,8 @@ import gov.nasa.jpl.aerie.scheduler.simulation.CheckpointSimulationFacade; import gov.nasa.jpl.aerie.scheduler.simulation.InMemoryCachedEngineStore; import gov.nasa.jpl.aerie.scheduler.solver.PrioritySolver; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.apache.commons.lang3.function.TriFunction; import org.junit.jupiter.api.Test; import org.slf4j.Logger; diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/AnchorSchedulerTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/AnchorSchedulerTest.java index e9196c5a76..b09ef69b90 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/AnchorSchedulerTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/AnchorSchedulerTest.java @@ -1,14 +1,10 @@ package gov.nasa.jpl.aerie.scheduler.simulation; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.CachedSimulationEngine; import gov.nasa.jpl.aerie.merlin.driver.CheckpointSimulationDriver; import gov.nasa.jpl.aerie.merlin.driver.DirectiveTypeRegistry; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.driver.OneStepTask; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; @@ -29,7 +25,10 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.TaskStatus; import gov.nasa.jpl.aerie.merlin.protocol.types.Unit; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; -import gov.nasa.jpl.aerie.scheduler.SchedulingInterruptedException; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.SerializedActivity; import org.apache.commons.lang3.tuple.Triple; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; @@ -138,7 +137,7 @@ private static void assertEqualsAsideFromChildren(ActivityInstance expected, Act @Test @DisplayName("Activities depending on no activities simulate at the correct time") - public void activitiesAnchoredToPlan() throws SchedulingInterruptedException { + public void activitiesAnchoredToPlan() { final var minusOneMinute = Duration.of(-60, Duration.SECONDS); final var resolveToPlanStartAnchors = new HashMap(415); final Map simulatedActivities = new HashMap<>(415); @@ -245,7 +244,7 @@ public void activitiesAnchoredToPlan() throws SchedulingInterruptedException { @Test @DisplayName("Activities depending on another activities simulate at the correct time") - public void activitiesAnchoredToOtherActivities() throws SchedulingInterruptedException { + public void activitiesAnchoredToOtherActivities() { final var allEndTimeAnchors = new HashMap(400); final var endTimeAnchorEveryFifth = new HashMap(400); final Map simulatedActivities = new HashMap<>(800); @@ -356,7 +355,7 @@ public void activitiesAnchoredToOtherActivities() throws SchedulingInterruptedEx @Test @DisplayName("Reference to anchored activities are correctly maintained by the driver") - public void activitiesAnchoredToOtherActivitiesSimple() throws SchedulingInterruptedException { + public void activitiesAnchoredToOtherActivitiesSimple() { final var activitiesToSimulate = new HashMap(2); activitiesToSimulate.put( new ActivityDirectiveId(0), @@ -371,7 +370,7 @@ public void activitiesAnchoredToOtherActivitiesSimple() throws SchedulingInterru @Test @DisplayName("Decomposition and anchors do not interfere with each other") - public void decomposingActivitiesAndAnchors() throws SchedulingInterruptedException{ + public void decomposingActivitiesAndAnchors() { // Given positions Left, Center, Right in an anchor chain, where each position can either contain a Non-Decomposition (ND) activity or a Decomposition (D) activity, // and the connection between Center and Left and Right and Center can be either Start (<-s-) or End (<-e-), // and two NDs cannot be adjacent to each other, there are 20 permutations. @@ -611,7 +610,7 @@ public void decomposingActivitiesAndAnchors() throws SchedulingInterruptedExcept @Test @DisplayName("Activities arranged in a wide anchor tree simulate at the correct time") - public void naryTreeAnchorChain() throws SchedulingInterruptedException{ + public void naryTreeAnchorChain() { // Full and complete 5-ary tree, 6 levels deep // Number of activity directives = 5^0 + 5^1 + 5^2 + 5^3 + 5^4 + 5^5 = 3906 diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacadeTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacadeTest.java index 6425adbd4f..6bf447e4b0 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacadeTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/CheckpointSimulationFacadeTest.java @@ -1,6 +1,5 @@ package gov.nasa.jpl.aerie.scheduler.simulation; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.merlin.framework.ThreadedTask; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; @@ -12,6 +11,7 @@ import gov.nasa.jpl.aerie.scheduler.model.PlanInMemory; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.model.SchedulingActivity; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/InMemoryCachedEngineStoreTest.java b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/InMemoryCachedEngineStoreTest.java index 9edf6e229a..7334871761 100644 --- a/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/InMemoryCachedEngineStoreTest.java +++ b/scheduler-driver/src/test/java/gov/nasa/jpl/aerie/scheduler/simulation/InMemoryCachedEngineStoreTest.java @@ -1,14 +1,14 @@ package gov.nasa.jpl.aerie.scheduler.simulation; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.CachedSimulationEngine; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.merlin.driver.engine.SimulationEngine; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.driver.resources.InMemorySimulationResourceManager; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.scheduler.SimulationUtility; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/scheduler-server/build.gradle b/scheduler-server/build.gradle index 80affd74df..c4ddee4905 100644 --- a/scheduler-server/build.gradle +++ b/scheduler-server/build.gradle @@ -24,6 +24,7 @@ dependencies { implementation project(':permissions') implementation project(':constraints') implementation project(':scheduler-driver') + implementation project(':type-utils') implementation 'io.javalin:javalin:5.6.3' implementation 'org.eclipse:yasson:3.0.3' diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/exceptions/NoSuchActivityInstanceException.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/exceptions/NoSuchActivityInstanceException.java index 37733a8f6f..9f1197099e 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/exceptions/NoSuchActivityInstanceException.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/exceptions/NoSuchActivityInstanceException.java @@ -1,6 +1,6 @@ package gov.nasa.jpl.aerie.scheduler.server.exceptions; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; public class NoSuchActivityInstanceException extends Exception { private final ActivityDirectiveId id; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/exceptions/NoSuchMissionModelException.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/exceptions/NoSuchMissionModelException.java index 050ff5ebb4..5dd1742cf6 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/exceptions/NoSuchMissionModelException.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/exceptions/NoSuchMissionModelException.java @@ -1,6 +1,6 @@ package gov.nasa.jpl.aerie.scheduler.server.exceptions; -import gov.nasa.jpl.aerie.scheduler.server.models.MissionModelId; +import gov.nasa.jpl.aerie.types.MissionModelId; public class NoSuchMissionModelException extends Exception { private final MissionModelId id; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/graphql/GraphQLParsers.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/graphql/GraphQLParsers.java index 03e79be087..884ee472e8 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/graphql/GraphQLParsers.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/graphql/GraphQLParsers.java @@ -7,7 +7,7 @@ import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.merlin.protocol.types.ValueSchema; import gov.nasa.jpl.aerie.scheduler.server.models.ActivityAttributesRecord; -import gov.nasa.jpl.aerie.scheduler.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import org.postgresql.util.PGInterval; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/http/SchedulerParsers.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/http/SchedulerParsers.java index 21d2b1a770..abf6b5da35 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/http/SchedulerParsers.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/http/SchedulerParsers.java @@ -2,11 +2,11 @@ import gov.nasa.jpl.aerie.json.JsonParser; import gov.nasa.jpl.aerie.scheduler.server.models.HasuraAction; -import gov.nasa.jpl.aerie.scheduler.server.models.MissionModelId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanId; import gov.nasa.jpl.aerie.scheduler.server.models.SpecificationId; -import gov.nasa.jpl.aerie.scheduler.server.models.Timestamp; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleFailure; +import gov.nasa.jpl.aerie.types.MissionModelId; +import gov.nasa.jpl.aerie.types.Timestamp; import java.util.Optional; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/HasuraAction.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/HasuraAction.java index 8c111b7e64..c3c0c9b88a 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/HasuraAction.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/HasuraAction.java @@ -1,5 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.server.models; +import gov.nasa.jpl.aerie.types.MissionModelId; + import java.util.Optional; public record HasuraAction(String name, I input, Session session) diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/MerlinPlan.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/MerlinPlan.java index 015f4550f3..64f24ea2b9 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/MerlinPlan.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/MerlinPlan.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.server.models; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import java.util.Collections; import java.util.HashMap; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/MissionModelId.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/MissionModelId.java deleted file mode 100644 index 917dc5f6d0..0000000000 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/MissionModelId.java +++ /dev/null @@ -1,3 +0,0 @@ -package gov.nasa.jpl.aerie.scheduler.server.models; - -public record MissionModelId(long id) {} diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/Specification.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/Specification.java index 8f92a55986..42d471e34f 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/Specification.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/Specification.java @@ -1,6 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.server.models; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; +import gov.nasa.jpl.aerie.types.Timestamp; import java.util.List; import java.util.Map; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/Timestamp.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/Timestamp.java deleted file mode 100644 index c8459e74c0..0000000000 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/models/Timestamp.java +++ /dev/null @@ -1,50 +0,0 @@ -package gov.nasa.jpl.aerie.scheduler.server.models; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.DateTimeParseException; -import java.time.temporal.ChronoField; -import java.time.temporal.ChronoUnit; - -public record Timestamp(ZonedDateTime time) { - // This builder must be used to get optional subsecond values - // See: https://stackoverflow.com/questions/30090710/java-8-datetimeformatter-parsing-for-optional-fractional-seconds-of-varying-sign - public static final DateTimeFormatter format = - new DateTimeFormatterBuilder() - .appendPattern("uuuu-DDD'T'HH:mm:ss") - .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true) - .toFormatter(); - - private Timestamp(String timestamp) throws DateTimeParseException { - this(LocalDateTime.parse(timestamp, format).atZone(ZoneOffset.UTC)); - } - - public Timestamp(Instant instant) { - this(instant.atZone(ZoneOffset.UTC)); - } - - public static Timestamp fromString(String timestamp) throws DateTimeParseException { - return new Timestamp(timestamp); - } - - public Timestamp plusMicros(final long micros) { - return new Timestamp(this.time.plus(micros, ChronoUnit.MICROS)); - } - - public long microsUntil(final Timestamp other) { - return this.time.until(other.time, ChronoUnit.MICROS); - } - - public Instant toInstant() { - return time.toInstant(); - } - - @Override - public String toString() { - return format.format(time); - } -} diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetCreatedActivitiesAction.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetCreatedActivitiesAction.java index 7bbd88b621..0caeafdd23 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetCreatedActivitiesAction.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetCreatedActivitiesAction.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.server.models.GoalId; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetSatisfyingActivitiesAction.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetSatisfyingActivitiesAction.java index 19240ee2af..4254634d26 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetSatisfyingActivitiesAction.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetSatisfyingActivitiesAction.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.server.models.GoalId; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetSpecificationAction.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetSpecificationAction.java index 5ed47ae8d1..0a1639db26 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetSpecificationAction.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GetSpecificationAction.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.server.remotes.postgres; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import gov.nasa.jpl.aerie.scheduler.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.intellij.lang.annotations.Language; import javax.json.Json; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GoalBuilder.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GoalBuilder.java index bd4050a00d..6059c06b7a 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GoalBuilder.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/GoalBuilder.java @@ -27,8 +27,8 @@ import gov.nasa.jpl.aerie.scheduler.model.PersistentTimeAnchor; import gov.nasa.jpl.aerie.scheduler.model.PlanningHorizon; import gov.nasa.jpl.aerie.scheduler.server.models.SchedulingDSL; -import gov.nasa.jpl.aerie.scheduler.server.models.Timestamp; import gov.nasa.jpl.aerie.scheduler.server.services.UnexpectedSubtypeError; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.function.TriFunction; import org.jetbrains.annotations.NotNull; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/InsertCreatedActivitiesAction.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/InsertCreatedActivitiesAction.java index 8a17bc5279..65770d1da5 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/InsertCreatedActivitiesAction.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/InsertCreatedActivitiesAction.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.server.models.GoalId; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/InsertSatisfyingActivitiesAction.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/InsertSatisfyingActivitiesAction.java index 1282c5891d..0b6b9a5f79 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/InsertSatisfyingActivitiesAction.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/InsertSatisfyingActivitiesAction.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.server.remotes.postgres; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.server.models.GoalId; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.intellij.lang.annotations.Language; import java.sql.Connection; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/PostgresParsers.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/PostgresParsers.java index 901a1502f3..07beef7596 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/PostgresParsers.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/PostgresParsers.java @@ -4,8 +4,8 @@ import gov.nasa.jpl.aerie.json.JsonParser; import gov.nasa.jpl.aerie.json.SchemaCache; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import gov.nasa.jpl.aerie.scheduler.server.models.Timestamp; import gov.nasa.jpl.aerie.scheduler.server.services.UnexpectedSubtypeError; +import gov.nasa.jpl.aerie.types.Timestamp; import javax.json.Json; import javax.json.JsonObject; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/PostgresResultsCellRepository.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/PostgresResultsCellRepository.java index 11455b06c2..87bd7daaf0 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/PostgresResultsCellRepository.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/PostgresResultsCellRepository.java @@ -8,7 +8,6 @@ import java.util.HashMap; import java.util.Optional; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.SchedulingInterruptedException; import gov.nasa.jpl.aerie.scheduler.server.ResultsProtocol; import gov.nasa.jpl.aerie.scheduler.server.exceptions.NoSuchRequestException; @@ -21,6 +20,7 @@ import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleRequest; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleResults; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleResults.GoalResult; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/SpecificationRecord.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/SpecificationRecord.java index c97bca9a34..c01fbe846a 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/SpecificationRecord.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/remotes/postgres/SpecificationRecord.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.server.remotes.postgres; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; -import gov.nasa.jpl.aerie.scheduler.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import java.util.Map; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GenerateSchedulingLibAction.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GenerateSchedulingLibAction.java index ff38298154..6782920a8b 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GenerateSchedulingLibAction.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GenerateSchedulingLibAction.java @@ -10,8 +10,8 @@ import gov.nasa.jpl.aerie.scheduler.server.exceptions.NoSuchMissionModelException; import gov.nasa.jpl.aerie.scheduler.server.exceptions.NoSuchPlanException; -import gov.nasa.jpl.aerie.scheduler.server.models.MissionModelId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanId; +import gov.nasa.jpl.aerie.types.MissionModelId; public record GenerateSchedulingLibAction( MerlinDatabaseService.ReaderRole merlinDatabaseService diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GraphQLMerlinDatabaseService.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GraphQLMerlinDatabaseService.java index a2be8388c6..f1d3e5e111 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GraphQLMerlinDatabaseService.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/GraphQLMerlinDatabaseService.java @@ -4,8 +4,6 @@ import gov.nasa.jpl.aerie.constraints.model.LinearProfile; import gov.nasa.jpl.aerie.json.BasicParsers; import gov.nasa.jpl.aerie.json.JsonParser; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstance; import gov.nasa.jpl.aerie.merlin.driver.ActivityInstanceId; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; @@ -37,12 +35,14 @@ import gov.nasa.jpl.aerie.scheduler.server.models.ExternalProfiles; import gov.nasa.jpl.aerie.scheduler.server.models.GoalId; import gov.nasa.jpl.aerie.scheduler.server.models.MerlinPlan; -import gov.nasa.jpl.aerie.scheduler.server.models.MissionModelId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanMetadata; import gov.nasa.jpl.aerie.scheduler.server.models.ProfileSet; import gov.nasa.jpl.aerie.scheduler.server.models.ResourceType; import gov.nasa.jpl.aerie.scheduler.server.models.UnwrappedProfileSet; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/MerlinDatabaseService.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/MerlinDatabaseService.java index 8120ce5d95..8856c101fc 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/MerlinDatabaseService.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/MerlinDatabaseService.java @@ -1,6 +1,5 @@ package gov.nasa.jpl.aerie.scheduler.server.services; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; @@ -17,10 +16,11 @@ import gov.nasa.jpl.aerie.scheduler.server.models.ExternalProfiles; import gov.nasa.jpl.aerie.scheduler.server.models.GoalId; import gov.nasa.jpl.aerie.scheduler.server.models.MerlinPlan; -import gov.nasa.jpl.aerie.scheduler.server.models.MissionModelId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanMetadata; import gov.nasa.jpl.aerie.scheduler.server.models.ResourceType; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.apache.commons.lang3.tuple.Pair; import java.io.IOException; diff --git a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/ScheduleResults.java b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/ScheduleResults.java index ec7699dad3..755ca3c313 100644 --- a/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/ScheduleResults.java +++ b/scheduler-server/src/main/java/gov/nasa/jpl/aerie/scheduler/server/services/ScheduleResults.java @@ -3,8 +3,8 @@ import java.util.Collection; import java.util.Map; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.scheduler.server.models.GoalId; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; /** * summary of results from running the scheduler, including goal satisfaction metrics and changes made diff --git a/scheduler-server/src/test/java/gov/nasa/jpl/aerie/scheduler/server/graphql/GraphQLParsersTest.java b/scheduler-server/src/test/java/gov/nasa/jpl/aerie/scheduler/server/graphql/GraphQLParsersTest.java index 7afe66fa4a..23ebddbcf2 100644 --- a/scheduler-server/src/test/java/gov/nasa/jpl/aerie/scheduler/server/graphql/GraphQLParsersTest.java +++ b/scheduler-server/src/test/java/gov/nasa/jpl/aerie/scheduler/server/graphql/GraphQLParsersTest.java @@ -1,7 +1,7 @@ package gov.nasa.jpl.aerie.scheduler.server.graphql; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; -import gov.nasa.jpl.aerie.scheduler.server.models.Timestamp; +import gov.nasa.jpl.aerie.types.Timestamp; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; diff --git a/scheduler-worker/build.gradle b/scheduler-worker/build.gradle index ccd1ccaebf..b139bcbc25 100644 --- a/scheduler-worker/build.gradle +++ b/scheduler-worker/build.gradle @@ -108,6 +108,7 @@ javadoc.options.addStringOption('Xdoclint:none', '-quiet') dependencies { implementation project(':merlin-driver') + implementation project(':type-utils') implementation project(':scheduler-driver') implementation project(':scheduler-server') implementation project(':parsing-utilities') diff --git a/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SynchronousSchedulerAgent.java b/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SynchronousSchedulerAgent.java index dfc27ccaaa..56a1af35e2 100644 --- a/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SynchronousSchedulerAgent.java +++ b/scheduler-worker/src/main/java/gov/nasa/jpl/aerie/scheduler/worker/services/SynchronousSchedulerAgent.java @@ -20,9 +20,7 @@ import java.util.jar.JarFile; import java.util.stream.Collectors; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.MissionModel; -import gov.nasa.jpl.aerie.merlin.driver.MissionModelId; import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; import gov.nasa.jpl.aerie.merlin.driver.SimulationEngineConfiguration; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; @@ -71,6 +69,8 @@ import gov.nasa.jpl.aerie.scheduler.simulation.InMemoryCachedEngineStore; import gov.nasa.jpl.aerie.scheduler.simulation.SimulationData; import gov.nasa.jpl.aerie.scheduler.solver.PrioritySolver; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/MockMerlinDatabaseService.java b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/MockMerlinDatabaseService.java index aead83f693..67ba1bbe02 100644 --- a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/MockMerlinDatabaseService.java +++ b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/MockMerlinDatabaseService.java @@ -1,7 +1,5 @@ package gov.nasa.jpl.aerie.scheduler.worker.services; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.SimulationResults; import gov.nasa.jpl.aerie.merlin.protocol.model.SchedulerModel; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; @@ -16,11 +14,13 @@ import gov.nasa.jpl.aerie.scheduler.server.models.ExternalProfiles; import gov.nasa.jpl.aerie.scheduler.server.models.GoalId; import gov.nasa.jpl.aerie.scheduler.server.models.MerlinPlan; -import gov.nasa.jpl.aerie.scheduler.server.models.MissionModelId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanMetadata; import gov.nasa.jpl.aerie.scheduler.server.models.ResourceType; import gov.nasa.jpl.aerie.scheduler.server.services.MerlinDatabaseService; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.apache.commons.lang3.tuple.Pair; import java.nio.file.Path; diff --git a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationServiceTests.java b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationServiceTests.java index dd6848d4b2..d2e0c2fc26 100644 --- a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationServiceTests.java +++ b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingDSLCompilationServiceTests.java @@ -35,13 +35,13 @@ import gov.nasa.jpl.aerie.scheduler.server.models.DatasetId; import gov.nasa.jpl.aerie.scheduler.server.models.ExternalProfiles; import gov.nasa.jpl.aerie.scheduler.server.models.MerlinPlan; -import gov.nasa.jpl.aerie.scheduler.server.models.MissionModelId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanId; import gov.nasa.jpl.aerie.scheduler.server.models.PlanMetadata; import gov.nasa.jpl.aerie.scheduler.server.models.ResourceType; import gov.nasa.jpl.aerie.scheduler.server.models.SchedulingDSL; import gov.nasa.jpl.aerie.scheduler.server.services.MerlinDatabaseService; import gov.nasa.jpl.aerie.scheduler.server.services.MerlinServiceException; +import gov.nasa.jpl.aerie.types.MissionModelId; import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -80,45 +80,37 @@ public MerlinDatabaseService.MissionModelTypes getMissionModelTypes(final Missio } @Override - public long getPlanRevision(final PlanId planId) throws IOException, NoSuchPlanException, MerlinServiceException { + public long getPlanRevision(final PlanId planId) { return 0; } @Override - public PlanMetadata getPlanMetadata(final PlanId planId) - throws IOException, NoSuchPlanException, MerlinServiceException - { + public PlanMetadata getPlanMetadata(final PlanId planId) { return null; } @Override - public MerlinPlan getPlanActivityDirectives(final PlanMetadata planMetadata, final Problem mission) - throws IOException, NoSuchPlanException, MerlinServiceException, InvalidJsonException, InstantiationException - { + public MerlinPlan getPlanActivityDirectives(final PlanMetadata planMetadata, final Problem mission) { return null; } @Override - public void ensurePlanExists(final PlanId planId) throws IOException, NoSuchPlanException, MerlinServiceException { + public void ensurePlanExists(final PlanId planId) { } @Override - public Optional> getSimulationResults(final PlanMetadata planMetadata) - throws MerlinServiceException, IOException, InvalidJsonException - { + public Optional> getSimulationResults(final PlanMetadata planMetadata) { return Optional.empty(); } @Override - public ExternalProfiles getExternalProfiles(final PlanId planId) throws MerlinServiceException, IOException { + public ExternalProfiles getExternalProfiles(final PlanId planId) { return null; } @Override - public Collection getResourceTypes(final PlanId planId) - throws IOException, MerlinServiceException, NoSuchPlanException - { + public Collection getResourceTypes(final PlanId planId) { return null; } }; diff --git a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingIntegrationTests.java b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingIntegrationTests.java index 70b2d2d71d..3242e7ef39 100644 --- a/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingIntegrationTests.java +++ b/scheduler-worker/src/test/java/gov/nasa/jpl/aerie/scheduler/worker/services/SchedulingIntegrationTests.java @@ -27,10 +27,7 @@ import gov.nasa.jpl.aerie.constraints.model.DiscreteProfile; import gov.nasa.jpl.aerie.constraints.time.Interval; import gov.nasa.jpl.aerie.constraints.time.Segment; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; -import gov.nasa.jpl.aerie.merlin.driver.SerializedActivity; import gov.nasa.jpl.aerie.merlin.protocol.model.DirectiveType; import gov.nasa.jpl.aerie.merlin.protocol.model.InputType.Parameter; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; @@ -51,13 +48,16 @@ import gov.nasa.jpl.aerie.scheduler.server.models.ResourceType; import gov.nasa.jpl.aerie.scheduler.server.models.Specification; import gov.nasa.jpl.aerie.scheduler.server.models.SpecificationId; -import gov.nasa.jpl.aerie.scheduler.server.models.Timestamp; import gov.nasa.jpl.aerie.scheduler.server.remotes.postgres.SpecificationRevisionData; import gov.nasa.jpl.aerie.scheduler.server.services.MerlinDatabaseService; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleRequest; import gov.nasa.jpl.aerie.scheduler.server.services.ScheduleResults; import gov.nasa.jpl.aerie.scheduler.model.Plan; import gov.nasa.jpl.aerie.scheduler.server.services.SpecificationService; +import gov.nasa.jpl.aerie.types.ActivityDirective; +import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.SerializedActivity; +import gov.nasa.jpl.aerie.types.Timestamp; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -166,7 +166,7 @@ export default function myGoal() { specification : {duration: Temporal.Duration.from({seconds: 10})} }) } - """, true)),List.of(createAutoMutex("GrowBanana")), PLANNING_HORIZON); + """, true)),List.of(createAutoMutex("GrowBanana")), PLANNING_HORIZON); assertEquals(1, results.scheduleResults.goalResults().size()); final var goalResult = results.scheduleResults.goalResults().get(new GoalId(0L, 0L)); @@ -207,7 +207,7 @@ export default function myGoal() { specification : {occurrence: 10} }) } - """, true)),List.of(createAutoMutex("GrowBanana")),PLANNING_HORIZON); + """, true)),List.of(createAutoMutex("GrowBanana")),PLANNING_HORIZON); assertEquals(1, results.scheduleResults.goalResults().size()); final var goalResult = results.scheduleResults.goalResults().get(new GoalId(0L, 0L)); @@ -655,7 +655,7 @@ export default () => Goal.CoexistenceGoal({ assertEquals(2, planByTime.get(MINUTES.times(10)).size()); var lookingFor = false; final var expectedCreation = new SerializedActivity("GrowBanana", - Map.of("quantity", SerializedValue.of(1), + Map.of("quantity", SerializedValue.of(1), "growingDuration", SerializedValue.of(MINUTES.in(MICROSECONDS)))); for(final var actAtTime10: planByTime.get(MINUTES.times(10))){ if(actAtTime10.serializedActivity().equals(expectedCreation)){ @@ -751,7 +751,7 @@ export default function myGoal() { specification : {duration: Temporal.Duration.from({seconds: 10})} }) } - """, true)),List.of(createAutoMutex("GrowBanana")), PLANNING_HORIZON); + """, true)),List.of(createAutoMutex("GrowBanana")), PLANNING_HORIZON); assertEquals(1, results.scheduleResults.goalResults().size()); final var goalResult = results.scheduleResults.goalResults().get(new GoalId(0L, 0L)); @@ -2531,7 +2531,7 @@ export default function myGoal() { interval: Temporal.Duration.from({hours: 1}) }) } - """, true)), + """, true)), PLANNING_HORIZON); assertEquals(96, results.updatedPlan().size()); } @@ -2553,7 +2553,7 @@ export default (): Goal => { interval: Temporal.Duration.from({ days: 30}) }) } - """, true)), PLANNING_HORIZON); + """, true)), PLANNING_HORIZON); //parent takes much more than 134 - 90 = 44 days to finish assertEquals(0, results.updatedPlan.size()); final var goalResult = results.scheduleResults.goalResults().get(new GoalId(0L, 0L)); @@ -3261,7 +3261,7 @@ export default () => Goal.CoexistenceGoal({ activityTemplate: ActivityTemplates.BananaNap(), startsAt: TimingConstraint.singleton(WindowProperty.START).plus(Temporal.Duration.from({ minutes: 5 })) }) - """, true, true) + """, true, true) ), PLANNING_HORIZON); @@ -3441,7 +3441,7 @@ export default function myGoal() { specification : {occurrence: 1} }) } - """, true)),List.of(), PLANNING_HORIZON); + """, true)),List.of(), PLANNING_HORIZON); assertEquals(1, results.scheduleResults.goalResults().size()); final var goalResult = results.scheduleResults.goalResults().get(new GoalId(0L, 0L)); diff --git a/settings.gradle b/settings.gradle index ce6c145ad4..cd72036376 100644 --- a/settings.gradle +++ b/settings.gradle @@ -43,3 +43,4 @@ include 'examples:minimal-mission-model' include 'examples:streamline-demo' include 'stateless-aerie' include 'orchestration-utils' +include 'type-utils' diff --git a/stateless-aerie/build.gradle b/stateless-aerie/build.gradle index 2168fc812a..fd6c9ac8bd 100644 --- a/stateless-aerie/build.gradle +++ b/stateless-aerie/build.gradle @@ -16,10 +16,11 @@ java { jar { dependsOn(':parsing-utilities:jar') - dependsOn(':merlin-sdk:jar') - dependsOn(':merlin-driver:jar') - dependsOn(':constraints:jar') + dependsOn(':type-utils:jar') dependsOn(':orchestration-utils:jar') + dependsOn(':constraints:jar') + dependsOn(':merlin-driver:jar') + dependsOn(':merlin-sdk:jar') duplicatesStrategy = DuplicatesStrategy.EXCLUDE @@ -55,9 +56,9 @@ javadoc.options.links 'https://commons.apache.org/proper/commons-lang/javadocs/a javadoc.options.addStringOption('Xdoclint:none', '-quiet') dependencies { + implementation project(':type-utils') implementation project(':orchestration-utils') implementation project(':merlin-driver') - implementation project(':merlin-server') implementation 'commons-cli:commons-cli:1.8.0' testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0' diff --git a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java index 6fdc079d2d..07c4acafd6 100644 --- a/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java +++ b/stateless-aerie/src/main/java/gov/nasa/jpl/aerie/stateless/Main.java @@ -8,7 +8,6 @@ import gov.nasa.jpl.aerie.merlin.driver.MissionModel; import gov.nasa.jpl.aerie.merlin.driver.MissionModelLoader; import gov.nasa.jpl.aerie.merlin.driver.SimulationException; -import gov.nasa.jpl.aerie.merlin.server.models.Plan; import java.nio.file.Path; import java.util.Map; @@ -16,6 +15,7 @@ import java.util.concurrent.ExecutionException; import gov.nasa.jpl.aerie.orchestration.simulation.SimulationUtility; +import gov.nasa.jpl.aerie.types.Plan; import org.apache.commons.cli.*; import javax.json.Json; diff --git a/type-utils/build.gradle b/type-utils/build.gradle new file mode 100644 index 0000000000..b83c826453 --- /dev/null +++ b/type-utils/build.gradle @@ -0,0 +1,23 @@ +plugins { + id 'java' +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + + withJavadocJar() + withSourcesJar() +} + +dependencies { + implementation project(":merlin-sdk") + + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() +} diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityDirective.java b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/ActivityDirective.java similarity index 94% rename from merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityDirective.java rename to type-utils/src/main/java/gov/nasa/jpl/aerie/types/ActivityDirective.java index 76b87e312f..461db012ab 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityDirective.java +++ b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/ActivityDirective.java @@ -1,4 +1,4 @@ -package gov.nasa.jpl.aerie.merlin.driver; +package gov.nasa.jpl.aerie.types; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityDirectiveId.java b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/ActivityDirectiveId.java similarity index 52% rename from merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityDirectiveId.java rename to type-utils/src/main/java/gov/nasa/jpl/aerie/types/ActivityDirectiveId.java index cc0e0d6376..c264c39dfc 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/ActivityDirectiveId.java +++ b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/ActivityDirectiveId.java @@ -1,3 +1,3 @@ -package gov.nasa.jpl.aerie.merlin.driver; +package gov.nasa.jpl.aerie.types; public record ActivityDirectiveId(long id) {} diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/MissionModelId.java b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/MissionModelId.java similarity index 72% rename from merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/MissionModelId.java rename to type-utils/src/main/java/gov/nasa/jpl/aerie/types/MissionModelId.java index d212b7f442..eb6f31d445 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/MissionModelId.java +++ b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/MissionModelId.java @@ -1,4 +1,4 @@ -package gov.nasa.jpl.aerie.merlin.server.models; +package gov.nasa.jpl.aerie.types; public record MissionModelId(long id) { @Override diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/Plan.java similarity index 97% rename from merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java rename to type-utils/src/main/java/gov/nasa/jpl/aerie/types/Plan.java index 35d4a8c82c..eb1efdf0e1 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Plan.java +++ b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/Plan.java @@ -1,7 +1,5 @@ -package gov.nasa.jpl.aerie.merlin.server.models; +package gov.nasa.jpl.aerie.types; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirective; -import gov.nasa.jpl.aerie.merlin.driver.ActivityDirectiveId; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; diff --git a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SerializedActivity.java b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/SerializedActivity.java similarity index 96% rename from merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SerializedActivity.java rename to type-utils/src/main/java/gov/nasa/jpl/aerie/types/SerializedActivity.java index 712eabebe7..a861b64592 100644 --- a/merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/SerializedActivity.java +++ b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/SerializedActivity.java @@ -1,4 +1,4 @@ -package gov.nasa.jpl.aerie.merlin.driver; +package gov.nasa.jpl.aerie.types; import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; @@ -68,6 +68,6 @@ public int hashCode() { @Override public String toString() { - return "SerializedActivity { typeName = " + this.typeName + ", arguments = " + this.arguments.toString() + " }"; + return "SerializedActivity { typeName = " + this.typeName + ", arguments = " + this.arguments + " }"; } } diff --git a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Timestamp.java b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/Timestamp.java similarity index 96% rename from merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Timestamp.java rename to type-utils/src/main/java/gov/nasa/jpl/aerie/types/Timestamp.java index 16932f0fde..309c756d21 100644 --- a/merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/Timestamp.java +++ b/type-utils/src/main/java/gov/nasa/jpl/aerie/types/Timestamp.java @@ -1,4 +1,4 @@ -package gov.nasa.jpl.aerie.merlin.server.models; +package gov.nasa.jpl.aerie.types; import java.time.Instant; import java.time.LocalDateTime; From db45acab303312b1d3dfe26ac9c9e1ad89782886 Mon Sep 17 00:00:00 2001 From: Theresa Kamerman Date: Tue, 13 Aug 2024 15:25:18 -0700 Subject: [PATCH 17/17] Update Bananation's SimUtil --- .../aerie/banananation/SimulationUtility.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java index 093b93fce7..e0383b3a08 100644 --- a/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java +++ b/examples/banananation/src/test/java/gov/nasa/jpl/aerie/banananation/SimulationUtility.java @@ -3,15 +3,20 @@ import gov.nasa.jpl.aerie.banananation.generated.GeneratedModelType; import gov.nasa.jpl.aerie.merlin.driver.*; import gov.nasa.jpl.aerie.merlin.protocol.types.Duration; +import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue; import gov.nasa.jpl.aerie.types.ActivityDirective; import gov.nasa.jpl.aerie.types.ActivityDirectiveId; +import gov.nasa.jpl.aerie.types.Plan; import gov.nasa.jpl.aerie.types.SerializedActivity; +import gov.nasa.jpl.aerie.types.Timestamp; import org.apache.commons.lang3.tuple.Pair; import java.nio.file.Path; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ExecutionException; public final class SimulationUtility { public static SimulationResults @@ -19,19 +24,23 @@ public final class SimulationUtility { final var dataPath = Path.of(SimulationUtility.class.getResource("data/lorem_ipsum.txt").getPath()); final var config = new Configuration(Configuration.DEFAULT_PLANT_COUNT, Configuration.DEFAULT_PRODUCER, dataPath, Configuration.DEFAULT_INITIAL_CONDITIONS); final var startTime = Instant.now(); - final var missionModel = gov.nasa.jpl.aerie.stateless.simulation.SimulationUtility.instantiateMissionModel( + final var missionModel = gov.nasa.jpl.aerie.orchestration.simulation.SimulationUtility.instantiateMissionModel( new GeneratedModelType(), Instant.EPOCH, config); - return SimulationDriver.simulate( - missionModel, + final var plan = new Plan( + "plan", + new Timestamp(startTime), + new Timestamp(startTime.plus(simulationDuration.in(Duration.MICROSECOND), ChronoUnit.MICROS)), schedule, - startTime, - simulationDuration, - startTime, - simulationDuration, - () -> false); + Map.of("initialDataPath", SerializedValue.of(dataPath.toString()))); + + try(final var simUtil = new gov.nasa.jpl.aerie.orchestration.simulation.SimulationUtility()) { + return simUtil.simulate(missionModel, plan).get(); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } } @SafeVarargs