diff --git a/src/main/java/org/gridsuite/mapping/server/MappingConstants.java b/src/main/java/org/gridsuite/mapping/server/MappingConstants.java index d201932f..cf9ed5f2 100644 --- a/src/main/java/org/gridsuite/mapping/server/MappingConstants.java +++ b/src/main/java/org/gridsuite/mapping/server/MappingConstants.java @@ -17,6 +17,7 @@ private MappingConstants() { public static String EQUIPMENT_ID = "equipment.id"; public static String IMPORT = "import com.powsybl.iidm.network."; + public static String AUTOMATON_IMPORT = "import com.powsybl.dynawaltz.automatons.CurrentLimitAutomaton\nimport com.powsybl.iidm.network.Branch"; public static String DEFAULT_MAPPING_NAME = "default"; public static final String CASE_API_VERSION = "v1"; @@ -33,4 +34,5 @@ private MappingConstants() { // Loads public static final String LOAD_TYPE_PROPERTY = "loadType"; + public static final String CURRENT_LIMIT_MODEL_CLASS = "CurrentLimitAutomaton"; } diff --git a/src/main/java/org/gridsuite/mapping/server/dto/InputMapping.java b/src/main/java/org/gridsuite/mapping/server/dto/InputMapping.java index 908f0a99..488a335d 100644 --- a/src/main/java/org/gridsuite/mapping/server/dto/InputMapping.java +++ b/src/main/java/org/gridsuite/mapping/server/dto/InputMapping.java @@ -9,6 +9,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Data; +import org.gridsuite.mapping.server.dto.automata.AbstractAutomaton; import org.gridsuite.mapping.server.model.MappingEntity; import java.util.List; @@ -27,15 +28,20 @@ public class InputMapping implements Mapping { @Schema(description = "Mapping rules") private List rules; + @Schema(description = "Mapping automata") + private List automata; + public MappingEntity convertMappingToEntity() { MappingEntity convertedMapping = new MappingEntity(); convertedMapping.setName(name); convertedMapping.setRules(rules.stream().map(rule -> rule.convertRuleToEntity(convertedMapping)).collect(Collectors.toList())); + convertedMapping.setAutomata(automata.stream().map(automaton -> automaton.convertAutomatonToEntity(convertedMapping)).collect(Collectors.toList())); return convertedMapping; } public InputMapping(MappingEntity mappingEntity) { name = mappingEntity.getName(); rules = mappingEntity.getRules().stream().map(ruleEntity -> new Rule(ruleEntity)).collect(Collectors.toList()); + automata = mappingEntity.getAutomata().stream().map(automatonEntity -> AbstractAutomaton.instantiateFromEntity(automatonEntity)).collect(Collectors.toList()); } } diff --git a/src/main/java/org/gridsuite/mapping/server/dto/automata/AbstractAutomaton.java b/src/main/java/org/gridsuite/mapping/server/dto/automata/AbstractAutomaton.java new file mode 100644 index 00000000..80413f79 --- /dev/null +++ b/src/main/java/org/gridsuite/mapping/server/dto/automata/AbstractAutomaton.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2021, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.mapping.server.dto.automata; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.gridsuite.mapping.server.model.AutomatonEntity; +import org.gridsuite.mapping.server.model.MappingEntity; +import org.gridsuite.mapping.server.utils.AutomatonFamily; +import org.springframework.http.HttpStatus; +import org.springframework.web.client.HttpClientErrorException; + +import java.util.ArrayList; + +/** + * @author Mathieu Scalbert + */ +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "family", visible = true) +@JsonSubTypes({ + @JsonSubTypes.Type(value = CurrentLimitAutomaton.class, name = "CURRENT_LIMIT")}) +@Data +public abstract class AbstractAutomaton { + @Schema(description = "Automaton family") + @JsonProperty + private AutomatonFamily family; + + @Schema(description = "Mapped Model Instance ID") + private String model; + + @Schema(description = "Element watched by the automaton") + private String watchedElement; + + public abstract ArrayList convertToBasicProperties(); + + public abstract AutomatonEntity convertAutomatonToEntity(MappingEntity parentMapping); + + public static AbstractAutomaton instantiateFromEntity(AutomatonEntity automatonEntity) { + if (automatonEntity.getFamily() == AutomatonFamily.CURRENT_LIMIT) { + return new CurrentLimitAutomaton(automatonEntity); + } else { + throw new HttpClientErrorException(HttpStatus.BAD_REQUEST); + } + } +} + diff --git a/src/main/java/org/gridsuite/mapping/server/dto/automata/BasicProperty.java b/src/main/java/org/gridsuite/mapping/server/dto/automata/BasicProperty.java new file mode 100644 index 00000000..f63323cb --- /dev/null +++ b/src/main/java/org/gridsuite/mapping/server/dto/automata/BasicProperty.java @@ -0,0 +1,12 @@ +package org.gridsuite.mapping.server.dto.automata; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class BasicProperty { + private String name; + + private String value; +} diff --git a/src/main/java/org/gridsuite/mapping/server/dto/automata/CurrentLimitAutomaton.java b/src/main/java/org/gridsuite/mapping/server/dto/automata/CurrentLimitAutomaton.java new file mode 100644 index 00000000..366d370f --- /dev/null +++ b/src/main/java/org/gridsuite/mapping/server/dto/automata/CurrentLimitAutomaton.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2021, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.mapping.server.dto.automata; + +import lombok.*; +import org.gridsuite.mapping.server.model.AutomatonEntity; +import org.gridsuite.mapping.server.model.AutomatonPropertyEntity; +import org.gridsuite.mapping.server.model.MappingEntity; +import org.gridsuite.mapping.server.utils.PropertyType; + +import java.util.ArrayList; +import java.util.Optional; +import java.util.UUID; + +/** + * @author Mathieu Scalbert + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +public class CurrentLimitAutomaton extends AbstractAutomaton { + private String side; + + public ArrayList convertToBasicProperties() { + ArrayList propertiesList = new ArrayList<>(); + propertiesList.add(new BasicProperty("side", side)); + return propertiesList; + } + + public CurrentLimitAutomaton(AutomatonEntity automatonEntity) { + this.setFamily(automatonEntity.getFamily()); + this.setModel(automatonEntity.getModel()); + this.setWatchedElement(automatonEntity.getWatchedElement()); + // TODO Create generic function for all properties + Optional foundSideProperty = automatonEntity.getProperties().stream().filter(property -> property.getName().equals("side")).findAny(); + if (foundSideProperty.isPresent()) { + side = foundSideProperty.get().getValue(); + } + } + + public AutomatonEntity convertAutomatonToEntity(MappingEntity parentMapping) { + UUID createdId = UUID.randomUUID(); + AutomatonEntity convertedAutomaton = new AutomatonEntity(); + convertedAutomaton.setAutomatonId(createdId); + convertedAutomaton.setFamily(this.getFamily()); + convertedAutomaton.setModel(this.getModel()); + convertedAutomaton.setWatchedElement(this.getWatchedElement()); + convertedAutomaton.setMapping(parentMapping); + ArrayList convertedProperties = new ArrayList<>(); + AutomatonPropertyEntity convertedProperty = new AutomatonPropertyEntity(); + convertedProperty.setAutomatonId(createdId); + convertedProperty.setName("side"); + convertedProperty.setValue(this.getSide()); + convertedProperty.setType(PropertyType.STRING); + convertedProperties.add(convertedProperty); + convertedAutomaton.setProperties(convertedProperties); + return convertedAutomaton; + } +} + + diff --git a/src/main/java/org/gridsuite/mapping/server/model/AutomatonEntity.java b/src/main/java/org/gridsuite/mapping/server/model/AutomatonEntity.java new file mode 100644 index 00000000..47f89ce7 --- /dev/null +++ b/src/main/java/org/gridsuite/mapping/server/model/AutomatonEntity.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2021, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.mapping.server.model; + +import lombok.*; +import org.gridsuite.mapping.server.utils.AutomatonFamily; +import javax.persistence.*; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author Mathieu Scalbert + */ +@Entity +@Builder +@Table(name = "automata", indexes = {@Index(name = "automaton_mappingName_index", columnList = "mappingName")}) +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class AutomatonEntity extends AbstractManuallyAssignedIdentifierEntity { + + @Id + @Column(name = "automaton_id") + private UUID automatonId; + + @Column(name = "type", nullable = false) + @Enumerated + private AutomatonFamily family; + + @Column(name = "model", nullable = false) + private String model; + + @Column(name = "watched_element", nullable = false) + private String watchedElement; + + @OneToMany(targetEntity = AutomatonPropertyEntity.class, mappedBy = "automaton", cascade = CascadeType.ALL, orphanRemoval = true) + private List properties; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "mappingName", foreignKey = @ForeignKey(name = "mapping_automata_fk"), referencedColumnName = "name") + private MappingEntity mapping; + + @Override + public UUID getId() { + return automatonId; + } + + public AutomatonEntity(MappingEntity mapping, AutomatonEntity automatonToCopy) { + UUID newID = UUID.randomUUID(); + this.automatonId = newID; + this.mapping = mapping; + this.family = automatonToCopy.getFamily(); + this.model = automatonToCopy.getModel(); + this.watchedElement = automatonToCopy.getWatchedElement(); + this.properties = automatonToCopy.getProperties().stream().map(automatonPropertyEntity -> new AutomatonPropertyEntity(newID, automatonPropertyEntity)).collect(Collectors.toList()); + + } +} diff --git a/src/main/java/org/gridsuite/mapping/server/model/AutomatonPropertyEntity.java b/src/main/java/org/gridsuite/mapping/server/model/AutomatonPropertyEntity.java new file mode 100644 index 00000000..980bc4de --- /dev/null +++ b/src/main/java/org/gridsuite/mapping/server/model/AutomatonPropertyEntity.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2021, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.mapping.server.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.gridsuite.mapping.server.utils.PropertyType; + +import javax.persistence.*; +import java.io.Serializable; +import java.util.UUID; + +/** + * @author Mathieu Scalbert + */ + +@Inheritance +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Entity +@Table(name = "automaton_properties", indexes = {@Index(name = "property_automaton_id_index", columnList = "automaton_id")}) +@IdClass(AutomatonPropertyId.class) +public class AutomatonPropertyEntity implements Serializable { + + @Id + @Column(name = "automaton_id") + private UUID automatonId; + + @Id + @Column(name = "name") + private String name; + + @Column(name = "value") + private String value; + + @Column(name = "type") + private PropertyType type; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "automaton_id", foreignKey = @ForeignKey(name = "automata_property_fk")) + @MapsId("automatonId") + private AutomatonEntity automaton; + + public AutomatonPropertyEntity(UUID automatonId, AutomatonPropertyEntity automatonPropertyEntity) { + this.automatonId = automatonId; + this.name = automatonPropertyEntity.getName(); + this.type = automatonPropertyEntity.getType(); + this.value = automatonPropertyEntity.getValue(); + + } + +} diff --git a/src/main/java/org/gridsuite/mapping/server/model/AutomatonPropertyId.java b/src/main/java/org/gridsuite/mapping/server/model/AutomatonPropertyId.java new file mode 100644 index 00000000..30ee0b60 --- /dev/null +++ b/src/main/java/org/gridsuite/mapping/server/model/AutomatonPropertyId.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2021, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.mapping.server.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.persistence.Embeddable; +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; + +/** + * @author Mathieu Scalbert + */ +@NoArgsConstructor +@AllArgsConstructor +@Embeddable +@Getter +@Setter +public class AutomatonPropertyId implements Serializable { + + private String name; + + private UUID automatonId; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AutomatonPropertyId automatonPropertyIdClass = (AutomatonPropertyId) o; + return name.equals(automatonPropertyIdClass.name) && + automatonId.equals(automatonPropertyIdClass.automatonId); + } + + @Override + public int hashCode() { + return Objects.hash(name, automatonId); + } + +} diff --git a/src/main/java/org/gridsuite/mapping/server/model/MappingEntity.java b/src/main/java/org/gridsuite/mapping/server/model/MappingEntity.java index 44e1ac91..3d692048 100644 --- a/src/main/java/org/gridsuite/mapping/server/model/MappingEntity.java +++ b/src/main/java/org/gridsuite/mapping/server/model/MappingEntity.java @@ -28,6 +28,9 @@ public class MappingEntity extends AbstractManuallyAssignedIdentifierEntity rules; + @OneToMany(targetEntity = AutomatonEntity.class, mappedBy = "mapping", cascade = CascadeType.ALL, orphanRemoval = true) + private List automata; + @Override public String getId() { return name; @@ -36,5 +39,6 @@ public String getId() { public MappingEntity(String name, MappingEntity mappingToCopy) { this.name = name; this.rules = mappingToCopy.getRules().stream().map(ruleEntity -> new RuleEntity(this, ruleEntity)).collect(Collectors.toList()); + this.automata = mappingToCopy.getAutomata().stream().map(automatonEntity -> new AutomatonEntity(this, automatonEntity)).collect(Collectors.toList()); } } diff --git a/src/main/java/org/gridsuite/mapping/server/service/implementation/MappingServiceImpl.java b/src/main/java/org/gridsuite/mapping/server/service/implementation/MappingServiceImpl.java index 74fe172f..32f44c94 100644 --- a/src/main/java/org/gridsuite/mapping/server/service/implementation/MappingServiceImpl.java +++ b/src/main/java/org/gridsuite/mapping/server/service/implementation/MappingServiceImpl.java @@ -75,7 +75,7 @@ public RenameObject renameMapping(String oldName, String newName) { } else if (oldName.equals(DEFAULT_MAPPING_NAME)) { // In case of naming of new mapping, save it to db. try { - mappingRepository.save(new MappingEntity(newName, new ArrayList<>())); + mappingRepository.save(new MappingEntity(newName, new ArrayList<>(), new ArrayList<>())); return new RenameObject(DEFAULT_MAPPING_NAME, newName); } catch (DataIntegrityViolationException ex) { diff --git a/src/main/java/org/gridsuite/mapping/server/service/implementation/ScriptServiceImpl.java b/src/main/java/org/gridsuite/mapping/server/service/implementation/ScriptServiceImpl.java index b773b983..0c3a304c 100644 --- a/src/main/java/org/gridsuite/mapping/server/service/implementation/ScriptServiceImpl.java +++ b/src/main/java/org/gridsuite/mapping/server/service/implementation/ScriptServiceImpl.java @@ -14,6 +14,7 @@ import static java.util.stream.Collectors.groupingBy; import org.gridsuite.mapping.server.dto.*; +import org.gridsuite.mapping.server.dto.automata.AbstractAutomaton; import org.gridsuite.mapping.server.model.InstanceModelEntity; import org.gridsuite.mapping.server.model.MappingEntity; import org.gridsuite.mapping.server.model.ScriptEntity; @@ -123,9 +124,11 @@ public Script copyScript(String originalName, String copyName) { public class SortedMapping implements Mapping { private String name; private ArrayList sortedRules; + private ArrayList automata; public SortedMapping(InputMapping mapping) { name = mapping.getName(); + automata = (ArrayList) mapping.getAutomata(); sortedRules = new ArrayList<>(); Map> sortingRules = mapping.getRules().stream().collect(groupingBy(Rule::getEquipmentType)); for (EquipmentType type : sortingRules.keySet()) { diff --git a/src/main/java/org/gridsuite/mapping/server/utils/AutomatonFamily.java b/src/main/java/org/gridsuite/mapping/server/utils/AutomatonFamily.java new file mode 100644 index 00000000..5687c8af --- /dev/null +++ b/src/main/java/org/gridsuite/mapping/server/utils/AutomatonFamily.java @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2021, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.mapping.server.utils; + +/** + * @author Mathieu Scalbert + */ +public enum AutomatonFamily { + CURRENT_LIMIT, +} diff --git a/src/main/java/org/gridsuite/mapping/server/utils/Templater.java b/src/main/java/org/gridsuite/mapping/server/utils/Templater.java index 1288fbfc..388b3066 100644 --- a/src/main/java/org/gridsuite/mapping/server/utils/Templater.java +++ b/src/main/java/org/gridsuite/mapping/server/utils/Templater.java @@ -42,16 +42,21 @@ public static String mappingToScript(ScriptServiceImpl.SortedMapping sortedMappi String scriptTemplate; String sortedRulesTemplate; String ruleTemplate; + String automatonTemplate; + String automatonPropertyTemplate; try { scriptTemplate = IOUtils.toString(new ClassPathResource("script.st").getInputStream(), Charset.defaultCharset()); sortedRulesTemplate = IOUtils.toString(new ClassPathResource("sortedRules.st").getInputStream(), Charset.defaultCharset()); ruleTemplate = IOUtils.toString(new ClassPathResource("rule.st").getInputStream(), Charset.defaultCharset()); + automatonTemplate = IOUtils.toString(new ClassPathResource("automaton.st").getInputStream(), Charset.defaultCharset()); + automatonPropertyTemplate = IOUtils.toString(new ClassPathResource("automatonProperty.st").getInputStream(), Charset.defaultCharset()); } catch (IOException e) { throw new RuntimeException("Unable to load templates for groovy script generation !!"); } ST script = new ST(scriptTemplate); ArrayList imports = new ArrayList<>(); + // Rules String[] sortedRulesScripts = sortedMapping.getSortedRules().stream().map(sortedRules -> { // Preparing the imports imports.add(MappingConstants.IMPORT + sortedRules.getEquipmentClass()); @@ -71,11 +76,34 @@ public static String mappingToScript(ScriptServiceImpl.SortedMapping sortedMappi return sortedRulesScript.render(); }).toArray(String[]::new); + // Automata + String[] automataScripts = sortedMapping.getAutomata().stream().map(automaton -> { + String familyModel = new String(); + switch (automaton.getFamily()) { + case CURRENT_LIMIT: + familyModel = MappingConstants.CURRENT_LIMIT_MODEL_CLASS; + } + imports.add(MappingConstants.AUTOMATON_IMPORT); + ST automatonScript = new ST(automatonTemplate); + automatonScript.add("familyModel", familyModel); + automatonScript.add("watchedElement", automaton.getWatchedElement()); + automatonScript.add("modelName", automaton.getModel()); + // TODO add separation if different + automatonScript.add("parameterSetId", automaton.getModel()); + String[] propertiesScripts = automaton.convertToBasicProperties().stream().map(property -> { + ST propertyScript = new ST(automatonPropertyTemplate); + propertyScript.add("name", property.getName()); + propertyScript.add("value", property.getValue()); + return propertyScript.render(); + }).toArray(String[]::new); + automatonScript.add("properties", propertiesScripts); + return automatonScript.render(); + }).toArray(String[]::new); // Filling the main template script.add("imports", imports.toArray()); script.add("sortedRules", sortedRulesScripts); - - // TODO + script.add("automata", automataScripts); + script.add("addReturns", automataScripts.length > 0 && sortedRulesScripts.length > 0); return script.render(); } diff --git a/src/main/resources/automaton.st b/src/main/resources/automaton.st new file mode 100644 index 00000000..352469f1 --- /dev/null +++ b/src/main/resources/automaton.st @@ -0,0 +1,6 @@ + { + staticId "" + dynamicModelId "" + parameterSetId "" + +} \ No newline at end of file diff --git a/src/main/resources/automatonProperty.st b/src/main/resources/automatonProperty.st new file mode 100644 index 00000000..688d7a78 --- /dev/null +++ b/src/main/resources/automatonProperty.st @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/mappings.sql b/src/main/resources/mappings.sql index bf46c152..16c797ab 100644 --- a/src/main/resources/mappings.sql +++ b/src/main/resources/mappings.sql @@ -1,4 +1,21 @@ + create table automata ( + automaton_id uuid not null, + type int4 not null, + model varchar(255) not null, + watched_element varchar(255) not null, + mappingName varchar(255), + primary key (automaton_id) + ); + + create table automaton_properties ( + automaton_id uuid not null, + name varchar(255) not null, + type int4, + value varchar(255), + primary key (automaton_id, name) + ); + create table filters ( filter_id varchar(255) not null, rule_id uuid not null, @@ -44,9 +61,21 @@ script TEXT not null, primary key (name) ); +create index automaton_mappingName_index on automata (mappingName); +create index property_automaton_id_index on automaton_properties (automaton_id); create index filter_rule_id_index on filters (rule_id); create index rule_mappingName_index on rules (mappingName); + alter table if exists automata + add constraint mapping_automata_fk + foreign key (mappingName) + references mappings; + + alter table if exists automaton_properties + add constraint automata_property_fk + foreign key (automaton_id) + references automata; + alter table if exists filters add constraint rules_filter_fk foreign key (rule_id) diff --git a/src/main/resources/script.st b/src/main/resources/script.st index 0fda65f4..daad9095 100644 --- a/src/main/resources/script.st +++ b/src/main/resources/script.st @@ -7,4 +7,6 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/src/test/java/org/gridsuite/mapping/server/MappingControllerTest.java b/src/test/java/org/gridsuite/mapping/server/MappingControllerTest.java index 9aac7fe1..292dac19 100644 --- a/src/test/java/org/gridsuite/mapping/server/MappingControllerTest.java +++ b/src/test/java/org/gridsuite/mapping/server/MappingControllerTest.java @@ -85,6 +85,14 @@ String mapping(String name) { " ],\n" + " \"mappedModel\": \"mappedExample\"\n" + " }\n" + + " ],\n" + + " \"automata\": [\n" + + " {\n" + + " \"family\": \"CURRENT_LIMIT\",\n" + + " \"model\": \"automaton_model\",\n" + + " \"watchedElement\": \"element_id\",\n" + + " \"side\": \"Branch.Side.ONE\"\n" + + " }\n" + " ]\n" + "}"; diff --git a/src/test/java/org/gridsuite/mapping/server/ScriptControllerTest.java b/src/test/java/org/gridsuite/mapping/server/ScriptControllerTest.java index cffe56bd..aa2ef764 100644 --- a/src/test/java/org/gridsuite/mapping/server/ScriptControllerTest.java +++ b/src/test/java/org/gridsuite/mapping/server/ScriptControllerTest.java @@ -23,9 +23,7 @@ import org.springframework.test.web.servlet.MockMvc; import static org.springframework.http.MediaType.APPLICATION_JSON; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -102,13 +100,27 @@ String mapping(String name, String modelName) { " ],\n" + " \"mappedModel\": \"" + modelName + "\"\n" + " }\n" + + " ],\n" + + " \"automata\": [\n" + + " {\n" + + " \"family\": \"CURRENT_LIMIT\",\n" + + " \"model\": \"automaton_model\",\n" + + " \"watchedElement\": \"element_id\",\n" + + " \"side\": \"Branch.Side.ONE\"\n" + + " }\n" + " ]\n" + "}"; } String scriptOutput(String scriptName, String parentName) { - return "{\"name\":\"" + scriptName + "\",\"parentName\":\"" + parentName + "\",\"script\":\"/**\n * Copyright (c) 2021, RTE (http://www.rte-france.com)\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n */\n\nimport com.powsybl.iidm.network.Generator\n\nfor (Generator equipment : network.generators) {\n if (equipment.id.equals(\\\"test\\\") && equipment.minP > 3.000000 && [\\\"HYDRO\\\", \\\"OTHERS\\\"].contains(equipment.energySource) && equipment.voltageRegulatorOn != true) {\n GeneratorFourWindings {\n staticId equipment.id\n parameterSetId \\\"GSFWPR\\\" + equipment.id\n }\n }\n\n OmegaRef {\n generatorDynamicModelId equipment.id\n }\n}\"}"; + return "{\"name\":\"" + scriptName + "\",\"parentName\":\"" + parentName + "\",\"script\":\"/**\n * Copyright (c) 2021, RTE (http://www.rte-france.com)\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n */\n\nimport com.powsybl.iidm.network.Generator\nimport com.powsybl.dynawaltz.automatons.CurrentLimitAutomaton\nimport com.powsybl.iidm.network.Branch\n\nfor (Generator equipment : network.generators) {\n if (equipment.id.equals(\\\"test\\\") && equipment.minP > 3.000000 && [\\\"HYDRO\\\", \\\"OTHERS\\\"].contains(equipment.energySource) && equipment.voltageRegulatorOn != true) {\n GeneratorFourWindings {\n staticId equipment.id\n parameterSetId \\\"GSFWPR\\\" + equipment.id\n }\n }\n\n OmegaRef {\n generatorDynamicModelId equipment.id\n }\n}\n\n" + + "CurrentLimitAutomaton {\n" + + " staticId \\\"element_id\\\"\n" + + " dynamicModelId \\\"automaton_model\\\"\n" + + " parameterSetId \\\"automaton_model\\\"\n" + + " side Branch.Side.ONE\n" + + "}\"}"; } @Test @@ -119,32 +131,32 @@ public void conversionTest() throws Exception { // Put data mvc.perform(post("/mappings/" + name) - .content(mapping(name, modelName)) - .contentType(APPLICATION_JSON)) + .content(mapping(name, modelName)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // convert to script mvc.perform(get("/scripts/from/" + name) - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(APPLICATION_JSON)) .andExpect(content().json(scriptOutput(name + "-script", name), true)); // try to convert unknown script mvc.perform(get("/scripts/from/" + "unknown") - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isNotFound()); // Post a mapping without known model (OK car model not needed yet) mvc.perform(post("/mappings/" + name) - .content(mapping(name, "unknownModel")) - .contentType(APPLICATION_JSON)) + .content(mapping(name, "unknownModel")) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // Try to convert this script // try to convert unknown script mvc.perform(get("/scripts/from/" + name) - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isNotFound()); } @@ -158,49 +170,49 @@ public void testRename() throws Exception { // Put data mvc.perform(post("/mappings/" + mappingName) - .content(mapping(mappingName, modelName)) - .contentType(APPLICATION_JSON)) + .content(mapping(mappingName, modelName)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // convert to script mvc.perform(get("/scripts/from/" + mappingName) - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // Rename data mvc.perform(post("/scripts/rename/" + mappingName + "-script/to/" + newName - ) - .contentType(APPLICATION_JSON)) + ) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // get all data mvc.perform(get("/scripts/") - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(APPLICATION_JSON)) .andExpect(content().json("[" + scriptOutput(newName, mappingName) + "]", true)); // Add a new script mvc.perform(post("/mappings/" + mappingName) - .content(mapping(mappingName, modelName)) - .contentType(APPLICATION_JSON)) + .content(mapping(mappingName, modelName)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // convert to script mvc.perform(get("/scripts/from/" + mappingName) - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // Fail to rename to existing mapping mvc.perform(post("/scripts/rename/" + mappingName + "-script/to/" + newName - ) - .contentType(APPLICATION_JSON)) + ) + .contentType(APPLICATION_JSON)) .andExpect(status().isConflict()); // Fail to copy from missing mapping mvc.perform(post("/scripts/rename/NotUsed/to/AnyScript" - ) - .contentType(APPLICATION_JSON)) + ) + .contentType(APPLICATION_JSON)) .andExpect(status().isNotFound()); } @@ -214,49 +226,49 @@ public void testCopy() throws Exception { // Put data mvc.perform(post("/mappings/" + mappingName) - .content(mapping(mappingName, modelName)) - .contentType(APPLICATION_JSON)) + .content(mapping(mappingName, modelName)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // convert to script mvc.perform(get("/scripts/from/" + mappingName) - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // Copy data mvc.perform(post("/scripts/copy/" + mappingName + "-script/to/" + copyName - ) - .contentType(APPLICATION_JSON)) + ) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // get all data mvc.perform(get("/scripts/") - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(APPLICATION_JSON)) .andExpect(content().json("[" + scriptOutput(mappingName + "-script", mappingName) + ", " + scriptOutput(copyName, mappingName) + "]", true)); // Add a new script mvc.perform(post("/mappings/" + mappingName) - .content(mapping(mappingName, modelName)) - .contentType(APPLICATION_JSON)) + .content(mapping(mappingName, modelName)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // convert to script mvc.perform(get("/scripts/from/" + mappingName) - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // Fail to copy to existing mapping mvc.perform(post("/scripts/copy/" + mappingName + "-script/to/" + copyName - ) - .contentType(APPLICATION_JSON)) + ) + .contentType(APPLICATION_JSON)) .andExpect(status().isConflict()); // Fail to copy from missing mapping mvc.perform(post("/scripts/copy/NotUsed/to/AnyMapping" - ) - .contentType(APPLICATION_JSON)) + ) + .contentType(APPLICATION_JSON)) .andExpect(status().isNotFound()); } @@ -268,13 +280,13 @@ public void testSaveAndDelete() throws Exception { // Put data mvc.perform(post("/scripts/" + name) - .content(simpleScript) - .contentType(APPLICATION_JSON)) + .content(simpleScript) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()); // Get Data mvc.perform(get("/scripts/") - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(APPLICATION_JSON)) .andExpect(content().json("[" + simpleScript + "]", true)); @@ -285,7 +297,7 @@ public void testSaveAndDelete() throws Exception { // Get Data mvc.perform(get("/scripts/") - .contentType(APPLICATION_JSON)) + .contentType(APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith(APPLICATION_JSON)) .andExpect(content().json("[]", true));