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

internal.spreadsheet.base.api.SpreadSheetSupport Maven / Gradle / Ivy

/*
 * Copyright 2016 National Bank of Belgium
 *
 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
 * by the European Commission - subsequent versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://ec.europa.eu/idabc/eupl
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the Licence is distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Licence for the specific language governing permissions and
 * limitations under the Licence.
 */
package internal.spreadsheet.base.api;

import jdplus.toolkit.base.api.timeseries.Ts;
import jdplus.toolkit.base.api.timeseries.TsCollection;
import jdplus.toolkit.base.api.timeseries.TsData;
import jdplus.toolkit.base.api.timeseries.TsInformationType;
import jdplus.toolkit.base.tsp.DataSet;
import jdplus.toolkit.base.tsp.DataSource;
import jdplus.toolkit.base.tsp.HasDataHierarchy;
import jdplus.toolkit.base.tsp.grid.GridLayout;
import jdplus.toolkit.base.tsp.stream.DataSetTs;
import jdplus.toolkit.base.tsp.stream.HasTsStream;
import jdplus.toolkit.base.tsp.util.DataSourcePreconditions;
import jdplus.toolkit.base.tsp.util.DataSetConversion;
import jdplus.toolkit.base.tsp.util.ResourceFactory;
import jdplus.toolkit.base.tsp.util.ResourcePool;
import jdplus.toolkit.base.api.util.MultiLineNameUtil;
import nbbrd.design.ThreadSafe;
import lombok.NonNull;

import java.io.Closeable;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Philippe Charles
 */
@ThreadSafe
@lombok.AllArgsConstructor(staticName = "of")
public final class SpreadSheetSupport implements HasDataHierarchy, HasTsStream {

    @lombok.NonNull
    private final String providerName;

    @lombok.NonNull
    private final ResourceFactory spreadsheet;

    @lombok.NonNull
    private final DataSetConversion sheetName;

    @lombok.NonNull
    private final DataSetConversion seriesName;

    @Override
    public @NonNull List children(@NonNull DataSource dataSource) throws IllegalArgumentException, IOException {
        DataSourcePreconditions.checkProvider(providerName, dataSource);

        try (SpreadSheetConnection connection = spreadsheet.open(dataSource)) {
            DataSet.Converter sheetNameConverter = sheetName.getConverter(connection);

            return connection
                    .getSheetNames()
                    .stream()
                    .map(childrenMapper(dataSource, sheetNameConverter))
                    .collect(Collectors.toList());
        }
    }

    @Override
    public @NonNull List children(@NonNull DataSet parent) throws IllegalArgumentException, IOException {
        DataSourcePreconditions.checkProvider(providerName, parent);

        try (SpreadSheetConnection connection = spreadsheet.open(parent.getDataSource())) {
            DataSet.Converter sheetNameConverter = sheetName.getConverter(connection);
            DataSet.Converter seriesNameConverter = seriesName.getConverter(connection);

            return connection
                    .getSheetByName(sheetNameConverter.get(parent))
                    .orElseThrow(() -> sheetNotFound(parent))
                    .stream()
                    .map(childrenMapper(parent, seriesNameConverter))
                    .collect(Collectors.toList());
        }
    }

    @Override
    public @NonNull Stream getData(@NonNull DataSource dataSource, @NonNull TsInformationType type) throws IOException {
        DataSourcePreconditions.checkProvider(providerName, dataSource);

        try (SpreadSheetConnection connection = spreadsheet.open(dataSource)) {
            DataSet.Converter sheetNameConverter = sheetName.getConverter(connection);
            DataSet.Converter seriesNameConverter = seriesName.getConverter(connection);

            Stream data = connection
                    .getSheets()
                    .stream()
                    .flatMap(SheetTs::allOf);

            return streamOf(data, dataSource, sheetNameConverter, seriesNameConverter);
        }
    }

    @Override
    public @NonNull Stream getData(@NonNull DataSet dataSet, @NonNull TsInformationType type) throws IllegalArgumentException, IOException {
        DataSourcePreconditions.checkProvider(providerName, dataSet);

        try (SpreadSheetConnection connection = spreadsheet.open(dataSet.getDataSource())) {
            DataSet.Converter sheetNameConverter = sheetName.getConverter(connection);
            DataSet.Converter seriesNameConverter = seriesName.getConverter(connection);

            Stream data = connection
                    .getSheetByName(sheetNameConverter.get(dataSet))
                    .map(SheetTs::allOf)
                    .orElseThrow(() -> sheetNotFound(dataSet))
                    .filter(getSeriesFilter(dataSet, seriesNameConverter));

            return streamOf(data, dataSet.getDataSource(), sheetNameConverter, seriesNameConverter);
        }
    }

    private static IOException sheetNotFound(DataSet dataSet) {
        return new IOException("Sheet not found: " + dataSet.toString());
    }

    private static Function childrenMapper(DataSource dataSource, DataSet.Converter sheetParam) {
        DataSet.Builder builder = DataSet.builder(dataSource, DataSet.Kind.COLLECTION);
        return o -> {
            sheetParam.set(builder, o);
            return builder.build();
        };
    }

    private static Function childrenMapper(DataSet parent, DataSet.Converter seriesParam) {
        DataSet.Builder builder = parent.toBuilder(DataSet.Kind.SERIES);
        return o -> {
            seriesParam.set(builder, o.getName());
            return builder.build();
        };
    }

    private static Function dataMapper(DataSource dataSource, DataSet.Converter sheetParam, DataSet.Converter seriesParam) {
        DataSet.Builder builder = DataSet.builder(dataSource, DataSet.Kind.SERIES);
        return o -> {
            sheetParam.set(builder, o.sheetName);
            seriesParam.set(builder, o.seriesName);
            return builder.build();
        };
    }

    private Predicate getSeriesFilter(DataSet dataSet, DataSet.Converter seriesParam) {
        switch (dataSet.getKind()) {
            case COLLECTION:
                return o -> true;
            case SERIES:
                return o -> o.seriesName.equals(seriesParam.get(dataSet));
            default:
                throw new IllegalArgumentException(dataSet.getKind().name());
        }
    }

    private static Stream streamOf(Stream data, DataSource dataSource, DataSet.Converter sheetParam, DataSet.Converter seriesParam) {
        Function mapper = dataMapper(dataSource, sheetParam, seriesParam);
        return data.map(sheetTs -> new DataSetTs(mapper.apply(sheetTs), sheetTs.getLabel(), sheetTs.getMeta(), sheetTs.getData()));
    }

    @lombok.AllArgsConstructor
    private static final class SheetTs {

        static Stream allOf(TsCollection sheet) {
            return sheet.stream().map(series -> SheetTs.of(sheet, series));
        }

        static SheetTs of(TsCollection sheet, Ts series) {
            return new SheetTs(sheet.getName(), sheet.getMeta().getOrDefault(GridLayout.PROPERTY, ""), series.getName(), series.getData());
        }

        private final String sheetName;
        private final String sheetLayout;
        private final String seriesName;
        private final TsData seriesData;

        TsData getData() {
            return seriesData;
        }

        Map getMeta() {
            Map result = new HashMap<>();
            result.put(SHEET_NAME_META, sheetName);
            result.put(SHEET_GRID_LAYOUT_META, sheetLayout);
            result.put(SERIES_NAME_META, seriesName);
            return result;
        }

        String getLabel() {
            return sheetName + MultiLineNameUtil.SEPARATOR + seriesName;
        }
    }

    public static final String SHEET_NAME_META = "sheet.name";
    public static final String SHEET_GRID_LAYOUT_META = "sheet.gridLayout";
    public static final String SERIES_NAME_META = "series.name";

    @NonNull
    public static ResourcePool newConnectionPool() {
        return ResourcePool.of(PooledSpreadSheetConnection::new);
    }

    @lombok.RequiredArgsConstructor
    private static final class PooledSpreadSheetConnection implements SpreadSheetConnection {

        @lombok.NonNull
        @lombok.experimental.Delegate(excludes = Closeable.class)
        private final SpreadSheetConnection delegate;

        @lombok.NonNull
        @lombok.experimental.Delegate
        private final Closeable onClose;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy