diff --git a/commons/src/main/java/com/powsybl/commons/extensions/AbstractAlternativeExtensionSerDe.java b/commons/src/main/java/com/powsybl/commons/extensions/AbstractAlternativeExtensionSerDe.java new file mode 100644 index 00000000000..e45e2739fd7 --- /dev/null +++ b/commons/src/main/java/com/powsybl/commons/extensions/AbstractAlternativeExtensionSerDe.java @@ -0,0 +1,21 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.commons.extensions; + +/** + * @author Olivier Perrin {@literal } + */ +public abstract class AbstractAlternativeExtensionSerDe> + extends AbstractExtensionSerDe + implements AlternativeExtensionSerDe { + + protected AbstractAlternativeExtensionSerDe(String extensionName, String categoryName, Class extensionClass, + String xsdFileName, String namespaceUri, String namespacePrefix) { + super(extensionName, categoryName, extensionClass, xsdFileName, namespaceUri, namespacePrefix); + } +} diff --git a/commons/src/main/java/com/powsybl/commons/extensions/AlternativeExtensionSerDe.java b/commons/src/main/java/com/powsybl/commons/extensions/AlternativeExtensionSerDe.java new file mode 100644 index 00000000000..e1dcad3c8ba --- /dev/null +++ b/commons/src/main/java/com/powsybl/commons/extensions/AlternativeExtensionSerDe.java @@ -0,0 +1,14 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.commons.extensions; + +/** + * @author Olivier Perrin {@literal } + */ +public interface AlternativeExtensionSerDe> extends ExtensionProviderAlternative, ExtensionSerDe { +} diff --git a/commons/src/main/java/com/powsybl/commons/extensions/ExtensionProviderAlternative.java b/commons/src/main/java/com/powsybl/commons/extensions/ExtensionProviderAlternative.java new file mode 100644 index 00000000000..5d3278884a8 --- /dev/null +++ b/commons/src/main/java/com/powsybl/commons/extensions/ExtensionProviderAlternative.java @@ -0,0 +1,15 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.commons.extensions; + +/** + * @author Olivier Perrin {@literal } + */ +public interface ExtensionProviderAlternative> extends ExtensionSerDe { + String getOriginalExtensionName(); +} diff --git a/commons/src/main/java/com/powsybl/commons/extensions/ExtensionProviders.java b/commons/src/main/java/com/powsybl/commons/extensions/ExtensionProviders.java index faeda78c612..ab48b020536 100644 --- a/commons/src/main/java/com/powsybl/commons/extensions/ExtensionProviders.java +++ b/commons/src/main/java/com/powsybl/commons/extensions/ExtensionProviders.java @@ -12,6 +12,7 @@ import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * @author Mathieu Bague {@literal } @@ -19,6 +20,7 @@ public final class ExtensionProviders { private final Map providers; + private final Map alternativeProviders; public static ExtensionProviders createProvider(Class clazz) { return new ExtensionProviders<>(clazz); @@ -33,9 +35,7 @@ public static ExtensionProviders createProvider } private ExtensionProviders(Class clazz) { - Objects.requireNonNull(clazz); - providers = new ServiceLoaderCache<>(clazz).getServices().stream() - .collect(Collectors.toMap(T::getExtensionName, e -> e)); + this(clazz, null, null); } private ExtensionProviders(Class clazz, String categoryName) { @@ -44,29 +44,65 @@ private ExtensionProviders(Class clazz, String categoryName) { private ExtensionProviders(Class clazz, String categoryName, Set extensionNames) { Objects.requireNonNull(clazz); - Objects.requireNonNull(categoryName); - List services = new ServiceLoaderCache<>(clazz).getServices(); - providers = services.stream() - .filter(s -> s.getCategoryName().equals(categoryName) && (extensionNames == null || extensionNames.contains(s.getExtensionName()))) - .collect(Collectors.toMap(T::getExtensionName, e -> e)); + Stream providersStream = new ServiceLoaderCache<>(clazz).getServices().stream(); + if (categoryName != null) { + providersStream = providersStream.filter(s -> s.getCategoryName().equals(categoryName) && + (extensionNames == null || extensionNames.contains(s.getExtensionName()))); + } + providers = providersStream.collect(Collectors.toMap(T::getExtensionName, e -> e)); + + Class alternativeClass = getExtensionProviderAlternativeClass(clazz); + if (alternativeClass != null) { + Stream providerAlternativeStream = new ServiceLoaderCache<>(alternativeClass).getServices().stream(); + if (categoryName != null) { + providerAlternativeStream = providerAlternativeStream.filter(s -> s.getCategoryName().equals(categoryName) && + (extensionNames == null || extensionNames.contains(s.getOriginalExtensionName()))); + } + alternativeProviders = providerAlternativeStream + .collect(Collectors.toMap(ExtensionProviderAlternative::getOriginalExtensionName, e -> (T) e)); + } else { + alternativeProviders = Collections.emptyMap(); + } + } + + private Class getExtensionProviderAlternativeClass(Class clazz) { + if (clazz.equals(ExtensionSerDe.class)) { + return AlternativeExtensionSerDe.class; + } + return null; } public T findProvider(String name) { + return findProvider(name, null); + } + + public T findProvider(String name, ExtensionProvidersOptions options) { + if (options != null && options.useAlternativeVersion(name)) { + T alternative = alternativeProviders.get(name); + if (alternative != null) { + return alternative; + } + } return providers.get(name); } public T findProviderOrThrowException(String name) { - T serializer = findProvider(name); - if (serializer == null) { + return findProviderOrThrowException(name, null); + } + + public T findProviderOrThrowException(String name, ExtensionProvidersOptions options) { + T provider = findProvider(name, options); + if (provider == null) { throw new PowsyblException("Provider not found for extension " + name); } - - return serializer; + return provider; } public Collection getProviders() { - return providers.values(); + return providers.keySet().stream() + .map(this::findProvider) + .toList(); } public void addExtensions(Extendable extendable, Collection> extensions) { diff --git a/commons/src/main/java/com/powsybl/commons/extensions/ExtensionProvidersOptions.java b/commons/src/main/java/com/powsybl/commons/extensions/ExtensionProvidersOptions.java new file mode 100644 index 00000000000..7e9bb72aeee --- /dev/null +++ b/commons/src/main/java/com/powsybl/commons/extensions/ExtensionProvidersOptions.java @@ -0,0 +1,17 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.commons.extensions; + +/** + * @author Olivier Perrin {@literal } + */ +public interface ExtensionProvidersOptions { + + boolean useAlternativeVersion(String extensionName); + +} diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ExportOptions.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ExportOptions.java index e9b0caaa6ff..043a97114f7 100644 --- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ExportOptions.java +++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/ExportOptions.java @@ -9,6 +9,7 @@ import com.google.common.collect.Sets; import com.powsybl.commons.PowsyblException; +import com.powsybl.commons.extensions.ExtensionProvidersOptions; import com.powsybl.iidm.network.TopologyLevel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,7 +24,7 @@ * @author Geoffroy Jamgotchian {@literal } * @author Miora Ralambotiana {@literal } */ -public class ExportOptions extends AbstractOptions { +public class ExportOptions extends AbstractOptions implements ExtensionProvidersOptions { public enum IidmVersionIncompatibilityBehavior { THROW_EXCEPTION, @@ -32,6 +33,8 @@ public enum IidmVersionIncompatibilityBehavior { private static final Logger LOGGER = LoggerFactory.getLogger(ExportOptions.class); + public static final String ALTERNATIVE_VERSION = "alternative"; + private boolean withBranchSV = true; private boolean indent = true; @@ -225,7 +228,8 @@ public ExportOptions addExtensionVersion(String extensionName, String extensionV * If it has never been added, return an empty optional. */ public Optional getExtensionVersion(String extensionName) { - return Optional.ofNullable(extensionsVersions.get(extensionName)); + return Optional.ofNullable(extensionsVersions.get(extensionName)) + .map(v -> ALTERNATIVE_VERSION.equals(v) ? null : v); } public boolean isSorted() { @@ -245,4 +249,10 @@ public ExportOptions setWithAutomationSystems(boolean withAutomationSystems) { this.withAutomationSystems = withAutomationSystems; return this; } + + @Override + public boolean useAlternativeVersion(String extensionName) { + String v = extensionsVersions.get(extensionName); + return ALTERNATIVE_VERSION.equals(v); + } } diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/NetworkSerDe.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/NetworkSerDe.java index c9e243c829e..3b768c8dd9b 100644 --- a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/NetworkSerDe.java +++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/NetworkSerDe.java @@ -158,7 +158,7 @@ private static void writeExtension(Extension> extensio throw new IllegalStateException("Extension Serializer of " + extension.getName() + " should not be null"); } String namespaceUri = getNamespaceUri(extensionSerDe, context.getOptions()); - writer.writeStartNode(namespaceUri, extension.getName()); + writer.writeStartNode(namespaceUri, extensionSerDe.getExtensionName()); context.getExtensionVersion(extension.getName()).ifPresent(extensionSerDe::checkExtensionVersionSupported); extensionSerDe.write(extension, context); writer.writeEndNode(); @@ -167,8 +167,8 @@ private static void writeExtension(Extension> extensio private static ExtensionSerDe getExtensionSerializer(ExportOptions options, Extension> extension) { if (options.withExtension(extension.getName())) { ExtensionSerDe extensionSerDe = options.isThrowExceptionIfExtensionNotFound() - ? EXTENSIONS_SUPPLIER.get().findProviderOrThrowException(extension.getName()) - : EXTENSIONS_SUPPLIER.get().findProvider(extension.getName()); + ? EXTENSIONS_SUPPLIER.get().findProviderOrThrowException(extension.getName(), options) + : EXTENSIONS_SUPPLIER.get().findProvider(extension.getName(), options); if (extensionSerDe == null) { String message = "XmlSerializer for " + extension.getName() + " not found"; throwExceptionIfOption(options, message); diff --git a/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/extensions/AbstractAlternativeVersionableNetworkExtensionSerDe.java b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/extensions/AbstractAlternativeVersionableNetworkExtensionSerDe.java new file mode 100644 index 00000000000..ee06dd244bb --- /dev/null +++ b/iidm/iidm-serde/src/main/java/com/powsybl/iidm/serde/extensions/AbstractAlternativeVersionableNetworkExtensionSerDe.java @@ -0,0 +1,29 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.serde.extensions; + +import com.google.common.collect.ImmutableSortedSet; +import com.powsybl.commons.extensions.AlternativeExtensionSerDe; +import com.powsybl.commons.extensions.Extendable; +import com.powsybl.commons.extensions.Extension; +import com.powsybl.iidm.serde.IidmVersion; + +import java.util.Map; + +/** + * @author Olivier Perrin {@literal } + */ +public abstract class AbstractAlternativeVersionableNetworkExtensionSerDe> + extends AbstractVersionableNetworkExtensionSerDe + implements AlternativeExtensionSerDe { + + protected AbstractAlternativeVersionableNetworkExtensionSerDe(String extensionName, Class extensionClass, String namespacePrefix, + Map> extensionVersions, Map namespaceUris) { + super(extensionName, extensionClass, namespacePrefix, extensionVersions, namespaceUris); + } +} diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/AlternativeExtensionXmlTest.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/AlternativeExtensionXmlTest.java new file mode 100644 index 00000000000..3a2f4ea2179 --- /dev/null +++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/AlternativeExtensionXmlTest.java @@ -0,0 +1,102 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.serde.extensions; + +import com.powsybl.iidm.network.Battery; +import com.powsybl.iidm.network.Generator; +import com.powsybl.iidm.network.Line; +import com.powsybl.iidm.network.Network; +import com.powsybl.iidm.network.extensions.ActivePowerControl; +import com.powsybl.iidm.network.extensions.OperatingStatus; +import com.powsybl.iidm.network.impl.extensions.ActivePowerControlImpl; +import com.powsybl.iidm.network.impl.extensions.OperatingStatusImpl; +import com.powsybl.iidm.network.test.BatteryNetworkFactory; +import com.powsybl.iidm.serde.AbstractIidmSerDeTest; +import com.powsybl.iidm.serde.ExportOptions; +import com.powsybl.iidm.serde.IidmVersion; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @author Olivier Perrin {@literal } + */ +class AlternativeExtensionXmlTest extends AbstractIidmSerDeTest { + + // This test is the same as OperatingStatusXmlTest::test, but the extension is exported/imported + // using the defined alternative (which is not versioned). + @Test + void nonVersionedAlternativeTest() throws IOException { + Network network = OperatingStatusXmlTest.createTestNetwork(); + + // extend line + Line line = network.getLine("L"); + assertNotNull(line); + OperatingStatus lineOperatingStatus = new OperatingStatusImpl<>(line, + OperatingStatus.Status.PLANNED_OUTAGE); + line.addExtension(OperatingStatus.class, lineOperatingStatus); + + var exportOptions = new ExportOptions().addExtensionVersion(OperatingStatus.NAME, "alternative"); + Network network2 = allFormatsRoundTripTest(network, "/alternativeOperatingStatusRef.xml", exportOptions); + + Line line2 = network2.getLine("L"); + assertNotNull(line2); + OperatingStatus lineOperatingStatus2 = line2.getExtension(OperatingStatus.class); + assertNotNull(lineOperatingStatus2); + assertEquals(lineOperatingStatus.getStatus(), lineOperatingStatus2.getStatus()); + + lineOperatingStatus2.setStatus(OperatingStatus.Status.IN_OPERATION); + assertEquals(OperatingStatus.Status.IN_OPERATION, lineOperatingStatus2.getStatus()); + } + + @Test + void versionedAlternativeWithDefaultVersionTest() throws IOException { + Network network = BatteryNetworkFactory.create(); + + Battery bat = network.getBattery("BAT"); + bat.addExtension(ActivePowerControl.class, new ActivePowerControlImpl<>(bat, true, 4.0, 1.2)); + + Generator generator = network.getGenerator("GEN"); + generator.addExtension(ActivePowerControl.class, new ActivePowerControlImpl<>(generator, false, 3.0, 1.0)); + + // No version is specified for the alternative: it should use the default version (v1.1) + var exportOptions = new ExportOptions().addExtensionVersion(ActivePowerControl.NAME, ExportOptions.ALTERNATIVE_VERSION); + Network network2 = allFormatsRoundTripTest(network, "/alternativeActivePowerControlV1_1.xml", IidmVersion.V_1_0, exportOptions); + + Battery bat2 = network2.getBattery("BAT"); + assertNotNull(bat2); + ActivePowerControl activePowerControl2 = bat2.getExtension(ActivePowerControl.class); + assertNotNull(activePowerControl2); + assertEquals(1.2, activePowerControl2.getParticipationFactor(), 0.001d); // default version supports participationFactor + } + + @Test + void versionedAlternativeWithSpecificVersionTest() throws IOException { + Network network = BatteryNetworkFactory.create(); + + Battery bat = network.getBattery("BAT"); + bat.addExtension(ActivePowerControl.class, new ActivePowerControlImpl<>(bat, true, 4.0, 1.2)); + + Generator generator = network.getGenerator("GEN"); + generator.addExtension(ActivePowerControl.class, new ActivePowerControlImpl<>(generator, false, 3.0, 1.0)); + + // Explicitly ask for version 1.0 of the alternative + var exportOptions = new ExportOptions() + .addExtensionVersion("legacyActivePowerControl", "1.0") + .addExtensionVersion(ActivePowerControl.NAME, ExportOptions.ALTERNATIVE_VERSION); + Network network2 = allFormatsRoundTripTest(network, "/alternativeActivePowerControlV1_0.xml", IidmVersion.V_1_0, exportOptions); + + Battery bat2 = network2.getBattery("BAT"); + assertNotNull(bat2); + ActivePowerControl activePowerControl2 = bat2.getExtension(ActivePowerControl.class); + assertNotNull(activePowerControl2); + assertTrue(Double.isNaN(activePowerControl2.getParticipationFactor())); // version 1.0 does NOT support participationFactor + } +} diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/OperatingStatusXmlTest.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/OperatingStatusXmlTest.java index 9ac57d3b426..195fdc82bb7 100644 --- a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/OperatingStatusXmlTest.java +++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/OperatingStatusXmlTest.java @@ -24,14 +24,14 @@ */ class OperatingStatusXmlTest extends AbstractIidmSerDeTest { - private static Network createTestNetwork() { + protected static Network createTestNetwork() { Network network = Network.create("test", "test"); network.setCaseDate(ZonedDateTime.parse("2016-06-27T12:27:58.535+02:00")); Substation s = network.newSubstation() .setId("S") .setCountry(Country.FR) .add(); - VoltageLevel vl = s.newVoltageLevel() + s.newVoltageLevel() .setId("VL") .setNominalV(400) .setTopologyKind(TopologyKind.NODE_BREAKER) @@ -40,7 +40,7 @@ private static Network createTestNetwork() { .setId("S2") .setCountry(Country.FR) .add(); - VoltageLevel vl2 = s2.newVoltageLevel() + s2.newVoltageLevel() .setId("VL2") .setNominalV(400) .setTopologyKind(TopologyKind.NODE_BREAKER) diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/alternatives/LegacyActivePowerControlSerDe.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/alternatives/LegacyActivePowerControlSerDe.java new file mode 100644 index 00000000000..5a7ddf594ac --- /dev/null +++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/alternatives/LegacyActivePowerControlSerDe.java @@ -0,0 +1,92 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.serde.extensions.alternatives; + +import com.google.auto.service.AutoService; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSortedSet; +import com.powsybl.commons.extensions.AlternativeExtensionSerDe; +import com.powsybl.commons.extensions.ExtensionSerDe; +import com.powsybl.commons.io.DeserializerContext; +import com.powsybl.commons.io.SerializerContext; +import com.powsybl.iidm.network.Injection; +import com.powsybl.iidm.network.extensions.ActivePowerControl; +import com.powsybl.iidm.network.extensions.ActivePowerControlAdder; +import com.powsybl.iidm.serde.IidmVersion; +import com.powsybl.iidm.serde.NetworkDeserializerContext; +import com.powsybl.iidm.serde.NetworkSerializerContext; +import com.powsybl.iidm.serde.extensions.AbstractAlternativeVersionableNetworkExtensionSerDe; + +import java.io.InputStream; +import java.util.List; + +/** + * @author Olivier Perrin {@literal } + */ +@AutoService({AlternativeExtensionSerDe.class, ExtensionSerDe.class}) +public class LegacyActivePowerControlSerDe> + extends AbstractAlternativeVersionableNetworkExtensionSerDe> { + + public LegacyActivePowerControlSerDe() { + super("legacyActivePowerControl", ActivePowerControl.class, "lapc", + new ImmutableMap.Builder>() + .put(IidmVersion.V_1_0, ImmutableSortedSet.of("1.0", "1.1")) + .build(), + new ImmutableMap.Builder() + .put("1.0", "http://www.itesla_project.eu/schema/iidm/ext/legacy_active_power_control/1_0") + .put("1.1", "http://www.powsybl.org/schema/iidm/ext/legacy_active_power_control/1_1") + .build()); + } + + @Override + public String getOriginalExtensionName() { + return ActivePowerControl.NAME; + } + + @Override + public void write(ActivePowerControl activePowerControl, SerializerContext context) { + context.getWriter().writeBooleanAttribute("legacyParticipate", activePowerControl.isParticipate()); + context.getWriter().writeDoubleAttribute("legacyDroop", activePowerControl.getDroop()); + NetworkSerializerContext networkContext = (NetworkSerializerContext) context; + String extVersionStr = networkContext.getExtensionVersion(getExtensionName()) + .orElseGet(() -> getVersion(networkContext.getVersion())); + if ("1.1".compareTo(extVersionStr) <= 0) { + context.getWriter().writeDoubleAttribute("legacyParticipationFactor", activePowerControl.getParticipationFactor()); + } + } + + @Override + public InputStream getXsdAsStream() { + return getClass().getResourceAsStream("/xsd/legacyActivePowerControlV1_1.xsd"); + } + + @Override + public List getXsdAsStreamList() { + return List.of(getClass().getResourceAsStream("/xsd/legacyActivePowerControlV1_1.xsd"), + getClass().getResourceAsStream("/xsd/legacyActivePowerControlV1_0.xsd")); + } + + @Override + public ActivePowerControl read(T identifiable, DeserializerContext context) { + boolean participate = context.getReader().readBooleanAttribute("legacyParticipate"); + double droop = context.getReader().readDoubleAttribute("legacyDroop"); + double participationFactor = Double.NaN; + NetworkDeserializerContext networkContext = (NetworkDeserializerContext) context; + String extVersionStr = networkContext.getExtensionVersion(this).orElseThrow(IllegalStateException::new); + if ("1.1".compareTo(extVersionStr) <= 0) { + participationFactor = context.getReader().readDoubleAttribute("legacyParticipationFactor"); + } + context.getReader().readEndNode(); + ActivePowerControlAdder activePowerControlAdder = identifiable.newExtension(ActivePowerControlAdder.class); + return activePowerControlAdder.withParticipate(participate) + .withDroop(droop) + .withParticipationFactor(participationFactor) + .add(); + } + +} diff --git a/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/alternatives/LegacyOperatingStatusSerDe.java b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/alternatives/LegacyOperatingStatusSerDe.java new file mode 100644 index 00000000000..2811a177f9b --- /dev/null +++ b/iidm/iidm-serde/src/test/java/com/powsybl/iidm/serde/extensions/alternatives/LegacyOperatingStatusSerDe.java @@ -0,0 +1,51 @@ +/** + * 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/. + * SPDX-License-Identifier: MPL-2.0 + */ +package com.powsybl.iidm.serde.extensions.alternatives; + +import com.google.auto.service.AutoService; +import com.powsybl.commons.extensions.AbstractAlternativeExtensionSerDe; +import com.powsybl.commons.extensions.AlternativeExtensionSerDe; +import com.powsybl.commons.extensions.ExtensionSerDe; +import com.powsybl.commons.io.DeserializerContext; +import com.powsybl.commons.io.SerializerContext; +import com.powsybl.iidm.network.Identifiable; +import com.powsybl.iidm.network.extensions.OperatingStatus; +import com.powsybl.iidm.network.extensions.OperatingStatusAdder; + +/** + * @author Olivier Perrin {@literal } + */ +@AutoService({AlternativeExtensionSerDe.class, ExtensionSerDe.class}) +public class LegacyOperatingStatusSerDe> + extends AbstractAlternativeExtensionSerDe> { + + public LegacyOperatingStatusSerDe() { + super("legacyOperatingStatus", "network", OperatingStatus.class, + "legacyOperatingStatus.xsd", "http://www.powsybl.org/schema/iidm/ext/legacy_operating_status/1_0", + "los"); + } + + @Override + public String getOriginalExtensionName() { + return OperatingStatus.NAME; + } + + @Override + public void write(OperatingStatus status, SerializerContext context) { + context.getWriter().writeNodeContent(status.getStatus().name()); + } + + @Override + public OperatingStatus read(I identifiable, DeserializerContext context) { + OperatingStatus.Status status = OperatingStatus.Status.valueOf(context.getReader().readContent()); + OperatingStatusAdder adder = identifiable.newExtension(OperatingStatusAdder.class); + return adder.withStatus(status) + .add(); + } + +} diff --git a/iidm/iidm-serde/src/test/resources/V1_0/alternativeActivePowerControlV1_0.xml b/iidm/iidm-serde/src/test/resources/V1_0/alternativeActivePowerControlV1_0.xml new file mode 100644 index 00000000000..5dfd71183b4 --- /dev/null +++ b/iidm/iidm-serde/src/test/resources/V1_0/alternativeActivePowerControlV1_0.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/iidm/iidm-serde/src/test/resources/V1_0/alternativeActivePowerControlV1_1.xml b/iidm/iidm-serde/src/test/resources/V1_0/alternativeActivePowerControlV1_1.xml new file mode 100644 index 00000000000..c0b5e06f86d --- /dev/null +++ b/iidm/iidm-serde/src/test/resources/V1_0/alternativeActivePowerControlV1_1.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/iidm/iidm-serde/src/test/resources/alternativeOperatingStatusRef.xml b/iidm/iidm-serde/src/test/resources/alternativeOperatingStatusRef.xml new file mode 100644 index 00000000000..fd55f68bf0e --- /dev/null +++ b/iidm/iidm-serde/src/test/resources/alternativeOperatingStatusRef.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + PLANNED_OUTAGE + + \ No newline at end of file diff --git a/iidm/iidm-serde/src/test/resources/xsd/legacyActivePowerControlV1_0.xsd b/iidm/iidm-serde/src/test/resources/xsd/legacyActivePowerControlV1_0.xsd new file mode 100644 index 00000000000..1ba9515a77f --- /dev/null +++ b/iidm/iidm-serde/src/test/resources/xsd/legacyActivePowerControlV1_0.xsd @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/iidm/iidm-serde/src/test/resources/xsd/legacyActivePowerControlV1_1.xsd b/iidm/iidm-serde/src/test/resources/xsd/legacyActivePowerControlV1_1.xsd new file mode 100644 index 00000000000..62416143470 --- /dev/null +++ b/iidm/iidm-serde/src/test/resources/xsd/legacyActivePowerControlV1_1.xsd @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/iidm/iidm-serde/src/test/resources/xsd/legacyOperatingStatus.xsd b/iidm/iidm-serde/src/test/resources/xsd/legacyOperatingStatus.xsd new file mode 100644 index 00000000000..5f2f0b1b2ec --- /dev/null +++ b/iidm/iidm-serde/src/test/resources/xsd/legacyOperatingStatus.xsd @@ -0,0 +1,24 @@ + + + + + + + + + + + +