/*
* Copyright (c) 2014 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.io.xls.reader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import org.springframework.core.convert.ConversionService;
import eu.esdihumboldt.hale.common.core.HalePlatform;
import eu.esdihumboldt.hale.common.core.io.IOProviderConfigurationException;
import eu.esdihumboldt.hale.common.core.io.ProgressIndicator;
import eu.esdihumboldt.hale.common.core.io.report.IOReport;
import eu.esdihumboldt.hale.common.core.io.report.IOReporter;
import eu.esdihumboldt.hale.common.core.io.report.impl.IOMessageImpl;
import eu.esdihumboldt.hale.common.instance.io.impl.AbstractInstanceReader;
import eu.esdihumboldt.hale.common.instance.model.Instance;
import eu.esdihumboldt.hale.common.instance.model.InstanceCollection;
import eu.esdihumboldt.hale.common.instance.model.MutableInstance;
import eu.esdihumboldt.hale.common.instance.model.impl.DefaultInstance;
import eu.esdihumboldt.hale.common.instance.model.impl.DefaultInstanceCollection;
import eu.esdihumboldt.hale.common.schema.model.PropertyDefinition;
import eu.esdihumboldt.hale.common.schema.model.TypeDefinition;
import eu.esdihumboldt.hale.common.schema.model.constraint.type.Binding;
import eu.esdihumboldt.hale.io.csv.InstanceTableIOConstants;
import eu.esdihumboldt.hale.io.csv.reader.CommonSchemaConstants;
import eu.esdihumboldt.hale.io.csv.reader.internal.CSVInstanceReader;
import eu.esdihumboldt.hale.io.xls.AnalyseXLSSchemaTable;
/**
* Read source data of xls instance files (based on the
* {@link CSVInstanceReader}
*
* @author Patrick Lieb
*/
public class XLSInstanceReader extends AbstractInstanceReader {
private DefaultInstanceCollection instances;
private PropertyDefinition[] propAr;
private TypeDefinition type;
private AnalyseXLSSchemaTable analyser;
// only needed for correct error description
private int line = 0;
// first sheet as default
private int sheetNum = 0;
/**
* @see eu.esdihumboldt.hale.common.instance.io.InstanceReader#getInstances()
*/
@Override
public InstanceCollection getInstances() {
return instances;
}
/**
* @see eu.esdihumboldt.hale.common.core.io.IOProvider#isCancelable()
*/
@Override
public boolean isCancelable() {
return false;
}
@Override
protected IOReport execute(ProgressIndicator progress, IOReporter reporter)
throws IOProviderConfigurationException, IOException {
boolean skipFirst = getParameter(CommonSchemaConstants.PARAM_SKIP_FIRST_LINE).as(
Boolean.class);
// first sheet as default
sheetNum = getParameter(InstanceTableIOConstants.SHEET_INDEX).as(int.class, 0);
instances = new DefaultInstanceCollection(new ArrayList<Instance>());
try {
// analyze the excel sheet to get all information
analyser = new AnalyseXLSSchemaTable(getSource().getLocation(), sheetNum);
} catch (Exception e) {
reporter.error(new IOMessageImpl("Reading the excel sheet has failed", e));
return reporter;
}
// get type definition of the schema
type = getSourceSchema().getType(
QName.valueOf(getParameter(CommonSchemaConstants.PARAM_TYPENAME).as(String.class)));
// get property definition
propAr = type.getChildren().toArray(new PropertyDefinition[type.getChildren().size()]);
Collection<List<String>> rows = analyser.getRows();
// skip if first row is a header
if (!skipFirst) {
// otherwise first line is also an instance
createInstanceCollection(analyser.getHeader(), reporter);
line++;
}
// iterate over all rows to create the instances
Iterator<List<String>> allRows = rows.iterator();
while (allRows.hasNext()) {
List<String> row = allRows.next();
createInstanceCollection(row, reporter);
line++;
}
reporter.setSuccess(true);
return reporter;
}
/**
* create instances, see
* {@link CSVInstanceReader#execute(ProgressIndicator, IOReporter)}
*
* @param row the current row
* @param reporter the reporter of the writer
* @param solveNestedProperties true, if schema should not be flat <b>(not
* implemented yet)</b>
**/
@SuppressWarnings("javadoc")
private void createInstanceCollection(List<String> row, IOReporter reporter) {
MutableInstance instance = new DefaultInstance(type, null);
// int propertyIndex = 0;
for (int index = 0; index < propAr.length; index++) {
String part = null;
if (index < row.size())
part = row.get(index);
if (part != null) {
PropertyDefinition property = propAr[index];
if (part.isEmpty()) {
// FIXME make this configurable
part = null;
}
Object value = part;
if (value != null) {
Binding binding = property.getPropertyType().getConstraint(Binding.class);
try {
if (!binding.getBinding().equals(String.class)) {
ConversionService conversionService = HalePlatform
.getService(ConversionService.class);
if (conversionService.canConvert(String.class, binding.getBinding())) {
value = conversionService.convert(part, binding.getBinding());
}
else {
throw new IllegalStateException("Conversion not possible!");
}
}
} catch (Exception e) {
reporter.error(new IOMessageImpl("Cannot convert property value to {0}", e,
line, -1, binding.getBinding().getSimpleName()));
}
instance.addProperty(property.getName(), value);
}
// propertyIndex++;
}
}
instances.add(instance);
}
/**
* @see eu.esdihumboldt.hale.common.core.io.impl.AbstractIOProvider#getDefaultTypeName()
*/
@Override
protected String getDefaultTypeName() {
return "XLS Instance Reader";
}
}