Package org.milyn.flatfile.variablefield

Source Code of org.milyn.flatfile.variablefield.VariableFieldRecordParser

/*
* Milyn - Copyright (C) 2006 - 2010
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License (version 2.1) as published by the Free Software
* Foundation.
*
* This library 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:
* http://www.gnu.org/licenses/lgpl.txt
*/

package org.milyn.flatfile.variablefield;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.milyn.flatfile.Field;
import org.milyn.flatfile.FieldMetaData;
import org.milyn.flatfile.Record;
import org.milyn.flatfile.RecordMetaData;
import org.milyn.flatfile.RecordParser;
import org.milyn.function.StringFunctionExecutor;

/**
* Abstract variable field record parser.
*
* @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
*/
public abstract class VariableFieldRecordParser<T extends VariableFieldRecordParserFactory> implements RecordParser<T> {

    private Log logger = LogFactory.getLog(getClass());

    private T factory;
    private int lineNumber = 0;
    private int recordCount = 0;
    private RecordMetaData inMessageRecordMetaData;

    /**
     * Parse the next record from the flat file input stream and produce the set
     * of record field values.
     *
     * @return The next records field values.
     * @throws IOException Error reading message stream.
     */
    public abstract List<String> nextRecordFieldValues() throws IOException;

    /**
     * {@inheritDoc}
     */
    public final void setRecordParserFactory(T factory) {
        this.factory = factory;
    }

    /**
     * {@inheritDoc}
     */
    public void initialize() throws IOException {
        int skipLines = factory.getSkipLines();

        // Move past the lines to be skipped ...
        while (lineNumber < skipLines) {
            _nextRecordFieldValues();
        }

        // If the fields are defined in the message... read the next record
        if (factory.fieldsInMessage() || factory.validateHeader()) {
            List<String> fields = _nextRecordFieldValues();

            if (factory.validateHeader()) {
                validateHeader(fields);
            }

            if (factory.fieldsInMessage()) {
                // In message field definitions do not support variable field definitions... just one record type supported...
                inMessageRecordMetaData = VariableFieldRecordMetaData.buildRecordMetaData(factory.getRecordElementName(), fields);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public void uninitialize() {
    }

    /**
     * Get the parser factory instance that created this parser instance.
     *
     * @return The parser factory instance that created this parser instance.
     */
    public T getFactory() {
        return factory;
    }

    /**
     * Get the number of records read so far by this parser instance.
     *
     * @return The number of records read so far by this parser instance.
     */
    public int getRecordCount() {
        return recordCount;
    }

    private List<String> _nextRecordFieldValues() throws IOException {
        lineNumber++;
        return nextRecordFieldValues();
    }

    /**
     * {@inheritDoc}
     */
    public final Record nextRecord() throws IOException {
        List<String> fieldValues = _nextRecordFieldValues();

        if (fieldValues == null || fieldValues.isEmpty()) {
            return null;
        }

        RecordMetaData recordMetaData;
        if (inMessageRecordMetaData != null) {
            recordMetaData = inMessageRecordMetaData;
        } else {
            recordMetaData = factory.getRecordMetaData(fieldValues);
        }

        List<FieldMetaData> fieldsMetaData = recordMetaData.getFields();
        if (factory.strict() && fieldValues.size() < getUnignoredFieldCount(recordMetaData)) {
            logger.debug("[CORRUPT] Record #" + recordCount + " invalid [" + fieldValues
                    + "].  The record should contain " + fieldsMetaData.size() + " fields ["
                    + recordMetaData.getFieldNames() + "], but contains " + fieldValues.size() + " fields.  Ignoring!!");
            return nextRecord();
        }

        List<Field> fields = new ArrayList<Field>();

        try {
            if (recordMetaData == VariableFieldRecordMetaData.UNKNOWN_RECORD_TYPE) {
                fields.add(new Field(recordMetaData.getFields().get(0).getName(), fieldValues.get(0)));
                return new Record(recordMetaData.getName(), fields, recordMetaData);
            } else {
                int fieldValueOffset = 0;

                // In message field definitions do not support variable field definitions... just one record type supported...
                if (inMessageRecordMetaData == null && factory.isMultiTypeRecordSet()) {
                    // Skip the first field value because it's the field name...
                    fieldValueOffset = +1;
                }

                for (int i = 0; i < fieldValues.size(); i++) {
                    int fieldValueIndex = i + fieldValueOffset;

                    if (fieldValueIndex > fieldValues.size() - 1) {
                        break;
                    }
                    if (!recordMetaData.isWildCardRecord() && i > fieldsMetaData.size() - 1) {
                        // We're done... ignore the rest of the fields...
                        break;
                    }

                    Field field;
                    String value = fieldValues.get(fieldValueIndex);

                    if (recordMetaData.isWildCardRecord() || i > fieldsMetaData.size() - 1) {
                        field = new Field("field_" + i, value);
                    } else {
                        FieldMetaData fieldMetaData = fieldsMetaData.get(i);

                        if (fieldMetaData.ignore()) {
                            i += fieldMetaData.getIgnoreCount() - 1;
                            if (i < 0) {
                                // An overflow has resulted...
                                i = Integer.MAX_VALUE - 1;
                            }
                            continue;
                        }

                        StringFunctionExecutor stringFunction = fieldMetaData.getStringFunctionExecutor();
                        if (stringFunction != null) {
                            value = stringFunction.execute(value);
                        }

                        field = new Field(fieldMetaData.getName(), value);
                        field.setMetaData(fieldMetaData);
                    }

                    fields.add(field);
                }
            }
        } finally {
            recordCount++;
        }

        return new Record(recordMetaData.getName(), fields, recordMetaData);
    }

    /**
     * Get the unignored field count for the specified record.
     *
     * @param recordMetaData The record metadata.
     * @return The unignored field count.
     */
    public int getUnignoredFieldCount(RecordMetaData recordMetaData) {
        if (factory.isMultiTypeRecordSet()) {
            // Need to account for the leading identifier field on each
            // record...
            return recordMetaData.getUnignoredFieldCount() + 1;
        } else {
            return recordMetaData.getUnignoredFieldCount();
        }
    }

    protected void validateHeader(List<String> headers) throws IOException {
        if (factory.isMultiTypeRecordSet()) {
            throw new IOException("Cannot validate the 'header' field of a Multi-Type Record Set.  Reader fields definition defines multiple record definitions.");
        }

        RecordMetaData recordMetaData = factory.getRecordMetaData();

        if (headers == null) {
            throw new IOException("Null header.");
        }

        if (validateHeader(headers, recordMetaData.getFields())) {
            return;
        }

        throw new IOException("Invalid header.");
    }

    private boolean validateHeader(List<String> headers, final List<FieldMetaData> fieldsMetaData) {
        if (fieldsMetaData.size() != headers.size()) {
            return false;
        }

        int n = 0;
        for (FieldMetaData field : fieldsMetaData) {
            if (!field.ignore()) {
                if (headers.size() <= n) {
                    return false;
                }

                String header = headers.get(n);
                if (header == null) {
                    header = "";
                }

                String name = field.getName();
                if (name == null) {
                    name = "";
                }

                if (!name.equals(header)) {
                    return false;
                }
            }
            n++;
        }

        return true;
    }
}
TOP

Related Classes of org.milyn.flatfile.variablefield.VariableFieldRecordParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.