Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

### Changed
- Abstracting some methods in `ValidationUtils` [#852](https://github.com/ie3-institute/PowerSystemDataModel/issues/852)

## [4.1.0] - 2023-11-02

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* © 2023. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/
package edu.ie3.datamodel.exceptions;

import edu.ie3.datamodel.models.UniqueEntity;
import edu.ie3.datamodel.utils.ExceptionUtils;
import java.util.Collection;

public class DuplicateEntitiesException extends ValidationException {

protected DuplicateEntitiesException(String s) {
super(s);
}

protected DuplicateEntitiesException(String s, String entities) {
super(s + entities);
}

public DuplicateEntitiesException(String fieldName, Collection<? extends UniqueEntity> entities) {
this(
"The following entities have duplicate '" + fieldName + "':",
ExceptionUtils.combine(entities));
}
}
13 changes: 13 additions & 0 deletions src/main/java/edu/ie3/datamodel/utils/ExceptionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
*/
package edu.ie3.datamodel.utils;

import edu.ie3.datamodel.models.UniqueEntity;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class ExceptionUtils {
private ExceptionUtils() {
Expand All @@ -24,4 +27,14 @@ public static String getMessages(List<? extends Exception> exceptions) {
.reduce("", (a, b) -> a + "\n " + b)
.replaceFirst("\n ", "");
}

/**
* Combines multiple {@link UniqueEntity} into a string.
*
* @param entities to be combined
* @return a string
*/
public static String combine(Collection<? extends UniqueEntity> entities) {
return entities.stream().map(UniqueEntity::toString).collect(Collectors.joining("\n - "));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
*/
package edu.ie3.datamodel.utils.validation;

import edu.ie3.datamodel.exceptions.InvalidEntityException;
import edu.ie3.datamodel.exceptions.InvalidGridException;
import edu.ie3.datamodel.exceptions.UnsafeEntityException;
import edu.ie3.datamodel.exceptions.ValidationException;
import edu.ie3.datamodel.exceptions.*;
import edu.ie3.datamodel.models.UniqueEntity;
import edu.ie3.datamodel.models.input.AssetInput;
import edu.ie3.datamodel.models.input.MeasurementUnitInput;
import edu.ie3.datamodel.models.input.NodeInput;
Expand All @@ -24,14 +22,6 @@

public class GridContainerValidationUtils extends ValidationUtils {

private static String duplicateUuidsString(String simpleName, Optional<String> exceptionString) {
return "The provided entities in '"
+ simpleName
+ "' contains duplicate UUIDs. "
+ "This is not allowed!\nDuplicated uuids:\n\n"
+ exceptionString;
}

/** Private Constructor as this class is not meant to be instantiated */
private GridContainerValidationUtils() {
throw new IllegalStateException("Don't try and instantiate a Utility class.");
Expand All @@ -52,18 +42,10 @@ private GridContainerValidationUtils() {
return List.of(isNull);
}

List<Try<Void, ? extends ValidationException>> exceptions = new ArrayList<>();

/* sanity check to ensure distinct UUIDs */
Optional<String> exceptionString =
checkForDuplicateUuids(new HashSet<>(gridContainer.allEntitiesAsList()));
exceptions.add(
Try.ofVoid(
exceptionString.isPresent(),
() ->
new InvalidGridException(
duplicateUuidsString(
gridContainer.getClass().getSimpleName(), exceptionString))));
List<Try<Void, ? extends ValidationException>> exceptions =
new ArrayList<>(
checkForDuplicate(gridContainer.allEntitiesAsList(), UniqueEntity::getUuid));

exceptions.addAll(checkRawGridElements(gridContainer.getRawGrid()));
exceptions.addAll(
Expand Down Expand Up @@ -98,18 +80,10 @@ private GridContainerValidationUtils() {
return List.of(isNull);
}

List<Try<Void, ? extends ValidationException>> exceptions = new ArrayList<>();

/* sanity check to ensure distinct UUIDs */
Optional<String> exceptionString =
checkForDuplicateUuids(new HashSet<>(rawGridElements.allEntitiesAsList()));
exceptions.add(
Try.ofVoid(
exceptionString.isPresent(),
() ->
new InvalidGridException(
duplicateUuidsString(
rawGridElements.getClass().getSimpleName(), exceptionString))));
List<Try<Void, ? extends ValidationException>> exceptions =
new ArrayList<>(
checkForDuplicate(rawGridElements.allEntitiesAsList(), UniqueEntity::getUuid));

/* Checking nodes */
Set<NodeInput> nodes = rawGridElements.getNodes();
Expand Down Expand Up @@ -183,18 +157,18 @@ private GridContainerValidationUtils() {
* Checks the validity of type ids of every entity.
*
* @param rawGridElements the raw grid elements
* @return a list of try objects either containing an {@link UnsafeEntityException} or an empty
* Success
* @return a list of try objects either containing an {@link DuplicateEntitiesException} or an
* empty Success
*/
protected static List<Try<Void, UnsafeEntityException>> checkRawGridTypeIds(
protected static List<Try<Void, DuplicateEntitiesException>> checkRawGridTypeIds(
RawGridElements rawGridElements) {
List<Try<Void, UnsafeEntityException>> exceptions = new ArrayList<>();
exceptions.addAll(ValidationUtils.checkIds(rawGridElements.getNodes()));
exceptions.addAll(ValidationUtils.checkIds(rawGridElements.getLines()));
exceptions.addAll(ValidationUtils.checkIds(rawGridElements.getTransformer2Ws()));
exceptions.addAll(ValidationUtils.checkIds(rawGridElements.getTransformer3Ws()));
exceptions.addAll(ValidationUtils.checkIds(rawGridElements.getSwitches()));
exceptions.addAll(ValidationUtils.checkIds(rawGridElements.getMeasurementUnits()));
List<Try<Void, DuplicateEntitiesException>> exceptions = new ArrayList<>();
exceptions.addAll(checkForDuplicate(rawGridElements.getNodes(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(rawGridElements.getLines(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(rawGridElements.getTransformer2Ws(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(rawGridElements.getTransformer3Ws(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(rawGridElements.getSwitches(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(rawGridElements.getMeasurementUnits(), AssetInput::getId));

return exceptions;
}
Expand All @@ -217,19 +191,10 @@ protected static List<Try<Void, UnsafeEntityException>> checkRawGridTypeIds(
return List.of(isNull);
}

List<Try<Void, ? extends ValidationException>> exceptions = new ArrayList<>();

// sanity check for distinct uuids
Optional<String> exceptionString =
ValidationUtils.checkForDuplicateUuids(
new HashSet<>(systemParticipants.allEntitiesAsList()));
exceptions.add(
Try.ofVoid(
exceptionString.isPresent(),
() ->
new InvalidGridException(
duplicateUuidsString(
systemParticipants.getClass().getSimpleName(), exceptionString))));
List<Try<Void, ? extends ValidationException>> exceptions =
new ArrayList<>(
checkForDuplicate(systemParticipants.allEntitiesAsList(), UniqueEntity::getUuid));

exceptions.addAll(checkSystemParticipants(systemParticipants.getBmPlants(), nodes));
exceptions.addAll(checkSystemParticipants(systemParticipants.getChpPlants(), nodes));
Expand Down Expand Up @@ -274,23 +239,23 @@ protected static List<Try<Void, UnsafeEntityException>> checkRawGridTypeIds(
* Checks the validity of type ids of every entity.
*
* @param systemParticipants the system participants
* @return a list of try objects either containing an {@link UnsafeEntityException} or an empty
* Success
* @return a list of try objects either containing an {@link DuplicateEntitiesException} or an
* empty Success
*/
protected static List<Try<Void, UnsafeEntityException>> checkSystemParticipantsTypeIds(
protected static List<Try<Void, DuplicateEntitiesException>> checkSystemParticipantsTypeIds(
SystemParticipants systemParticipants) {
List<Try<Void, UnsafeEntityException>> exceptions = new ArrayList<>();
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getBmPlants()));
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getChpPlants()));
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getEvCS()));
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getEvs()));
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getFixedFeedIns()));
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getHeatPumps()));
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getLoads()));
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getPvPlants()));
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getStorages()));
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getWecPlants()));
exceptions.addAll(ValidationUtils.checkIds(systemParticipants.getEmSystems()));
List<Try<Void, DuplicateEntitiesException>> exceptions = new ArrayList<>();
exceptions.addAll(checkForDuplicate(systemParticipants.getBmPlants(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(systemParticipants.getChpPlants(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(systemParticipants.getEvCS(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(systemParticipants.getEvs(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(systemParticipants.getFixedFeedIns(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(systemParticipants.getHeatPumps(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(systemParticipants.getLoads(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(systemParticipants.getPvPlants(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(systemParticipants.getStorages(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(systemParticipants.getWecPlants(), AssetInput::getId));
exceptions.addAll(checkForDuplicate(systemParticipants.getEmSystems(), AssetInput::getId));

return exceptions;
}
Expand All @@ -312,18 +277,10 @@ protected static List<Try<Void, UnsafeEntityException>> checkSystemParticipantsT
return List.of(isNull);
}

List<Try<Void, ? extends ValidationException>> exceptions = new ArrayList<>();

// sanity check for distinct uuids
Optional<String> exceptionString =
checkForDuplicateUuids(new HashSet<>(graphicElements.allEntitiesAsList()));
exceptions.add(
Try.ofVoid(
exceptionString.isPresent(),
() ->
new InvalidGridException(
duplicateUuidsString(
graphicElements.getClass().getSimpleName(), exceptionString))));
List<Try<Void, ? extends ValidationException>> exceptions =
new ArrayList<>(
checkForDuplicate(graphicElements.allEntitiesAsList(), UniqueEntity::getUuid));

graphicElements
.getNodeGraphics()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,34 +216,6 @@ else if (SystemParticipantTypeInput.class.isAssignableFrom(assetTypeInput.getCla
return exceptions;
}

/**
* Checks the validity of the ids for a given set of {@link AssetInput}.
*
* @param inputs a set of asset inputs
* @return a list of try objects either containing an {@link UnsafeEntityException} or an empty
* Success
*/
protected static List<Try<Void, UnsafeEntityException>> checkIds(
Set<? extends AssetInput> inputs) {
List<String> ids = new ArrayList<>();
List<Try<Void, UnsafeEntityException>> exceptions = new ArrayList<>();

inputs.forEach(
input -> {
String id = input.getId();
if (!ids.contains(id)) {
ids.add(id);
} else {
exceptions.add(
new Failure<>(
new UnsafeEntityException(
"There is already an entity with the id " + id, input)));
}
});

return exceptions;
}

/**
* Checks, if the given object is null. If so, an {@link InvalidEntityException} wrapped in a
* {@link Failure} is returned.
Expand Down Expand Up @@ -354,38 +326,44 @@ public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor
}

/**
* Checks if the provided set of unique entities only contains elements with distinct UUIDs and
* either returns a string with duplicated UUIDs or an empty optional otherwise.
* Method to check for duplicate fields in a set of {@link UniqueEntity}.
*
* @param entities the entities that should be checkd for UUID uniqueness
* @return either a string wrapped in an optional with duplicate UUIDs or an empty optional
* @param entities to be checked
* @param supplier for the field
* @return a list of {@link Try}.
* @param <A> type of the field
* @param <B> type of the {@link UniqueEntity}
*/
protected static Optional<String> checkForDuplicateUuids(Set<UniqueEntity> entities) {
if (distinctUuids(entities)) {
return Optional.empty();
}
String duplicationsString =
entities.stream()
.collect(Collectors.groupingBy(UniqueEntity::getUuid, Collectors.counting()))
.entrySet()
.stream()
.filter(entry -> entry.getValue() > 1)
.map(
entry -> {
String duplicateEntitiesString =
entities.stream()
.filter(entity -> entity.getUuid().equals(entry.getKey()))
.map(UniqueEntity::toString)
.collect(Collectors.joining("\n - "));

return entry.getKey()
+ ": "
+ entry.getValue()
+ "\n - "
+ duplicateEntitiesString;
})
.collect(Collectors.joining("\n\n"));

return Optional.of(duplicationsString);
protected static <A, B extends UniqueEntity>
List<Try<Void, DuplicateEntitiesException>> checkForDuplicate(
Collection<B> entities, FieldSupplier<A, B> supplier) {
Map<A, List<B>> duplicates =
entities.stream().collect(Collectors.groupingBy(supplier::getField));

List<Try<Void, DuplicateEntitiesException>> exceptions = new ArrayList<>();

duplicates.entrySet().stream()
.filter(e -> e.getValue().size() > 1)
.forEach(
duplicate -> {
A key = duplicate.getKey();
exceptions.add(
Failure.ofVoid(
new DuplicateEntitiesException(
key.getClass().getSimpleName(), duplicates.get(key))));
});

return exceptions;
}

/**
* Supplier for unique entity fields.
*
* @param <A> type of field
* @param <B> type of unique entity
*/
@FunctionalInterface
protected interface FieldSupplier<A, B extends UniqueEntity> {
A getField(B entity);
}
}
Loading