org.jasig.ssp.util.importer.job.csv.RawItemCsvReader.java Source code

Java tutorial

Introduction

Here is the source code for org.jasig.ssp.util.importer.job.csv.RawItemCsvReader.java

Source

/**
 * Licensed to Jasig under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Jasig licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a
 * copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.jasig.ssp.util.importer.job.csv;

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.jasig.ssp.util.importer.job.domain.RawItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.core.annotation.BeforeStep;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.LineCallbackHandler;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.batch.item.file.transform.LineTokenizer;
import org.springframework.core.io.Resource;
import org.springframework.validation.BindException;

public class RawItemCsvReader extends FlatFileItemReaderNewLine<RawItem>
        implements StepExecutionListener, LineCallbackHandler, FieldSetMapper<RawItem> {

    private static final Logger logger = LoggerFactory.getLogger(RawItemCsvReader.class);
    final private String COLUMN_NAMES_KEY = "COLUMNS_NAMES_KEY";
    private StepExecution stepExecution;
    private DefaultLineMapper<RawItem> lineMapper;
    private String[] columnNames;
    private Resource itemResource;
    private String delimiter = DelimitedLineTokenizer.DELIMITER_COMMA;
    private char quoteCharacter = DelimitedLineTokenizer.DEFAULT_QUOTE_CHARACTER;

    public RawItemCsvReader() {
        setLinesToSkip(1);
        setSkippedLinesCallback(this);
    }

    @Override
    public void afterPropertiesSet() {
        // not in constructor to ensure we invoke the override
        final DefaultLineMapper<RawItem> lineMapper = new RawItemLineMapper();
        setLineMapper(lineMapper);
    }

    /**
     * Satisfies {@link LineCallbackHandler} contract and and Acts as the {@code skippedLinesCallback}.
     *
     * @param line
     */
    @Override
    public void handleLine(String line) {
        getLineMapper().setLineTokenizer(getTokenizer(line));
        getLineMapper().setFieldSetMapper(this);
    }

    private LineTokenizer getTokenizer(String line) {
        this.columnNames = line.split(delimiter);
        DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
        lineTokenizer.setQuoteCharacter(quoteCharacter);
        lineTokenizer.setDelimiter(delimiter);
        lineTokenizer.setStrict(false);
        lineTokenizer.setNames(columnNames);
        addColumnNames();
        return lineTokenizer;
    }

    private void addColumnNames() {
        stepExecution.getExecutionContext().put(COLUMN_NAMES_KEY, columnNames);
    }

    @Override
    public void setResource(Resource resource) {
        //No longer using MultiResource Reader
        this.itemResource = resource;
        super.setResource(resource);
    }

    /**
     * Provides acces to an otherwise hidden field in parent class. We need this because we have to reconfigure
     * the {@link LineMapper} based on file contents.
     * @param lineMapper
     */
    @Override
    public void setLineMapper(LineMapper<RawItem> lineMapper) {
        if (!(lineMapper instanceof DefaultLineMapper)) {
            throw new IllegalArgumentException("Must specify a DefaultLineMapper");
        }
        this.lineMapper = (DefaultLineMapper) lineMapper;

        super.setLineMapper(lineMapper);
    }

    private DefaultLineMapper getLineMapper() {
        return this.lineMapper;
    }

    /**
     * Satisfies {@link FieldSetMapper} contract.
     * @param fs
     * @return
     * @throws BindException
     */
    @Override
    public RawItem mapFieldSet(FieldSet fs) throws BindException {
        if (fs == null) {
            return null;
        }
        Map<String, String> record = new LinkedHashMap<String, String>();
        for (String columnName : this.columnNames) {
            record.put(columnName, StringUtils.trimToNull(fs.readString(columnName)));
        }
        RawItem item = new RawItem();
        item.setResource(itemResource);
        item.setRecord(record);
        return item;
    }

    @BeforeStep
    public void saveStepExecution(StepExecution stepExecution) {
        this.stepExecution = stepExecution;
    }

    @Override
    public void beforeStep(StepExecution stepExecution) {
        logger.info("Start Raw Read Step for " + itemResource.getFilename());
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        logger.info("End Raw Read Step for " + itemResource.getFilename() + " lines read: "
                + stepExecution.getReadCount() + " lines skipped: " + stepExecution.getReadSkipCount());
        return ExitStatus.COMPLETED;
    }

    public void setDelimiter(String delimiter) {
        this.delimiter = delimiter;
    }

    public void setQuoteCharacter(char quoteCharacter) {
        this.quoteCharacter = quoteCharacter;
    }
}