/*
* This is eMonocot, a global online biodiversity information resource.
*
* Copyright © 2011–2015 The Board of Trustees of the Royal Botanic Gardens, Kew and The University of Oxford
*
* eMonocot is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* eMonocot 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 Affero General Public License for more details.
*
* The complete text of the GNU Affero General Public License is in the source repository as the file
* ‘COPYING’. It is also available from <http://www.gnu.org/licenses/>.
*/
package org.emonocot.harvest.common;
import java.util.List;
import org.emonocot.model.BaseData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.batch.item.file.MultiResourceItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
/**
* @author jk00kg
* This class is intended for allowing a small number of readers to be used in a similar manner to the {@link MultiResourceItemReader}
* with the difference of supporting different file structures by allowing different {@link LineMapper}s etc. to be used
* N.B. Not designed for use with
*/
public class CompositeItemReader<T> implements ItemReader<T> {
private Logger logger = LoggerFactory.getLogger(CompositeItemReader.class);
private ItemReader<T> currentDelegate;
private List<ItemReader<T>> delegates;
private Class<? extends BaseData> targetType;
@Autowired
private ConversionService conversionService;
public List<ItemReader<T>> getDelegates() {
return delegates;
}
public void setDelegates(List<ItemReader<T>> delegates) {
this.delegates = delegates;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void setTargetType(Class targetType) {
this.targetType = targetType;
}
public void setConversionService(ConversionService conversionService) {
this.conversionService = conversionService;
}
/* (non-Javadoc)
* @see org.springframework.batch.item.ItemReader#read()
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public T read() throws Exception, UnexpectedInputException, ParseException,
NonTransientResourceException {
T item;
//TODO Separate two steps and refactor
if(currentDelegate == null || (item = currentDelegate.read()) == null) {
logger.debug("Loading new item reader");
try {
if(currentDelegate != null && ItemStream.class.isAssignableFrom(currentDelegate.getClass())) {
((ItemStream) currentDelegate).close();
}
currentDelegate = delegates.remove(0);
logger.info("The current ItemReader is now " + currentDelegate);
if(currentDelegate != null && ItemStream.class.isAssignableFrom(currentDelegate.getClass())) {
((ItemStream) currentDelegate).open(new ExecutionContext());
}
} catch (IndexOutOfBoundsException e) {
//if there are no more delegates
logger.info("No more readers, returning null");
return null;
}
item = read();
}
//If targetType is null use the first delegate to define the expected type
if (targetType == null) {
targetType = (Class) item.getClass();
} else {
if(!targetType.isInstance(item)) {
logger.debug("Attempting to cast " + item + " to " + targetType);
item = (T) conversionService.convert(item, targetType);
}
}
logger.debug("Returning " + item);
return item;
}
}