FullModel.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.cgmes.model;
import com.google.common.base.Suppliers;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.exceptions.UncheckedXmlStreamException;
import com.powsybl.commons.xml.XmlUtil;
import javax.xml.XMLConstants;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.Reader;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.Supplier;
/**
*
* @author Geoffroy Jamgotchian {@literal <geoffroy.jamgotchian at rte-france.com>}
*/
public class FullModel {
private static final Supplier<XMLInputFactory> XML_INPUT_FACTORY_SUPPLIER = Suppliers.memoize(() -> {
XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
return factory;
});
private final String id;
private final ZonedDateTime scenarioTime;
private final ZonedDateTime created;
private final String description;
private final int version;
private final List<String> profiles;
private final List<String> dependentOn;
private final List<String> supersedes;
private final String modelingAuthoritySet;
public FullModel(String id, ZonedDateTime scenarioTime, ZonedDateTime created, String description, int version, List<String> profiles,
List<String> dependentOn, List<String> supersedes, String modelingAuthoritySet) {
this.id = Objects.requireNonNull(id, "ID is missing");
this.scenarioTime = Objects.requireNonNull(scenarioTime, "Scenario time is missing");
this.created = Objects.requireNonNull(created, "Created time is missing");
this.description = description;
this.version = version;
if (profiles == null || profiles.isEmpty()) {
throw new PowsyblException("At least one profile is required");
}
this.profiles = new ArrayList<>(profiles);
this.dependentOn = new ArrayList<>(Objects.requireNonNull(dependentOn));
this.supersedes = new ArrayList<>(Objects.requireNonNull(supersedes));
this.modelingAuthoritySet = Objects.requireNonNull(modelingAuthoritySet, "Modeling authority set is missing");
}
public String getId() {
return id;
}
public ZonedDateTime getScenarioTime() {
return scenarioTime;
}
public ZonedDateTime getCreated() {
return created;
}
public Optional<String> getDescription() {
return Optional.ofNullable(description);
}
public int getVersion() {
return version;
}
public List<String> getProfiles() {
return Collections.unmodifiableList(profiles);
}
public List<String> getDependentOn() {
return Collections.unmodifiableList(dependentOn);
}
public List<String> getSupersedes() {
return Collections.unmodifiableList(supersedes);
}
public String getModelingAuthoritySet() {
return modelingAuthoritySet;
}
@Override
public String toString() {
return "FullModel(" +
"id='" + id + '\'' +
", scenarioTime=" + scenarioTime +
", created=" + created +
", description='" + description + '\'' +
", version=" + version +
", profiles=" + profiles +
", dependentOn=" + dependentOn +
", supersedes=" + supersedes +
", modelingAuthoritySet='" + modelingAuthoritySet + '\'' +
')';
}
private static final class ParsingContext {
private String id;
private ZonedDateTime scenarioTime;
private ZonedDateTime created;
private String description;
private Integer version;
private final List<String> profiles = new ArrayList<>();
private final List<String> dependentOn = new ArrayList<>();
private final List<String> supersedes = new ArrayList<>();
private String modelingAuthoritySet;
}
public static FullModel parse(Reader reader) {
Objects.requireNonNull(reader);
ParsingContext context = new ParsingContext();
try {
XMLStreamReader xmlReader = XML_INPUT_FACTORY_SUPPLIER.get().createXMLStreamReader(reader);
try {
XmlUtil.readUntilStartElement(new String[] {"/", CgmesNames.RDF, CgmesNames.FULL_MODEL}, xmlReader, elementName1 -> {
context.id = xmlReader.getAttributeValue(CgmesNamespace.RDF_NAMESPACE, CgmesNames.ABOUT);
XmlUtil.readSubElements(xmlReader, subElementName -> readSubElement(subElementName, context, xmlReader));
});
} finally {
xmlReader.close();
XmlUtil.gcXmlInputFactory(XML_INPUT_FACTORY_SUPPLIER.get());
}
} catch (XMLStreamException e) {
throw new UncheckedXmlStreamException(e);
}
// the other attributes are checked in the constructor
if (context.version == null) {
throw new PowsyblException("Version is missing");
}
return new FullModel(context.id, context.scenarioTime, context.created, context.description, context.version,
context.profiles, context.dependentOn, context.supersedes, context.modelingAuthoritySet);
}
private static void readSubElement(String subElementName, ParsingContext context, XMLStreamReader xmlReader) {
try {
switch (subElementName) {
case CgmesNames.SCENARIO_TIME -> context.scenarioTime = ZonedDateTime.parse(xmlReader.getElementText());
case CgmesNames.CREATED -> context.created = ZonedDateTime.parse(xmlReader.getElementText());
case CgmesNames.DESCRIPTION -> context.description = XmlUtil.readText(xmlReader);
case CgmesNames.VERSION -> context.version = Integer.parseInt(xmlReader.getElementText());
case CgmesNames.PROFILE -> context.profiles.add(XmlUtil.readText(xmlReader));
case CgmesNames.DEPENDENT_ON -> {
context.dependentOn.add(xmlReader.getAttributeValue(CgmesNamespace.RDF_NAMESPACE, CgmesNames.RESOURCE));
XmlUtil.readEndElementOrThrow(xmlReader);
}
case CgmesNames.SUPERSEDES -> {
context.supersedes.add(xmlReader.getAttributeValue(CgmesNamespace.RDF_NAMESPACE, CgmesNames.RESOURCE));
XmlUtil.readEndElementOrThrow(xmlReader);
}
case CgmesNames.MODELING_AUTHORITY_SET -> context.modelingAuthoritySet = XmlUtil.readText(xmlReader);
default -> {
// not yet interesting like superseded
}
}
} catch (XMLStreamException e) {
throw new UncheckedXmlStreamException(e);
}
}
}