br.com.tecsinapse.exporter.importer.parser.FixedLengthFileParser.java Source code

Java tutorial

Introduction

Here is the source code for br.com.tecsinapse.exporter.importer.parser.FixedLengthFileParser.java

Source

/*
 * Tecsinapse Data Input and Output
 *
 * License: GNU Lesser General Public License (LGPL), version 3 or later
 * See the LICENSE file in the root directory or <http://www.gnu.org/licenses/lgpl-3.0.html>.
 */
package br.com.tecsinapse.exporter.importer.parser;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.reflections.ReflectionUtils;

import com.google.common.collect.Iterables;
import com.google.common.primitives.Ints;

import br.com.tecsinapse.exporter.annotation.FixedLengthColumn;
import br.com.tecsinapse.exporter.annotation.LineFixedLengthFile;
import br.com.tecsinapse.exporter.converter.Converter;
import br.com.tecsinapse.exporter.util.FixedLengthFileUtil;

public class FixedLengthFileParser<T> {

    private final Class<T> clazz;

    private Charset charset = Charset.defaultCharset();
    private boolean ignoreFirstLine = false;
    private boolean ignoreLineWhenError = false;
    private boolean removeDuplicatedSpaces = true;
    private int afterLine = 0;
    private String eof = null;
    private int ignoreLastLines = 0;
    private boolean ignoreColumnLengthError = false;

    public FixedLengthFileParser(Class<T> clazz) {
        this.clazz = clazz;
    }

    public FixedLengthFileParser<T> withAfterLine(int afterLine) {
        this.afterLine = afterLine;
        return this;
    }

    public FixedLengthFileParser<T> withCharset(Charset charset) {
        this.charset = charset;
        return this;
    }

    public FixedLengthFileParser<T> withIgnoreFirstLine(boolean ignoreFirstLine) {
        this.ignoreFirstLine = ignoreFirstLine;
        return this;
    }

    public FixedLengthFileParser<T> withIgnoreLineWhenErrors(boolean ignoreLineWhenError) {
        this.ignoreLineWhenError = ignoreLineWhenError;
        return this;
    }

    public FixedLengthFileParser<T> withRemoveDuplicatedSpaces(boolean removeDuplicatedSpaces) {
        this.removeDuplicatedSpaces = removeDuplicatedSpaces;
        return this;
    }

    public FixedLengthFileParser<T> withEofCharacter(String eof) {
        this.eof = eof;
        return this;
    }

    public FixedLengthFileParser<T> withIgnoreLastLines(int linesToIgnore) {
        this.ignoreLastLines = linesToIgnore;
        return this;
    }

    public FixedLengthFileParser<T> withIgnoreColumnLengthError(boolean ignoreColumnLengthError) {
        this.ignoreColumnLengthError = ignoreColumnLengthError;
        return this;
    }

    public List<T> parse(File file) throws IOException, ReflectiveOperationException {
        return parse(new FileInputStream(file));
    }

    public List<T> parse(InputStream inputStream) throws IOException, ReflectiveOperationException {

        final List<T> list = new ArrayList<>();
        final List<String> lines = FixedLengthFileUtil.getLines(inputStream, ignoreFirstLine, afterLine,
                ignoreLastLines, eof, charset);

        @SuppressWarnings("unchecked")
        final Set<Method> methods = ReflectionUtils.getAllMethods(clazz,
                ReflectionUtils.<Method>withAnnotation(FixedLengthColumn.class));

        @SuppressWarnings("unchecked")
        Method lineMethod = Iterables.getFirst(ReflectionUtils.getMethods(clazz,
                ReflectionUtils.<Method>withAnnotation(LineFixedLengthFile.class)), null);

        final List<AnnotationMethod> methodsAndAnnotations = orderedAnnotationsAndMethods(methods);

        final Constructor<T> constructor = clazz.getDeclaredConstructor();
        constructor.setAccessible(true);
        for (int i = 0; i < lines.size(); i++) {
            T instance = constructor.newInstance();
            String workingLine = lines.get(i);
            boolean ignoreLine = false;
            for (AnnotationMethod annotationMethod : methodsAndAnnotations) {
                if (workingLine.length() == 0) {
                    break;
                }
                Method method = annotationMethod.getMethod();
                FixedLengthColumn flc = annotationMethod.getFlc();
                final boolean naoValidouTamanhoDaLinha = !flc.useLineLength()
                        && workingLine.length() < flc.columnSize() && !ignoreColumnLengthError;
                if (naoValidouTamanhoDaLinha) {
                    if (ignoreLineWhenError) {
                        ignoreLine = true;
                        break;
                    } else {
                        int line = ignoreFirstLine ? i + 1 : i;
                        throw new IllegalStateException(String.format(
                                "Malformed file or wrong configuration. Line %s size doesn't match the configuration.",
                                line));
                    }
                }
                int length = flc.useLineLength() || workingLine.length() < flc.columnSize() ? workingLine.length()
                        : flc.columnSize();
                String value = workingLine.substring(0, length).trim();
                if (removeDuplicatedSpaces) {
                    value = value.replaceAll("\\s+", " ");
                }
                Converter<?, ?> converter = flc.converter().newInstance();
                Object obj;
                try {
                    obj = converter.apply(value);
                } catch (Exception e) {
                    if (ignoreLineWhenError) {
                        ignoreLine = true;
                        break;
                    } else {
                        throw e;
                    }
                }
                method.invoke(instance, obj);
                workingLine = workingLine.substring(length, workingLine.length());
            }
            if (lineMethod != null) {
                lineMethod.invoke(instance, lines.get(i));
            }
            if (!ignoreLine) {
                list.add(instance);
            }
        }
        return list;
    }

    private List<AnnotationMethod> orderedAnnotationsAndMethods(final Set<Method> methods) {
        final List<AnnotationMethod> methodsAndAnnotations = new ArrayList<>();
        for (Method method : methods) {
            FixedLengthColumn flc = method.getAnnotation(FixedLengthColumn.class);
            if (flc == null) {
                continue;
            }
            AnnotationMethod annotationMethod = new AnnotationMethod(method, flc);
            methodsAndAnnotations.add(annotationMethod);
        }
        Collections.sort(methodsAndAnnotations);

        return methodsAndAnnotations;
    }

    private static class AnnotationMethod implements Comparable<AnnotationMethod> {

        private final Method method;
        private final FixedLengthColumn flc;

        public AnnotationMethod(Method method, FixedLengthColumn flc) {
            this.method = method;
            this.flc = flc;
        }

        public Method getMethod() {
            return method;
        }

        public FixedLengthColumn getFlc() {
            return flc;
        }

        @Override
        public int compareTo(AnnotationMethod other) {
            return Ints.compare(this.flc.columnIndex(), other.getFlc().columnIndex());
        }

    }
}