AbstractIdentifiable.java
/**
* Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
* 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.network.impl;
import com.google.common.base.Strings;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.extensions.AbstractExtendable;
import com.powsybl.commons.extensions.Extension;
import com.powsybl.iidm.network.Identifiable;
import com.powsybl.iidm.network.Validable;
import com.powsybl.iidm.network.util.Identifiables;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
*/
abstract class AbstractIdentifiable<I extends Identifiable<I>> extends AbstractExtendable<I> implements Identifiable<I>, Validable, MultiVariantObject {
protected String id;
protected String name;
protected boolean fictitious = false;
protected final Properties properties = new Properties();
private final Set<String> aliasesWithoutType = new HashSet<>();
private final Map<String, String> aliasesByType = new HashMap<>();
AbstractIdentifiable(String id, String name) {
this.id = id;
this.name = name;
}
AbstractIdentifiable(String id, String name, boolean fictitious) {
this(id, name);
this.fictitious = fictitious;
}
@Override
public String getId() {
return id;
}
void replaceId(String newId) {
throw new PowsyblException("Cannot change ID");
}
@Override
public Optional<String> getOptionalName() {
return Optional.ofNullable(name);
}
@Override
public String getNameOrId() {
return name != null ? name : id;
}
@Override
public I setName(String name) {
String oldName = this.name;
this.name = name;
getNetwork().getListeners().notifyUpdate(this, "name", oldName, name);
return (I) this;
}
@Override
public Set<String> getAliases() {
Set<String> aliases = new HashSet<>();
aliases.addAll(aliasesWithoutType);
aliases.addAll(aliasesByType.values());
return Collections.unmodifiableSet(aliases);
}
@Override
public Optional<String> getAliasType(String alias) {
Objects.requireNonNull(alias);
if (aliasesWithoutType.contains(alias)) {
return Optional.empty();
}
return aliasesByType.entrySet().stream().filter(entry -> entry.getValue().equals(alias)).map(Map.Entry::getKey).findFirst();
}
@Override
public Optional<String> getAliasFromType(String aliasType) {
if (Strings.isNullOrEmpty(aliasType)) {
throw new PowsyblException("Alias type must not be null or empty");
}
return Optional.ofNullable(aliasesByType.get(aliasType));
}
@Override
public void addAlias(String alias) {
addAlias(alias, false);
}
@Override
public void addAlias(String alias, boolean ensureAliasUnicity) {
addAlias(alias, null, ensureAliasUnicity);
}
@Override
public void addAlias(String alias, String aliasType) {
addAlias(alias, aliasType, false);
}
@Override
public void addAlias(String alias, String aliasType, boolean ensureAliasUnicity) {
Objects.requireNonNull(alias);
String uniqueAlias = alias;
if (ensureAliasUnicity) {
uniqueAlias = Identifiables.getUniqueId(alias, getNetwork().getIndex()::contains);
}
if (!Strings.isNullOrEmpty(aliasType) && aliasesByType.containsKey(aliasType)) {
throw new PowsyblException(id + " already has an alias of type " + aliasType);
}
if (getNetwork().getIndex().addAlias(this, uniqueAlias)) {
if (Strings.isNullOrEmpty(aliasType)) {
aliasesWithoutType.add(uniqueAlias);
} else {
aliasesByType.put(aliasType, uniqueAlias);
}
}
}
@Override
public void removeAlias(String alias) {
Objects.requireNonNull(alias);
getNetwork().getIndex().removeAlias(this, alias);
String type = aliasesByType.entrySet().stream().filter(entry -> entry.getValue().equals(alias)).map(Map.Entry::getKey).filter(Objects::nonNull).findFirst().orElse(null);
if (Strings.isNullOrEmpty(type)) {
aliasesWithoutType.remove(alias);
} else {
aliasesByType.remove(type);
}
}
@Override
public boolean hasAliases() {
return !aliasesWithoutType.isEmpty() || !aliasesByType.isEmpty();
}
@Override
public boolean isFictitious() {
return fictitious;
}
@Override
public void setFictitious(boolean fictitious) {
boolean oldValue = this.fictitious;
this.fictitious = fictitious;
getNetwork().getListeners().notifyUpdate(this, "fictitious", oldValue, fictitious);
}
@Override
public abstract NetworkImpl getNetwork();
protected abstract String getTypeDescription();
@Override
public String getMessageHeader() {
return getTypeDescription() + " '" + id + "': ";
}
public Properties getProperties() {
return properties;
}
@Override
public boolean hasProperty() {
return !properties.isEmpty();
}
@Override
public boolean hasProperty(String key) {
return properties.containsKey(key);
}
@Override
public String getProperty(String key) {
Object val = properties.get(key);
return val != null ? val.toString() : null;
}
@Override
public String getProperty(String key, String defaultValue) {
Object val = properties.getOrDefault(key, defaultValue);
return val != null ? val.toString() : null;
}
@Override
public String setProperty(String key, String value) {
String oldValue = (String) properties.put(key, value);
if (Objects.isNull(oldValue)) {
getNetwork().getListeners().notifyPropertyAdded(this, () -> getPropertyStringForNotification(key), value);
} else {
getNetwork().getListeners().notifyPropertyReplaced(this, () -> getPropertyStringForNotification(key), oldValue, value);
}
return oldValue;
}
@Override
public boolean removeProperty(String key) {
Object oldValue = properties.remove(key);
if (oldValue != null) {
getNetwork().getListeners().notifyPropertyRemoved(this, () -> getPropertyStringForNotification(key), oldValue);
return true;
}
return false;
}
@Override
public Set<String> getPropertyNames() {
return properties.keySet().stream().map(Object::toString).collect(Collectors.toSet());
}
@Override
public String toString() {
return id;
}
@Override
public void extendVariantArraySize(int initVariantArraySize, int number, int sourceIndex) {
getExtensions().stream()
.filter(e -> e instanceof MultiVariantObject)
.map(e -> (MultiVariantObject) e)
.forEach(e -> e.extendVariantArraySize(initVariantArraySize, number, sourceIndex));
}
@Override
public void reduceVariantArraySize(int number) {
getExtensions().stream()
.filter(e -> e instanceof MultiVariantObject)
.map(e -> (MultiVariantObject) e)
.forEach(e -> e.reduceVariantArraySize(number));
}
@Override
public void deleteVariantArrayElement(int index) {
getExtensions().stream()
.filter(e -> e instanceof MultiVariantObject)
.map(e -> (MultiVariantObject) e)
.forEach(e -> e.deleteVariantArrayElement(index));
}
@Override
public void allocateVariantArrayElement(int[] indexes, int sourceIndex) {
getExtensions().stream()
.filter(e -> e instanceof MultiVariantObject)
.map(e -> (MultiVariantObject) e)
.forEach(e -> e.allocateVariantArrayElement(indexes, sourceIndex));
}
@Override
public <E extends Extension<I>> boolean removeExtension(Class<E> type) {
return removeExtension(type, true);
}
public <E extends Extension<I>> boolean removeExtension(Class<E> type, boolean cleanup) {
E extension = getExtension(type);
NetworkListenerList listeners = getNetwork().getListeners();
if (extension != null) {
listeners.notifyExtensionBeforeRemoval(extension);
if (cleanup) {
extension.cleanup();
}
removeExtension(type, extension);
listeners.notifyExtensionAfterRemoval(this, extension.getName());
return true;
}
return false;
}
private static String getPropertyStringForNotification(String key) {
return "properties[" + key + "]";
}
}