org.springframework.batch.item.file.transform.FixedLengthTokenizer.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.batch.item.file.transform.FixedLengthTokenizer.java

Source

/*
 * Copyright 2006-2014 the original author or authors.
 *
 * Licensed 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
 *
 *      https://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.springframework.batch.item.file.transform;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Tokenizer used to process data obtained from files with fixed-length format.
 * Columns are specified by array of Range objects ({@link #setColumns(Range[])}
 * ).
 * 
 * @author tomas.slanina
 * @author peter.zozom
 * @author Dave Syer
 * @author Lucas Ward
 * @author Michael Minella
 */
public class FixedLengthTokenizer extends AbstractLineTokenizer {

    private Range[] ranges;

    private int maxRange = 0;

    boolean open = false;

    /**
     * Set the column ranges. Used in conjunction with the
     * {@link RangeArrayPropertyEditor} this property can be set in the form of
     * a String describing the range boundaries, e.g. "1,4,7" or "1-3,4-6,7" or
     * "1-2,4-5,7-10". If the last range is open then the rest of the line is
     * read into that column (irrespective of the strict flag setting).
     * 
     * @see #setStrict(boolean)
     * 
     * @param ranges the column ranges expected in the input
     */
    public void setColumns(Range... ranges) {
        this.ranges = Arrays.asList(ranges).toArray(new Range[ranges.length]);
        calculateMaxRange(ranges);
    }

    /*
     * Calculate the highest value within an array of ranges. The ranges aren't
     * necessarily in order. For example: "5-10, 1-4,11-15". Furthermore, there
     * isn't always a min and max, such as: "1,4-20, 22"
     */
    private void calculateMaxRange(Range[] ranges) {
        if (ranges == null || ranges.length == 0) {
            maxRange = 0;
            return;
        }

        open = false;
        maxRange = ranges[0].getMin();

        for (int i = 0; i < ranges.length; i++) {
            int upperBound;
            if (ranges[i].hasMaxValue()) {
                upperBound = ranges[i].getMax();
            } else {
                upperBound = ranges[i].getMin();
                if (upperBound > maxRange) {
                    open = true;
                }
            }

            if (upperBound > maxRange) {
                maxRange = upperBound;
            }
        }
    }

    /**
     * Yields the tokens resulting from the splitting of the supplied
     * <code>line</code>.
     * 
     * @param line the line to be tokenized (can be <code>null</code>)
     * 
     * @return the resulting tokens (empty if the line is null)
     * @throws IncorrectLineLengthException if line length is greater than or
     * less than the max range set.
     */
    @Override
    protected List<String> doTokenize(String line) {
        List<String> tokens = new ArrayList<>(ranges.length);
        int lineLength;
        String token;

        lineLength = line.length();

        if (lineLength < maxRange && isStrict()) {
            throw new IncorrectLineLengthException("Line is shorter than max range " + maxRange, maxRange,
                    lineLength, line);
        }

        if (!open && lineLength > maxRange && isStrict()) {
            throw new IncorrectLineLengthException("Line is longer than max range " + maxRange, maxRange,
                    lineLength, line);
        }

        for (int i = 0; i < ranges.length; i++) {

            int startPos = ranges[i].getMin() - 1;
            int endPos = ranges[i].getMax();

            if (lineLength >= endPos) {
                token = line.substring(startPos, endPos);
            } else if (lineLength >= startPos) {
                token = line.substring(startPos);
            } else {
                token = "";
            }

            tokens.add(token);
        }

        return tokens;
    }
}