From 9b859d6fcc6e78e77657b2611efd98f033145758 Mon Sep 17 00:00:00 2001
From: Tristan Chuine
Date: Thu, 25 Sep 2025 08:24:13 +0200
Subject: [PATCH 1/7] Move utility functions from computation library
---
.../AbstractGlobalFilterService.java | 29 +++
.../filter/globalfilter/GlobalFilter.java | 34 +++
.../globalfilter/GlobalFilterUtils.java | 200 ++++++++++++++++++
.../gridsuite/filter/utils/FiltersUtils.java | 28 +++
.../utils/expertfilter/ExpertFilterUtils.java | 30 +++
5 files changed, 321 insertions(+)
create mode 100644 src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java
create mode 100644 src/main/java/org/gridsuite/filter/globalfilter/GlobalFilter.java
create mode 100644 src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java
diff --git a/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java b/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java
new file mode 100644
index 0000000..be4021d
--- /dev/null
+++ b/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java
@@ -0,0 +1,29 @@
+package org.gridsuite.filter.globalfilter;
+
+import com.powsybl.iidm.network.Network;
+import lombok.NonNull;
+import org.gridsuite.filter.AbstractFilter;
+import org.gridsuite.filter.FilterLoader;
+import org.gridsuite.filter.utils.EquipmentType;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
+
+public abstract class AbstractGlobalFilterService implements FilterLoader {
+ protected abstract Network getNetwork(@NonNull UUID networkUuid, @NonNull String variantId);
+
+ protected List getIdsFilter(@NonNull final UUID networkUuid, @NonNull final String variantId,
+ @NonNull final GlobalFilter globalFilter, @NonNull final List equipmentTypes) {
+ final Network network = getNetwork(networkUuid, variantId);
+ final List genericFilters = getFilters(globalFilter.getGenericFilter());
+ return GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, genericFilters, equipmentTypes, this)
+ // Filter equipments by type
+ .values()
+ .stream()
+ .filter(Objects::nonNull)
+ // Combine all results into one list
+ .flatMap(List::stream)
+ .toList();
+ }
+}
diff --git a/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilter.java b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilter.java
new file mode 100644
index 0000000..61d609c
--- /dev/null
+++ b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilter.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2024, 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.filter.globalfilter;
+
+import com.powsybl.iidm.network.Country;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.FieldNameConstants;
+import lombok.experimental.SuperBuilder;
+
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * @author maissa Souissi
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@SuperBuilder
+@FieldNameConstants
+// TODO convert to record when loadflow-server and computation lib stop to extends it
+public class GlobalFilter {
+ private List nominalV;
+ private List countryCode;
+ private List genericFilter;
+ private Map> substationProperty;
+}
diff --git a/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java
new file mode 100644
index 0000000..61bef61
--- /dev/null
+++ b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java
@@ -0,0 +1,200 @@
+package org.gridsuite.filter.globalfilter;
+
+import com.powsybl.iidm.network.Country;
+import com.powsybl.iidm.network.Identifiable;
+import com.powsybl.iidm.network.Network;
+import org.gridsuite.filter.AbstractFilter;
+import org.gridsuite.filter.FilterLoader;
+import org.gridsuite.filter.expertfilter.ExpertFilter;
+import org.gridsuite.filter.expertfilter.expertrule.*;
+import org.gridsuite.filter.utils.EquipmentType;
+import org.gridsuite.filter.utils.FiltersUtils;
+import org.gridsuite.filter.utils.expertfilter.CombinatorType;
+import org.gridsuite.filter.utils.expertfilter.ExpertFilterUtils;
+import org.gridsuite.filter.utils.expertfilter.FieldType;
+import org.gridsuite.filter.utils.expertfilter.OperatorType;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.*;
+import java.util.function.Predicate;
+
+public final class GlobalFilterUtils {
+ private GlobalFilterUtils() {
+ throw new IllegalCallerException("Utility class should not be instantiated");
+ }
+
+ public static List getNominalVoltageFieldType(@Nonnull final EquipmentType equipmentType) {
+ return switch (equipmentType) {
+ case LINE, TWO_WINDINGS_TRANSFORMER -> List.of(FieldType.NOMINAL_VOLTAGE_1, FieldType.NOMINAL_VOLTAGE_2);
+ case VOLTAGE_LEVEL -> List.of(FieldType.NOMINAL_VOLTAGE);
+ default -> List.of();
+ };
+ }
+
+ /**
+ * Builds nominal voltage rules combining all relevant field types
+ * @see GlobalFilter#getNominalV()
+ */
+ public static Optional buildNominalVoltageRules(
+ @Nonnull final List nominalVoltages, @Nonnull final EquipmentType equipmentType) {
+ final List fields = getNominalVoltageFieldType(equipmentType);
+ return ExpertFilterUtils.buildOrCombination(nominalVoltages.stream()
+ .filter(Predicate.not(String::isBlank))
+ .map(Double::valueOf)
+ .mapMulti((value, accumulator) -> {
+ for (final FieldType field : fields) {
+ accumulator.accept(NumberExpertRule.builder()
+ .value(value)
+ .field(field)
+ .operator(OperatorType.EQUALS)
+ .build());
+ }
+ }).toList());
+ }
+
+ public static List getCountryCodeFieldType(@Nonnull final EquipmentType equipmentType) {
+ return switch (equipmentType) {
+ case VOLTAGE_LEVEL, TWO_WINDINGS_TRANSFORMER -> List.of(FieldType.COUNTRY);
+ case LINE -> List.of(FieldType.COUNTRY_1, FieldType.COUNTRY_2);
+ default -> List.of();
+ };
+ }
+
+ /**
+ * Builds country code rules combining all relevant field types
+ */
+ public static Optional buildCountryCodeRules(
+ @Nonnull final List countryCodes, @Nonnull final EquipmentType equipmentType) {
+ final List fields = getCountryCodeFieldType(equipmentType);
+ return ExpertFilterUtils.buildOrCombination(countryCodes.stream()
+ .map(Country::name)
+ .mapMulti((countryCode, accumulator) -> {
+ for (final FieldType field : fields) {
+ accumulator.accept(EnumExpertRule.builder()
+ .value(countryCode)
+ .field(field)
+ .operator(OperatorType.EQUALS)
+ .build());
+ }
+ })
+ .toList());
+ }
+
+ public static List getSubstationPropertiesFieldTypes(@Nonnull final EquipmentType equipmentType) {
+ return equipmentType == EquipmentType.LINE
+ ? List.of(FieldType.SUBSTATION_PROPERTIES_1, FieldType.SUBSTATION_PROPERTIES_2)
+ : List.of(FieldType.SUBSTATION_PROPERTIES);
+ }
+
+ /**
+ * Builds substation property rules combining all relevant field types
+ */
+ protected static Optional buildSubstationPropertyRules(
+ @Nonnull final Map> properties, @Nonnull final EquipmentType equipmentType) {
+ final List fields = getSubstationPropertiesFieldTypes(equipmentType);
+ return ExpertFilterUtils.buildOrCombination(properties.entrySet()
+ .stream()
+ .mapMulti((entry, accumulator) -> {
+ for (final FieldType field : fields) {
+ accumulator.accept(PropertiesExpertRule.builder()
+ .combinator(CombinatorType.OR)
+ .operator(OperatorType.IN)
+ .field(field)
+ .propertyName(entry.getKey())
+ .propertyValues(entry.getValue())
+ .build());
+ }
+ })
+ .toList());
+ }
+
+ /**
+ * Builds expert filter from a {@link GlobalFilter global filter} for an {@link EquipmentType equipment type}.
+ */
+ @Nullable
+ public static ExpertFilter buildExpertFilter(@Nonnull final GlobalFilter globalFilter, @Nonnull final EquipmentType equipmentType) {
+ final List andRules = new ArrayList<>();
+
+ // Nominal voltage rules
+ buildNominalVoltageRules(globalFilter.getNominalV(), equipmentType).ifPresent(andRules::add);
+
+ // Country code rules
+ buildCountryCodeRules(globalFilter.getCountryCode(), equipmentType).ifPresent(andRules::add);
+
+ // Substation property rules
+ if (globalFilter.getSubstationProperty() != null) {
+ buildSubstationPropertyRules(globalFilter.getSubstationProperty(), equipmentType).ifPresent(andRules::add);
+ }
+
+ return andRules.isEmpty() ? null : new ExpertFilter(UUID.randomUUID(), new Date(), equipmentType,
+ CombinatorExpertRule.builder().combinator(CombinatorType.AND).rules(andRules).build());
+ }
+
+ @Nonnull
+ private static List filterNetwork(@Nonnull final AbstractFilter filter, @Nonnull final Network network, @Nonnull final FilterLoader filterLoader) {
+ return FiltersUtils.getIdentifiables(filter, network, filterLoader)
+ .stream()
+ .map(Identifiable::getId)
+ .toList();
+ }
+
+ /**
+ * Extracts {@link Identifiable#getId() equipment ID}s from a generic filter based on {@link EquipmentType equipment type}.
+ */
+ @Nonnull
+ public static List applyFilterOnNetwork(@Nonnull final AbstractFilter filter, @Nonnull final EquipmentType targetEquipmentType,
+ @Nonnull final Network network, @Nonnull final FilterLoader filterLoader) {
+ if (filter.getEquipmentType() == targetEquipmentType) {
+ return filterNetwork(filter, network, filterLoader);
+ } else if (filter.getEquipmentType() == EquipmentType.VOLTAGE_LEVEL) {
+ return filterNetwork(ExpertFilterUtils.buildExpertFilterWithVoltageLevelIdsCriteria(filter.getId(), targetEquipmentType), network, filterLoader);
+ }
+ return List.of();
+ }
+
+ /**
+ * Extracts filtered {@link Identifiable#getId() equipment ID}s by applying {@link ExpertFilter expert}
+ * and {@link AbstractFilter generic filter}s.
+ */
+ public static List applyGlobalFilterOnNetwork(@Nonnull final Network network,
+ @Nonnull final GlobalFilter globalFilter, @Nonnull final List genericFilters,
+ @Nonnull final EquipmentType equipmentType, @Nonnull final FilterLoader filterLoader) {
+ List> allFilterResults = new ArrayList<>(1 + genericFilters.size());
+
+ // Extract IDs from expert filter
+ final ExpertFilter expertFilter = buildExpertFilter(globalFilter, equipmentType);
+ if (expertFilter != null) {
+ allFilterResults.add(filterNetwork(expertFilter, network, filterLoader));
+ }
+
+ // Extract IDs from generic filters
+ for (final AbstractFilter filter : genericFilters) {
+ final List filterResult = applyFilterOnNetwork(filter, equipmentType, network, filterLoader);
+ if (!filterResult.isEmpty()) {
+ allFilterResults.add(filterResult);
+ }
+ }
+
+ // Combine results with appropriate logic
+ // Expert filters use OR between them, generic filters use AND
+ return FiltersUtils.combineFilterResults(allFilterResults, !genericFilters.isEmpty());
+ }
+
+ /**
+ * Filters equipments by {@link EquipmentType type}
+ * @return map of {@link Identifiable#getId() equipment ID}s grouped by {@link EquipmentType equipment type}
+ */
+ public static Map> applyGlobalFilterOnNetwork(@Nonnull final Network network,
+ @Nonnull final GlobalFilter globalFilter, @Nonnull final List genericFilters,
+ @Nonnull final List equipmentTypes, @Nonnull final FilterLoader filterLoader) {
+ Map> result = new EnumMap<>(EquipmentType.class);
+ for (final EquipmentType equipmentType : equipmentTypes) {
+ final List filteredIds = applyGlobalFilterOnNetwork(network, globalFilter, genericFilters, equipmentType, filterLoader);
+ if (!filteredIds.isEmpty()) {
+ result.put(equipmentType, filteredIds);
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/org/gridsuite/filter/utils/FiltersUtils.java b/src/main/java/org/gridsuite/filter/utils/FiltersUtils.java
index 77255fe..191705e 100644
--- a/src/main/java/org/gridsuite/filter/utils/FiltersUtils.java
+++ b/src/main/java/org/gridsuite/filter/utils/FiltersUtils.java
@@ -14,6 +14,8 @@
import org.gridsuite.filter.identifierlistfilter.IdentifierListFilter;
import org.gridsuite.filter.identifierlistfilter.IdentifierListFilterEquipmentAttributes;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -237,4 +239,30 @@ public static List> getIdentifiables(AbstractFilter filter, Netw
case SUBSTATION -> getSubstationList(network, filter, filterLoader);
};
}
+
+ /**
+ * Combines multiple filter results using AND or OR logic.
+ */
+ @Nonnull
+ public static List combineFilterResults(@Nullable final List> filterResults, final boolean useAndLogic) {
+ if (filterResults == null || filterResults.isEmpty()) {
+ return List.of();
+ }
+ if (filterResults.size() == 1) {
+ return filterResults.getFirst();
+ }
+ if (useAndLogic) {
+ // Intersection of all results
+ Set result = new HashSet<>(filterResults.getFirst());
+ for (int i = 1; i < filterResults.size(); i++) {
+ result.retainAll(filterResults.get(i));
+ }
+ return new ArrayList<>(result);
+ } else {
+ // Union of all results
+ Set result = new HashSet<>();
+ filterResults.forEach(result::addAll);
+ return new ArrayList<>(result);
+ }
+ }
}
diff --git a/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java b/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java
index c9a22ec..29c1310 100644
--- a/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java
+++ b/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java
@@ -13,8 +13,13 @@
import com.powsybl.iidm.network.extensions.StandbyAutomaton;
import org.apache.commons.collections4.CollectionUtils;
import org.gridsuite.filter.FilterLoader;
+import org.gridsuite.filter.expertfilter.ExpertFilter;
+import org.gridsuite.filter.expertfilter.expertrule.AbstractExpertRule;
+import org.gridsuite.filter.expertfilter.expertrule.CombinatorExpertRule;
+import org.gridsuite.filter.expertfilter.expertrule.FilterUuidExpertRule;
import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
import org.gridsuite.filter.identifierlistfilter.IdentifiableAttributes;
+import org.gridsuite.filter.utils.EquipmentType;
import org.gridsuite.filter.utils.FilterServiceUtils;
import org.gridsuite.filter.utils.RegulationType;
@@ -626,4 +631,29 @@ public static boolean isPartOf(Network network, String value, Set uuids,
return equipments.stream().flatMap(e -> e.getIdentifiableAttributes().stream()
.map(IdentifiableAttributes::getId)).collect(Collectors.toSet()).contains(value);
}
+
+ /**
+ * Build an "OR" rule from the rules passed.
+ * @param rules the rule(s) to be applied
+ * @return {@link Optional#empty() Empty} if no rule is passed,
+ * the {@link AbstractExpertRule rule} if the list has only 1 rule inside,
+ * otherwise an {@link CombinatorExpertRule OR combinator} with the rules.
+ */
+ @Nonnull
+ public static Optional buildOrCombination(@Nullable final List rules) {
+ if (rules == null || rules.isEmpty()) {
+ return Optional.empty();
+ }
+ return Optional.of(rules.size() > 1 ? CombinatorExpertRule.builder().combinator(CombinatorType.OR).rules(rules).build() : rules.getFirst());
+ }
+
+ /**
+ * Builds expert filter with {@link VoltageLevel voltage level} IDs criteria.
+ */
+ public static ExpertFilter buildExpertFilterWithVoltageLevelIdsCriteria(@Nonnull final UUID filterUuid, @Nonnull final EquipmentType equipmentType) {
+ return new ExpertFilter(UUID.randomUUID(), new Date(), equipmentType, CombinatorExpertRule.builder().combinator(CombinatorType.OR).rules(List.of(
+ FilterUuidExpertRule.builder().operator(OperatorType.IS_PART_OF).field(FieldType.VOLTAGE_LEVEL_ID_1).values(Set.of(filterUuid.toString())).build(),
+ FilterUuidExpertRule.builder().operator(OperatorType.IS_PART_OF).field(FieldType.VOLTAGE_LEVEL_ID_2).values(Set.of(filterUuid.toString())).build()
+ )).build());
+ }
}
From 3a9bddd7b808ac0c61948f7366374221de86e7bf Mon Sep 17 00:00:00 2001
From: Tristan Chuine
Date: Wed, 17 Sep 2025 16:22:56 +0200
Subject: [PATCH 2/7] prepare class test
---
.../org/gridsuite/filter/utils/TimeUtils.java | 24 ++++++++++
.../org/gridsuite/filter/utils/UuidUtils.java | 24 ++++++++++
.../globalfilter/GlobalFilterUtilsTest.java | 4 ++
.../filter/utils/FiltersUtilsTest.java | 45 ++++++++++++-------
.../expertfilter/ExpertFilterUtilsTest.java | 4 ++
5 files changed, 85 insertions(+), 16 deletions(-)
create mode 100644 src/main/java/org/gridsuite/filter/utils/TimeUtils.java
create mode 100644 src/main/java/org/gridsuite/filter/utils/UuidUtils.java
create mode 100644 src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java
create mode 100644 src/test/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtilsTest.java
diff --git a/src/main/java/org/gridsuite/filter/utils/TimeUtils.java b/src/main/java/org/gridsuite/filter/utils/TimeUtils.java
new file mode 100644
index 0000000..d154e1c
--- /dev/null
+++ b/src/main/java/org/gridsuite/filter/utils/TimeUtils.java
@@ -0,0 +1,24 @@
+package org.gridsuite.filter.utils;
+
+import com.google.common.annotations.VisibleForTesting;
+import lombok.Setter;
+
+import java.util.UUID;
+import java.util.function.Supplier;
+
+/**
+ * Utility class for UUID to permit during tests to mock {@link UUID} generation..
+ */
+@VisibleForTesting
+public final class TimeUtils {
+ private TimeUtils() {
+ throw new AssertionError("Utility class should not be instantiated");
+ }
+
+ @Setter
+ private static Supplier uuidSupplier = UUID::randomUUID;
+
+ public static UUID generateUUID() {
+ return uuidSupplier.get();
+ }
+}
diff --git a/src/main/java/org/gridsuite/filter/utils/UuidUtils.java b/src/main/java/org/gridsuite/filter/utils/UuidUtils.java
new file mode 100644
index 0000000..9ce29d1
--- /dev/null
+++ b/src/main/java/org/gridsuite/filter/utils/UuidUtils.java
@@ -0,0 +1,24 @@
+package org.gridsuite.filter.utils;
+
+import com.google.common.annotations.VisibleForTesting;
+import lombok.Setter;
+
+import java.util.UUID;
+import java.util.function.Supplier;
+
+/**
+ * Utility class for UUID to permit during tests to mock {@link UUID} generation..
+ */
+@VisibleForTesting
+public final class UuidUtils {
+ private UuidUtils() {
+ throw new AssertionError("Utility class should not be instantiated");
+ }
+
+ @Setter
+ private static Supplier uuidSupplier = UUID::randomUUID;
+
+ public static UUID generateUUID() {
+ return uuidSupplier.get();
+ }
+}
diff --git a/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java b/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java
new file mode 100644
index 0000000..9d50f61
--- /dev/null
+++ b/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java
@@ -0,0 +1,4 @@
+package org.gridsuite.filter.globalfilter;
+
+public class GlobalFilterUtilsTest {
+}
diff --git a/src/test/java/org/gridsuite/filter/utils/FiltersUtilsTest.java b/src/test/java/org/gridsuite/filter/utils/FiltersUtilsTest.java
index 6a9f279..2ed06fd 100644
--- a/src/test/java/org/gridsuite/filter/utils/FiltersUtilsTest.java
+++ b/src/test/java/org/gridsuite/filter/utils/FiltersUtilsTest.java
@@ -21,7 +21,6 @@
import org.gridsuite.filter.identifierlistfilter.IdentifierListFilterEquipmentAttributes;
import org.gridsuite.filter.utils.expertfilter.CombinatorType;
import org.gridsuite.filter.utils.expertfilter.OperatorType;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.*;
@@ -34,17 +33,10 @@
* @author Franck Lecuyer
*/
class FiltersUtilsTest {
- private Network network;
- private Network network2;
- private Network network3;
- private Network network4;
- private Network network5;
+ private final FilterLoader filterLoader = uuids -> null;
- private FilterLoader filterLoader;
-
- @BeforeEach
- void setUp() {
- network = EurostagTutorialExample1Factory.createWithMoreGenerators();
+ private static Network prepareNetwork() {
+ Network network = EurostagTutorialExample1Factory.createWithMoreGenerators();
network.getSubstation("P1").setProperty("region", "north");
network.getSubstation("P2").setProperty("region", "south");
network.getGenerator("GEN").setProperty("region", "north");
@@ -54,17 +46,18 @@ void setUp() {
network.getTwoWindingsTransformer("NHV2_NLOAD").setProperty("region", "south");
network.getLine("NHV1_NHV2_1").setProperty("region", "south");
network.getLine("NHV1_NHV2_2").setProperty("region", "south");
+ return network;
+ }
- network2 = HvdcTestNetwork.createVsc();
+ private static Network prepareHvdcNetwork() {
+ Network network2 = HvdcTestNetwork.createVsc();
network2.getSubstation("S2").setProperty("region", "north");
- network3 = SvcTestCaseFactory.createWithMoreSVCs();
- network4 = ShuntTestCaseFactory.create();
- network5 = ThreeWindingsTransformerNetworkFactory.create();
- filterLoader = uuids -> null;
+ return network2;
}
@Test
void testSubstationFilter() {
+ final Network network = prepareNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -95,6 +88,7 @@ void testSubstationFilter() {
@Test
void testVoltageLevelFilter() {
+ final Network network = prepareNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -124,6 +118,7 @@ void testVoltageLevelFilter() {
@Test
void testLineFilter() {
+ final Network network = prepareNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -155,6 +150,7 @@ void testLineFilter() {
@Test
void testTwoWindingsTransformerFilter() {
+ final Network network = prepareNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -184,6 +180,7 @@ void testTwoWindingsTransformerFilter() {
@Test
void testThreeWindingsTransformerFilter() {
+ final Network network5 = ThreeWindingsTransformerNetworkFactory.create();
// expert filter
ExpertFilter expertFilter = new ExpertFilter(
@@ -200,6 +197,7 @@ void testThreeWindingsTransformerFilter() {
@Test
void testGeneratorFilter() {
+ final Network network = prepareNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -232,6 +230,7 @@ void testGeneratorFilter() {
@Test
void testLoadFilter() {
+ final Network network = prepareNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -261,6 +260,7 @@ void testLoadFilter() {
@Test
void testBatteryFilter() {
+ final Network network = prepareNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -288,6 +288,7 @@ void testBatteryFilter() {
@Test
void testShuntCompensatorFilter() {
+ final Network network4 = ShuntTestCaseFactory.create();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -317,6 +318,7 @@ void testShuntCompensatorFilter() {
@Test
void testStaticVarCompensatorFilter() {
+ final Network network3 = SvcTestCaseFactory.createWithMoreSVCs();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -349,6 +351,7 @@ void testStaticVarCompensatorFilter() {
@Test
void testDanglingLineFilter() {
+ final Network network = prepareNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -376,6 +379,7 @@ void testDanglingLineFilter() {
@Test
void testBusbarSectionFilter() {
+ final Network network = prepareNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -403,6 +407,8 @@ void testBusbarSectionFilter() {
@Test
void testBusFilter() {
+ final Network network = prepareNetwork();
+
// expert filter only for bus
ExpertFilter expertFilter = new ExpertFilter(
UUID.randomUUID(),
@@ -417,6 +423,7 @@ void testBusFilter() {
@Test
void testLccConverterStationFilter() {
+ final Network network = prepareNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -444,6 +451,7 @@ void testLccConverterStationFilter() {
@Test
void testHvdcLineFilter() {
+ final Network network2 = prepareHvdcNetwork();
// identifier list filter
List filterEquipmentAttributes = List.of(
@@ -474,6 +482,7 @@ void testHvdcLineFilter() {
@Test
void testIdentifierListFilter() {
+ final Network network = prepareNetwork();
List filterEquipmentAttributes = List.of(
new IdentifierListFilterEquipmentAttributes("GEN", 30.),
new IdentifierListFilterEquipmentAttributes("notFound1", 50.),
@@ -513,6 +522,7 @@ void testIdentifierListFilter() {
@Test
void testFilterLoader() {
+ final Network network = prepareNetwork();
// with identifier list filter
List filterEquipmentAttributes = List.of(
new IdentifierListFilterEquipmentAttributes("GEN", 30.),
@@ -539,6 +549,7 @@ void testFilterLoader() {
@Test
void testEquipmentNameFilterNoMatch() {
+ final Network network2 = prepareHvdcNetwork();
List rules = new ArrayList<>();
rules.add(StringExpertRule.builder().field(NAME).operator(IS).value("unexisting name").build());
AbstractExpertRule parentRule = CombinatorExpertRule.builder().combinator(CombinatorType.AND).rules(rules).build();
@@ -555,6 +566,7 @@ void testEquipmentNameFilterNoMatch() {
@Test
void testEquipmentNameFilterWithMatch() {
+ final Network network2 = prepareHvdcNetwork();
List rules = new ArrayList<>();
rules.add(StringExpertRule.builder().field(NAME).operator(IS).value("Converter1").build());
AbstractExpertRule parentRule = CombinatorExpertRule.builder().combinator(CombinatorType.AND).rules(rules).build();
@@ -570,6 +582,7 @@ void testEquipmentNameFilterWithMatch() {
@Test
void testEquipmentNameFilterWithNullValueInEquipments() {
+ final Network network = prepareNetwork();
List rules = new ArrayList<>();
rules.add(StringExpertRule.builder().field(NAME).operator(IS).value("some name").build());
AbstractExpertRule parentRule = CombinatorExpertRule.builder().combinator(CombinatorType.AND).rules(rules).build();
diff --git a/src/test/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtilsTest.java b/src/test/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtilsTest.java
new file mode 100644
index 0000000..456de08
--- /dev/null
+++ b/src/test/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtilsTest.java
@@ -0,0 +1,4 @@
+package org.gridsuite.filter.utils.expertfilter;
+
+public class ExpertFilterUtilsTest {
+}
From 34de3c63498456b2fe3269eddbdff04300635769 Mon Sep 17 00:00:00 2001
From: Tristan Chuine
Date: Wed, 17 Sep 2025 17:08:17 +0200
Subject: [PATCH 3/7] Set API nullable
---
.../filter/globalfilter/GlobalFilterUtils.java | 12 ++++++++++--
.../filter/utils/expertfilter/ExpertFilterUtils.java | 1 +
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java
index 61bef61..42ac8e6 100644
--- a/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java
+++ b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java
@@ -24,6 +24,7 @@ private GlobalFilterUtils() {
throw new IllegalCallerException("Utility class should not be instantiated");
}
+ @Nonnull
public static List getNominalVoltageFieldType(@Nonnull final EquipmentType equipmentType) {
return switch (equipmentType) {
case LINE, TWO_WINDINGS_TRANSFORMER -> List.of(FieldType.NOMINAL_VOLTAGE_1, FieldType.NOMINAL_VOLTAGE_2);
@@ -36,6 +37,7 @@ public static List getNominalVoltageFieldType(@Nonnull final Equipmen
* Builds nominal voltage rules combining all relevant field types
* @see GlobalFilter#getNominalV()
*/
+ @Nonnull
public static Optional buildNominalVoltageRules(
@Nonnull final List nominalVoltages, @Nonnull final EquipmentType equipmentType) {
final List fields = getNominalVoltageFieldType(equipmentType);
@@ -53,6 +55,7 @@ public static Optional buildNominalVoltageRules(
}).toList());
}
+ @Nonnull
public static List getCountryCodeFieldType(@Nonnull final EquipmentType equipmentType) {
return switch (equipmentType) {
case VOLTAGE_LEVEL, TWO_WINDINGS_TRANSFORMER -> List.of(FieldType.COUNTRY);
@@ -64,6 +67,7 @@ public static List getCountryCodeFieldType(@Nonnull final EquipmentTy
/**
* Builds country code rules combining all relevant field types
*/
+ @Nonnull
public static Optional buildCountryCodeRules(
@Nonnull final List countryCodes, @Nonnull final EquipmentType equipmentType) {
final List fields = getCountryCodeFieldType(equipmentType);
@@ -81,7 +85,8 @@ public static Optional buildCountryCodeRules(
.toList());
}
- public static List getSubstationPropertiesFieldTypes(@Nonnull final EquipmentType equipmentType) {
+ @Nonnull
+ public static List getSubstationPropertiesFieldTypes(@Nullable final EquipmentType equipmentType) {
return equipmentType == EquipmentType.LINE
? List.of(FieldType.SUBSTATION_PROPERTIES_1, FieldType.SUBSTATION_PROPERTIES_2)
: List.of(FieldType.SUBSTATION_PROPERTIES);
@@ -90,7 +95,8 @@ public static List getSubstationPropertiesFieldTypes(@Nonnull final E
/**
* Builds substation property rules combining all relevant field types
*/
- protected static Optional buildSubstationPropertyRules(
+ @Nonnull
+ public static Optional buildSubstationPropertyRules(
@Nonnull final Map> properties, @Nonnull final EquipmentType equipmentType) {
final List fields = getSubstationPropertiesFieldTypes(equipmentType);
return ExpertFilterUtils.buildOrCombination(properties.entrySet()
@@ -157,6 +163,7 @@ public static List applyFilterOnNetwork(@Nonnull final AbstractFilter fi
* Extracts filtered {@link Identifiable#getId() equipment ID}s by applying {@link ExpertFilter expert}
* and {@link AbstractFilter generic filter}s.
*/
+ @Nonnull
public static List applyGlobalFilterOnNetwork(@Nonnull final Network network,
@Nonnull final GlobalFilter globalFilter, @Nonnull final List genericFilters,
@Nonnull final EquipmentType equipmentType, @Nonnull final FilterLoader filterLoader) {
@@ -185,6 +192,7 @@ public static List applyGlobalFilterOnNetwork(@Nonnull final Network net
* Filters equipments by {@link EquipmentType type}
* @return map of {@link Identifiable#getId() equipment ID}s grouped by {@link EquipmentType equipment type}
*/
+ @Nonnull
public static Map> applyGlobalFilterOnNetwork(@Nonnull final Network network,
@Nonnull final GlobalFilter globalFilter, @Nonnull final List genericFilters,
@Nonnull final List equipmentTypes, @Nonnull final FilterLoader filterLoader) {
diff --git a/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java b/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java
index 29c1310..4407603 100644
--- a/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java
+++ b/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java
@@ -650,6 +650,7 @@ public static Optional buildOrCombination(@Nullable final Li
/**
* Builds expert filter with {@link VoltageLevel voltage level} IDs criteria.
*/
+ @Nonnull
public static ExpertFilter buildExpertFilterWithVoltageLevelIdsCriteria(@Nonnull final UUID filterUuid, @Nonnull final EquipmentType equipmentType) {
return new ExpertFilter(UUID.randomUUID(), new Date(), equipmentType, CombinatorExpertRule.builder().combinator(CombinatorType.OR).rules(List.of(
FilterUuidExpertRule.builder().operator(OperatorType.IS_PART_OF).field(FieldType.VOLTAGE_LEVEL_ID_1).values(Set.of(filterUuid.toString())).build(),
From 68d1edf97a4134e90d8f70993ce228f702f0eacf Mon Sep 17 00:00:00 2001
From: Tristan Chuine
Date: Wed, 17 Sep 2025 17:08:45 +0200
Subject: [PATCH 4/7] note
---
src/main/java/org/gridsuite/filter/AbstractFilter.java | 6 ++++--
src/main/java/org/gridsuite/filter/IFilterAttributes.java | 7 +++++--
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/main/java/org/gridsuite/filter/AbstractFilter.java b/src/main/java/org/gridsuite/filter/AbstractFilter.java
index 41942dd..b8457de 100644
--- a/src/main/java/org/gridsuite/filter/AbstractFilter.java
+++ b/src/main/java/org/gridsuite/filter/AbstractFilter.java
@@ -8,7 +8,9 @@
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import lombok.*;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.gridsuite.filter.expertfilter.ExpertFilter;
import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
@@ -43,7 +45,7 @@ public abstract class AbstractFilter implements IFilterAttributes {
private UUID id;
- private Date modificationDate;
+ private Date modificationDate; // TODO use Instant like in servers (client not on same timezone than server)
private EquipmentType equipmentType;
diff --git a/src/main/java/org/gridsuite/filter/IFilterAttributes.java b/src/main/java/org/gridsuite/filter/IFilterAttributes.java
index d4799fb..b4d668e 100644
--- a/src/main/java/org/gridsuite/filter/IFilterAttributes.java
+++ b/src/main/java/org/gridsuite/filter/IFilterAttributes.java
@@ -10,13 +10,16 @@
import org.gridsuite.filter.utils.EquipmentType;
import org.gridsuite.filter.utils.FilterType;
+import java.util.Date;
+import java.util.UUID;
+
/**
* @author Jacques Borsenberger
*/
public interface IFilterAttributes {
- java.util.UUID getId();
+ UUID getId();
- java.util.Date getModificationDate();
+ Date getModificationDate(); // TODO use Instant like in servers (client not on same timezone than server)
FilterType getType();
From 94733e65d0d768e4aecb49ca8af02ff3f058ec16 Mon Sep 17 00:00:00 2001
From: Tristan Chuine
Date: Thu, 25 Sep 2025 22:56:33 +0200
Subject: [PATCH 5/7] enhance
---
.../globalfilter/AbstractGlobalFilterService.java | 12 ++++++++++--
.../gridsuite/filter/globalfilter/GlobalFilter.java | 13 +++++++++++++
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java b/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java
index be4021d..0b23757 100644
--- a/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java
+++ b/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java
@@ -13,8 +13,16 @@
public abstract class AbstractGlobalFilterService implements FilterLoader {
protected abstract Network getNetwork(@NonNull UUID networkUuid, @NonNull String variantId);
- protected List getIdsFilter(@NonNull final UUID networkUuid, @NonNull final String variantId,
- @NonNull final GlobalFilter globalFilter, @NonNull final List equipmentTypes) {
+ /**
+ * Get filtered equipment IDs.
+ * @param networkUuid the network to load
+ * @param variantId the network variant to work on
+ * @param globalFilter the filter(s) to apply
+ * @param equipmentTypes the {@link EquipmentType equipment types} to filter
+ * @return the {@link List list} of {@link UUID IDs} of filtered {@link EquipmentType equipments}.
+ */
+ protected List getFilteredIds(@NonNull final UUID networkUuid, @NonNull final String variantId,
+ @NonNull final GlobalFilter globalFilter, @NonNull final List equipmentTypes) {
final Network network = getNetwork(networkUuid, variantId);
final List genericFilters = getFilters(globalFilter.getGenericFilter());
return GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, genericFilters, equipmentTypes, this)
diff --git a/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilter.java b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilter.java
index 61d609c..981ce96 100644
--- a/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilter.java
+++ b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilter.java
@@ -12,6 +12,8 @@
import lombok.NoArgsConstructor;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
import java.util.List;
import java.util.Map;
@@ -31,4 +33,15 @@ public class GlobalFilter {
private List countryCode;
private List genericFilter;
private Map> substationProperty;
+
+ /**
+ * @return {@code true} if all filter parameters are empty, else {@code false}.
+ */
+ public boolean isEmpty() {
+ return CollectionUtils.isEmpty(this.nominalV)
+ && CollectionUtils.isEmpty(this.countryCode)
+ && CollectionUtils.isEmpty(this.genericFilter)
+ && MapUtils.isEmpty(this.substationProperty)
+ && this.substationProperty.values().stream().allMatch(CollectionUtils::isEmpty);
+ }
}
From 138e31875e6ee2f87d1b883961b45161322f28fc Mon Sep 17 00:00:00 2001
From: Tristan Chuine
Date: Tue, 7 Oct 2025 08:30:06 +0200
Subject: [PATCH 6/7] Move tests from computation
---
pom.xml | 5 +
.../filter/expertfilter/ExpertFilter.java | 9 +-
.../expertrule/AbstractExpertRule.java | 6 +-
.../expertrule/BooleanExpertRule.java | 10 +-
.../expertrule/CombinatorExpertRule.java | 6 +
.../expertrule/EnumExpertRule.java | 6 +
.../expertrule/FilterUuidExpertRule.java | 8 +-
.../expertrule/NumberExpertRule.java | 10 +-
.../expertrule/PropertiesExpertRule.java | 18 +-
.../expertrule/StringExpertRule.java | 10 +-
.../globalfilter/GlobalFilterUtils.java | 12 +-
.../IdentifierListFilter.java | 12 +-
.../org/gridsuite/filter/utils/TimeUtils.java | 24 +-
.../org/gridsuite/filter/utils/UuidUtils.java | 70 +++-
.../utils/expertfilter/ExpertFilterUtils.java | 15 +-
.../globalfilter/GlobalFilterUtilsTest.java | 353 +++++++++++++++++-
.../filter/utils/FiltersUtilsTest.java | 37 +-
.../expertfilter/ExpertFilterUtilsTest.java | 69 +++-
18 files changed, 597 insertions(+), 83 deletions(-)
diff --git a/pom.xml b/pom.xml
index 2a8b2fb..8b08366 100644
--- a/pom.xml
+++ b/pom.xml
@@ -141,6 +141,11 @@
hamcrest
test
+
+ org.assertj
+ assertj-core
+ test
+
com.powsybl
powsybl-iidm-test
diff --git a/src/main/java/org/gridsuite/filter/expertfilter/ExpertFilter.java b/src/main/java/org/gridsuite/filter/expertfilter/ExpertFilter.java
index 2a9b8f3..3bf4217 100644
--- a/src/main/java/org/gridsuite/filter/expertfilter/ExpertFilter.java
+++ b/src/main/java/org/gridsuite/filter/expertfilter/ExpertFilter.java
@@ -8,10 +8,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.powsybl.iidm.network.TopologyKind;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
+import lombok.*;
import lombok.experimental.SuperBuilder;
import org.gridsuite.filter.AbstractFilter;
import org.gridsuite.filter.expertfilter.expertrule.AbstractExpertRule;
@@ -24,11 +21,11 @@
/**
* @author Antoine Bouhours
*/
-@Getter
-@Setter
@SuperBuilder
@NoArgsConstructor
+@Data
@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
public class ExpertFilter extends AbstractFilter {
private AbstractExpertRule rules;
diff --git a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/AbstractExpertRule.java b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/AbstractExpertRule.java
index 72ccd07..ab046e0 100644
--- a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/AbstractExpertRule.java
+++ b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/AbstractExpertRule.java
@@ -12,9 +12,8 @@
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.powsybl.iidm.network.Identifiable;
import lombok.AllArgsConstructor;
-import lombok.Getter;
+import lombok.Data;
import lombok.NoArgsConstructor;
-import lombok.Setter;
import lombok.experimental.SuperBuilder;
import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
@@ -46,8 +45,7 @@
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
@AllArgsConstructor
-@Getter
-@Setter
+@Data
@SuperBuilder
public abstract class AbstractExpertRule {
diff --git a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/BooleanExpertRule.java b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/BooleanExpertRule.java
index 2687960..16a1f83 100644
--- a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/BooleanExpertRule.java
+++ b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/BooleanExpertRule.java
@@ -9,10 +9,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Identifiable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
+import lombok.*;
import lombok.experimental.SuperBuilder;
import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
@@ -30,8 +27,9 @@
*/
@AllArgsConstructor
@NoArgsConstructor
-@Getter
-@Setter
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
@SuperBuilder
public class BooleanExpertRule extends AbstractExpertRule {
private Boolean value;
diff --git a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/CombinatorExpertRule.java b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/CombinatorExpertRule.java
index c869828..2c39f70 100644
--- a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/CombinatorExpertRule.java
+++ b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/CombinatorExpertRule.java
@@ -9,7 +9,10 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Identifiable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
+import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
@@ -23,6 +26,9 @@
* @author Antoine Bouhours
*/
@NoArgsConstructor
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
@SuperBuilder
public class CombinatorExpertRule extends AbstractExpertRule {
@Override
diff --git a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/EnumExpertRule.java b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/EnumExpertRule.java
index 332425e..7f0ac99 100644
--- a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/EnumExpertRule.java
+++ b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/EnumExpertRule.java
@@ -9,7 +9,10 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Identifiable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
+import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
@@ -24,6 +27,9 @@
* @author Antoine Bouhours
*/
@NoArgsConstructor
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
@SuperBuilder
public class EnumExpertRule extends StringExpertRule {
@Override
diff --git a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/FilterUuidExpertRule.java b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/FilterUuidExpertRule.java
index d551edd..4632ffe 100644
--- a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/FilterUuidExpertRule.java
+++ b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/FilterUuidExpertRule.java
@@ -9,12 +9,15 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Identifiable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
+import lombok.ToString;
import lombok.experimental.SuperBuilder;
+import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
import org.gridsuite.filter.utils.expertfilter.DataType;
import org.gridsuite.filter.utils.expertfilter.ExpertFilterUtils;
-import org.gridsuite.filter.FilterLoader;
import java.util.Map;
import java.util.UUID;
@@ -25,6 +28,9 @@
* @author Franck Lecuyer
*/
@NoArgsConstructor
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
@SuperBuilder
public class FilterUuidExpertRule extends StringExpertRule {
@Override
diff --git a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/NumberExpertRule.java b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/NumberExpertRule.java
index 72b8760..0a22199 100644
--- a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/NumberExpertRule.java
+++ b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/NumberExpertRule.java
@@ -10,10 +10,7 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Identifiable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
+import lombok.*;
import lombok.experimental.SuperBuilder;
import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
@@ -31,8 +28,9 @@
*/
@AllArgsConstructor
@NoArgsConstructor
-@Getter
-@Setter
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
@SuperBuilder
public class NumberExpertRule extends AbstractExpertRule {
private Double value;
diff --git a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/PropertiesExpertRule.java b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/PropertiesExpertRule.java
index 7c052e4..f729f02 100644
--- a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/PropertiesExpertRule.java
+++ b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/PropertiesExpertRule.java
@@ -9,10 +9,7 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Identifiable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
+import lombok.*;
import lombok.experimental.SuperBuilder;
import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
@@ -30,8 +27,9 @@
*/
@AllArgsConstructor
@NoArgsConstructor
-@Getter
-@Setter
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
@SuperBuilder
public class PropertiesExpertRule extends AbstractExpertRule {
private String propertyName;
@@ -64,12 +62,4 @@ public DataType getDataType() {
public String getStringValue() {
return this.getPropertyName();
}
-
- public String getPropertyName() {
- return this.propertyName;
- }
-
- public List getPropertyValues() {
- return this.propertyValues;
- }
}
diff --git a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/StringExpertRule.java b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/StringExpertRule.java
index 82feea3..adf3303 100644
--- a/src/main/java/org/gridsuite/filter/expertfilter/expertrule/StringExpertRule.java
+++ b/src/main/java/org/gridsuite/filter/expertfilter/expertrule/StringExpertRule.java
@@ -10,10 +10,7 @@
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Identifiable;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
+import lombok.*;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.StringUtils;
import org.gridsuite.filter.FilterLoader;
@@ -34,8 +31,9 @@
*/
@AllArgsConstructor
@NoArgsConstructor
-@Getter
-@Setter
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
@SuperBuilder
public class StringExpertRule extends AbstractExpertRule {
private String value;
diff --git a/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java
index 42ac8e6..7fba83f 100644
--- a/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java
+++ b/src/main/java/org/gridsuite/filter/globalfilter/GlobalFilterUtils.java
@@ -9,6 +9,8 @@
import org.gridsuite.filter.expertfilter.expertrule.*;
import org.gridsuite.filter.utils.EquipmentType;
import org.gridsuite.filter.utils.FiltersUtils;
+import org.gridsuite.filter.utils.TimeUtils;
+import org.gridsuite.filter.utils.UuidUtils;
import org.gridsuite.filter.utils.expertfilter.CombinatorType;
import org.gridsuite.filter.utils.expertfilter.ExpertFilterUtils;
import org.gridsuite.filter.utils.expertfilter.FieldType;
@@ -123,17 +125,21 @@ public static ExpertFilter buildExpertFilter(@Nonnull final GlobalFilter globalF
final List andRules = new ArrayList<>();
// Nominal voltage rules
- buildNominalVoltageRules(globalFilter.getNominalV(), equipmentType).ifPresent(andRules::add);
+ if (globalFilter.getNominalV() != null) {
+ buildNominalVoltageRules(globalFilter.getNominalV(), equipmentType).ifPresent(andRules::add);
+ }
// Country code rules
- buildCountryCodeRules(globalFilter.getCountryCode(), equipmentType).ifPresent(andRules::add);
+ if (globalFilter.getCountryCode() != null) {
+ buildCountryCodeRules(globalFilter.getCountryCode(), equipmentType).ifPresent(andRules::add);
+ }
// Substation property rules
if (globalFilter.getSubstationProperty() != null) {
buildSubstationPropertyRules(globalFilter.getSubstationProperty(), equipmentType).ifPresent(andRules::add);
}
- return andRules.isEmpty() ? null : new ExpertFilter(UUID.randomUUID(), new Date(), equipmentType,
+ return andRules.isEmpty() ? null : new ExpertFilter(UuidUtils.generateUUID(), TimeUtils.nowAsDate(), equipmentType,
CombinatorExpertRule.builder().combinator(CombinatorType.AND).rules(andRules).build());
}
diff --git a/src/main/java/org/gridsuite/filter/identifierlistfilter/IdentifierListFilter.java b/src/main/java/org/gridsuite/filter/identifierlistfilter/IdentifierListFilter.java
index 1f32490..eb49f4e 100644
--- a/src/main/java/org/gridsuite/filter/identifierlistfilter/IdentifierListFilter.java
+++ b/src/main/java/org/gridsuite/filter/identifierlistfilter/IdentifierListFilter.java
@@ -9,10 +9,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.powsybl.iidm.network.IdentifiableType;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
+import lombok.*;
import lombok.experimental.SuperBuilder;
import org.gridsuite.filter.AbstractFilter;
import org.gridsuite.filter.utils.EquipmentType;
@@ -20,16 +17,15 @@
import java.util.*;
-
/**
* @author Seddik Yengui
*/
-@NoArgsConstructor
-@Getter
-@Setter
@SuperBuilder
+@NoArgsConstructor
+@Data
@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
public class IdentifierListFilter extends AbstractFilter {
private List filterEquipmentsAttributes;
diff --git a/src/main/java/org/gridsuite/filter/utils/TimeUtils.java b/src/main/java/org/gridsuite/filter/utils/TimeUtils.java
index d154e1c..e1662ca 100644
--- a/src/main/java/org/gridsuite/filter/utils/TimeUtils.java
+++ b/src/main/java/org/gridsuite/filter/utils/TimeUtils.java
@@ -1,24 +1,32 @@
package org.gridsuite.filter.utils;
import com.google.common.annotations.VisibleForTesting;
+import lombok.Getter;
import lombok.Setter;
-import java.util.UUID;
-import java.util.function.Supplier;
+import java.time.Clock;
+import java.time.Instant;
+import java.util.Date;
/**
- * Utility class for UUID to permit during tests to mock {@link UUID} generation..
+ * Utility class for datetime to permit during tests to mock time related operations.
+ * @apiNote This class is to permit tests to intercept date/time
*/
-@VisibleForTesting
+
public final class TimeUtils {
private TimeUtils() {
throw new AssertionError("Utility class should not be instantiated");
}
- @Setter
- private static Supplier uuidSupplier = UUID::randomUUID;
+ @Setter(onMethod_ = {@VisibleForTesting})
+ @Getter
+ private static Clock clock = Clock.systemUTC();
+
+ public static Instant now() {
+ return Instant.now(clock);
+ }
- public static UUID generateUUID() {
- return uuidSupplier.get();
+ public static Date nowAsDate() {
+ return Date.from(now());
}
}
diff --git a/src/main/java/org/gridsuite/filter/utils/UuidUtils.java b/src/main/java/org/gridsuite/filter/utils/UuidUtils.java
index 9ce29d1..4419e4c 100644
--- a/src/main/java/org/gridsuite/filter/utils/UuidUtils.java
+++ b/src/main/java/org/gridsuite/filter/utils/UuidUtils.java
@@ -7,18 +7,82 @@
import java.util.function.Supplier;
/**
- * Utility class for UUID to permit during tests to mock {@link UUID} generation..
+ * Utility class for UUID to permit during tests to mock {@link UUID} generation.
+ * @apiNote This class is to permit tests to intercept {@link UUID} generation
*/
-@VisibleForTesting
public final class UuidUtils {
private UuidUtils() {
throw new AssertionError("Utility class should not be instantiated");
}
- @Setter
+ @Setter(onMethod_ = {@VisibleForTesting})
private static Supplier uuidSupplier = UUID::randomUUID;
public static UUID generateUUID() {
return uuidSupplier.get();
}
+
+ /**
+ * Like {@link UUID#randomUUID()} generate UUID v4 variant 2, but not random.
+ * This utility function is intended to be used in tests to have predictable UUID.
+ * Some information on UUID:
+ *
+ * textual format: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
+ * bytes: 0 1 2 3 4 5 6 7 8 9 10 ↓12 ↓14 ↓
+ * 11 13 15
+ * size: 4b-2b-2b-2b-6b
+ *
+ * Where
+ * - M = version field (4 bits).
+ * - N = variant field (3 bits).
+ * - All other bits = random (for v4).
+ *
+ * UUID bytes structure:
+ *
+ * /-------mostSigBits-------\ /--------leastSigBits---------\
+ * b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15
+ * |-----------| |-----| |-----| |-----| |-----------------------|
+ * random random v4+random variant+random random
+ * b6 = [0100 LLLL] ⇒ version 4
+ * b8 = [10xL LLLL] → [1000 LLLL] ⇒ RFC 4122 / IETF / Leach–Salz variant
+ *
+ *
+ * @param b0to3 the bits from b0 to b3
+ * @param b4to5 the bits from b4 and b5
+ * @param b7 the bits of b7
+ * @param nibblesB6lowB8low the upper nibble is for the lower half of b6
+ * and the lower nibble is for the lower half of b8
+ * @param b9 the bits of b9
+ * @param b10to11 the bits for b10 and b11
+ * @param b12to15 the bits for b12 to b15
+ * @return a UUID v4 in variant 2 with the bits passed
+ * @implNote Bits 5–4 of b8 are left to {@code 0} for simplicity,
+ * so the UUID is of the form {@code xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx}.
+ */
+ // regexp: ^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-8[0-9a-f]{3}-[0-9a-f]{12}$
+ @VisibleForTesting
+ public static UUID createUUID(final int b0to3, final short b4to5, final byte b7,
+ final byte nibblesB6lowB8low,
+ final byte b9, final short b10to11, final int b12to15) {
+ return new UUID(
+ // Construct mostSigBits directly
+ (b0to3 & 0xFFFFFFFFL) << 32
+ | (b4to5 & 0xFFFFL) << 16
+ | (0x40L | ((nibblesB6lowB8low >>> 4) & 0x0FL)) << 8 // version 4
+ | (b7 & 0xFFL),
+ // Construct leastSigBits directly
+ (0x80L | (nibblesB6lowB8low & 0xFL)) << 56 // variant 2
+ | (b9 & 0xFFL) << 48
+ | (b10to11 & 0xFFFFL) << 32
+ | (b12to15 & 0xFFFFFFFFL)
+ );
+ }
+
+ /**
+ * @see #createUUID(int, short, byte, byte, byte, short, int)
+ */
+ @VisibleForTesting
+ public static UUID createUUID(final int b12to15) {
+ return createUUID(0, (short) 0, (byte) 0, (byte) 0, (byte) 0, (short) 0, b12to15);
+ }
}
diff --git a/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java b/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java
index 4407603..db70edd 100644
--- a/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java
+++ b/src/main/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtils.java
@@ -19,9 +19,7 @@
import org.gridsuite.filter.expertfilter.expertrule.FilterUuidExpertRule;
import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
import org.gridsuite.filter.identifierlistfilter.IdentifiableAttributes;
-import org.gridsuite.filter.utils.EquipmentType;
-import org.gridsuite.filter.utils.FilterServiceUtils;
-import org.gridsuite.filter.utils.RegulationType;
+import org.gridsuite.filter.utils.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -619,7 +617,7 @@ public static List getFilterEquipments(Network network, Set FilterCycleDetector.checkNoCycle(filter, filterLoader));
List filterEquipments = FilterServiceUtils.getFilterEquipmentsFromUuid(network, uuid, filterLoader);
- cachedUuidFilters.put(uuid, !CollectionUtils.isEmpty(filterEquipments) ? filterEquipments.getFirst() : null);
+ cachedUuidFilters.put(uuid, CollectionUtils.isNotEmpty(filterEquipments) ? filterEquipments.getFirst() : null);
res.addAll(filterEquipments);
}
});
@@ -652,9 +650,10 @@ public static Optional buildOrCombination(@Nullable final Li
*/
@Nonnull
public static ExpertFilter buildExpertFilterWithVoltageLevelIdsCriteria(@Nonnull final UUID filterUuid, @Nonnull final EquipmentType equipmentType) {
- return new ExpertFilter(UUID.randomUUID(), new Date(), equipmentType, CombinatorExpertRule.builder().combinator(CombinatorType.OR).rules(List.of(
- FilterUuidExpertRule.builder().operator(OperatorType.IS_PART_OF).field(FieldType.VOLTAGE_LEVEL_ID_1).values(Set.of(filterUuid.toString())).build(),
- FilterUuidExpertRule.builder().operator(OperatorType.IS_PART_OF).field(FieldType.VOLTAGE_LEVEL_ID_2).values(Set.of(filterUuid.toString())).build()
- )).build());
+ return new ExpertFilter(UuidUtils.generateUUID(), TimeUtils.nowAsDate(), equipmentType,
+ CombinatorExpertRule.builder().combinator(CombinatorType.OR).rules(List.of(
+ FilterUuidExpertRule.builder().operator(OperatorType.IS_PART_OF).field(FieldType.VOLTAGE_LEVEL_ID_1).values(Set.of(filterUuid.toString())).build(),
+ FilterUuidExpertRule.builder().operator(OperatorType.IS_PART_OF).field(FieldType.VOLTAGE_LEVEL_ID_2).values(Set.of(filterUuid.toString())).build()
+ )).build());
}
}
diff --git a/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java b/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java
index 9d50f61..f6fcded 100644
--- a/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java
+++ b/src/test/java/org/gridsuite/filter/globalfilter/GlobalFilterUtilsTest.java
@@ -1,4 +1,355 @@
package org.gridsuite.filter.globalfilter;
-public class GlobalFilterUtilsTest {
+import com.powsybl.iidm.network.Country;
+import com.powsybl.iidm.network.Identifiable;
+import com.powsybl.iidm.network.Network;
+import org.assertj.core.api.*;
+import org.gridsuite.filter.AbstractFilter;
+import org.gridsuite.filter.FilterLoader;
+import org.gridsuite.filter.expertfilter.ExpertFilter;
+import org.gridsuite.filter.expertfilter.expertrule.*;
+import org.gridsuite.filter.utils.EquipmentType;
+import org.gridsuite.filter.utils.FiltersUtils;
+import org.gridsuite.filter.utils.UuidUtils;
+import org.gridsuite.filter.utils.expertfilter.CombinatorType;
+import org.gridsuite.filter.utils.expertfilter.FieldType;
+import org.gridsuite.filter.utils.expertfilter.OperatorType;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+/* Methods dependencies:
+ * applyGlobalFilterOnNetwork
+ * ↳ applyGlobalFilterOnNetwork
+ * ↳ applyFilterOnNetwork
+ * ⇃ ↳ filterNetwork
+ * ↳ buildExpertFilter
+ * ↳ buildNominalVoltageRules
+ * ⇃ ↳ getNominalVoltageFieldType
+ * ↳ buildCountryCodeRules
+ * ⇃ ↳ getCountryCodeFieldType
+ * ↳ buildSubstationPropertyRules
+ * ↳ getSubstationPropertiesFieldTypes
+ */
+class GlobalFilterUtilsTest implements WithAssertions {
+ private static void testVariableOrCombinationRules(final Optional result, final int inputSize,
+ final Class ruleClass, final ThrowingConsumer[] singleRuleAsserts,
+ final Iterable multiAssertElements) {
+ final OptionalAssert assertion = Assertions.assertThat(result).as("result");
+ if (inputSize <= 0) {
+ assertion.isEmpty();
+ } else {
+ assertion.isPresent();
+ if (inputSize == 1) {
+ assertion.get(InstanceOfAssertFactories.type(ruleClass))
+ .as("expert rule")
+ .satisfies(singleRuleAsserts);
+ } else {
+ assertion.get(InstanceOfAssertFactories.type(CombinatorExpertRule.class))
+ .as("combinator expert rule")
+ .satisfies(cer -> Assertions.assertThat(cer.getCombinator()).as("combinator").isEqualTo(CombinatorType.OR))
+ .extracting(CombinatorExpertRule::getRules, InstanceOfAssertFactories.list(AbstractExpertRule.class)).as("expert rules")
+ .containsExactlyInAnyOrderElementsOf(multiAssertElements);
+ }
+ }
+ }
+
+ /** Trick Java to create generic array */
+ @SafeVarargs
+ private static ThrowingConsumer[] createAssertArray(final ThrowingConsumer... assertions) {
+ return assertions;
+ }
+
+ @Nested
+ @DisplayName("buildNominalVoltageRules(...)")
+ class BuildNominalVoltageRules {
+ @ParameterizedTest
+ @MethodSource({"expertRulesData"})
+ void shouldCreateExpertRules(final List nominalVoltages) {
+ testVariableOrCombinationRules(
+ GlobalFilterUtils.buildNominalVoltageRules(nominalVoltages, EquipmentType.VOLTAGE_LEVEL),
+ nominalVoltages.size(),
+ NumberExpertRule.class,
+ createAssertArray(
+ ner -> assertThat(ner.getValue()).as("value").hasToString(nominalVoltages.getFirst()),
+ ner -> assertThat(ner.getField()).as("field").isEqualTo(FieldType.NOMINAL_VOLTAGE),
+ ner -> assertThat(ner.getOperator()).as("operator").isEqualTo(OperatorType.EQUALS)
+ ),
+ nominalVoltages.stream().map(nv -> NumberExpertRule.builder().value(Double.valueOf(nv))
+ .field(FieldType.NOMINAL_VOLTAGE).operator(OperatorType.EQUALS).build()).collect(Collectors.toUnmodifiableList()));
+ }
+
+ private static Stream expertRulesData() {
+ return Stream.of(
+ Arguments.of(List.of()),
+ Arguments.of(List.of("300.0")),
+ Arguments.of(List.of("400.0", "225.0"))
+ );
+ }
+ }
+
+ @Nested
+ @DisplayName("buildCountryCodeRules(...)")
+ class BuildCountryCodeRules {
+ @ParameterizedTest
+ @MethodSource({"enumRulesData"})
+ void shouldCreateEnumRules(final List countries) {
+ testVariableOrCombinationRules(
+ GlobalFilterUtils.buildCountryCodeRules(countries, EquipmentType.VOLTAGE_LEVEL),
+ countries.size(),
+ EnumExpertRule.class,
+ createAssertArray(
+ ner -> assertThat(ner.getValue()).as("value").hasToString(countries.getFirst().name()),
+ ner -> assertThat(ner.getField()).as("field").isEqualTo(FieldType.COUNTRY),
+ ner -> assertThat(ner.getOperator()).as("operator").isEqualTo(OperatorType.EQUALS)
+ ),
+ (List) countries.stream().map(c -> EnumExpertRule.builder().value(c.name())
+ .field(FieldType.COUNTRY).operator(OperatorType.EQUALS).build()).toList());
+ }
+
+ private static Stream enumRulesData() {
+ return Stream.of(
+ Arguments.of(List.of()),
+ Arguments.of(List.of(Country.YT)),
+ Arguments.of(List.of(Country.FR, Country.DE))
+ );
+ }
+ }
+
+ @Nested
+ @DisplayName("buildSubstationPropertyRules(...)")
+ class BuildSubstationPropertyRules {
+ @ParameterizedTest
+ @MethodSource({"propertiesRulesData"})
+ void shouldCreateCorrectPropertiesRules(final Map> properties) {
+ testVariableOrCombinationRules(
+ GlobalFilterUtils.buildSubstationPropertyRules(properties, EquipmentType.VOLTAGE_LEVEL),
+ properties.size(),
+ PropertiesExpertRule.class,
+ createAssertArray(
+ per -> assertThat(per.getCombinator()).as("combinator").isEqualTo(CombinatorType.OR),
+ per -> assertThat(per.getOperator()).as("operator").isEqualTo(OperatorType.IN),
+ per -> assertThat(per.getField()).as("field").isEqualTo(FieldType.SUBSTATION_PROPERTIES),
+ per -> assertThat(per.getPropertyName()).as("property name").isEqualTo("prop1"),
+ per -> assertThat(per.getPropertyValues()).as("property values").containsExactlyInAnyOrderElementsOf(properties.values().iterator().next())
+ ),
+ (List) properties.entrySet().stream().map(e -> PropertiesExpertRule.builder().combinator(CombinatorType.OR)
+ .operator(OperatorType.IN).field(FieldType.SUBSTATION_PROPERTIES).propertyName(e.getKey()).propertyValues(e.getValue()).build()).toList());
+ }
+
+ private static Stream propertiesRulesData() {
+ return Stream.of(
+ Arguments.of(Map.of()),
+ Arguments.of(Map.of("prop1", List.of("value0"))),
+ Arguments.of(Map.of("prop1", List.of("value1", "value2"), "prop2", List.of("value3")))
+ );
+ }
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("nominalVoltageFieldTypeData")
+ void shouldReturnCorrectNominalVoltageFieldTypes(final EquipmentType equipmentType, final List expectedFields) {
+ assertThat(GlobalFilterUtils.getNominalVoltageFieldType(equipmentType))
+ .as("result").containsExactlyInAnyOrderElementsOf(expectedFields);
+ }
+
+ private static Stream nominalVoltageFieldTypeData() {
+ return Stream.of(
+ // Nominal voltage
+ Arguments.of(EquipmentType.LINE, List.of(FieldType.NOMINAL_VOLTAGE_1, FieldType.NOMINAL_VOLTAGE_2)),
+ Arguments.of(EquipmentType.TWO_WINDINGS_TRANSFORMER, List.of(FieldType.NOMINAL_VOLTAGE_1, FieldType.NOMINAL_VOLTAGE_2)),
+ Arguments.of(EquipmentType.VOLTAGE_LEVEL, List.of(FieldType.NOMINAL_VOLTAGE)),
+ Arguments.of(EquipmentType.GENERATOR, Collections.emptyList())
+ );
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("countryCodeFieldTypeData")
+ void shouldReturnCorrectCountryCodeFieldTypes(final EquipmentType equipmentType, final List expectedFields) {
+ assertThat(GlobalFilterUtils.getCountryCodeFieldType(equipmentType))
+ .as("result").containsExactlyInAnyOrderElementsOf(expectedFields);
+ }
+
+ private static Stream countryCodeFieldTypeData() {
+ return Stream.of(
+ // Country code
+ Arguments.of(EquipmentType.VOLTAGE_LEVEL, List.of(FieldType.COUNTRY)),
+ Arguments.of(EquipmentType.TWO_WINDINGS_TRANSFORMER, List.of(FieldType.COUNTRY)),
+ Arguments.of(EquipmentType.LINE, List.of(FieldType.COUNTRY_1, FieldType.COUNTRY_2)),
+ Arguments.of(EquipmentType.GENERATOR, Collections.emptyList())
+ );
+ }
+
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("substationPropertyFieldTypeData")
+ void shouldReturnCorrectSubstationPropertyFieldTypes(final EquipmentType equipmentType, final List expectedFields) {
+ assertThat(GlobalFilterUtils.getSubstationPropertiesFieldTypes(equipmentType))
+ .as("result").containsExactlyInAnyOrderElementsOf(expectedFields);
+ }
+
+ private static Stream substationPropertyFieldTypeData() {
+ return Stream.of(
+ // Substation properties
+ Arguments.of(EquipmentType.LINE, List.of(FieldType.SUBSTATION_PROPERTIES_1, FieldType.SUBSTATION_PROPERTIES_2)),
+ Arguments.of(EquipmentType.GENERATOR, List.of(FieldType.SUBSTATION_PROPERTIES))
+ );
+ }
+
+ @Nested
+ @DisplayName("buildExpertFilter(...)")
+ class BuildExpertFilter {
+ @Test
+ void shouldReturnNullWhenNoExpertFiltersProvided() {
+ final GlobalFilter globalFilter = new GlobalFilter(null, null, null, null);
+ assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR))
+ .as("result").isNull();
+ }
+
+ @Test
+ void shouldReturnNullWhenNoRules() {
+ final GlobalFilter globalFilter = new GlobalFilter(List.of(), List.of(), List.of(), Map.of());
+ assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR))
+ .as("result").isNull();
+ }
+
+ @Test
+ void shouldCreateFilterWhenRulesExist() {
+ final List nv = List.of("400.0");
+ final GlobalFilter globalFilter = Mockito.spy(new GlobalFilter(nv, null, null, null));
+ try (final MockedStatic mockedGFU = Mockito.mockStatic(GlobalFilterUtils.class, Mockito.CALLS_REAL_METHODS)) {
+ mockedGFU.when(() -> GlobalFilterUtils.buildNominalVoltageRules(nv, EquipmentType.GENERATOR))
+ .thenReturn(Optional.of(Mockito.mock(AbstractExpertRule.class)));
+ mockedGFU.clearInvocations(); //important because stubbing static method counts as call
+ assertThat(GlobalFilterUtils.buildExpertFilter(globalFilter, EquipmentType.GENERATOR)).as("result")
+ .isNotNull().satisfies(
+ ef -> assertThat(ef.getEquipmentType()).as("equipment type").isEqualTo(EquipmentType.GENERATOR),
+ ef -> assertThat(ef.getRules()).as("rule combinator")
+ .asInstanceOf(InstanceOfAssertFactories.type(CombinatorExpertRule.class))
+ .extracting(CombinatorExpertRule::getRules, InstanceOfAssertFactories.list(AbstractExpertRule.class))
+ .as("rules").hasSize(1)
+ );
+ Mockito.verify(globalFilter, Mockito.atLeastOnce()).getNominalV();
+ Mockito.verify(globalFilter, Mockito.atLeastOnce()).getCountryCode();
+ Mockito.verify(globalFilter, Mockito.atLeastOnce()).getSubstationProperty();
+ mockedGFU.verify(() -> GlobalFilterUtils.buildNominalVoltageRules(Mockito.anyList(), any(EquipmentType.class)), Mockito.times(1));
+ mockedGFU.verify(() -> GlobalFilterUtils.buildExpertFilter(any(GlobalFilter.class), any(EquipmentType.class)), Mockito.times(1));
+ mockedGFU.verifyNoMoreInteractions(); //check if forget to mock a method
+ Mockito.verifyNoMoreInteractions(globalFilter);
+ }
+ }
+ }
+
+ @Nested
+ @DisplayName("filterNetwork(...)")
+ class FilterNetwork {
+ @Test
+ void shouldReturnIdsFromFilteredNetwork() {
+ final Network network = Mockito.mock(Network.class);
+ final FilterLoader loader = Mockito.mock(FilterLoader.class);
+ final AbstractFilter filter = Mockito.mock(AbstractFilter.class);
+ when(filter.getEquipmentType()).thenReturn(EquipmentType.GENERATOR);
+ try (final MockedStatic mockedFU = Mockito.mockStatic(FiltersUtils.class, Mockito.CALLS_REAL_METHODS)) {
+ final Identifiable> i1 = Mockito.mock(Identifiable.class);
+ when(i1.getId()).thenReturn("id1");
+ final Identifiable> i2 = Mockito.mock(Identifiable.class);
+ when(i2.getId()).thenReturn("id2");
+ final List> attributes = List.of(i1, i2);
+ mockedFU.when(() -> FiltersUtils.getIdentifiables(filter, network, loader)).thenReturn(attributes);
+ mockedFU.clearInvocations(); //important because stubbing static method counts as call
+ assertThat(GlobalFilterUtils.filterNetwork(filter, network, loader)).as("result")
+ .containsExactlyInAnyOrder("id1", "id2");
+ Mockito.verify(i1, Mockito.atLeastOnce()).getId();
+ Mockito.verify(i2, Mockito.atLeastOnce()).getId();
+ Mockito.verify(filter, Mockito.atLeastOnce()).getEquipmentType();
+ Mockito.verifyNoMoreInteractions(filter, network, loader, i1, i2);
+ mockedFU.verify(() -> FiltersUtils.getIdentifiables(eq(filter), eq(network), eq(loader)), Mockito.times(1));
+ mockedFU.verifyNoMoreInteractions(); //check if forget to mock a method
+ }
+ }
+ }
+
+ @Nested
+ @DisplayName("applyFilterOnNetwork(...)")
+ class ApplyFilterOnNetwork {
+ @Test
+ void shouldReturnFilteredNetworkWhenSameEquipmentType() {
+ final Network network = Mockito.mock(Network.class);
+ final FilterLoader loader = Mockito.mock(FilterLoader.class);
+ final AbstractFilter filter = Mockito.mock(AbstractFilter.class);
+ when(filter.getEquipmentType()).thenReturn(EquipmentType.GENERATOR);
+ try (final MockedStatic mockedFU = Mockito.mockStatic(FiltersUtils.class, Mockito.CALLS_REAL_METHODS)) {
+ final Identifiable> gen1 = Mockito.mock(Identifiable.class);
+ when(gen1.getId()).thenReturn("gen1");
+ final Identifiable> gen2 = Mockito.mock(Identifiable.class);
+ when(gen2.getId()).thenReturn("gen2");
+ final List> attributes = List.of(gen1, gen2);
+ mockedFU.when(() -> FiltersUtils.getIdentifiables(filter, network, loader)).thenReturn(attributes);
+ mockedFU.clearInvocations(); //important because stubbing static method counts as call
+ assertThat(GlobalFilterUtils.applyFilterOnNetwork(filter, EquipmentType.GENERATOR, network, loader))
+ .as("result").containsExactlyInAnyOrder("gen1", "gen2");
+ Mockito.verify(filter, Mockito.atLeastOnce()).getEquipmentType();
+ Mockito.verify(gen1, Mockito.atLeastOnce()).getId();
+ Mockito.verify(gen2, Mockito.atLeastOnce()).getId();
+ Mockito.verifyNoMoreInteractions(filter, network, loader, gen1, gen2);
+ mockedFU.verify(() -> FiltersUtils.getIdentifiables(eq(filter), eq(network), eq(loader)), Mockito.atLeastOnce());
+ mockedFU.verifyNoMoreInteractions(); //check if forget to mock a method
+ }
+ }
+
+ @Test
+ void shouldBuildVoltageLevelFilterWhenVoltageLevelType() {
+ final Network network = Mockito.mock(Network.class);
+ final FilterLoader loader = Mockito.mock(FilterLoader.class);
+ final AbstractFilter filter = Mockito.mock(AbstractFilter.class);
+ when(filter.getEquipmentType()).thenReturn(EquipmentType.VOLTAGE_LEVEL);
+ final UUID filterUuid = UuidUtils.createUUID(0);
+ when(filter.getId()).thenReturn(filterUuid);
+ try (final MockedStatic mockedFU = Mockito.mockStatic(FiltersUtils.class, Mockito.CALLS_REAL_METHODS)) {
+ final Identifiable> line1 = Mockito.mock(Identifiable.class);
+ when(line1.getId()).thenReturn("line1");
+ final Identifiable> line2 = Mockito.mock(Identifiable.class);
+ when(line2.getId()).thenReturn("line2");
+ final List> attributes = List.of(line1, line2);
+ mockedFU.when(() -> FiltersUtils.getIdentifiables(any(ExpertFilter.class), eq(network), eq(loader))).thenReturn(attributes);
+ mockedFU.clearInvocations(); //important because stubbing static method counts as call
+ assertThat(GlobalFilterUtils.applyFilterOnNetwork(filter, EquipmentType.LINE, network, loader))
+ .as("result").containsExactlyInAnyOrder("line1", "line2");
+ Mockito.verify(filter, Mockito.atLeastOnce()).getEquipmentType();
+ Mockito.verify(filter, Mockito.atLeastOnce()).getId();
+ Mockito.verify(line1, Mockito.atLeastOnce()).getId();
+ Mockito.verify(line2, Mockito.atLeastOnce()).getId();
+ Mockito.verifyNoMoreInteractions(filter, network, loader, line1, line2);
+ mockedFU.verify(() -> FiltersUtils.getIdentifiables(any(ExpertFilter.class), eq(network), eq(loader)), Mockito.atLeastOnce());
+ mockedFU.verifyNoMoreInteractions(); //check if forget to mock a method
+ }
+ }
+
+ @Test
+ void shouldReturnEmptyWhenDifferentEquipmentType() {
+ final FilterLoader loader = Mockito.mock(FilterLoader.class);
+ final Network network = Mockito.mock(Network.class);
+ final AbstractFilter filter = Mockito.mock(AbstractFilter.class);
+ when(filter.getEquipmentType()).thenReturn(EquipmentType.LOAD);
+ assertThat(GlobalFilterUtils.applyFilterOnNetwork(filter, EquipmentType.GENERATOR, network, loader))
+ .as("result").isEmpty();
+ Mockito.verify(filter, Mockito.atLeastOnce()).getEquipmentType();
+ Mockito.verifyNoMoreInteractions(loader, network, filter);
+ }
+ }
+
+ //TODO applyGlobalFilterOnNetwork(single)
+ //TODO applyGlobalFilterOnNetwork(list)
}
diff --git a/src/test/java/org/gridsuite/filter/utils/FiltersUtilsTest.java b/src/test/java/org/gridsuite/filter/utils/FiltersUtilsTest.java
index 2ed06fd..f657ddc 100644
--- a/src/test/java/org/gridsuite/filter/utils/FiltersUtilsTest.java
+++ b/src/test/java/org/gridsuite/filter/utils/FiltersUtilsTest.java
@@ -9,30 +9,28 @@
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.test.*;
import org.apache.commons.collections4.CollectionUtils;
+import org.assertj.core.api.WithAssertions;
import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.expertfilter.ExpertFilter;
import org.gridsuite.filter.expertfilter.expertrule.AbstractExpertRule;
import org.gridsuite.filter.expertfilter.expertrule.CombinatorExpertRule;
import org.gridsuite.filter.expertfilter.expertrule.StringExpertRule;
-import org.gridsuite.filter.identifierlistfilter.FilterEquipments;
-import org.gridsuite.filter.identifierlistfilter.FilteredIdentifiables;
-import org.gridsuite.filter.identifierlistfilter.IdentifiableAttributes;
-import org.gridsuite.filter.identifierlistfilter.IdentifierListFilter;
-import org.gridsuite.filter.identifierlistfilter.IdentifierListFilterEquipmentAttributes;
+import org.gridsuite.filter.identifierlistfilter.*;
import org.gridsuite.filter.utils.expertfilter.CombinatorType;
import org.gridsuite.filter.utils.expertfilter.OperatorType;
import org.junit.jupiter.api.Test;
import java.util.*;
-import static org.gridsuite.filter.utils.expertfilter.FieldType.*;
-import static org.gridsuite.filter.utils.expertfilter.OperatorType.*;
+import static org.gridsuite.filter.utils.expertfilter.FieldType.ID;
+import static org.gridsuite.filter.utils.expertfilter.FieldType.NAME;
+import static org.gridsuite.filter.utils.expertfilter.OperatorType.IS;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author Franck Lecuyer
*/
-class FiltersUtilsTest {
+class FiltersUtilsTest implements WithAssertions {
private final FilterLoader filterLoader = uuids -> null;
private static Network prepareNetwork() {
@@ -596,4 +594,27 @@ void testEquipmentNameFilterWithNullValueInEquipments() {
// in this network, VL equipments have null name => no match
assertEquals(0, identifiables.size());
}
+
+ @Test
+ void shouldReturnEmptyWhenCombineFilterResultsInputIsEmpty() {
+ assertThat(FiltersUtils.combineFilterResults(List.of(), true)).as("result").isEmpty();
+ }
+
+ @Test
+ void shouldReturnIntersectionWhenUsingAndLogic() {
+ assertThat(FiltersUtils.combineFilterResults(Arrays.asList(
+ List.of("item1", "item2", "item3"),
+ List.of("item2", "item3", "item4"),
+ List.of("item2", "item5")), true))
+ .as("result").singleElement().isEqualTo("item2");
+ }
+
+ @Test
+ void shouldReturnUnionWhenUsingOrLogic() {
+ assertThat(FiltersUtils.combineFilterResults(Arrays.asList(
+ List.of("item1", "item2"),
+ List.of("item3", "item4"),
+ List.of("item5")), false))
+ .as("result").containsExactlyInAnyOrder("item1", "item2", "item3", "item4", "item5");
+ }
}
diff --git a/src/test/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtilsTest.java b/src/test/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtilsTest.java
index 456de08..2de5c5c 100644
--- a/src/test/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtilsTest.java
+++ b/src/test/java/org/gridsuite/filter/utils/expertfilter/ExpertFilterUtilsTest.java
@@ -1,4 +1,71 @@
package org.gridsuite.filter.utils.expertfilter;
-public class ExpertFilterUtilsTest {
+import org.assertj.core.api.InstanceOfAssertFactories;
+import org.assertj.core.api.OptionalAssert;
+import org.assertj.core.api.WithAssertions;
+import org.gridsuite.filter.expertfilter.expertrule.AbstractExpertRule;
+import org.gridsuite.filter.expertfilter.expertrule.CombinatorExpertRule;
+import org.gridsuite.filter.expertfilter.expertrule.FilterUuidExpertRule;
+import org.gridsuite.filter.utils.EquipmentType;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import static org.mockito.Mockito.mock;
+
+class ExpertFilterUtilsTest implements WithAssertions {
+ @ParameterizedTest
+ @MethodSource("orCombinationData")
+ void shouldCreateOrCombination(final List rules, final boolean expectEmpty, final boolean expectSingle) {
+ final OptionalAssert assertOpt = assertThat(ExpertFilterUtils.buildOrCombination(rules)).as("result");
+ if (expectEmpty) {
+ assertOpt.isEmpty();
+ } else {
+ assertOpt.isPresent();
+ final var assertRule = assertOpt.get().as("rule");
+ if (expectSingle) {
+ assertRule.isEqualTo(rules.getFirst());
+ } else {
+ assertRule.asInstanceOf(InstanceOfAssertFactories.type(CombinatorExpertRule.class)).satisfies(
+ cer -> assertThat(cer.getCombinator()).as("combinator").isEqualTo(CombinatorType.OR),
+ cer -> assertThat(cer.getRules()).as("rules").containsExactlyInAnyOrderElementsOf(rules)
+ );
+ }
+ }
+ }
+
+ private static Stream orCombinationData() {
+ return Stream.of(
+ Arguments.of(List.of(), true, false),
+ Arguments.of(List.of(mock(AbstractExpertRule.class)), false, true),
+ Arguments.of(List.of(mock(AbstractExpertRule.class), mock(AbstractExpertRule.class)), false, false)
+ );
+ }
+
+ @Test
+ void shouldCreateExpertFilterWithVoltageLevelIdsCriteria() {
+ final UUID filterUuid = UUID.randomUUID();
+ final EquipmentType equipmentType = EquipmentType.LINE;
+ assertThat(ExpertFilterUtils.buildExpertFilterWithVoltageLevelIdsCriteria(filterUuid, equipmentType)).as("result").isNotNull().satisfies(
+ ef -> assertThat(ef.getEquipmentType()).as("equipmentType").isEqualTo(equipmentType),
+ ef -> assertThat(ef.getRules()).as("expert rules").isNotNull()
+ .asInstanceOf(InstanceOfAssertFactories.type(CombinatorExpertRule.class))
+ .satisfies(
+ cer -> assertThat(cer.getCombinator()).as("combinator").isEqualTo(CombinatorType.OR),
+ cer -> assertThat(cer.getRules()).as("combinator rules").hasSize(2)
+ .allSatisfy(er -> assertThat(er).as("expert rule")
+ .asInstanceOf(InstanceOfAssertFactories.type(FilterUuidExpertRule.class))
+ .satisfies(fuer -> assertThat(fuer.getOperator()).as("operator").isEqualTo(OperatorType.IS_PART_OF))
+ .extracting(FilterUuidExpertRule::getValues, InstanceOfAssertFactories.set(String.class)).as("UUIDs")
+ .containsExactly(filterUuid.toString()))
+ .map(AbstractExpertRule::getField).as("fields")
+ .containsExactly(FieldType.VOLTAGE_LEVEL_ID_1, FieldType.VOLTAGE_LEVEL_ID_2)
+ )
+ );
+ }
}
From 4a0c85652c460bad14d3f81bb1885e25a956283e Mon Sep 17 00:00:00 2001
From: Tristan Chuine
Date: Tue, 7 Oct 2025 08:30:27 +0200
Subject: [PATCH 7/7] fix error
---
.../AbstractGlobalFilterService.java | 29 ++++++++++++-------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java b/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java
index 0b23757..6eeb68a 100644
--- a/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java
+++ b/src/main/java/org/gridsuite/filter/globalfilter/AbstractGlobalFilterService.java
@@ -2,10 +2,12 @@
import com.powsybl.iidm.network.Network;
import lombok.NonNull;
+import org.apache.commons.lang3.ObjectUtils;
import org.gridsuite.filter.AbstractFilter;
import org.gridsuite.filter.FilterLoader;
import org.gridsuite.filter.utils.EquipmentType;
+import javax.annotation.Nullable;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@@ -13,25 +15,32 @@
public abstract class AbstractGlobalFilterService implements FilterLoader {
protected abstract Network getNetwork(@NonNull UUID networkUuid, @NonNull String variantId);
+ /** @see #getFilteredIds(UUID, String, GlobalFilter, List) */
+ protected List getFilteredIds(@NonNull final UUID networkUuid, @NonNull final String variantId,
+ @NonNull final GlobalFilter globalFilter, @NonNull final List equipmentTypes) {
+ return getFilteredIds(networkUuid, variantId, globalFilter, equipmentTypes, null);
+ }
+
/**
* Get filtered equipment IDs.
* @param networkUuid the network to load
* @param variantId the network variant to work on
* @param globalFilter the filter(s) to apply
* @param equipmentTypes the {@link EquipmentType equipment types} to filter
+ * @param genericFilters additional generic filters to apply
* @return the {@link List list} of {@link UUID IDs} of filtered {@link EquipmentType equipments}.
*/
protected List getFilteredIds(@NonNull final UUID networkUuid, @NonNull final String variantId,
- @NonNull final GlobalFilter globalFilter, @NonNull final List equipmentTypes) {
+ @NonNull final GlobalFilter globalFilter, @NonNull final List equipmentTypes,
+ @Nullable final List genericFilters) {
final Network network = getNetwork(networkUuid, variantId);
- final List genericFilters = getFilters(globalFilter.getGenericFilter());
- return GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, genericFilters, equipmentTypes, this)
- // Filter equipments by type
- .values()
- .stream()
- .filter(Objects::nonNull)
- // Combine all results into one list
- .flatMap(List::stream)
- .toList();
+ return GlobalFilterUtils.applyGlobalFilterOnNetwork(network, globalFilter, ObjectUtils.getIfNull(genericFilters, List::of), equipmentTypes, this)
+ // Filter equipments by type
+ .values()
+ .stream()
+ .filter(Objects::nonNull)
+ // Combine all results into one list
+ .flatMap(List::stream)
+ .toList();
}
}