// $HeadURL$ // $Id$ // // Copyright © 2006, 2010, 2011, 2012 by the President and Fellows of Harvard College. // // Screensaver is an open-source project developed by the ICCB-L and NSRB labs // at Harvard Medical School. This software is distributed under the terms of // the GNU General Public License. package edu.harvard.med.screensaver.io.workbook2; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import jxl.WorkbookSettings; import jxl.write.WritableWorkbook; import org.apache.log4j.Logger; /** * Encapsulates the (lazy) instantiation of an jxl.Workbook from a file. Also * allows the workbook to be associated with the filename it originated from. * * @author <a mailto="andrew_tolopko@hms.harvard.edu">Andrew Tolopko</a> * @author <a mailto="john_sullivan@hms.harvard.edu">John Sullivan</a> */ public class Workbook implements Iterable<Worksheet> { private static Logger log = Logger.getLogger(Workbook.class); public static final String MIME_TYPE = "application/vnd.ms-excel"; private InputStream _workbookStream; private jxl.Workbook _workbook; private ParseErrorManager _errors; private WorkbookSettings _workbookSettings; private String _name; public Workbook(File workbookFile) throws FileNotFoundException { this(workbookFile.getAbsolutePath(), new FileInputStream(workbookFile)); } public Workbook(String name, InputStream workbookStream, WorkbookSettings workbookSettings) throws FileNotFoundException { this(name, workbookStream); _workbookSettings = workbookSettings; } /** * @param name - as the encapsulated workbook does not infer the name * @param workbookStream */ public Workbook(String name, InputStream workbookStream) { _workbookStream = workbookStream; _name = name; _errors = new ParseErrorManager(); } public WorkbookSettings getWorkbookSettings() { if(_workbookSettings == null) _workbookSettings = new WorkbookSettings(); return _workbookSettings; } /** * Returns a jxl.Workbook, with lazy instantiation. * @return an jxl.Workbook * @throws IOException if file is not found or cannot be read */ public jxl.Workbook getWorkbook() { if (_workbook == null) { try { WorkbookSettings workbookSettings = getWorkbookSettings(); workbookSettings.setGCDisabled(true); // when GC feature is enabled, performance is much slower! _workbook = jxl.Workbook.getWorkbook(_workbookStream, workbookSettings); } catch (Exception e) { // TODO: on error, initialize ourself with an empty workbook String errorMsg = "could not read workbook: " + e.getMessage(); _errors.addError(errorMsg); log.error(errorMsg); return null; } } return _workbook; } /** * Find a worksheet with the given name, case-insensitively. * * @motivation the jxl.Workbook API is case sensitive for worksheet names * @param targetSheetName the worksheet name * @return the first Sheet to match the specified name (case-insensitively), otherwise null */ public Worksheet getWorksheet(String targetSheetName) { int i = 0; for (String sheetName : getWorkbook().getSheetNames()) { if (sheetName.equalsIgnoreCase(targetSheetName)) { return getWorksheet(i); } ++i; } return null; } /** * Find a worksheet with a name that matches the specified regular expression. * * @param nameRegex * @return the first Sheet to match the specified regex, otherwise null */ public Worksheet getWorksheet(Pattern nameRegex) { int i = 0; for (String sheetName : getWorkbook().getSheetNames()) { if (nameRegex.matcher(sheetName).matches()) { return getWorksheet(i); } ++i; } return null; } public Worksheet getWorksheet(int i) { return new Worksheet(this, i); } public WritableWorkbook save(OutputStream out) throws IOException { WritableWorkbook outputWorkbook = jxl.Workbook.createWorkbook(out, getWorkbook()); outputWorkbook.write(); log.info("saved workbook"); return outputWorkbook; } /** * Add a workbook-global parsing error message. For cell-specific parsing * error messages, use {@link Cell#addError}. * * @param msg the error message */ public void addError(String msg) { _errors.addError(msg); } /** * @motivation for usage by Cell (avoid having to pass in a ParseErrorManager * when instantiating Cell objects, since Workbook is already * passed in) */ /*package*/ ParseErrorManager getParseErrorManager() { return _errors; } public WritableWorkbook writeErrorAnnotatedWorkbook(File out) { if (_errors.getHasErrors()) { try { WritableWorkbook errorAnnotatedWorkbook = _errors.getErrorAnnotatedWorkbook(); errorAnnotatedWorkbook.setOutputFile(out); errorAnnotatedWorkbook.write(); errorAnnotatedWorkbook.close(); return errorAnnotatedWorkbook; } catch (Exception e) { log.error("could not write error annotated workbook: " + e.getMessage()); } } return null; } public Iterator<Worksheet> iterator() { return new WorksheetIterator(0,getWorkbook().getNumberOfSheets()-1) ; } public class WorksheetIterator implements Iterator<Worksheet> { private int _currentSheet; private int _end; /** * Create RowIterator that iterates between the specified range of rows. * @param begin the first row index to be iterated, zero-based, inclusive * @param end the last row index to be iterated, zero-based, inclusive; must be <= max supported row index by worksheet */ public WorksheetIterator(int begin, int end) { _currentSheet = begin; _end = end; } public boolean hasNext() { return _end >= 0 && _currentSheet <= _end; } public Worksheet next() { return Workbook.this.getWorksheet(_currentSheet++); } public void remove() { throw new UnsupportedOperationException(); } } public boolean getHasErrors() { return _errors.getHasErrors(); } public List<WorkbookParseError> getErrors() { return _errors.getErrors(); } public WritableWorkbook getErrorAnnotatedWorkbook() { return _errors.getErrorAnnotatedWorkbook(); } public String getName() { return _name; } }