/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF 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.apache.camel.dataformat.univocity; import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import com.univocity.parsers.common.AbstractParser; /** * This class unmarshalls the exchange body using an uniVocity parser. * * @param <P> Parser class */ final class Unmarshaller<P extends AbstractParser<?>> { private final boolean lazyLoad; private final boolean asMap; /** * Creates a new instance. * * @param lazyLoad whether or not the lines must be lazily read * @param asMap whether or not we must produce maps instead of lists for each row */ Unmarshaller(boolean lazyLoad, boolean asMap) { this.lazyLoad = lazyLoad; this.asMap = asMap; } /** * Unmarshal from the given reader. * * @param reader reader to read from * @param parser uniVocity parser to use * @param headerRowProcessor Row processor that retrieves the header * @return Unmarshalled data */ public Object unmarshal(Reader reader, P parser, HeaderRowProcessor headerRowProcessor) { parser.beginParsing(reader); Iterator<?> iterator = asMap ? new MapRowIterator<P>(parser, headerRowProcessor) : new ListRowIterator<P>(parser); return lazyLoad ? iterator : convertToList(iterator); } /** * Converts the given iterator into a list. * * @param iterator iterator to convert * @param <T> item class * @return a list that contains all the items of the iterator */ private static <T> List<T> convertToList(Iterator<T> iterator) { List<T> result = new ArrayList<T>(); while (iterator.hasNext()) { result.add(iterator.next()); } return result; } /** * This abstract class helps iterating over the rows using uniVocity. * * @param <E> Row class * @param <P> Parser class */ private abstract static class RowIterator<E, P extends AbstractParser<?>> implements Iterator<E> { private final P parser; private String[] row; /** * Creates a new instance. * * @param parser parser to use */ protected RowIterator(P parser) { this.parser = parser; row = this.parser.parseNext(); } /** * {@inheritDoc} */ @Override public final boolean hasNext() { return row != null; } /** * {@inheritDoc} */ @Override public final E next() { if (row == null) { throw new NoSuchElementException(); } E result = convertRow(row); row = parser.parseNext(); return result; } /** * Warning: it always throws an {@code UnsupportedOperationException} */ @Override public final void remove() { throw new UnsupportedOperationException(); } /** * Converts the rows into the expected object. * * @param row row to convert * @return converted row */ protected abstract E convertRow(String[] row); } /** * This class is an iterator that transforms each row into a List. * * @param <P> Parser class */ private static final class ListRowIterator<P extends AbstractParser<?>> extends RowIterator<List<String>, P> { /** * Creates a new instance. * * @param parser parser to use */ protected ListRowIterator(P parser) { super(parser); } /** * {@inheritDoc} */ @Override protected List<String> convertRow(String[] row) { return Arrays.asList(row); } } /** * This class is an iterator that transform each row into a Map. * * @param <P> Parser class */ private static class MapRowIterator<P extends AbstractParser<?>> extends RowIterator<Map<String, String>, P> { private final HeaderRowProcessor headerRowProcessor; /** * Creates a new instance * * @param parser parser to use * @param headerRowProcessor row processor to use in order to retrieve the headers */ protected MapRowIterator(P parser, HeaderRowProcessor headerRowProcessor) { super(parser); this.headerRowProcessor = headerRowProcessor; } /** * {@inheritDoc} */ @Override protected Map<String, String> convertRow(String[] row) { String[] headers = headerRowProcessor.getHeaders(); int size = Math.min(row.length, headers.length); Map<String, String> result = new LinkedHashMap<String, String>(size); for (int i = 0; i < size; i++) { result.put(headers[i], row[i]); } return result; } } }