Skip to content

Commit

Permalink
new auto-gen activity value mappers to use activity types as parameters.
Browse files Browse the repository at this point in the history
  • Loading branch information
amgreer99 committed Jan 22, 2024
1 parent a636850 commit 33291f4
Show file tree
Hide file tree
Showing 11 changed files with 331 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package gov.nasa.jpl.aerie.banananation.activities;

import gov.nasa.jpl.aerie.banananation.Mission;
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export;
import gov.nasa.jpl.aerie.merlin.protocol.types.Duration;

import java.util.List;

import static gov.nasa.jpl.aerie.banananation.generated.ActivityActions.call;
import static gov.nasa.jpl.aerie.merlin.framework.ModelActions.delay;

/**
* Russian Banana Encloses Banana
*
* This activity causes a piece of banana to be bitten off and consumed.
*
* @subsystem fruit
* @contact John Doe
*/
@ActivityType("RussianBanana")
public final class RussianBanana {

@Export.Parameter
public List<Integer> testints;

@Export.Parameter
public List<BiteBananaActivity> biteBananaActivity;

@Export.Parameter
public PeelBananaActivity peelBananaActivity;


@ActivityType.EffectModel
public void run(final Mission mission) {
for (final var bite : biteBananaActivity) {
call(mission, bite);
delay(Duration.of(30, Duration.MINUTE));
}
call(mission, peelBananaActivity);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
@WithActivityType(ControllableDurationActivity.class)
@WithActivityType(RipenBananaActivity.class)
@WithActivityType(ExceptionActivity.class)

@WithActivityType(RussianBanana.class)
package gov.nasa.jpl.aerie.banananation;

import gov.nasa.jpl.aerie.banananation.activities.BakeBananaBreadActivity;
Expand All @@ -46,6 +46,7 @@
import gov.nasa.jpl.aerie.banananation.activities.PeelBananaActivity;
import gov.nasa.jpl.aerie.banananation.activities.PickBananaActivity;
import gov.nasa.jpl.aerie.banananation.activities.RipenBananaActivity;
import gov.nasa.jpl.aerie.banananation.activities.RussianBanana;
import gov.nasa.jpl.aerie.banananation.activities.ThrowBananaActivity;
import gov.nasa.jpl.aerie.contrib.serialization.rulesets.BasicValueMappers;
import gov.nasa.jpl.aerie.merlin.framework.annotations.MissionModel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import gov.nasa.jpl.aerie.contrib.serialization.mappers.RecordValueMapper;
import gov.nasa.jpl.aerie.merlin.framework.Result;
import gov.nasa.jpl.aerie.merlin.framework.ValueMapper;
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType;
import gov.nasa.jpl.aerie.merlin.framework.annotations.AutoValueMapper;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.MissionModelRecord;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.TypeRule;
Expand Down Expand Up @@ -61,6 +62,24 @@ static TypeRule recordTypeRule(final Element autoValueMapperElement, final Class
ClassName.get((TypeElement) autoValueMapperElement).canonicalName().replace(".", "_"));
}

static TypeRule activityTypeRule(final Element activityTypeElement, final ClassName generatedClassName) throws InvalidMissionModelException {
if (!(activityTypeElement.getKind().equals(ElementKind.CLASS) || activityTypeElement.getKind().equals(ElementKind.RECORD))) { //todo: check if activities are constrained to class and record
throw new InvalidMissionModelException(
"@%s is only allowed on classes and records".formatted(
ActivityType.class.getSimpleName()),
activityTypeElement);
}

return new TypeRule(
new TypePattern.ClassPattern(
ClassName.get(ValueMapper.class),
List.of(TypePattern.from(activityTypeElement.asType()))),
Set.of(),
List.of(),
generatedClassName,
ClassName.get((TypeElement) activityTypeElement).canonicalName().replace("activities", "generated_activitiesValueMappers").replace(".", "_") + "ValueMapper");
}

static TypeRule annotationTypeRule(final Element autoValueMapperElement, final ClassName generatedClassName) throws InvalidMissionModelException {
if (!autoValueMapperElement.getKind().equals(ElementKind.ANNOTATION_TYPE)) {
throw new InvalidMissionModelException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export;
import gov.nasa.jpl.aerie.merlin.framework.annotations.MissionModel;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ActivityTypeRecord;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ActivityValueMapperRecord;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.InputTypeRecord;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.EffectModelRecord;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ExportDefaultsStyle;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.MapperRecord;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ActivityMapperRecord;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.MissionModelRecord;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ParameterRecord;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.ParameterValidationRecord;
Expand Down Expand Up @@ -183,9 +184,10 @@ private Optional<InputTypeRecord> getMissionModelConfigurationType(final Package
final var name = declaration.getSimpleName().toString();
final var parameters = getExportParameters(declaration);
final var validations = this.getExportValidations(declaration, parameters);
final var mapper = getExportMapper(missionModelElement, declaration);
final var activityMapper = getExportActivityMapper(missionModelElement, declaration);
final var valueMapper = getExportValueMapper(missionModelElement, declaration);
final var defaultsStyle = getExportDefaultsStyle(declaration);
return Optional.of(new InputTypeRecord(name, declaration, parameters, validations, mapper, defaultsStyle));
return Optional.of(new InputTypeRecord(name, declaration, parameters, validations, activityMapper, valueMapper, defaultsStyle));
}

private List<TypeElement> getMissionModelMapperClasses(final PackageElement missionModelElement)
Expand Down Expand Up @@ -381,7 +383,8 @@ private ActivityTypeRecord parseActivityType(final PackageElement missionModelEl
{
final var fullyQualifiedClassName = activityTypeElement.getQualifiedName();
final var name = this.getActivityTypeName(activityTypeElement);
final var mapper = this.getExportMapper(missionModelElement, activityTypeElement);
final var activityMapper = getExportActivityMapper(missionModelElement, activityTypeElement);
final var valueMapper = getExportValueMapper(missionModelElement, activityTypeElement);
final var parameters = this.getExportParameters(activityTypeElement);
final var validations = this.getExportValidations(activityTypeElement, parameters);
final var effectModel = this.getActivityEffectModel(activityTypeElement);
Expand All @@ -405,7 +408,7 @@ class (old-style) or as a record (new-style) by determining
return new ActivityTypeRecord(
fullyQualifiedClassName.toString(),
name,
new InputTypeRecord(name, activityTypeElement, parameters, validations, mapper, defaultsStyle),
new InputTypeRecord(name, activityTypeElement, parameters, validations, activityMapper, valueMapper, defaultsStyle),
effectModel);
}

Expand Down Expand Up @@ -471,12 +474,12 @@ private String getActivityTypeName(final TypeElement activityTypeElement)
return (String) nameAttribute.getValue();
}

private MapperRecord getExportMapper(final PackageElement missionModelElement, final TypeElement exportTypeElement)
private ActivityMapperRecord getExportActivityMapper(final PackageElement missionModelElement, final TypeElement exportTypeElement)
throws InvalidMissionModelException
{
final var annotationMirror = this.getAnnotationMirrorByType(exportTypeElement, ActivityType.WithMapper.class);
if (annotationMirror.isEmpty()) {
return MapperRecord.generatedFor(
return ActivityMapperRecord.generatedFor(
ClassName.get(exportTypeElement),
missionModelElement);
}
Expand All @@ -488,7 +491,27 @@ private MapperRecord getExportMapper(final PackageElement missionModelElement, f
annotationMirror.get()))
.getValue();

return MapperRecord.custom(
return ActivityMapperRecord.custom(
ClassName.get((TypeElement) mapperType.asElement()));
}
private ActivityValueMapperRecord getExportValueMapper(final PackageElement missionModelElement, final TypeElement exportTypeElement)
throws InvalidMissionModelException
{
final var annotationMirror = this.getAnnotationMirrorByType(exportTypeElement, ActivityType.WithMapper.class);
if (annotationMirror.isEmpty()) {
return ActivityValueMapperRecord.generatedFor(
ClassName.get(exportTypeElement),
missionModelElement);
}

final var mapperType = (DeclaredType) getAnnotationAttribute(annotationMirror.get(), "value")
.orElseThrow(() -> new InvalidMissionModelException(
"Unable to get value attribute of annotation",
exportTypeElement,
annotationMirror.get()))
.getValue();

return ActivityValueMapperRecord.custom(
ClassName.get((TypeElement) mapperType.asElement()));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package gov.nasa.jpl.aerie.merlin.processor;

import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.TypeName;
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType;
import gov.nasa.jpl.aerie.merlin.framework.annotations.AutoValueMapper;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export;
import gov.nasa.jpl.aerie.merlin.framework.annotations.MissionModel;
import gov.nasa.jpl.aerie.merlin.processor.generator.MissionModelGenerator;
import gov.nasa.jpl.aerie.merlin.processor.metamodel.MissionModelRecord;
Expand All @@ -26,6 +29,7 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -92,9 +96,10 @@ public boolean process(final Set<? extends TypeElement> annotations, final Round
for (final var element : roundEnv.getElementsAnnotatedWith(MissionModel.class)) {
final var recordAutoValueMapperRequests = roundEnv.getElementsAnnotatedWith(AutoValueMapper.Record.class);
final var annotationAutoValueMapperRequests = roundEnv.getElementsAnnotatedWith(AutoValueMapper.Annotation.class);

final var packageElement = (PackageElement) element;
try {
final var missionModelRecord$ = missionModelParser.parseMissionModel(packageElement);
final var missionModelRecord$ = missionModelParser.parseMissionModel(packageElement); //todo: add typerules for activity parameters

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

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


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


for (final var activityRecord : missionModelRecord.activityTypes()) {
this.ownedActivityTypes.add(activityRecord.inputType().declaration());
if (!activityRecord.inputType().mapper().isCustom) {
if (!activityRecord.inputType().activityMapper().isCustom) {
missionModelGen.generateActivityMapper(missionModelRecord, activityRecord).ifPresent(generatedFiles::add);
}
}

generatedFiles.add(missionModelGen.generateActivityValueMappers(missionModelRecord));

for (final var generatedFile : generatedFiles) {
this.messager.printMessage(
Diagnostic.Kind.NOTE,
Expand Down
Loading

0 comments on commit 33291f4

Please sign in to comment.