ddf.catalog.transformer.csv.CsvQueryResponseTransformer.java Source code

Java tutorial

Introduction

Here is the source code for ddf.catalog.transformer.csv.CsvQueryResponseTransformer.java

Source

/*
 * Copyright (c) Codice Foundation
 * <p>
 * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or any later version.
 * <p>
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details. A copy of the GNU Lesser General Public License
 * is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */

package ddf.catalog.transformer.csv;

import ddf.catalog.data.AttributeDescriptor;
import ddf.catalog.data.AttributeType;
import ddf.catalog.data.BinaryContent;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.MetacardType;
import ddf.catalog.data.Result;
import ddf.catalog.data.impl.BinaryContentImpl;
import ddf.catalog.operation.SourceResponse;
import ddf.catalog.transform.CatalogTransformerException;
import ddf.catalog.transform.QueryResponseTransformer;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An implementation of QueryResponseTransformer that produces CSV output.
 *
 * @see ddf.catalog.transform.QueryResponseTransformer
 */
public class CsvQueryResponseTransformer implements QueryResponseTransformer {
    private static final Logger LOGGER = LoggerFactory.getLogger(CsvQueryResponseTransformer.class);

    private static final String HIDDEN_FIELDS_KEY = "hiddenFields";

    private static final String COLUMN_ORDER_KEY = "columnOrder";

    private static final String COLUMN_ALIAS_KEY = "aliases";

    /**
     * @param upstreamResponse the SourceResponse to be converted.
     * @param arguments this transformer accepts 3 parameters in the 'arguments' map. 1) key:
     *     'hiddenFields' value: a java.util.Set containing Attribute names (as Strings) to be
     *     excluded from the output. 2) key: 'attributeOrder' value: a java.utilList containing
     *     Attribute name (as Strings) to identify the order that the columns will appear in the
     *     output. 3) key: 'aliases' value: a java.util.Map whose keys are attribute names and values
     *     are the how that attribute column should be aliased in the output. For example, if the key
     *     is 'title' and the value is 'Product' then the resulting CSV will have a column name of
     *     'Product' instead of 'title'.
     * @return a BinaryContent object that contains an InputStream with the CSV content.
     * @throws CatalogTransformerException during processing, the CSV output is written to an
     *     Appendable, whose 'append()' method signature declares that it throws IOException. When
     *     that Appendable throws IOException, this class will theoretically convert that into a
     *     CatalogTransformerException and raise that. Because this implementation uses a
     *     StringBuilder which doesn't throw IOException, this will never occur.
     */
    @Override
    public BinaryContent transform(SourceResponse upstreamResponse, Map<String, Serializable> arguments)
            throws CatalogTransformerException {

        Set<String> hiddenFields = Optional.ofNullable((Set<String>) arguments.get(HIDDEN_FIELDS_KEY))
                .orElse(Collections.emptySet());

        List<String> attributeOrder = Optional.ofNullable((List<String>) arguments.get(COLUMN_ORDER_KEY))
                .orElse(Collections.emptyList());

        Map<String, String> columnAliasMap = Optional
                .ofNullable((Map<String, String>) arguments.get(COLUMN_ALIAS_KEY)).orElse(Collections.emptyMap());

        Set<AttributeDescriptor> allAttributeDescriptors = getAllRequestedAttributes(upstreamResponse.getResults(),
                hiddenFields);

        List<AttributeDescriptor> sortedAttributeDescriptors = sortAttributes(allAttributeDescriptors,
                attributeOrder);

        Appendable csv = writeSearchResultsToCsv(upstreamResponse, columnAliasMap, sortedAttributeDescriptors);

        return createResponse(csv);
    }

    private BinaryContent createResponse(final Appendable csv) {
        InputStream inputStream = new ByteArrayInputStream(csv.toString().getBytes(Charset.defaultCharset()));
        BinaryContent binaryContent = new BinaryContentImpl(inputStream);
        return binaryContent;
    }

    private Appendable writeSearchResultsToCsv(final SourceResponse upstreamResponse,
            Map<String, String> columnAliasMap, List<AttributeDescriptor> sortedAttributeDescriptors)
            throws CatalogTransformerException {
        StringBuilder stringBuilder = new StringBuilder();

        try {
            CSVPrinter csvPrinter = new CSVPrinter(stringBuilder, CSVFormat.RFC4180);
            printColumnHeaders(csvPrinter, sortedAttributeDescriptors, columnAliasMap);

            upstreamResponse.getResults().stream().map(Result::getMetacard)
                    .forEach(mc -> printMetacard(csvPrinter, mc, sortedAttributeDescriptors));

            return csvPrinter.getOut();
        } catch (IOException ioe) {
            throw new CatalogTransformerException(ioe.getMessage(), ioe);
        }
    }

    private void printMetacard(final CSVPrinter csvPrinter, final Metacard metacard,
            final List<AttributeDescriptor> attributeDescriptors) {

        Iterator<Serializable> metacardIterator = new MetacardIterator(metacard, attributeDescriptors);

        printData(csvPrinter, metacardIterator);
    }

    private void printColumnHeaders(final CSVPrinter csvPrinter,
            final List<AttributeDescriptor> attributeDescriptors, Map<String, String> aliasMap) {
        Iterator<String> columnHeaderIterator = new ColumnHeaderIterator(attributeDescriptors, aliasMap);

        printData(csvPrinter, columnHeaderIterator);
    }

    private void printData(final CSVPrinter csvPrinter, final Iterator iterator) {
        try {
            csvPrinter.printRecord(() -> iterator);
        } catch (IOException ioe) {
            LOGGER.error(ioe.getMessage(), ioe);
        }
    }

    private List<AttributeDescriptor> sortAttributes(final Set<AttributeDescriptor> attributeSet,
            final List<String> attributeOrder) {
        CsvAttributeDescriptorComparator attributeComparator = new CsvAttributeDescriptorComparator(attributeOrder);

        return attributeSet.stream().sorted(attributeComparator).collect(Collectors.toList());
    }

    private Set<AttributeDescriptor> getAllRequestedAttributes(final List<Result> results,
            final Set<String> hiddenFields) {

        Set<AttributeDescriptor> allAttributes = new HashSet<>();

        results.stream().map(Result::getMetacard).map(Metacard::getMetacardType)
                .map(MetacardType::getAttributeDescriptors)
                .forEach(descriptorSet -> descriptorSet.stream().filter(
                        desc -> !AttributeType.AttributeFormat.BINARY.equals(desc.getType().getAttributeFormat()))
                        .filter(desc -> !AttributeType.AttributeFormat.OBJECT
                                .equals(desc.getType().getAttributeFormat()))
                        .filter(desc -> !hiddenFields.contains(desc.getName())).forEach(allAttributes::add));

        return allAttributes;
    }
}