AbstractVersionableNetworkExtensionSerDe.java
/**
* Copyright (c) 2020, 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.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableSortedSet;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.extensions.Extendable;
import com.powsybl.commons.extensions.Extension;
import com.powsybl.commons.extensions.ExtensionSerDe;
import com.powsybl.iidm.serde.IidmSerDeConstants;
import com.powsybl.iidm.serde.IidmVersion;
import com.powsybl.iidm.serde.NetworkDeserializerContext;
import java.util.*;
import java.util.stream.Stream;
/**
* @author Miora Ralambotiana {@literal <miora.ralambotiana at rte-france.com>}
*/
public abstract class AbstractVersionableNetworkExtensionSerDe<T extends Extendable, E extends Extension<T>> implements ExtensionSerDe<T, E> {
private static final String INCOMPATIBILITY_NETWORK_VERSION_MESSAGE = "IIDM version of network (";
private final String extensionName;
private final Class<? super E> extensionClass;
private final String namespacePrefix;
private final Map<IidmVersion, ImmutableSortedSet<String>> extensionVersions = new EnumMap<>(IidmVersion.class);
private final BiMap<String, String> namespaceUris = HashBiMap.create();
private final Map<String, String> serializationNameByVersion = new HashMap<>();
private final Map<String, String> namespacePrefixByVersion = new HashMap<>();
public record AlternativeSerializationData(String name, List<String> versions, String namespacePrefix) {
public AlternativeSerializationData(String name, List<String> versions) {
this(name, versions, null);
}
}
protected AbstractVersionableNetworkExtensionSerDe(String extensionName, Class<? super E> extensionClass, String namespacePrefix,
Map<IidmVersion, ImmutableSortedSet<String>> extensionVersions, Map<String, String> namespaceUris) {
this(extensionName, extensionClass, namespacePrefix, extensionVersions, namespaceUris, null);
}
protected AbstractVersionableNetworkExtensionSerDe(String extensionName, Class<? super E> extensionClass, String namespacePrefix,
Map<IidmVersion, ImmutableSortedSet<String>> extensionVersions,
Map<String, String> namespaceUris,
List<AlternativeSerializationData> alternativeSerializationData) {
this.extensionName = Objects.requireNonNull(extensionName);
this.extensionClass = Objects.requireNonNull(extensionClass);
this.namespacePrefix = Objects.requireNonNull(namespacePrefix);
this.extensionVersions.putAll(Objects.requireNonNull(extensionVersions));
this.namespaceUris.putAll(Objects.requireNonNull(namespaceUris));
if (alternativeSerializationData != null) {
Set<String> names = new HashSet<>();
for (AlternativeSerializationData data : alternativeSerializationData) {
if (!names.add(data.name())) {
throw new IllegalArgumentException("Duplicate alternative serialization name: " + data.name());
}
data.versions().forEach(version -> {
this.serializationNameByVersion.put(version, data.name());
if (data.namespacePrefix() != null) {
this.namespacePrefixByVersion.put(version, data.namespacePrefix());
}
});
}
}
}
@Override
public String getExtensionName() {
return extensionName;
}
@Override
public String getSerializationName(String extensionVersion) {
return serializationNameByVersion.getOrDefault(extensionVersion, extensionName);
}
@Override
public Set<String> getSerializationNames() {
Set<String> names = new HashSet<>(serializationNameByVersion.values());
names.add(extensionName);
return names;
}
@Override
public String getCategoryName() {
return "network";
}
@Override
public Class<? super E> getExtensionClass() {
return extensionClass;
}
@Override
public String getNamespaceUri() {
return getNamespaceUri(getVersion());
}
@Override
public Stream<String> getNamespaceUriStream() {
return namespaceUris.values().stream().distinct();
}
@Override
public String getNamespaceUri(String extensionVersion) {
return Optional.ofNullable(namespaceUris.get(extensionVersion))
.orElseThrow(() -> new PowsyblException("Namespace URI null for " + getExtensionName() +
" extension's version " + extensionVersion));
}
@Override
public String getVersion() {
return getVersion(IidmSerDeConstants.CURRENT_IIDM_VERSION);
}
public boolean versionExists(IidmVersion networkVersion) {
return extensionVersions.containsKey(networkVersion);
}
/**
* Get the oldest version of an extension working with a network version.
*/
public String getVersion(IidmVersion networkVersion) {
return extensionVersions.get(networkVersion).last();
}
@Override
public String getVersion(String namespaceUri) {
return Optional.ofNullable(namespaceUris.inverse().get(namespaceUri))
.orElseThrow(() -> new PowsyblException("The namespace URI " + namespaceUri + " of the " + extensionName + " extension is not supported."));
}
@Override
public Set<String> getVersions() {
return namespaceUris.keySet();
}
protected void checkReadingCompatibility(NetworkDeserializerContext networkContext) {
IidmVersion version = networkContext.getVersion();
checkCompatibilityNetworkVersion(version);
if (extensionVersions.get(version).stream().noneMatch(v -> networkContext.containsExtensionVersion(getExtensionName(), v))) {
throw new PowsyblException(INCOMPATIBILITY_NETWORK_VERSION_MESSAGE + version.toString(".")
+ ") is not compatible with the " + extensionName + " extension's namespace URI.");
}
}
public boolean checkWritingCompatibility(String extensionVersion, IidmVersion version) {
checkExtensionVersionSupported(extensionVersion);
checkCompatibilityNetworkVersion(version);
if (!extensionVersions.get(version).contains(extensionVersion)) {
throw new PowsyblException(INCOMPATIBILITY_NETWORK_VERSION_MESSAGE + version.toString(".")
+ ") is not compatible with " + extensionName + " version " + extensionVersion);
}
return true;
}
private void checkCompatibilityNetworkVersion(IidmVersion version) {
if (!extensionVersions.containsKey(version)) {
throw new PowsyblException(INCOMPATIBILITY_NETWORK_VERSION_MESSAGE + version.toString(".")
+ ") is not supported by the " + getExtensionName() + " extension's XML serializer.");
}
}
@Override
public String getNamespacePrefix() {
return namespacePrefix;
}
@Override
public String getNamespacePrefix(String extensionVersion) {
return namespacePrefixByVersion.getOrDefault(extensionVersion, namespacePrefix);
}
@Override
public void checkExtensionVersionSupported(String extensionVersion) {
if (!namespaceUris.containsKey(extensionVersion)) {
throw new PowsyblException("The " + extensionName + " extension version " + extensionVersion + " is not supported.");
}
}
}