diff --git a/Jenkinsfile b/Jenkinsfile index 8727ff060..a8aac394e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -314,23 +314,36 @@ if (env.BRANCH_NAME == "master") { getFeatureBranchProps() node { - // curl the api to get debugging details - def jsonObj = getGithubPRJsonObj(env.CHANGE_ID, orgNames.get(0), projects.get(0)) - // This displays colors using the 'xterm' ansi color map. + def repoName = "" + // init variables depending of this build is triggered by a branch with PR or without PR + if (env.CHANGE_ID == null) { + // no PR exists + featureBranchName = env.BRANCH_NAME + repoName = orgNames.get(0) + "/" + projects.get(0) + } else { + // PR exists + /// curl the api to get debugging details + def jsonObj = getGithubPRJsonObj(env.CHANGE_ID, orgNames.get(0), projects.get(0)) + + featureBranchName = jsonObj.head.ref + repoName = jsonObj.head.repo.full_name + + } + + ansiColor('xterm') { try { // set java version setJavaVersion(javaVersionId) /// set the build name - featureBranchName = jsonObj.head.ref currentBuild.displayName = featureBranchName + " (" + currentBuild.displayName + ")" // notify rocket chat about the started feature branch run rocketSend channel: rocketChatChannel, emoji: ':jenkins_triggered:', message: "feature branch build triggered:\n" + - "*repo:* ${jsonObj.head.repo.full_name}\n" + + "*repo:* ${repoName}\n" + "*branch:* ${featureBranchName}\n" rawMessage: true @@ -383,7 +396,7 @@ if (env.BRANCH_NAME == "master") { // notify rocket chat rocketSend channel: rocketChatChannel, emoji: ':jenkins_party:', message: "feature branch test successful!\n" + - "*repo:* ${jsonObj.head.repo.full_name}\n" + + "*repo:* ${repoName}\n" + "*branch:* ${featureBranchName}\n" rawMessage: true } @@ -401,7 +414,7 @@ if (env.BRANCH_NAME == "master") { // notify rocket chat rocketSend channel: rocketChatChannel, emoji: ':jenkins_explode:', message: "feature branch test failed!\n" + - "*repo:* ${jsonObj.head.repo.full_name}\n" + + "*repo:* ${repoName}\n" + "*branch:* ${featureBranchName}\n" rawMessage: true } diff --git a/docs/uml/main/InputDatamodelConcept.puml b/docs/uml/main/InputDatamodelConcept.puml index 79af3962e..267342b24 100644 --- a/docs/uml/main/InputDatamodelConcept.puml +++ b/docs/uml/main/InputDatamodelConcept.puml @@ -1,5 +1,23 @@ @startuml +'extractor interface information + +interface Nested + +interface Node +Node --|> Nested + +interface Nodes +Nodes --|> Nested + +interface NodeC +NodeC --|> Nested + +interface Type +Type --|> Nested + + + abstract Class UniqueEntity { + uuid: UUID } @@ -24,6 +42,7 @@ abstract Class SystemParticipantInput { - qCharacteristics: String } SystemParticipantInput --|> AssetInput +SystemParticipantInput --|> Node Class OperatorInput { + name: String @@ -35,6 +54,7 @@ abstract Class ConnectorInput { + nodeB: NodeInput } ConnectorInput --|> AssetInput +ConnectorInput --|> Nodes abstract Class AssetCharacteristicsInput { - type: T @@ -208,12 +228,14 @@ Class WecInput{ - marketReaction: Boolean } WecInput --|> SystemParticipantInput +WecInput --|> Type Class ChpInput { - type: ChpTypeInput - marketReaction: Boolean } ChpInput --|> SystemParticipantInput +ChpInput --|> Type Class BmInput { - type: BmTypeInput @@ -223,11 +245,13 @@ Class BmInput { - costControlled: Boolean } BmInput --|> SystemParticipantInput +BmInput --|> Type Class EvInput { - type: EvTypeInput } EvInput --|> SystemParticipantInput +EvInput --|> Type Class LoadInput { - scenario: String @@ -242,11 +266,13 @@ Class StorageInput { - behaviour: String } StorageInput --|> SystemParticipantInput +StorageInput --|> Type Class HpInput { - type: HpTypeInput } HpInput --|> SystemParticipantInput +HpInput --|> Type Abstract Class ThermalUnitInput { - uuid: UUID @@ -314,6 +340,7 @@ Class LineInput { + geoPosition: LineString } LineInput --|> ConnectorInput +LineInput --|> Type Class SwitchInput { + closed: Boolean @@ -331,12 +358,15 @@ Class Transformer2WInput { + type: Transformer2WTypeInput } Transformer2WInput --|> TransformerInput +Transformer2WInput --|> Type Class Transformer3WInput { + nodeC: NodeInput + type: Transformer3WTypeInput } Transformer3WInput --|> TransformerInput +Transformer3WInput --|> NodeC +Transformer3WInput --|> Type abstract Class GraphicInput { + graphicLayer: String diff --git a/gradle/scripts/tests.gradle b/gradle/scripts/tests.gradle index 0e4aa5e56..e7332351d 100644 --- a/gradle/scripts/tests.gradle +++ b/gradle/scripts/tests.gradle @@ -5,7 +5,7 @@ test { } useJUnitPlatform() testLogging { - events "passed", "skipped", "failed" + events "skipped", "failed" } } @@ -24,7 +24,7 @@ task allTests(type: Test) { useJUnitPlatform() testLogging { - events "passed", "skipped", "failed" + events "skipped", "failed" } filter { diff --git a/src/main/java/edu/ie3/datamodel/exceptions/ExtractorException.java b/src/main/java/edu/ie3/datamodel/exceptions/ExtractorException.java new file mode 100644 index 000000000..e9385ae93 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/exceptions/ExtractorException.java @@ -0,0 +1,28 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.exceptions; + +/** + * Exception that should be used whenevery something invalid happens in a implementation of a {@link + * edu.ie3.datamodel.io.connectors.DataConnector} + * + * @version 0.1 + * @since 20.03.20 + */ +public class ExtractorException extends Exception { + + public ExtractorException(final String message, final Throwable cause) { + super(message, cause); + } + + public ExtractorException(final Throwable cause) { + super(cause); + } + + public ExtractorException(final String message) { + super(message); + } +} diff --git a/src/main/java/edu/ie3/datamodel/io/extractor/Extractor.java b/src/main/java/edu/ie3/datamodel/io/extractor/Extractor.java new file mode 100644 index 000000000..ac8a40722 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/extractor/Extractor.java @@ -0,0 +1,59 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.extractor; + +import edu.ie3.datamodel.exceptions.ExtractorException; +import edu.ie3.datamodel.models.input.InputEntity; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * A simple utility class that can be used by sinks to extract nested elements (e.g. nodes, types) + * that should be persisted. + * + * @version 0.1 + * @since 31.03.20 + */ +public class Extractor { + + private final List extractedEntities; + + public Extractor(Nested nestedEntity) throws ExtractorException { + this.extractedEntities = extractElements(nestedEntity); + } + + private List extractElements(Nested nestedEntity) throws ExtractorException { + List resultingList = new ArrayList<>(); + if (nestedEntity instanceof Node) { + resultingList.add(((Node) nestedEntity).getNode()); + } + if (nestedEntity instanceof NodeC) { + resultingList.add(((NodeC) nestedEntity).getNodeC()); + } + if (nestedEntity instanceof Nodes) { + resultingList.addAll( + Arrays.asList(((Nodes) nestedEntity).getNodeA(), ((Nodes) nestedEntity).getNodeB())); + } + if (nestedEntity instanceof Type) { + resultingList.add(((Type) nestedEntity).getType()); + } + if (resultingList.isEmpty()) { + throw new ExtractorException( + "The interface 'Nested' is not meant to be extended. The provided entity of class '" + + nestedEntity.getClass().getSimpleName() + + "' and cannot be processed by " + + "the extractor! Currently only the interfaces 'Node', 'NodeC', ‘Nodes‘ and ‘Type' are supported!"); + } + + return Collections.unmodifiableList(resultingList); + } + + public List getExtractedEntities() { + return extractedEntities; + } +} diff --git a/src/main/java/edu/ie3/datamodel/io/extractor/Nested.java b/src/main/java/edu/ie3/datamodel/io/extractor/Nested.java new file mode 100644 index 000000000..1d34edccc --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/extractor/Nested.java @@ -0,0 +1,17 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.extractor; + +/** + * This interface should be implemented only by other interfaces that should be used by the {@link + * Extractor} It provides the entry point for the extraction method in the {@link Extractor}. If + * this interface is implemented by other interfaces one has to take care about, that the + * corresponding method {@link Extractor.extractElements()} is extended accordingly. + * + * @version 0.1 + * @since 31.03.20 + */ +public interface Nested {} diff --git a/src/main/java/edu/ie3/datamodel/io/extractor/Node.java b/src/main/java/edu/ie3/datamodel/io/extractor/Node.java new file mode 100644 index 000000000..6acc58cee --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/extractor/Node.java @@ -0,0 +1,20 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.extractor; + +import edu.ie3.datamodel.models.input.NodeInput; + +/** + * Interface that should be implemented by all elements holding a {@link NodeInput} and should be + * processable by the {@link Extractor} + * + * @version 0.1 + * @since 31.03.20 + */ +public interface Node extends Nested { + + NodeInput getNode(); +} diff --git a/src/main/java/edu/ie3/datamodel/io/extractor/NodeC.java b/src/main/java/edu/ie3/datamodel/io/extractor/NodeC.java new file mode 100644 index 000000000..163011736 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/extractor/NodeC.java @@ -0,0 +1,21 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.extractor; + +import edu.ie3.datamodel.models.input.NodeInput; + +/** + * Interface that should be implemented by all elements holding a third {@link NodeInput} and should + * be processable by the {@link Extractor}. For now, this only holds true by the {@link + * edu.ie3.datamodel.models.input.connector.Transformer3WInput} + * + * @version 0.1 + * @since 31.03.20 + */ +public interface NodeC extends Nested { + + NodeInput getNodeC(); +} diff --git a/src/main/java/edu/ie3/datamodel/io/extractor/Nodes.java b/src/main/java/edu/ie3/datamodel/io/extractor/Nodes.java new file mode 100644 index 000000000..3c996412c --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/extractor/Nodes.java @@ -0,0 +1,24 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.extractor; + +import edu.ie3.datamodel.models.input.NodeInput; + +/** + * Interface that should be implemented by all elements holding a two {@link NodeInput} elements and + * should be processable by the {@link Extractor}. For now, this only holds true by all {@link + * edu.ie3.datamodel.models.input.connector.ConnectorInput} and {@link + * edu.ie3.datamodel.models.input.connector.TransformerInput} + * + * @version 0.1 + * @since 31.03.20 + */ +public interface Nodes extends Nested { + + NodeInput getNodeA(); + + NodeInput getNodeB(); +} diff --git a/src/main/java/edu/ie3/datamodel/io/extractor/Type.java b/src/main/java/edu/ie3/datamodel/io/extractor/Type.java new file mode 100644 index 000000000..3ce40e09c --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/extractor/Type.java @@ -0,0 +1,20 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.extractor; + +import edu.ie3.datamodel.models.input.AssetTypeInput; + +/** + * Interface that should be implemented by all elements holding a {@link AssetTypeInput} and should + * be processable by the {@link Extractor}. + * + * @version 0.1 + * @since 31.03.20 + */ +public interface Type extends Nested { + + AssetTypeInput getType(); +} diff --git a/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java b/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java index 2301f1c20..36d2e82c2 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java @@ -130,12 +130,12 @@ private Collection> allProcessors() { Collection> resultingProcessors = new ArrayList<>(); // todo add missing processors here - // AssetInput + // Input Entity Processor for (Class cls : InputEntityProcessor.eligibleEntityClasses) { resultingProcessors.add(new InputEntityProcessor(cls)); } - // SystemParticipantResults + // Result Entity Processor for (Class cls : ResultEntityProcessor.eligibleEntityClasses) { resultingProcessors.add(new ResultEntityProcessor(cls)); } diff --git a/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java b/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java index dbc72b982..a82ed5079 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java @@ -5,15 +5,20 @@ */ package edu.ie3.datamodel.io.sink; +import edu.ie3.datamodel.exceptions.ExtractorException; import edu.ie3.datamodel.exceptions.SinkException; import edu.ie3.datamodel.io.FileNamingStrategy; import edu.ie3.datamodel.io.connectors.CsvFileConnector; import edu.ie3.datamodel.io.connectors.DataConnector; +import edu.ie3.datamodel.io.extractor.Extractor; +import edu.ie3.datamodel.io.extractor.Nested; import edu.ie3.datamodel.io.processor.ProcessorProvider; import edu.ie3.datamodel.models.UniqueEntity; +import edu.ie3.datamodel.models.input.InputEntity; import java.io.BufferedWriter; import java.io.IOException; import java.util.*; +import java.util.stream.Collectors; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -33,11 +38,36 @@ public class CsvFileSink implements DataSink { private final String csvSep; public CsvFileSink(String baseFolderPath) { - this(baseFolderPath, new ProcessorProvider(), new FileNamingStrategy(), false, ","); + this(baseFolderPath, new FileNamingStrategy(), false, ","); } /** - * Create an instance of a csv file sink + * Create an instance of a csv file sink that can be used to persist Unique entities. This + * implementation processes in sequential order. To parallelize this process one might consider + * starting several sinks and use them for specific entities. + * + * @param baseFolderPath the base folder path where the files should be put into + * @param fileNamingStrategy the file naming strategy that should be used + * @param initFiles true if the files should be created during initialization (might create files, + * that only consist of a headline, because no data will be writen into them), false otherwise + * @param csvSep the csv file separator that should be use + */ + public CsvFileSink( + String baseFolderPath, + FileNamingStrategy fileNamingStrategy, + boolean initFiles, + String csvSep) { + this(baseFolderPath, new ProcessorProvider(), fileNamingStrategy, initFiles, csvSep); + } + + /** + * Create an instance of a csv file sink that can be used to persist Unique entities. This + * implementation processes in sequential order. To parallelize this process one might consider + * starting several sinks and use them for specific entities. Be careful when providing your own + * {@link ProcessorProvider} because if you're not 100% sure that it knows about all entities + * you're going to process exceptions might occur. Therefore it is strongly advised to either use + * a constructor without providing the {@link ProcessorProvider} or provide a general {@link + * ProcessorProvider} by calling {@link ProcessorProvider()} * * @param baseFolderPath the base folder path where the files should be put into * @param processorProvider the processor provided that should be used for entity de-serialization @@ -72,8 +102,7 @@ public void persistAll(Collection entities) { } @Override - public void persist(T entity) { - + public void persistIgnoreNested(C entity) { LinkedHashMap entityFieldData = processorProvider .processEntity(entity) @@ -82,7 +111,11 @@ public void persist(T entity) { new SinkException( "Cannot persist entity of type '" + entity.getClass().getSimpleName() - + "'. Is this sink properly initialized?")); + + "'. This sink can only process the following entities: [" + + processorProvider.getRegisteredClasses().stream() + .map(Class::getSimpleName) + .collect(Collectors.joining(",")) + + "]")); String[] headerElements = processorProvider.getHeaderElements(entity.getClass()).orElse(new String[0]); @@ -90,6 +123,32 @@ public void persist(T entity) { write(entityFieldData, headerElements, writer); } + @Override + public void persistAllIgnoreNested(Collection entities) { + entities.parallelStream().forEach(this::persistIgnoreNested); + } + + @Override + public void persist(T entity) { + if (entity instanceof Nested) { + try { + persistIgnoreNested(entity); + for (InputEntity ent : new Extractor((Nested) entity).getExtractedEntities()) { + persistIgnoreNested(ent); + } + + } catch (ExtractorException e) { + log.error( + "An error occurred during extraction of nested entity'" + + entity.getClass().getSimpleName() + + "': ", + e); + } + } else { + persistIgnoreNested(entity); + } + } + /** * Initialize files, hence create a file for each expected class that will be processed in the * future. diff --git a/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java b/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java index 622790d94..980e1a5f3 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java @@ -6,16 +6,75 @@ package edu.ie3.datamodel.io.sink; import edu.ie3.datamodel.io.connectors.DataConnector; +import edu.ie3.datamodel.io.processor.EntityProcessor; import edu.ie3.datamodel.models.UniqueEntity; import java.util.Collection; -/** Describes a class that manages data persistence */ +/** + * Describes a class that manages data persistence. A sample implementation that can be used as a + * blueprint for all method implementation incl. entity handling with processors can be found in + * {@link CsvFileSink} + */ public interface DataSink { /** @return the connector of this sink */ DataConnector getDataConnector(); + /** + * Should implement the entry point of a data sink to persist an entity. By default this method + * should take care about the extraction process of nested entities (if any) and use {@link + * edu.ie3.datamodel.io.extractor.Extractor} accordingly. For an faster method e.g. that neglects + * the nested objects persistence and only persists the uuid of the nested objects (if any), + * instead of the object itself use {@link DataSink.persistIgnoreNested()} + * + * @param entity the entity that should be persisted + * @param bounded to be all unique entities. Handling of specific entities is normally then + * executed by a specific {@link EntityProcessor} + */ void persist(C entity); + /** + * Should implement the entry point of a data sink to persist multiple entities in a collection. + * By default this method should take care about the extraction process of nested entities (if + * any) and use {@link edu.ie3.datamodel.io.extractor.Extractor} accordingly. For an faster method + * e.g. that neglects the nested objects persistence and only persists the uuid of the nested + * objects (if any), instead of the object itself use {@link DataSink.persistAllIgnoreNested()} + * + * @param entities a collection of entities that should be persisted + * @param bounded to be all unique entities. Handling of specific entities is normally then + * executed by a specific {@link EntityProcessor} + */ void persistAll(Collection entities); + + /** + * Should implement the entry point of a data sink to persist an entity. In contrast to {@link + * DataSink.persist()}, this method should not take care about the extraction process of + * nested entities (if any) but only persist the uuid of the nested entity. This might + * speed up things a little bit because of missing if-/else-clauses but can also lead to missing + * persisted data that should be persisted, but is not e.g. nested types that are not available + * anymore afterwards. It might be useful especially for all entities without nested entities. For + * all doubts about if the provided entity contains needed nested data or not {@link + * DataSink.persist()} is the recommended method to be used. + * + * @param entity the entity that should be persisted + * @param bounded to be all unique entities. Handling of specific entities is normally then + * executed by a specific {@link EntityProcessor} + */ + void persistIgnoreNested(C entity); + + /** + * Should implement the entry point of a data sink to persist multiple entities in a collection. + * In contrast to {@link DataSink.persistAll()}, this method should not take care about the + * extraction process of nested entities (if any) but only persist the uuid of the nested entity. + * This might speed up things a little bit because of missing if-/else-clauses but but can + * also lead to missing persisted data that should be persisted, but is not e.g. nested types that + * are not available anymore afterwards. It might be useful especially for all entities without + * nested entities. For all doubts about if the provided entity contains needed nested data or not + * {@link DataSink.persistAll()} is the recommended method to be used. + * + * @param entities the entities that should be persisted + * @param bounded to be all unique entities. Handling of specific entities is normally then + * executed by a specific {@link EntityProcessor} + */ + void persistAllIgnoreNested(Collection entities); } diff --git a/src/main/java/edu/ie3/datamodel/models/input/MeasurementUnitInput.java b/src/main/java/edu/ie3/datamodel/models/input/MeasurementUnitInput.java index bfc3c92ba..66829a941 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/MeasurementUnitInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/MeasurementUnitInput.java @@ -5,12 +5,12 @@ */ package edu.ie3.datamodel.models.input; +import edu.ie3.datamodel.io.extractor.Node; import edu.ie3.datamodel.models.OperationTime; -import java.util.Objects; -import java.util.UUID; +import java.util.*; /** Model of a measuring unit attached to a certain {@link NodeInput}. */ -public class MeasurementUnitInput extends AssetInput { +public class MeasurementUnitInput extends AssetInput implements Node { /** Grid node, the asset is attached to */ private final NodeInput node; @@ -78,6 +78,7 @@ public MeasurementUnitInput( this.q = q; } + @Override public NodeInput getNode() { return node; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/connector/ConnectorInput.java b/src/main/java/edu/ie3/datamodel/models/input/connector/ConnectorInput.java index bb2ee53cb..2e9f3fcc7 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/connector/ConnectorInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/connector/ConnectorInput.java @@ -5,15 +5,15 @@ */ package edu.ie3.datamodel.models.input.connector; +import edu.ie3.datamodel.io.extractor.Nodes; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.input.AssetInput; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; -import java.util.Objects; -import java.util.UUID; +import java.util.*; /** Describes an asset that connects two {@link NodeInput}s */ -public abstract class ConnectorInput extends AssetInput { +public abstract class ConnectorInput extends AssetInput implements Nodes { /** Grid node at one side of the connector */ private final NodeInput nodeA; /** Grid node at the other side of the connector */ @@ -63,10 +63,12 @@ public ConnectorInput( this.noOfParallelDevices = noOfParallelDevices; } + @Override public NodeInput getNodeA() { return nodeA; } + @Override public NodeInput getNodeB() { return nodeB; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/connector/LineInput.java b/src/main/java/edu/ie3/datamodel/models/input/connector/LineInput.java index 1b6715150..102bee5f4 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/connector/LineInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/connector/LineInput.java @@ -5,6 +5,7 @@ */ package edu.ie3.datamodel.models.input.connector; +import edu.ie3.datamodel.io.extractor.Type; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.StandardUnits; import edu.ie3.datamodel.models.input.NodeInput; @@ -21,7 +22,7 @@ * Describes an electrical grid line that connects two {@link * edu.ie3.datamodel.models.input.NodeInput}s */ -public class LineInput extends ConnectorInput { +public class LineInput extends ConnectorInput implements Type { /** Type of this line, containing default values for lines of this kind */ private final LineTypeInput type; @@ -96,6 +97,7 @@ public LineInput( this.olmCharacteristic = olmCharacteristic; } + @Override public LineTypeInput getType() { return type; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/connector/Transformer2WInput.java b/src/main/java/edu/ie3/datamodel/models/input/connector/Transformer2WInput.java index 91d167e4a..d030eadcd 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/connector/Transformer2WInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/connector/Transformer2WInput.java @@ -5,6 +5,7 @@ */ package edu.ie3.datamodel.models.input.connector; +import edu.ie3.datamodel.io.extractor.Type; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; @@ -16,7 +17,7 @@ * Describes a two winding transformer, that is connected to two {@link * edu.ie3.datamodel.models.input.NodeInput}s */ -public class Transformer2WInput extends TransformerInput { +public class Transformer2WInput extends TransformerInput implements Type { /** Type of this 2W transformer, containing default values for transformers of this kind */ private final Transformer2WTypeInput type; @@ -74,6 +75,7 @@ public Transformer2WInput( this.type = type; } + @Override public Transformer2WTypeInput getType() { return type; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/connector/Transformer3WInput.java b/src/main/java/edu/ie3/datamodel/models/input/connector/Transformer3WInput.java index 9caf364b9..b95b1b106 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/connector/Transformer3WInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/connector/Transformer3WInput.java @@ -7,19 +7,20 @@ import static edu.ie3.util.quantities.PowerSystemUnits.PU; +import edu.ie3.datamodel.io.extractor.NodeC; +import edu.ie3.datamodel.io.extractor.Type; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; import edu.ie3.datamodel.models.input.connector.type.Transformer3WTypeInput; -import java.util.Objects; -import java.util.UUID; +import java.util.*; import tec.uom.se.quantity.Quantities; /** * Describes a three winding transformer, that is connected to three {@link * edu.ie3.datamodel.models.input.NodeInput}s */ -public class Transformer3WInput extends TransformerInput { +public class Transformer3WInput extends TransformerInput implements NodeC, Type { /** Type of this 3W transformer, containing default values for transformers of this kind */ private final Transformer3WTypeInput type; /** The lower voltage node */ @@ -109,6 +110,7 @@ public Transformer3WInput( nodeA.getSubnet()); } + @Override public Transformer3WTypeInput getType() { return type; } @@ -126,6 +128,7 @@ public NodeInput getNodeB() { } /** @return the node with the lowest voltage level */ + @Override public NodeInput getNodeC() { return nodeC; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/graphics/NodeGraphicInput.java b/src/main/java/edu/ie3/datamodel/models/input/graphics/NodeGraphicInput.java index 23a28a43c..813e2c28f 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/graphics/NodeGraphicInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/graphics/NodeGraphicInput.java @@ -5,14 +5,14 @@ */ package edu.ie3.datamodel.models.input.graphics; +import edu.ie3.datamodel.io.extractor.Node; import edu.ie3.datamodel.models.input.NodeInput; -import java.util.Objects; -import java.util.UUID; +import java.util.*; import org.locationtech.jts.geom.LineString; import org.locationtech.jts.geom.Point; /** Describes the graphic data belonging to a {@link NodeInput} */ -public class NodeGraphicInput extends GraphicInput { +public class NodeGraphicInput extends GraphicInput implements Node { /** The NodeInput to this graphic data */ private final NodeInput node; /** The geometric point of this node */ @@ -32,6 +32,7 @@ public NodeGraphicInput( this.point = point; } + @Override public NodeInput getNode() { return node; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/BmInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/BmInput.java index 0a8163946..5034a4b65 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/BmInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/BmInput.java @@ -5,6 +5,7 @@ */ package edu.ie3.datamodel.models.input.system; +import edu.ie3.datamodel.io.extractor.Type; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.StandardUnits; import edu.ie3.datamodel.models.input.NodeInput; @@ -16,7 +17,7 @@ import javax.measure.Quantity; /** Describes a biomass plant */ -public class BmInput extends SystemParticipantInput { +public class BmInput extends SystemParticipantInput implements Type { /** Type of this BM plant, containing default values for BM plants of this kind */ private final BmTypeInput type; /** Is this asset market oriented? */ @@ -90,6 +91,7 @@ public BmInput( this.feedInTariff = feedInTariff.to(StandardUnits.ENERGY_PRICE); } + @Override public BmTypeInput getType() { return type; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java index e54dab409..8635263b4 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/ChpInput.java @@ -5,6 +5,7 @@ */ package edu.ie3.datamodel.models.input.system; +import edu.ie3.datamodel.io.extractor.Type; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; @@ -15,7 +16,7 @@ import java.util.UUID; /** Describes a combined heat and power plant */ -public class ChpInput extends SystemParticipantInput { +public class ChpInput extends SystemParticipantInput implements Type { /** The thermal bus, this model is connected to */ private final ThermalBusInput thermalBus; /** Type of this CHP plant, containing default values for CHP plants of this kind */ @@ -91,6 +92,7 @@ public ThermalBusInput getThermalBus() { return thermalBus; } + @Override public ChpTypeInput getType() { return type; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/EvInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/EvInput.java index cac3c9d83..d84ee65de 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/EvInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/EvInput.java @@ -5,6 +5,7 @@ */ package edu.ie3.datamodel.models.input.system; +import edu.ie3.datamodel.io.extractor.Type; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; @@ -13,7 +14,7 @@ import java.util.UUID; /** Describes an electric vehicle */ -public class EvInput extends SystemParticipantInput { +public class EvInput extends SystemParticipantInput implements Type { /** Type of this EV, containing default values for EVs of this kind */ private final EvTypeInput type; /** @@ -53,6 +54,7 @@ public EvInput(UUID uuid, String id, NodeInput node, String qCharacteristics, Ev this.type = type; } + @Override public EvTypeInput getType() { return type; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/HpInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/HpInput.java index fc9cbc558..ebed7844a 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/HpInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/HpInput.java @@ -5,6 +5,7 @@ */ package edu.ie3.datamodel.models.input.system; +import edu.ie3.datamodel.io.extractor.Type; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; @@ -14,7 +15,7 @@ import java.util.UUID; /** Describes a heat pump */ -public class HpInput extends SystemParticipantInput { +public class HpInput extends SystemParticipantInput implements Type { /** Type of this heat pump, containing default values for heat pump of this kind */ private final HpTypeInput type; /** The thermal bus, this model is connected to */ @@ -68,6 +69,7 @@ public HpInput( this.type = type; } + @Override public HpTypeInput getType() { return type; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/StorageInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/StorageInput.java index 1b753906d..7df05a17c 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/StorageInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/StorageInput.java @@ -5,6 +5,7 @@ */ package edu.ie3.datamodel.models.input.system; +import edu.ie3.datamodel.io.extractor.Type; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; @@ -13,7 +14,7 @@ import java.util.UUID; /** Describes a battery storage */ -public class StorageInput extends SystemParticipantInput { +public class StorageInput extends SystemParticipantInput implements Type { /** Type of this storage, containing default values for storages of this kind */ private final StorageTypeInput type; @@ -68,6 +69,7 @@ public StorageInput( this.behaviour = StorageStrategy.get(behaviour); } + @Override public StorageTypeInput getType() { return type; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/SystemParticipantInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/SystemParticipantInput.java index 92bb81651..18ce7827f 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/SystemParticipantInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/SystemParticipantInput.java @@ -5,15 +5,15 @@ */ package edu.ie3.datamodel.models.input.system; +import edu.ie3.datamodel.io.extractor.Node; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.input.AssetInput; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; -import java.util.Objects; -import java.util.UUID; +import java.util.*; /** Describes a system asset that is connected to a node */ -public abstract class SystemParticipantInput extends AssetInput { +public abstract class SystemParticipantInput extends AssetInput implements Node { /** The node that the asset is connected to */ private final NodeInput node; @@ -61,6 +61,7 @@ public String getqCharacteristics() { return qCharacteristics; } + @Override public NodeInput getNode() { return node; } diff --git a/src/main/java/edu/ie3/datamodel/models/input/system/WecInput.java b/src/main/java/edu/ie3/datamodel/models/input/system/WecInput.java index eeb89f0a9..85f005ae1 100644 --- a/src/main/java/edu/ie3/datamodel/models/input/system/WecInput.java +++ b/src/main/java/edu/ie3/datamodel/models/input/system/WecInput.java @@ -5,6 +5,7 @@ */ package edu.ie3.datamodel.models.input.system; +import edu.ie3.datamodel.io.extractor.Type; import edu.ie3.datamodel.models.OperationTime; import edu.ie3.datamodel.models.input.NodeInput; import edu.ie3.datamodel.models.input.OperatorInput; @@ -13,7 +14,7 @@ import java.util.UUID; /** Describes a Wind Energy Converter */ -public class WecInput extends SystemParticipantInput { +public class WecInput extends SystemParticipantInput implements Type { /** Type of this WEC, containing default values for WEC assets of this kind */ private final WecTypeInput type; @@ -71,6 +72,7 @@ public boolean isMarketReaction() { return marketReaction; } + @Override public WecTypeInput getType() { return type; } diff --git a/src/test/groovy/edu/ie3/datamodel/io/extractor/ExtractorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/extractor/ExtractorTest.groovy new file mode 100644 index 000000000..02fba6f64 --- /dev/null +++ b/src/test/groovy/edu/ie3/datamodel/io/extractor/ExtractorTest.groovy @@ -0,0 +1,90 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ +package edu.ie3.datamodel.io.extractor + +import edu.ie3.datamodel.exceptions.ExtractorException +import edu.ie3.test.common.GridTestData as gtd +import edu.ie3.test.common.SystemParticipantTestData as sptd +import edu.ie3.util.TimeTools +import spock.lang.Specification + +import java.time.ZoneId + +class ExtractorTest extends Specification { + + private final class InvalidNestedExtensionClass implements Nested {} + + static { + TimeTools.initialize(ZoneId.of("UTC"), Locale.GERMANY, "yyyy-MM-dd HH:mm:ss") + } + + def "An Extractor should be able to extract an entity with nested elements correctly"() { + given: + def extractor = new Extractor(nestedEntity) + + expect: + extractor.extractedEntities == expectedExtractedEntities + + where: + nestedEntity || expectedExtractedEntities + gtd.lineCtoD || [ + gtd.lineCtoD.nodeA, + gtd.lineCtoD.nodeB, + gtd.lineCtoD.type + ] + gtd.transformerAtoBtoC || [ + gtd.transformerAtoBtoC.nodeC, + gtd.transformerAtoBtoC.nodeA, + gtd.transformerAtoBtoC.nodeB, + gtd.transformerAtoBtoC.type + ] + gtd.transformerCtoG || [ + gtd.transformerCtoG.nodeA, + gtd.transformerCtoG.nodeB, + gtd.transformerCtoG.type + ] + gtd.switchAtoB || [ + gtd.switchAtoB.nodeA, + gtd.switchAtoB.nodeB + ] + sptd.fixedFeedInInput || [sptd.fixedFeedInInput.node] + sptd.wecInput || [ + sptd.wecInput.node, + sptd.wecInput.type + ] + sptd.chpInput || [ + sptd.chpInput.node, + sptd.chpInput.type + ] + sptd.bmInput || [ + sptd.bmInput.node, + sptd.bmInput.type + ] + sptd.evInput || [ + sptd.evInput.node, + sptd.evInput.type + ] + sptd.storageInput || [ + sptd.storageInput.node, + sptd.storageInput.type + ] + sptd.hpInput || [ + sptd.hpInput.node, + sptd.hpInput.type + ] + } + + def "An Extractor should throw an ExtractorException if the provided Nested entity is unknown and or an invalid extension of the 'Nested' interface took place"() { + when: + new Extractor(new InvalidNestedExtensionClass()) + + then: + ExtractorException ex = thrown() + ex.message == "The interface 'Nested' is not meant to be extended. The provided entity of class " + + "'InvalidNestedExtensionClass' and cannot be processed by the extractor! Currently only the interfaces " + + "'Node', 'NodeC', ‘Nodes‘ and ‘Type' are supported!" + } +} diff --git a/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy index fa860ad24..793b64ac1 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy @@ -8,11 +8,16 @@ package edu.ie3.datamodel.io.sink import edu.ie3.datamodel.exceptions.SinkException import edu.ie3.datamodel.io.FileNamingStrategy import edu.ie3.datamodel.io.processor.ProcessorProvider +import edu.ie3.datamodel.io.processor.input.InputEntityProcessor import edu.ie3.datamodel.io.processor.result.ResultEntityProcessor import edu.ie3.datamodel.models.StandardUnits +import edu.ie3.datamodel.models.input.NodeInput +import edu.ie3.datamodel.models.input.connector.Transformer2WInput +import edu.ie3.datamodel.models.input.connector.type.Transformer2WTypeInput import edu.ie3.datamodel.models.result.system.EvResult import edu.ie3.datamodel.models.result.system.PvResult import edu.ie3.datamodel.models.result.system.WecResult +import edu.ie3.test.common.GridTestData import edu.ie3.util.TimeTools import edu.ie3.util.io.FileIOUtils import spock.lang.Shared @@ -68,7 +73,10 @@ class CsvFileSinkTest extends Specification { new ProcessorProvider([ new ResultEntityProcessor(PvResult), new ResultEntityProcessor(WecResult), - new ResultEntityProcessor(EvResult) + new ResultEntityProcessor(EvResult), + new InputEntityProcessor(Transformer2WInput), + new InputEntityProcessor(NodeInput), + new InputEntityProcessor(Transformer2WTypeInput) ]), new FileNamingStrategy(), false, @@ -82,13 +90,20 @@ class CsvFileSinkTest extends Specification { WecResult wecResult = new WecResult(uuid, TimeTools.toZonedDateTime("2020-01-30 17:26:44"), inputModel, p, q) when: - csvFileSink.persistAll([pvResult, wecResult]) + csvFileSink.persistAll([ + pvResult, + wecResult, + GridTestData.transformerCtoG + ]) csvFileSink.dataConnector.shutdown() then: new File(testBaseFolderPath).exists() new File(testBaseFolderPath + File.separator + "wec_res.csv").exists() new File(testBaseFolderPath + File.separator + "pv_res.csv").exists() + new File(testBaseFolderPath + File.separator + "transformer2w_type_input.csv").exists() + new File(testBaseFolderPath + File.separator + "node_input.csv").exists() + new File(testBaseFolderPath + File.separator + "transformer2w_input.csv").exists() !new File(testBaseFolderPath + File.separator + "ev_res.csv").exists() } @@ -116,4 +131,5 @@ class CsvFileSinkTest extends Specification { then: thrown(SinkException) } + }