package sushi.excel.importer; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import sushi.event.SushiEvent; import sushi.event.attribute.SushiAttribute; import sushi.event.attribute.SushiAttributeTypeEnum; import sushi.event.collection.SushiMapTree; /** * This class imports events from an excel file. */ public class ExcelImporter extends FileNormalizer implements Serializable { private static final long serialVersionUID = 1L; /** * Creates an {@link HSSFWorkbook} from an excel file. */ private HSSFWorkbook loadWorkbook(String fileName) { try { InputStream myxls = new FileInputStream(fileName); return new HSSFWorkbook(myxls); } catch (IOException e) { System.err.println("Workbook could not be load."); return null; } } @Override public ArrayList<String> getColumnTitlesFromFile(String fileName) { HSSFWorkbook workbook = this.loadWorkbook(fileName); HSSFSheet firstSheet = workbook.getSheetAt(0); return generateColumnTitlesFromSheet(firstSheet); } /** * Returns the column titles from the given workbook sheet. */ private ArrayList<String> generateColumnTitlesFromSheet(HSSFSheet sheet) { HSSFRow firstRow = sheet.getRow(0); if(firstRow != null){ ArrayList<String> columnTitles = new ArrayList<String>(); for(Cell currentCell : firstRow){ columnTitles.add(currentCell.getStringCellValue().trim().replaceAll(" +","_").replaceAll("[^a-zA-Z0-9_]+","")); } return columnTitles; } else { return new ArrayList<String>(); } } @Override public List<SushiImportEvent> importEventsForPreviewFromFile(String filePath, List<String> selectedColumnTitles) throws IllegalArgumentException { List<SushiImportEvent> eventList = new ArrayList<SushiImportEvent>(); List<String> columnTitles = this.getColumnTitlesFromFile(filePath); if (!columnTitles.isEmpty()) { String timestampName = getTimestampColumn(selectedColumnTitles); Iterator<Row> rowIterator = getRowIterator(filePath); // Eliminate headline row rowIterator.next(); while (rowIterator.hasNext()) { HSSFRow actualRow = (HSSFRow) rowIterator.next(); if(!isRowEmpty(actualRow)){ eventList.add(this.generateImportEventFromRow(actualRow, selectedColumnTitles, columnTitles, timestampName)); } } } return eventList; } @Override public List<SushiEvent> importEventsFromFile(String filePath, List<SushiAttribute> selectedAttributes, String timestamp) { List<SushiEvent> eventList = new ArrayList<SushiEvent>(); List<String> columnTitles = getColumnTitlesFromFile(filePath); List<String> selectedColumnTitles = new ArrayList<String>(); if (!columnTitles.isEmpty()) { for (SushiAttribute attribute : selectedAttributes) { selectedColumnTitles.add(attribute.getName()); } int timeStampColumnIndex = columnTitles.indexOf(timestamp); Iterator<Row> rowIterator = getRowIterator(filePath); // Eliminate headline row rowIterator.next(); while (rowIterator.hasNext()) { HSSFRow actualRow = (HSSFRow) rowIterator.next(); if (!isRowEmpty(actualRow)) { eventList.add(this.generateEventFromRow(actualRow, selectedColumnTitles, selectedAttributes, columnTitles, timeStampColumnIndex)); } } } return eventList; } /** * Generates a event for preview from the given row. The difference to the normal creation is the treatment of the date. Import events have * @param actualRow * @param selectedColumnTitles * @param columnTitles * @param timestampName */ private SushiImportEvent generateImportEventFromRow(HSSFRow actualRow, List<String> selectedColumnTitles, List<String> columnTitles, String timestampName) { Date timestamp; int timestampColumnIndex = columnTitles.indexOf(timestampName); if (timestampColumnIndex > -1) { timestamp = actualRow.getCell(timestampColumnIndex).getDateCellValue(); } else { timestamp = null; } SushiMapTree<String, Serializable> values = generateValueTree(actualRow, selectedColumnTitles, columnTitles, timestampColumnIndex); SushiImportEvent event = new SushiImportEvent(timestamp, values, timestampName, new Date()); return event; } /** * Generates a event from the given row. * @param actualRow * @param selectedColumnTitles * @param selectedAttributes * @param columnTitles * @param timeStampColumnIndex */ private SushiEvent generateEventFromRow(HSSFRow actualRow, List<String> selectedColumnTitles, List<SushiAttribute> selectedAttributes, List<String> columnTitles, int timeStampColumnIndex) { Date timestamp; //Falls kein TimeStamp gefunden wurde, wird die aktuelle Einlesezeit verwendet if(timeStampColumnIndex > -1){ timestamp = actualRow.getCell(timeStampColumnIndex).getDateCellValue(); } else{ timestamp = new Date(); } SushiMapTree<String, Serializable> values = generateValueTree(actualRow, selectedColumnTitles, selectedAttributes, columnTitles, timeStampColumnIndex); SushiEvent event = new SushiEvent(timestamp, values); return event; } private Iterator<Row> getRowIterator(String filePath) { HSSFWorkbook workbook = this.loadWorkbook(filePath); HSSFSheet firstSheet = workbook.getSheetAt(0); Iterator<Row> rowIterator = firstSheet.rowIterator(); return rowIterator; } /** * Returns true, if a {@link HSSFRow} has no values. * @param actualRow */ private boolean isRowEmpty(HSSFRow actualRow) { boolean emptyRow = true; Iterator<Cell> cellIterator = actualRow.cellIterator(); while(cellIterator.hasNext()){ Cell actualCell = cellIterator.next(); emptyRow = (actualCell.getCellType() != Cell.CELL_TYPE_BLANK) ? false : true; } return emptyRow; } /** * Returns a new {@link SushiMapTree} from the given row with the values for the selected columns. * @param actualRow * @param selectedColumnTitles * @param columnTitles * @param timeStampColumnIndex * @return */ private SushiMapTree<String, Serializable> generateValueTree(HSSFRow actualRow, List<String> selectedColumnTitles, List<String> columnTitles, int timeStampColumnIndex) { SushiMapTree<String, Serializable> values = new SushiMapTree<String, Serializable>(); Iterator<Cell> cellIterator = actualRow.cellIterator(); while (cellIterator.hasNext()) { Cell actualCell = cellIterator.next(); if (selectedColumnTitles.contains(columnTitles.get(actualCell.getColumnIndex())) && actualCell.getColumnIndex() != timeStampColumnIndex) { if (actualCell.getCellType() == Cell.CELL_TYPE_STRING) { values.put(columnTitles.get(actualCell.getColumnIndex()), actualCell.getStringCellValue()); } else if (actualCell.getCellType() == Cell.CELL_TYPE_NUMERIC) { values.put(columnTitles.get(actualCell.getColumnIndex()), Double.toString(actualCell.getNumericCellValue())); } } } return values; } /** * Returns a new {@link SushiMapTree} from the given row with the values for the selected columns. * It is possible to specify the selected {@link SushiAttribute}s. * @param actualRow * @param selectedColumnTitles * @param columnTitles * @param timeStampColumnIndex * @return */ private SushiMapTree<String, Serializable> generateValueTree(HSSFRow actualRow, List<String> selectedColumnTitles, List<SushiAttribute> selectedAttributes, List<String> columnTitles, int timeStampColumnIndex) { SushiMapTree<String, Serializable> values = new SushiMapTree<String, Serializable>(); Iterator<Cell> cellIterator = actualRow.cellIterator(); SushiAttributeTypeEnum attributeType = null; while (cellIterator.hasNext()) { Cell actualCell = cellIterator.next(); String attributeName = columnTitles.get(actualCell.getColumnIndex()); for (SushiAttribute attribute : selectedAttributes) { if (attribute.getName().equals(attributeName)) { attributeType = attribute.getType(); } } if (selectedColumnTitles.contains(columnTitles.get(actualCell.getColumnIndex())) && actualCell.getColumnIndex() != timeStampColumnIndex) { Serializable attributeValue = null; if (attributeType != null) { if (attributeType.equals(SushiAttributeTypeEnum.DATE)) { attributeValue = actualCell.getDateCellValue(); } else if (attributeType.equals(SushiAttributeTypeEnum.INTEGER)) { // TODO: support double/float // attributeValue = Math.round(actualCell.getNumericCellValue()); attributeValue = new Integer((int) actualCell.getNumericCellValue()); } else if (attributeType.equals(SushiAttributeTypeEnum.STRING)) { attributeValue = actualCell.getStringCellValue(); } } values.addRootElement(attributeName, attributeValue); } } return values; } }