Skip to content

Commit 92c4f31

Browse files
committed
Expose mission model to procedures
1 parent b7e6513 commit 92c4f31

File tree

11 files changed

+116
-7
lines changed

11 files changed

+116
-7
lines changed

contrib/src/main/java/gov/nasa/jpl/aerie/contrib/models/NamedResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import gov.nasa.jpl.aerie.merlin.framework.resources.NameableResource;
44

55
public abstract class NamedResource<D> implements NameableResource<D> {
6-
private String name = "";
6+
private String name = "ERROR: Name was not set during model construction";
77

88
@Override
99
public String getName() {

e2e-tests/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ dependencies {
6464
implementation project(':merlin-sdk')
6565
implementation project(':type-utils')
6666
implementation project(':contrib')
67+
compileOnly project(':examples:banananation')
6768

6869
testImplementation "com.zaxxer:HikariCP:5.1.0"
6970
testImplementation("org.postgresql:postgresql:42.6.0")
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package gov.nasa.jpl.aerie.e2e.procedural.scheduling.procedures;
2+
3+
import gov.nasa.ammos.aerie.procedural.scheduling.Goal;
4+
import gov.nasa.ammos.aerie.procedural.scheduling.annotations.SchedulingProcedure;
5+
import gov.nasa.ammos.aerie.procedural.scheduling.plan.EditablePlan;
6+
import gov.nasa.ammos.aerie.procedural.timeline.payloads.activities.DirectiveStart;
7+
import gov.nasa.ammos.aerie.procedural.timeline.util.WithModel;
8+
import gov.nasa.jpl.aerie.banananation.Mission;
9+
import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue;
10+
import org.jetbrains.annotations.NotNull;
11+
12+
import java.util.Map;
13+
14+
/**
15+
* Creates a bite banana every time /producer changes
16+
*/
17+
@SchedulingProcedure
18+
public record ModelIntegrationGoal() implements Goal, WithModel<Mission> {
19+
@Override
20+
public void run(@NotNull final EditablePlan plan) {
21+
final var changes = plan.simulate().resource(model().producer).changes().highlightTrue();
22+
for (final var interval: changes) {
23+
plan.create("BiteBanana", new DirectiveStart.Absolute(interval.start), Map.of("biteSize", SerializedValue.of(1)));
24+
}
25+
plan.commit();
26+
}
27+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package gov.nasa.jpl.aerie.e2e.procedural.scheduling;
2+
3+
import gov.nasa.jpl.aerie.e2e.types.GoalInvocationId;
4+
import gov.nasa.jpl.aerie.e2e.utils.GatewayRequests;
5+
import org.junit.jupiter.api.AfterEach;
6+
import org.junit.jupiter.api.BeforeEach;
7+
import org.junit.jupiter.api.Test;
8+
9+
import javax.json.Json;
10+
import javax.json.JsonValue;
11+
import java.io.IOException;
12+
import java.util.Objects;
13+
14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
import static org.junit.jupiter.api.Assertions.assertTrue;
16+
17+
public class ModelIntegrationTests extends ProceduralSchedulingSetup {
18+
private int procedureJarId;
19+
private GoalInvocationId procedureId;
20+
21+
@BeforeEach
22+
void localBeforeEach() throws IOException {
23+
try (final var gateway = new GatewayRequests(playwright)) {
24+
procedureJarId = gateway.uploadJarFile("build/libs/ModelIntegrationGoal.jar");
25+
// Add Scheduling Procedure
26+
procedureId = hasura.createSchedulingSpecProcedure(
27+
"Test Scheduling Procedure",
28+
procedureJarId,
29+
specId,
30+
0
31+
);
32+
}
33+
}
34+
35+
@AfterEach
36+
void localAfterEach() throws IOException {
37+
hasura.deleteSchedulingGoal(procedureId.goalId());
38+
}
39+
40+
@Test
41+
void testModelIntegration() throws IOException {
42+
hasura.insertActivityDirective(
43+
planId,
44+
"ChangeProducer",
45+
"1h",
46+
Json.createObjectBuilder().add("producer", Json.createValue("p")).build()
47+
);
48+
hasura.updatePlanRevisionSchedulingSpec(planId);
49+
50+
hasura.awaitScheduling(specId);
51+
52+
final var plan = hasura.getPlan(planId);
53+
final var activities = plan.activityDirectives();
54+
55+
assertEquals(2, activities.size());
56+
}
57+
}

merlin-driver/src/main/java/gov/nasa/jpl/aerie/merlin/driver/MissionModelLoader.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ public static MerlinPlugin loadMissionModelProvider(final Path path, final Strin
6666
final var className = getImplementingClassName(path, name, version);
6767

6868
// Construct a ClassLoader with access to classes in the mission model location.
69-
final var classLoader = new URLClassLoader(new URL[] {missionModelPathToUrl(path)});
69+
final var parentClassLoader = Thread.currentThread().getContextClassLoader();
70+
final var classLoader = new URLClassLoader(new URL[] {missionModelPathToUrl(path)}, parentClassLoader);
7071

7172
try {
7273
final var pluginClass$ = classLoader.loadClass(className);

merlin-server/src/main/java/gov/nasa/jpl/aerie/merlin/server/models/ProcedureLoader.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ public static ProcedureMapper<?> loadProcedure(final Path path)
1515
throws ProcedureLoadException
1616
{
1717
final var className = getImplementingClassName(path);
18-
final var classLoader = new URLClassLoader(new URL[] {pathToUrl(path)});
18+
final var parentClassLoader = Thread.currentThread().getContextClassLoader();
19+
final var classLoader = new URLClassLoader(new URL[] {pathToUrl(path)}, parentClassLoader);
1920

2021
try {
2122
final var pluginClass$ = classLoader.loadClass(className);

procedural/examples/banana-procedures/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ dependencies {
2424
implementation project(':type-utils')
2525
implementation project(':contrib')
2626

27+
implementation project(":examples:banananation")
28+
2729
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.0'
2830
testImplementation project(':procedural:utils')
2931
testImplementation project(':orchestration-utils')

procedural/examples/banana-procedures/src/main/java/gov/nasa/ammos/aerie/procedural/examples/bananaprocedures/procedures/SimulationDemo.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
package gov.nasa.ammos.aerie.procedural.examples.bananaprocedures.procedures;
22

3+
import gov.nasa.ammos.aerie.procedural.timeline.util.WithModel;
4+
import gov.nasa.jpl.aerie.banananation.Mission;
35
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
46
import gov.nasa.jpl.aerie.merlin.protocol.types.SerializedValue;
57
import gov.nasa.ammos.aerie.procedural.scheduling.Goal;
68
import gov.nasa.ammos.aerie.procedural.scheduling.annotations.SchedulingProcedure;
79
import gov.nasa.ammos.aerie.procedural.scheduling.plan.EditablePlan;
8-
import gov.nasa.ammos.aerie.procedural.timeline.collections.profiles.Real;
910
import gov.nasa.ammos.aerie.procedural.timeline.payloads.activities.DirectiveStart;
1011
import org.jetbrains.annotations.NotNull;
1112

1213
import java.util.Map;
1314

1415
@SchedulingProcedure
15-
public record SimulationDemo(int quantity) implements Goal {
16+
public record SimulationDemo(int quantity) implements Goal, WithModel<Mission> {
1617
@Override
1718
public void run(@NotNull final EditablePlan plan) {
1819

1920
var simResults = plan.latestResults();
2021
if (simResults == null) simResults = plan.simulate();
2122

22-
final var lowFruit = simResults.resource("/fruit", Real.deserializer()).lessThan(3.5).isolateTrue();
23+
final var lowFruit = simResults.resource(model().fruit).lessThan(3.5).isolateTrue();
2324
final var bites = simResults.instances("BiteBanana");
2425

2526
final var connections = lowFruit.starts().shift(Duration.MINUTE.negate())
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package gov.nasa.ammos.aerie.procedural.timeline.util
2+
3+
interface WithModel<M> {
4+
@Suppress("unchecked_cast")
5+
fun model(): M {
6+
if (modelSingleton == null) {
7+
throw IllegalStateException("modelSingleton was not initialized.")
8+
}
9+
10+
return modelSingleton as M
11+
}
12+
13+
companion object {
14+
@JvmStatic var modelSingleton: Any? = null
15+
}
16+
}

scheduler-driver/src/main/java/gov/nasa/jpl/aerie/scheduler/ProcedureLoader.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ public static ProcedureMapper<?> loadProcedure(final Path path)
1515
throws ProcedureLoadException
1616
{
1717
final var className = getImplementingClassName(path);
18-
final var classLoader = new URLClassLoader(new URL[] {pathToUrl(path)});
18+
final var parentClassLoader = Thread.currentThread().getContextClassLoader();
19+
final var classLoader = new URLClassLoader(new URL[] {pathToUrl(path)}, parentClassLoader);
1920

2021
try {
2122
final var pluginClass$ = classLoader.loadClass(className);

0 commit comments

Comments
 (0)