IdWithWildcardsNetworkElementIdentifier.java
/**
* 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.network.identifiers;
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.Identifiable;
import com.powsybl.iidm.network.Network;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.powsybl.iidm.network.identifiers.NetworkElementIdentifier.IdentifierType.ID_WITH_WILDCARDS;
/**
*
* <p>Identifier that finds a network element that have some unknown characters.</p>
* <p>The unknown characters should be replaced in the identifier by a wildcard character. There can be a maximum of 5 wildcards in the identifier.</p>
* <p>By default, the wildcard character is '?'. But you can change it if needed / wanted by using
* the {@link #IdWithWildcardsNetworkElementIdentifier(String, String, String)} constructor.</p>
*
* @author Etienne Lesot {@literal <etienne.lesot at rte-france.com>}
* @author Olivier Perrin {@literal <olivier.perrin at rte-france.com>}
*/
public class IdWithWildcardsNetworkElementIdentifier implements NetworkElementIdentifier {
public static final int ALLOWED_WILDCARDS_NUMBER = 5;
public static final String DEFAULT_WILDCARD_CHARACTER = "?";
private final String originalIdentifier;
private String identifierPattern;
private final String wildcardCharacter;
private final String contingencyId;
public IdWithWildcardsNetworkElementIdentifier(String identifier) {
this(identifier, DEFAULT_WILDCARD_CHARACTER, null);
}
public IdWithWildcardsNetworkElementIdentifier(String identifier, String contingencyId) {
this(identifier, DEFAULT_WILDCARD_CHARACTER, contingencyId);
}
public IdWithWildcardsNetworkElementIdentifier(String identifier, String wildcardCharacter, String contingencyId) {
this.originalIdentifier = Objects.requireNonNull(identifier);
this.contingencyId = contingencyId;
if (wildcardCharacter.codePointCount(0, wildcardCharacter.length()) != 1) { // Count code points to accept supplementary UTF-16 characters
throw new IllegalArgumentException("Wildcard character must be a single character");
}
this.wildcardCharacter = wildcardCharacter;
initialize();
}
private void initialize() {
int separatorNumber = StringUtils.countMatches(originalIdentifier, wildcardCharacter);
if (separatorNumber > ALLOWED_WILDCARDS_NUMBER) {
throw new PowsyblException("There can be a maximum of " + ALLOWED_WILDCARDS_NUMBER + " wildcards ('" + wildcardCharacter + "')");
}
if (separatorNumber == 0) {
throw new PowsyblException("There is no wildcard in your identifier, please use IdBasedNetworkElementIdentifier instead");
}
// Escape all non wildcard characters
String[] chunks = originalIdentifier.split(Pattern.quote(wildcardCharacter));
StringJoiner sj = new StringJoiner(".");
Stream.of(chunks).forEach(c -> sj.add(Pattern.quote(c)));
if (originalIdentifier.endsWith(wildcardCharacter)) {
sj.add("");
}
identifierPattern = sj.toString();
}
@Override
public Set<Identifiable> filterIdentifiable(Network network) {
return network.getIdentifiables()
.stream()
.filter(identifiable -> identifiable.getId().matches(identifierPattern))
.collect(Collectors.toUnmodifiableSet());
}
@Override
public Set<String> getNotFoundElements(Network network) {
Identifiable<?> identifiable = network.getIdentifiable(identifierPattern);
return identifiable == null ? Collections.singleton(identifierPattern) : Collections.emptySet();
}
@Override
public IdentifierType getType() {
return ID_WITH_WILDCARDS;
}
@Override
public Optional<String> getContingencyId() {
return Optional.ofNullable(contingencyId);
}
public String getIdentifier() {
return originalIdentifier;
}
public String getWildcardCharacter() {
return wildcardCharacter;
}
}