org.structr.rest.common.CsvHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.structr.rest.common.CsvHelper.java

Source

/**
 * Copyright (C) 2010-2018 Structr GmbH
 *
 * This file is part of Structr <http://structr.org>.
 *
 * Structr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Structr 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Structr.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.structr.rest.common;

import com.opencsv.CSVParser;
import com.opencsv.CSVReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.structr.api.util.RangesIterator;
import org.structr.common.SecurityContext;
import org.structr.common.error.FrameworkException;
import static org.structr.core.GraphObject.logger;
import org.structr.core.JsonInput;
import org.structr.core.app.StructrApp;
import org.structr.core.graph.TransactionCommand;
import static org.structr.rest.servlet.CsvServlet.DEFAULT_FIELD_SEPARATOR_COLLECTION_CONTENTS;
import static org.structr.rest.servlet.CsvServlet.DEFAULT_QUOTE_CHARACTER_COLLECTION_CONTENTS;

public class CsvHelper {

    public static Iterable<JsonInput> cleanAndParseCSV(final SecurityContext securityContext, final Reader input,
            final Class type, final Character fieldSeparator, final Character quoteCharacter, final String range)
            throws FrameworkException, IOException {
        return cleanAndParseCSV(securityContext, input, type, fieldSeparator, quoteCharacter, range, null, true);
    }

    public static Iterable<JsonInput> cleanAndParseCSV(final SecurityContext securityContext, final Reader input,
            final Class type, final Character fieldSeparator, final Character quoteCharacter, final String range,
            final Map<String, String> propertyMapping, final boolean strictQuotes)
            throws FrameworkException, IOException {

        final CSVReader reader;

        if (quoteCharacter == null) {

            reader = new CSVReader(input, fieldSeparator);

        } else {

            reader = new CSVReader(input, fieldSeparator, quoteCharacter, strictQuotes);
        }

        final String[] propertyNames = reader.readNext();

        return new Iterable<JsonInput>() {

            @Override
            public Iterator<JsonInput> iterator() {

                final Iterator<JsonInput> iterator = new CsvIterator(reader, propertyNames, propertyMapping, type,
                        securityContext.getUser(false).getName());

                if (StringUtils.isNotBlank(range)) {

                    return new RangesIterator<>(iterator, range);

                } else {

                    return iterator;
                }
            }
        };
    }

    // ----- private methods -----
    private static ArrayList<String> extractArrayContentsFromArray(final String value, final String propertyName)
            throws IOException {

        final CSVParser arrayParser = new CSVParser(DEFAULT_FIELD_SEPARATOR_COLLECTION_CONTENTS,
                DEFAULT_QUOTE_CHARACTER_COLLECTION_CONTENTS);
        final ArrayList<String> extractedStrings = new ArrayList();

        extractedStrings
                .addAll(Arrays.asList(arrayParser.parseLine(stripArrayBracketsFromString(value, propertyName))));

        return extractedStrings;
    }

    private static String stripArrayBracketsFromString(final String value, final String propertyName) {

        if (value.length() > 0) {

            if (value.charAt(0) != '[' || value.charAt(value.length() - 1) != ']') {

                logger.warn("Missing opening/closing brackets for array {}: {} ", propertyName, value);
                return value;

            } else {

                return value.substring(1, value.length() - 1);

            }

        } else {
            return "";
        }
    }

    // ----- nested classes -----
    private static class CsvIterator implements Iterator<JsonInput> {

        private Map<String, String> propertyMapping = null;
        private CSVReader reader = null;
        private String[] propertyNames = null;
        private String userName = null;
        private String[] fields = null;
        private Class type = null;

        public CsvIterator(final CSVReader reader, final String[] propertyNames,
                final Map<String, String> propertMapping, final Class type, final String userName) {

            this.propertyMapping = propertMapping;
            this.propertyNames = propertyNames;
            this.userName = userName;
            this.reader = reader;
            this.type = type;
        }

        @Override
        public boolean hasNext() {

            // return true if the line has not yet been consumed
            // (calling hasNext() more than once may not alter the
            // result of the next next() call!)
            if (fields != null) {
                return true;
            }

            try {

                fields = reader.readNext();

                return fields != null && fields.length > 0;

            } catch (IOException ioex) {
                logger.warn("", ioex);
            }

            return false;
        }

        @Override
        public JsonInput next() {

            try {
                final JsonInput jsonInput = new JsonInput();
                final int len = fields.length;

                for (int i = 0; i < len; i++) {

                    final String key = propertyNames[i];
                    String targetKey = key;

                    // map key name to its transformed name
                    if (propertyMapping != null && propertyMapping.containsKey(key)) {
                        targetKey = propertyMapping.get(key);
                    }

                    if (StructrApp.getConfiguration().getPropertyKeyForJSONName(type, targetKey).isCollection()) {

                        // if the current property is a collection, split it into its parts
                        jsonInput.add(key, extractArrayContentsFromArray(fields[i], key));

                    } else {

                        jsonInput.add(key, fields[i]);
                    }
                }

                return jsonInput;

            } catch (Throwable t) {

                logger.warn("Exception in CSV line: {}", fields);
                logger.warn("", t);

                final Map<String, Object> data = new LinkedHashMap();

                data.put("type", "CSV_IMPORT_ERROR");
                data.put("title", "CSV Import Error");
                data.put("text", "Error occured with dataset: " + fields);
                data.put("username", userName);

                TransactionCommand.simpleBroadcastGenericMessage(data);

            } finally {

                // mark line as "consumed"
                fields = null;
            }

            return null;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException("Removal not supported.");
        }
    }
}