Skip to content

Commit 33291f4

Browse files
committed
new auto-gen activity value mappers to use activity types as parameters.
1 parent a636850 commit 33291f4

File tree

11 files changed

+331
-73
lines changed

11 files changed

+331
-73
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package gov.nasa.jpl.aerie.banananation.activities;
2+
3+
import gov.nasa.jpl.aerie.banananation.Mission;
4+
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType;
5+
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export;
6+
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;
7+
8+
import java.util.List;
9+
10+
import static gov.nasa.jpl.aerie.banananation.generated.ActivityActions.call;
11+
import static gov.nasa.jpl.aerie.merlin.framework.ModelActions.delay;
12+
13+
/**
14+
* Russian Banana Encloses Banana
15+
*
16+
* This activity causes a piece of banana to be bitten off and consumed.
17+
*
18+
* @subsystem fruit
19+
* @contact John Doe
20+
*/
21+
@ActivityType("RussianBanana")
22+
public final class RussianBanana {
23+
24+
@Export.Parameter
25+
public List<Integer> testints;
26+
27+
@Export.Parameter
28+
public List<BiteBananaActivity> biteBananaActivity;
29+
30+
@Export.Parameter
31+
public PeelBananaActivity peelBananaActivity;
32+
33+
34+
@ActivityType.EffectModel
35+
public void run(final Mission mission) {
36+
for (final var bite : biteBananaActivity) {
37+
call(mission, bite);
38+
delay(Duration.of(30, Duration.MINUTE));
39+
}
40+
call(mission, peelBananaActivity);
41+
}
42+
43+
}

examples/banananation/src/main/java/gov/nasa/jpl/aerie/banananation/package-info.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
@WithActivityType(ControllableDurationActivity.class)
2727
@WithActivityType(RipenBananaActivity.class)
2828
@WithActivityType(ExceptionActivity.class)
29-
29+
@WithActivityType(RussianBanana.class)
3030
package gov.nasa.jpl.aerie.banananation;
3131

3232
import gov.nasa.jpl.aerie.banananation.activities.BakeBananaBreadActivity;
@@ -46,6 +46,7 @@
4646
import gov.nasa.jpl.aerie.banananation.activities.PeelBananaActivity;
4747
import gov.nasa.jpl.aerie.banananation.activities.PickBananaActivity;
4848
import gov.nasa.jpl.aerie.banananation.activities.RipenBananaActivity;
49+
import gov.nasa.jpl.aerie.banananation.activities.RussianBanana;
4950
import gov.nasa.jpl.aerie.banananation.activities.ThrowBananaActivity;
5051
import gov.nasa.jpl.aerie.contrib.serialization.rulesets.BasicValueMappers;
5152
import gov.nasa.jpl.aerie.merlin.framework.annotations.MissionModel;

merlin-framework-processor/src/main/java/gov/nasa/jpl/aerie/merlin/processor/AutoValueMappers.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import gov.nasa.jpl.aerie.contrib.serialization.mappers.RecordValueMapper;
1414
import gov.nasa.jpl.aerie.merlin.framework.Result;
1515
import gov.nasa.jpl.aerie.merlin.framework.ValueMapper;
16+
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType;
1617
import gov.nasa.jpl.aerie.merlin.framework.annotations.AutoValueMapper;
1718
import gov.nasa.jpl.aerie.merlin.processor.metamodel.MissionModelRecord;
1819
import gov.nasa.jpl.aerie.merlin.processor.metamodel.TypeRule;
@@ -61,6 +62,24 @@ static TypeRule recordTypeRule(final Element autoValueMapperElement, final Class
6162
ClassName.get((TypeElement) autoValueMapperElement).canonicalName().replace(".", "_"));
6263
}
6364

65+
static TypeRule activityTypeRule(final Element activityTypeElement, final ClassName generatedClassName) throws InvalidMissionModelException {
66+
if (!(activityTypeElement.getKind().equals(ElementKind.CLASS) || activityTypeElement.getKind().equals(ElementKind.RECORD))) { //todo: check if activities are constrained to class and record
67+
throw new InvalidMissionModelException(
68+
"@%s is only allowed on classes and records".formatted(
69+
ActivityType.class.getSimpleName()),
70+
activityTypeElement);
71+
}
72+
73+
return new TypeRule(
74+
new TypePattern.ClassPattern(
75+
ClassName.get(ValueMapper.class),
76+
List.of(TypePattern.from(activityTypeElement.asType()))),
77+
Set.of(),
78+
List.of(),
79+
generatedClassName,
80+
ClassName.get((TypeElement) activityTypeElement).canonicalName().replace("activities", "generated_activitiesValueMappers").replace(".", "_") + "ValueMapper");
81+
}
82+
6483
static TypeRule annotationTypeRule(final Element autoValueMapperElement, final ClassName generatedClassName) throws InvalidMissionModelException {
6584
if (!autoValueMapperElement.getKind().equals(ElementKind.ANNOTATION_TYPE)) {
6685
throw new InvalidMissionModelException(

merlin-framework-processor/src/main/java/gov/nasa/jpl/aerie/merlin/processor/MissionModelParser.java

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export;
1010
import gov.nasa.jpl.aerie.merlin.framework.annotations.MissionModel;
1111
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ActivityTypeRecord;
12+
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ActivityValueMapperRecord;
1213
import gov.nasa.jpl.aerie.merlin.processor.metamodel.InputTypeRecord;
1314
import gov.nasa.jpl.aerie.merlin.processor.metamodel.EffectModelRecord;
1415
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ExportDefaultsStyle;
15-
import gov.nasa.jpl.aerie.merlin.processor.metamodel.MapperRecord;
16+
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ActivityMapperRecord;
1617
import gov.nasa.jpl.aerie.merlin.processor.metamodel.MissionModelRecord;
1718
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ParameterRecord;
1819
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ParameterValidationRecord;
@@ -183,9 +184,10 @@ private Optional<InputTypeRecord> getMissionModelConfigurationType(final Package
183184
final var name = declaration.getSimpleName().toString();
184185
final var parameters = getExportParameters(declaration);
185186
final var validations = this.getExportValidations(declaration, parameters);
186-
final var mapper = getExportMapper(missionModelElement, declaration);
187+
final var activityMapper = getExportActivityMapper(missionModelElement, declaration);
188+
final var valueMapper = getExportValueMapper(missionModelElement, declaration);
187189
final var defaultsStyle = getExportDefaultsStyle(declaration);
188-
return Optional.of(new InputTypeRecord(name, declaration, parameters, validations, mapper, defaultsStyle));
190+
return Optional.of(new InputTypeRecord(name, declaration, parameters, validations, activityMapper, valueMapper, defaultsStyle));
189191
}
190192

191193
private List<TypeElement> getMissionModelMapperClasses(final PackageElement missionModelElement)
@@ -381,7 +383,8 @@ private ActivityTypeRecord parseActivityType(final PackageElement missionModelEl
381383
{
382384
final var fullyQualifiedClassName = activityTypeElement.getQualifiedName();
383385
final var name = this.getActivityTypeName(activityTypeElement);
384-
final var mapper = this.getExportMapper(missionModelElement, activityTypeElement);
386+
final var activityMapper = getExportActivityMapper(missionModelElement, activityTypeElement);
387+
final var valueMapper = getExportValueMapper(missionModelElement, activityTypeElement);
385388
final var parameters = this.getExportParameters(activityTypeElement);
386389
final var validations = this.getExportValidations(activityTypeElement, parameters);
387390
final var effectModel = this.getActivityEffectModel(activityTypeElement);
@@ -405,7 +408,7 @@ class (old-style) or as a record (new-style) by determining
405408
return new ActivityTypeRecord(
406409
fullyQualifiedClassName.toString(),
407410
name,
408-
new InputTypeRecord(name, activityTypeElement, parameters, validations, mapper, defaultsStyle),
411+
new InputTypeRecord(name, activityTypeElement, parameters, validations, activityMapper, valueMapper, defaultsStyle),
409412
effectModel);
410413
}
411414

@@ -471,12 +474,12 @@ private String getActivityTypeName(final TypeElement activityTypeElement)
471474
return (String) nameAttribute.getValue();
472475
}
473476

474-
private MapperRecord getExportMapper(final PackageElement missionModelElement, final TypeElement exportTypeElement)
477+
private ActivityMapperRecord getExportActivityMapper(final PackageElement missionModelElement, final TypeElement exportTypeElement)
475478
throws InvalidMissionModelException
476479
{
477480
final var annotationMirror = this.getAnnotationMirrorByType(exportTypeElement, ActivityType.WithMapper.class);
478481
if (annotationMirror.isEmpty()) {
479-
return MapperRecord.generatedFor(
482+
return ActivityMapperRecord.generatedFor(
480483
ClassName.get(exportTypeElement),
481484
missionModelElement);
482485
}
@@ -488,7 +491,27 @@ private MapperRecord getExportMapper(final PackageElement missionModelElement, f
488491
annotationMirror.get()))
489492
.getValue();
490493

491-
return MapperRecord.custom(
494+
return ActivityMapperRecord.custom(
495+
ClassName.get((TypeElement) mapperType.asElement()));
496+
}
497+
private ActivityValueMapperRecord getExportValueMapper(final PackageElement missionModelElement, final TypeElement exportTypeElement)
498+
throws InvalidMissionModelException
499+
{
500+
final var annotationMirror = this.getAnnotationMirrorByType(exportTypeElement, ActivityType.WithMapper.class);
501+
if (annotationMirror.isEmpty()) {
502+
return ActivityValueMapperRecord.generatedFor(
503+
ClassName.get(exportTypeElement),
504+
missionModelElement);
505+
}
506+
507+
final var mapperType = (DeclaredType) getAnnotationAttribute(annotationMirror.get(), "value")
508+
.orElseThrow(() -> new InvalidMissionModelException(
509+
"Unable to get value attribute of annotation",
510+
exportTypeElement,
511+
annotationMirror.get()))
512+
.getValue();
513+
514+
return ActivityValueMapperRecord.custom(
492515
ClassName.get((TypeElement) mapperType.asElement()));
493516
}
494517

merlin-framework-processor/src/main/java/gov/nasa/jpl/aerie/merlin/processor/MissionModelProcessor.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package gov.nasa.jpl.aerie.merlin.processor;
22

3+
import com.squareup.javapoet.JavaFile;
4+
import com.squareup.javapoet.TypeName;
35
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType;
46
import gov.nasa.jpl.aerie.merlin.framework.annotations.AutoValueMapper;
7+
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export;
58
import gov.nasa.jpl.aerie.merlin.framework.annotations.MissionModel;
69
import gov.nasa.jpl.aerie.merlin.processor.generator.MissionModelGenerator;
710
import gov.nasa.jpl.aerie.merlin.processor.metamodel.MissionModelRecord;
@@ -26,6 +29,7 @@
2629
import java.util.Collections;
2730
import java.util.HashSet;
2831
import java.util.List;
32+
import java.util.Optional;
2933
import java.util.Set;
3034
import java.util.stream.Collectors;
3135

@@ -92,9 +96,10 @@ public boolean process(final Set<? extends TypeElement> annotations, final Round
9296
for (final var element : roundEnv.getElementsAnnotatedWith(MissionModel.class)) {
9397
final var recordAutoValueMapperRequests = roundEnv.getElementsAnnotatedWith(AutoValueMapper.Record.class);
9498
final var annotationAutoValueMapperRequests = roundEnv.getElementsAnnotatedWith(AutoValueMapper.Annotation.class);
99+
95100
final var packageElement = (PackageElement) element;
96101
try {
97-
final var missionModelRecord$ = missionModelParser.parseMissionModel(packageElement);
102+
final var missionModelRecord$ = missionModelParser.parseMissionModel(packageElement); //todo: add typerules for activity parameters
98103

99104
final var concatenatedTypeRules = new ArrayList<>(missionModelRecord$.typeRules());
100105
for (final var request : recordAutoValueMapperRequests) {
@@ -103,6 +108,9 @@ public boolean process(final Set<? extends TypeElement> annotations, final Round
103108
for (final var request : annotationAutoValueMapperRequests) {
104109
concatenatedTypeRules.add(AutoValueMappers.annotationTypeRule(request, missionModelRecord$.getAutoValueMappersName()));
105110
}
111+
for(final var request : this.foundActivityTypes) {
112+
concatenatedTypeRules.add(AutoValueMappers.activityTypeRule(request, missionModelRecord$.getActivityValueMappers()));
113+
}
106114

107115
final var missionModelRecord = new MissionModelRecord(
108116
missionModelRecord$.$package(),
@@ -113,6 +121,7 @@ public boolean process(final Set<? extends TypeElement> annotations, final Round
113121
missionModelRecord$.activityTypes()
114122
);
115123

124+
116125
final var generatedFiles = new ArrayList<>(List.of(
117126
missionModelGen.generateMerlinPlugin(missionModelRecord),
118127
missionModelGen.generateSchedulerPlugin(missionModelRecord)));
@@ -134,13 +143,16 @@ public boolean process(final Set<? extends TypeElement> annotations, final Round
134143
annotationAutoValueMapperRequests);
135144
generatedFiles.add(autoValueMappers);
136145

146+
137147
for (final var activityRecord : missionModelRecord.activityTypes()) {
138148
this.ownedActivityTypes.add(activityRecord.inputType().declaration());
139-
if (!activityRecord.inputType().mapper().isCustom) {
149+
if (!activityRecord.inputType().activityMapper().isCustom) {
140150
missionModelGen.generateActivityMapper(missionModelRecord, activityRecord).ifPresent(generatedFiles::add);
141151
}
142152
}
143153

154+
generatedFiles.add(missionModelGen.generateActivityValueMappers(missionModelRecord));
155+
144156
for (final var generatedFile : generatedFiles) {
145157
this.messager.printMessage(
146158
Diagnostic.Kind.NOTE,

0 commit comments

Comments
 (0)