All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.powsybl.psse.model.io.AbstractRecordGroup Maven / Gradle / Ivy

There is a newer version: 6.6.0
Show newest version
/**
 * 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.psse.model.io;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.powsybl.psse.model.PsseException;
import com.powsybl.psse.model.PsseVersion;
import com.univocity.parsers.common.processor.BeanListProcessor;
import com.univocity.parsers.common.processor.BeanWriterProcessor;
import com.univocity.parsers.csv.CsvParser;
import com.univocity.parsers.csv.CsvParserSettings;
import com.univocity.parsers.csv.CsvWriter;
import com.univocity.parsers.csv.CsvWriterSettings;

import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

import org.apache.commons.lang3.ArrayUtils;

import static com.powsybl.psse.model.io.FileFormat.JSON;
import static com.powsybl.psse.model.io.FileFormat.LEGACY_TEXT;

/**
 * @author Luma Zamarreño {@literal }
 * @author José Antonio Marqués {@literal }
 */
public abstract class AbstractRecordGroup {

    protected final RecordGroupIdentification identification;
    private final String[] fieldNames;
    private final Map fieldNamesByVersionMajor = new EnumMap<>(PsseVersion.Major.class);
    private String[] quotedFields;
    private final Table> ioFormatVersion = HashBasedTable.create();
    private final Map> ioFormat = new EnumMap<>(FileFormat.class);

    protected AbstractRecordGroup(RecordGroupIdentification identification, String... fieldNames) {
        this.identification = identification;
        this.fieldNames = fieldNames.length > 0 ? fieldNames : null;
        ioFormat.put(LEGACY_TEXT, new RecordGroupIOLegacyText<>(this));
        ioFormat.put(JSON, new RecordGroupIOJson<>(this));
    }

    protected void withFieldNames(PsseVersion.Major version, String... fieldNames) {
        fieldNamesByVersionMajor.put(version, fieldNames);
    }

    protected void withIO(FileFormat fileFormat, RecordGroupIO rw) {
        Objects.requireNonNull(fileFormat);
        Objects.requireNonNull(rw);
        ioFormat.put(fileFormat, rw);
    }

    protected void withIO(FileFormat fileFormat, PsseVersion.Major version, RecordGroupIO io) {
        Objects.requireNonNull(fileFormat);
        Objects.requireNonNull(io);
        this.ioFormatVersion.put(fileFormat, version, io);
    }

    protected void withQuotedFields(String... quotedFields) {
        this.quotedFields = quotedFields;
    }

    public RecordGroupIdentification getIdentification() {
        return this.identification;
    }

    /**
     * Some record groups have a fine level of detail on which field names should be saved in the context depending on each record
     * This function will be override for Transformer data:
     * We want to save different field names for transformers with 2 / 3 windings
     *
     * @param object the object to be evaluated for a specific record group identification
     * @return the specific record group identification for the object
     */
    RecordGroupIdentification getIdentificationFor(T object) {
        return this.identification;
    }

    public String[] fieldNames(PsseVersion version) {
        if (fieldNames != null) {
            return fieldNames;
        }
        String[] fieldNamesVersion = fieldNamesByVersionMajor.get(version.major());
        if (fieldNamesVersion == null) {
            throw new PsseException("Missing fieldNames for version " + version.getMajorNumber() + " in record group " + identification);
        }
        return fieldNamesVersion;
    }

    // Record groups with multiline records
    String[][] getFieldNamesByLine(PsseVersion version, String line0) {
        throw new PsseException("Multiline records no supported at this level");
    }

    public String[] quotedFields() {
        return quotedFields;
    }

    protected abstract Class psseTypeClass();

    RecordGroupIO ioFor(FileFormat fileFormat, PsseVersion.Major version) {
        if (ioFormatVersion.contains(fileFormat, version)) {
            return ioFormatVersion.get(fileFormat, version);
        }
        return ioFor(fileFormat);
    }

    RecordGroupIO ioFor(FileFormat fileFormat) {
        RecordGroupIO r = ioFormat.get(fileFormat);
        if (r == null) {
            throw new PsseException("No reader/writer for file format " + fileFormat);
        }
        return r;
    }

    RecordGroupIO ioFor(Context context) {
        if (context.getVersion() == null) {
            return ioFor(context.getFileFormat());
        }
        return ioFor(context.getFileFormat(), context.getVersion().major());
    }

    public List read(LegacyTextReader reader, Context context) throws IOException {
        return ioFor(context).read(reader, context);
    }

    public void write(List psseObjects, Context context, OutputStream outputStream) {
        ioFor(context).write(psseObjects, context, outputStream);
    }

    public T readHead(LegacyTextReader reader, Context context) throws IOException {
        return ioFor(context).readHead(reader, context);
    }

    public void writeHead(T psseObject, Context context, OutputStream outputStream) {
        ioFor(context).writeHead(psseObject, context, outputStream);
    }

    public List readFromStrings(List records, Context context) {
        String[] allFieldNames = fieldNames(context.getVersion());
        List psseObjects = parseRecords(records, allFieldNames, context);
        String[] actualFieldNames = ArrayUtils.subarray(allFieldNames, 0, context.getCurrentRecordGroupMaxNumFields());
        context.setFieldNames(identification, actualFieldNames);
        return psseObjects;
    }

    public T parseSingleRecord(String record, String[] headers, Context context) {
        return parseRecords(Collections.singletonList(record), headers, context).get(0);
    }

    List parseRecords(List records, String[] headers, Context context) {
        int expectedCount = records.size();
        BeanListProcessor processor = new BeanListProcessor<>(psseTypeClass(), expectedCount);
        CsvParserSettings settings = context.getCsvParserSettings();
        settings.setHeaders(headers);
        settings.setProcessor(processor);
        CsvParser parser = new CsvParser(settings);
        context.resetCurrentRecordGroup();
        for (String record : records) {
            String[] fields = parser.parseLine(record);
            context.setCurrentRecordNumFields(fields.length);
        }
        List beans = processor.getBeans();
        if (beans.size() != expectedCount) {
            throw new PsseException("Parsing error");
        }
        return beans;
    }

    public String buildRecord(T object, String[] headers, String[] quoteFields, Context context) {
        return unquoteNullString(new CsvWriter(settingsForCsvWriter(headers, quoteFields, context)).processRecordToString(object));
    }

    public List buildRecords(List objects, String[] headers, String[] quoteFields, Context context) {
        return unquoteNullStrings(new CsvWriter(settingsForCsvWriter(headers, quoteFields, context)).processRecordsToString(objects));
    }

    // In rawx it is possible to define null as the value of the field
    // If the field is String when it is exported the result is quoted ("null") as the field is included in the
    // quoted fields. The final strings are processed to eliminate quotes in the null string fields.
    private static List unquoteNullStrings(List stringList) {
        return stringList.stream().map(AbstractRecordGroup::unquoteNullString).collect(Collectors.toList());
    }

    private static String unquoteNullString(String string) {
        return string.replace("\"null\"", "null");
    }

    CsvWriterSettings settingsForCsvWriter(String[] headers, String[] quotedFields, Context context) {
        BeanWriterProcessor processor = new BeanWriterProcessor<>(psseTypeClass());
        CsvWriterSettings settings = new CsvWriterSettings();
        settings.quoteFields(quotedFields);
        settings.setHeaders(headers);
        settings.getFormat().setQuote(context.getFileFormat().getQuote());
        settings.getFormat().setDelimiter(context.getDelimiter());
        settings.setIgnoreLeadingWhitespaces(false);
        settings.setIgnoreTrailingWhitespaces(false);
        settings.setRowWriterProcessor(processor);
        return settings;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy