Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package gov.nasa.jpl.aerie.contrib.metadata;

import gov.nasa.jpl.aerie.contrib.serialization.mappers.StringValueMapper;
import gov.nasa.jpl.aerie.merlin.framework.MetadataValueMapper;
import gov.nasa.jpl.aerie.merlin.framework.Registrar;
import gov.nasa.jpl.aerie.merlin.framework.Resource;
Expand All @@ -19,8 +18,17 @@ public static <T> ValueMapper<T> withUnit(final String unit, final ValueMapper<T
public static <T> void discreteResource(final Registrar registrar, final String name, final Resource<T> resource, final ValueMapper<T> valueMapper, final String unit) {
registrar.discrete(name, resource, withUnit(unit, valueMapper));
}

public static <T> void discreteResource(final Registrar registrar, final String name, final Resource<T> resource, final ValueMapper<T> valueMapper, final String unit, final String description) {
registrar.discrete(name, resource, withUnit(unit, valueMapper), description);
}

public static void realResource(final Registrar registrar, final String name, final Resource<RealDynamics> resource, final String unit) {
registrar.realWithMetadata(name, resource, "unit", unit, new ValueMapper<String>() {
realResource(registrar, name, resource, unit, null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not disagreeing with the design, but why was null chosen to represent a lack of description as opposed to a) Optional.empty() or b) the empty string?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with null because it keeps resource registration simple since you only have to pass a string instead of wrapping it in an optional.of() every time you want to add a description on a resource. I could change it to use an empty string instead if that is preferable!

}

public static void realResource(final Registrar registrar, final String name, final Resource<RealDynamics> resource, final String unit, final String description) {
registrar.realWithMetadata(name, resource, "unit", unit, new ValueMapper<>() {
@Override
public ValueSchema getValueSchema() {
return ValueSchema.ofStruct(Map.of("value", ValueSchema.STRING));
Expand All @@ -39,6 +47,6 @@ public Result<String, String> deserializeValue(final SerializedValue serializedV
public SerializedValue serializeValue(final String value) {
return SerializedValue.of(Map.of("value", SerializedValue.of(value)));
}
});
}, description);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,29 +79,37 @@ public void clearProfile() {
profile = false;
}

public <Value> void discrete(final String name, final Resource<Discrete<Value>> resource, final ValueMapper<Value> mapper) {
public <Value> void discrete(final String name, final Resource<Discrete<Value>> resource, final ValueMapper<Value> mapper, final String description) {
name(resource, name);
var debugResource = debug(name, resource);
gov.nasa.jpl.aerie.merlin.framework.Resource<Value> registeredResource = switch (errorBehavior) {
case Log -> () -> currentValue(debugResource, null);
case Throw -> wrapErrors(name, () -> currentValue(debugResource));
};
baseRegistrar.discrete(name, registeredResource, new NullableValueMapper<>(mapper));
baseRegistrar.discrete(name, registeredResource, new NullableValueMapper<>(mapper), description);
if (errorBehavior.equals(Log)) logErrors(name, debugResource);
}

public void real(final String name, final Resource<Linear> resource) {
public <Value> void discrete(final String name, final Resource<Discrete<Value>> resource, final ValueMapper<Value> mapper) {
discrete(name, resource, mapper, null);
}

public void real(final String name, final Resource<Linear> resource, final String description) {
name(resource, name);
var debugResource = debug(name, resource);
gov.nasa.jpl.aerie.merlin.framework.Resource<RealDynamics> registeredResource = switch (errorBehavior) {
case Log -> () -> realDynamics(currentData(debugResource, linear(0, 0)));
case Throw -> wrapErrors(name, () -> realDynamics(currentData(debugResource)));
};
baseRegistrar.real(name, registeredResource);
baseRegistrar.real(name, registeredResource, description);
if (errorBehavior.equals(Log)) logErrors(name, debugResource);
}

private static RealDynamics realDynamics(Linear linear) {
public void real(final String name, final Resource<Linear> resource) {
real(name, resource, null);
}

private static RealDynamics realDynamics(Linear linear) {
return RealDynamics.linear(linear.extract(), linear.rate());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

alter table merlin.activity_type
drop column description;
alter table merlin.resource_type
drop column description;

call migrations.mark_migration_rolled_back(28);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
alter table merlin.activity_type
add column description text default null;
comment on column merlin.activity_type.description is e''
'The description of this activity type.';

alter table merlin.resource_type
add column description text default null;
comment on column merlin.resource_type.description is e''
'The description of this resource type.';

call migrations.mark_migration_applied(28);
1 change: 1 addition & 0 deletions deployment/postgres-init-db/sql/applied_migrations.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ call migrations.mark_migration_applied(24);
call migrations.mark_migration_applied(25);
call migrations.mark_migration_applied(26);
call migrations.mark_migration_applied(27);
call migrations.mark_migration_applied(28);
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ create table merlin.activity_type (
subsystem integer references tags.tags
on update cascade
on delete restrict,
description text,

constraint activity_type_pkey
primary key (model_id, name),
Expand All @@ -31,3 +32,5 @@ comment on column merlin.activity_type.computed_attributes_value_schema is e''
'The type of value returned by the effect model of this activity type';
comment on column merlin.activity_type.subsystem is e''
'The subsystem this activity type belongs to.';
comment on column merlin.activity_type.description is e''
'The description of this activity type.';
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ create table merlin.resource_type (
model_id integer not null,
name text not null,
schema jsonb not null,
description text,

constraint resource_type_pkey
primary key (model_id, name),
Expand All @@ -20,3 +21,5 @@ comment on column merlin.resource_type.model_id is e''
'The model defining this resource type.';
comment on column merlin.resource_type.schema is e''
'The structure of this resource type.';
comment on column merlin.resource_type.description is e''
'The description of this resource type.';
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,18 @@ private ArrayList<ResourceType> expectedResourceTypesBanananation(){
resourceTypes.add(new ResourceType("/data/line_count", VALUE_SCHEMA_INT));
resourceTypes.add(new ResourceType(
"/flag",
new ValueSchemaVariant(List.of(new Variant("A", "A"), new Variant("B", "B")))));
new ValueSchemaVariant(List.of(new Variant("A", "A"), new Variant("B", "B"))),
"The flag set"
));
resourceTypes.add(new ResourceType("/flag/conflicted", VALUE_SCHEMA_BOOLEAN));
resourceTypes.add(new ResourceType(
"/fruit",
new ValueSchemaMeta(Map.of("unit", Json.createObjectBuilder(Map.of("value", "bananas")).build()), new ValueSchemaStruct(Map.of("rate", VALUE_SCHEMA_REAL, "initial", VALUE_SCHEMA_REAL)))));
new ValueSchemaMeta(Map.of("unit", Json.createObjectBuilder(Map.of("value", "bananas")).build()), new ValueSchemaStruct(Map.of("rate", VALUE_SCHEMA_REAL, "initial", VALUE_SCHEMA_REAL))),
"The number of fruits collected"
));
resourceTypes.add(new ResourceType("/peel", new ValueSchemaMeta(Map.of("unit", Json.createObjectBuilder(Map.of("value", "kg")).build()), VALUE_SCHEMA_REAL)));
resourceTypes.add(new ResourceType("/plant", new ValueSchemaMeta(Map.of("unit", Json.createObjectBuilder(Map.of("value", "count")).build()), VALUE_SCHEMA_INT)));
resourceTypes.add(new ResourceType("/producer", VALUE_SCHEMA_STRING));
resourceTypes.add(new ResourceType("/producer", VALUE_SCHEMA_STRING, "The producer of the fruit"));
return resourceTypes;
}

Expand All @@ -88,17 +92,19 @@ private ArrayList<ActivityType> expectedActivityTypesBanananation() {
activityTypes.add(new ActivityType(
"BakeBananaBread",
Map.of(
"tbSugar", new Parameter(1, VALUE_SCHEMA_INT),
"tbSugar", new Parameter(1, VALUE_SCHEMA_INT, "Tablespoons of sugar to add"),
"glutenFree", new Parameter(2, VALUE_SCHEMA_BOOLEAN),
"temperature", new Parameter(0, VALUE_SCHEMA_REAL)),
"temperature", new Parameter(0, VALUE_SCHEMA_REAL, "The baking temperature in degrees Fahrenheit")),
VALUE_SCHEMA_INT,
"Prepare"));
"Prepare",
"Bakes banana bread at a certain temperature"));
activityTypes.add(new ActivityType("BananaNap", Map.of()));
activityTypes.add(new ActivityType(
"BiteBanana",
Map.of("biteSize", new Parameter(0, new ValueSchemaMeta(Map.of("unit", Json.createObjectBuilder(Map.of("value", "m")).build(), "banannotation", Json.createObjectBuilder().add("value", Json.createValue("Specifies the size of bite to take")).build()), VALUE_SCHEMA_REAL))),
Map.of("biteSize", new Parameter(0, new ValueSchemaMeta(Map.of("unit", Json.createObjectBuilder(Map.of("value", "m")).build(), "banannotation", Json.createObjectBuilder().add("value", Json.createValue("Specifies the size of bite to take")).build()), VALUE_SCHEMA_REAL), "The size of the bite in meters")),
new ValueSchemaStruct(Map.of("biteSizeWasBig", VALUE_SCHEMA_BOOLEAN, "newFlag", new ValueSchemaVariant(List.of(new Variant("A", "A"), new Variant("B", "B"))))),
"Eat"
"Eat",
"Takes a bite out of the banana"
));
activityTypes.add(new ActivityType("ChangeProducer", Map.of("producer", new Parameter(0, VALUE_SCHEMA_STRING))));
activityTypes.add(new ActivityType("child", Map.of("counter", new Parameter(0, VALUE_SCHEMA_INT))));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,27 @@
import java.util.Map;


public record ActivityType(String name, Map<String, Parameter> parameters, ValueSchema computedAttributes, String subsystem) {
public record ActivityType(String name, Map<String, Parameter> parameters, ValueSchema computedAttributes, String subsystem, String description) {
/**
* Create an ActivityType with an empty computed attributes value schema.
*/
public ActivityType(final String name, final Map<String, Parameter> parameters, final String subsystem) {
this(name, parameters, new ValueSchema.ValueSchemaStruct(Map.of()), subsystem);
this(name, parameters, new ValueSchema.ValueSchemaStruct(Map.of()), subsystem, null);
}

/**
* Create an ActivityType with an empty computed attributes value schema and no subsystem.
* Create an ActivityType with an empty computed attributes value schema and no description.
*/
public ActivityType(final String name, final Map<String, Parameter> parameters) {
this(name, parameters, new ValueSchema.ValueSchemaStruct(Map.of()), null);
this(name, parameters, new ValueSchema.ValueSchemaStruct(Map.of()), null, null);
}

public ActivityType(final String name, final Map<String, Parameter> parameters, final ValueSchema computedAttributes, final String subsystem) {
this(name, parameters, computedAttributes, subsystem, null);
}

public ActivityType(final String name, final Map<String, Parameter> parameters, final ValueSchema computedAttributes) {
this(name, parameters, new ValueSchema.ValueSchemaStruct(Map.of()), null, null);
}

public static ActivityType fromJSON(JsonObject json) {
Expand All @@ -27,15 +35,26 @@ public static ActivityType fromJSON(JsonObject json) {
parameterMap.put(parameterName, Parameter.fromJSON(parameters.getJsonObject(parameterName)));
}
final var subsystem = json.isNull("subsystem") ? null : json.getJsonObject("subsystem").getString("name");
final var description = json.isNull("description") ? null : json.getString("description");
return new ActivityType(json.getString("name"),
parameterMap,
ValueSchema.fromJSON(json.getJsonObject("computed_attributes_value_schema")),
subsystem);
subsystem,
description);
}

public record Parameter(int order, ValueSchema schema) {
public record Parameter(int order, ValueSchema schema, String description) {
public static Parameter fromJSON(JsonObject json) {
return new Parameter(json.getInt("order"), ValueSchema.fromJSON(json.getJsonObject("schema")));
if (json.containsKey("description")) {
final var description = json.isNull("description") ? null : json.getString("description");
return new Parameter(json.getInt("order"), ValueSchema.fromJSON(json.getJsonObject("schema")), description);
} else {
return new Parameter(json.getInt("order"), ValueSchema.fromJSON(json.getJsonObject("schema")));
}
}

public Parameter(int order, ValueSchema schema) {
this(order, schema, null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

import javax.json.JsonObject;

public record ResourceType(String name, ValueSchema schema){
public record ResourceType(String name, ValueSchema schema, String description) {
public static ResourceType fromJSON(JsonObject json){
return new ResourceType(json.getString("name"), ValueSchema.fromJSON(json.getJsonObject("schema")));
final var description = json.isNull("description") ? null : json.getString("description");
return new ResourceType(json.getString("name"), ValueSchema.fromJSON(json.getJsonObject("schema")), description);
}
public ResourceType(String name, ValueSchema schema) {
this(name, schema, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ query GetActivityTypes($missionModelId: Int!) {
subsystem:subsystem_tag {
name
}
description
}
}"""),
GET_CONSTRAINT_REQUEST("""
Expand Down Expand Up @@ -489,6 +490,7 @@ query GetResourceTypes($missionModelId: Int!) {
resource_type(where: {model_id: {_eq: $missionModelId}}, order_by: {name: asc}) {
name
schema
description
}
}"""),
GET_ROLE_ACTION_PERMISSIONS("""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ public Mission(final Registrar registrar, final Configuration config) {
this.producer = Register.forImmutable(config.initialProducer());
this.dataLineCount = Register.forImmutable(countLines(config.initialDataPath()));

registrar.discrete("/flag", this.flag, new EnumValueMapper<>(Flag.class));
registrar.discrete("/flag", this.flag, new EnumValueMapper<>(Flag.class), "The flag set");
registrar.discrete("/flag/conflicted", this.flag::isConflicted, new BooleanValueMapper());
discreteResource(registrar, "/peel", this.peel, new DoubleValueMapper(), "kg");
realResource(registrar, "/fruit", this.fruit, "bananas");
realResource(registrar, "/fruit", this.fruit, "bananas", "The number of fruits collected");
discreteResource(registrar, "/plant", this.plant, new IntegerValueMapper(), "count");
registrar.discrete("/producer", this.producer, new StringValueMapper());
registrar.discrete("/producer", this.producer, new StringValueMapper(), "The producer of the fruit");
registrar.discrete("/data/line_count", this.dataLineCount, new IntegerValueMapper());
registrar.topic("/producer", this.producer.ref, new StringValueMapper());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import gov.nasa.jpl.aerie.contrib.models.ValidationResult;
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType;
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType.EffectModel;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Description;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export.Validation;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export.WithDefaults;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Subsystem;

@ActivityType("BakeBananaBread")
@Subsystem("Prepare")
public record BakeBananaBreadActivity(double temperature, int tbSugar, boolean glutenFree) {
@Description("Bakes banana bread at a certain temperature")
public record BakeBananaBreadActivity(@Description("The baking temperature in degrees Fahrenheit") double temperature,
@Description("Tablespoons of sugar to add") int tbSugar,
boolean glutenFree) {

@Validation
public ValidationResult validateTemperatures() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType;
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType.EffectModel;
import gov.nasa.jpl.aerie.merlin.framework.annotations.AutoValueMapper;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Description;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export.Parameter;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export.Validation;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Subsystem;
Expand All @@ -20,9 +21,10 @@
*/
@ActivityType("BiteBanana")
@Subsystem("Eat")
@Description("Takes a bite out of the banana")
public final class BiteBananaActivity {
@Parameter

@Description("The size of the bite in meters")
@Banannotation("Specifies the size of bite to take")
Comment on lines +27 to 28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between Description and Banannotation here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@description is an Aerie supported annotation; @Banannotation is a model specific custom annotation. They both hold the same kind of data (a description of the parameter), just created in two different ways. I can move one to a different parameter to avoid having both on the same field if that’s clearer.

@Unit("m")
public double biteSize = 1.0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import gov.nasa.jpl.aerie.banananation.Mission;
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType;
import gov.nasa.jpl.aerie.merlin.framework.annotations.ActivityType.EffectModel;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Description;
import gov.nasa.jpl.aerie.merlin.framework.annotations.Export.Parameter;

/**
* Changes the active banana producer.
*/
@ActivityType("ChangeProducer")
@Description("Changes the producer, the default being Dole")
public final class ChangeProducerActivity {
@Parameter
public String producer = "Dole";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,13 @@ public DataModel(final Registrar registrar, final Configuration config) {
}

private void registerStates(Registrar registrar, Configuration config) {
registrar.real("desiredRateA", assumeLinear(desiredRateA));
registrar.real("desiredRateB", assumeLinear(desiredRateB));
registrar.real("desiredRateC", assumeLinear(desiredRateC));
registrar.real("desiredRateA", assumeLinear(desiredRateA), "The desiredRateA description");
registrar.real("desiredRateB", assumeLinear(desiredRateB), "The desiredRateB description");
registrar.real("desiredRateC", assumeLinear(desiredRateC), "The desiredRateC description");

registrar.real("actualRateA", assumeLinear(actualRateA));
registrar.real("actualRateB", assumeLinear(actualRateB));
registrar.real("actualRateC", assumeLinear(actualRateC));
registrar.real("actualRateA", assumeLinear(actualRateA), "The actualRateA description");
registrar.real("actualRateB", assumeLinear(actualRateB), "The actualRateB description");
registrar.real("actualRateC", assumeLinear(actualRateC), "The actualRateC description");

registrar.real("volumeA", assumeLinear(volumeA));
registrar.real("volumeB", assumeLinear(volumeB));
Expand Down
Loading
Loading