/** | |
* 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; | |
} | |
} | |
} |