You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metamodel.apache.org by ka...@apache.org on 2013/07/19 11:32:56 UTC

[13/61] [partial] Hard rename of all 'org/eobjects' folders to 'org/apache'.

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/XlsxSheetToRowsHandler.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/XlsxSheetToRowsHandler.java b/excel/src/main/java/org/apache/metamodel/excel/XlsxSheetToRowsHandler.java
new file mode 100644
index 0000000..b43c5d6
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/XlsxSheetToRowsHandler.java
@@ -0,0 +1,341 @@
+/**
+ * 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.eobjects.metamodel.excel;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
+import org.apache.poi.ss.usermodel.BuiltinFormats;
+import org.apache.poi.ss.usermodel.DataFormatter;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.FontUnderline;
+import org.apache.poi.xssf.eventusermodel.XSSFReader;
+import org.apache.poi.xssf.model.SharedStringsTable;
+import org.apache.poi.xssf.model.StylesTable;
+import org.apache.poi.xssf.usermodel.XSSFCellStyle;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.apache.poi.xssf.usermodel.XSSFRichTextString;
+import org.eobjects.metamodel.data.Style;
+import org.eobjects.metamodel.data.Style.SizeUnit;
+import org.eobjects.metamodel.data.StyleBuilder;
+import org.eobjects.metamodel.util.DateUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * XML handler for transforming a sheet into rows. Uses an
+ * {@link XlsxRowCallback} to publish identified rows.
+ * 
+ * @author Kasper Sørensen
+ */
+final class XlsxSheetToRowsHandler extends DefaultHandler {
+
+	private static final Logger logger = LoggerFactory
+			.getLogger(XlsxSheetToRowsHandler.class);
+
+	private static enum XssfDataType {
+		BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER,
+	}
+
+	// global variables
+	private final XlsxRowCallback _callback;
+	private final ExcelConfiguration _configuration;
+	private final StylesTable _stylesTable;
+	private final SharedStringsTable _sharedStringTable;
+
+	// variables used to hold information about the current rows
+	private int _rowNumber;
+	private final List<String> _rowValues;
+	private final List<Style> _styles;
+
+	// variables used to hold information about the current visited cells
+	private final StringBuilder _value;
+	private final StyleBuilder _style;
+	private boolean _inCell;
+	private boolean _inFormula;
+	private int _columnNumber;
+	private XssfDataType _dataType;
+	private int _formatIndex;
+	private String _formatString;
+
+	public XlsxSheetToRowsHandler(XlsxRowCallback callback,
+			XSSFReader xssfReader, ExcelConfiguration configuration)
+			throws Exception {
+		_callback = callback;
+		_configuration = configuration;
+
+		_sharedStringTable = xssfReader.getSharedStringsTable();
+		_stylesTable = xssfReader.getStylesTable();
+
+		_value = new StringBuilder();
+		_style = new StyleBuilder();
+		_rowValues = new ArrayList<String>();
+		_styles = new ArrayList<Style>();
+		_rowNumber = -1;
+		_inCell = false;
+		_inFormula = false;
+	}
+
+	@Override
+	public void startElement(String uri, String localName, String qName,
+			Attributes attributes) throws SAXException {
+		if ("row".equals(qName)) {
+			// element is a row
+
+			// excel row numbers are 1-based
+			int rowNumber = Integer.parseInt(attributes.getValue("r"));
+			rowNumber = rowNumber - 1;
+
+			if (_configuration.isSkipEmptyLines()) {
+				_rowNumber++;
+			} else {
+				while (_rowNumber + 1 < rowNumber) {
+					// empty lines are not skipped, so dispatch empty lines
+					_rowNumber++;
+					List<String> emptyValues = Collections.emptyList();
+					List<Style> emptyStyles = Collections.emptyList();
+					_callback.row(_rowNumber, emptyValues, emptyStyles);
+				}
+				_rowNumber = rowNumber;
+			}
+		} else if ("c".equals(qName)) {
+			// element is a cell
+
+			_inCell = true;
+
+			final String r = attributes.getValue("r");
+			int firstDigit = -1;
+			for (int c = 0; c < r.length(); ++c) {
+				if (Character.isDigit(r.charAt(c))) {
+					firstDigit = c;
+					break;
+				}
+			}
+			_columnNumber = nameToColumn(r.substring(0, firstDigit));
+
+			// Set up defaults.
+			_dataType = XssfDataType.NUMBER;
+			_formatIndex = -1;
+			_formatString = null;
+
+			final String cellType = attributes.getValue("t");
+			if ("b".equals(cellType)) {
+				_dataType = XssfDataType.BOOL;
+			} else if ("e".equals(cellType)) {
+				_dataType = XssfDataType.ERROR;
+			} else if ("inlineStr".equals(cellType)) {
+				_dataType = XssfDataType.INLINESTR;
+			} else if ("s".equals(cellType)) {
+				_dataType = XssfDataType.SSTINDEX;
+			} else if ("str".equals(cellType)) {
+				_dataType = XssfDataType.FORMULA;
+			}
+
+			String cellStyleStr = attributes.getValue("s");
+			if (cellStyleStr != null) {
+				// It's a number, but almost certainly one
+				// with a special style or format
+				int styleIndex = Integer.parseInt(cellStyleStr);
+				XSSFCellStyle style = _stylesTable.getStyleAt(styleIndex);
+
+				configureStyle(style);
+
+				if (_dataType == XssfDataType.NUMBER) {
+					this._formatIndex = style.getDataFormat();
+					this._formatString = style.getDataFormatString();
+					if (this._formatString == null) {
+						this._formatString = BuiltinFormats
+								.getBuiltinFormat(this._formatIndex);
+					}
+				}
+			}
+		} else if (_inCell && "f".equals(qName)) {
+			// skip the actual formula line
+			_inFormula = true;
+		}
+	}
+
+	private void configureStyle(XSSFCellStyle style) {
+		XSSFFont font = style.getFont();
+		if (font.getBold()) {
+			_style.bold();
+		}
+		if (font.getItalic()) {
+			_style.italic();
+		}
+		if (font.getUnderline() != FontUnderline.NONE.getByteValue()) {
+			_style.underline();
+		}
+
+		if (style.getFillPatternEnum() == FillPatternType.SOLID_FOREGROUND) {
+			XSSFColor fillForegroundXSSFColor = style
+					.getFillForegroundXSSFColor();
+			String argb = fillForegroundXSSFColor.getARGBHex();
+			if (argb != null) {
+				_style.background(argb.substring(2));
+			}
+		}
+
+		final XSSFFont stdFont = _stylesTable.getStyleAt(0).getFont();
+		final short fontHeight = style.getFont().getFontHeightInPoints();
+		if (stdFont.getFontHeightInPoints() != fontHeight) {
+			_style.fontSize(fontHeight, SizeUnit.PT);
+		}
+
+		XSSFColor fontColor = style.getFont().getXSSFColor();
+		if (fontColor != null) {
+			String argbHex = fontColor.getARGBHex();
+			if (argbHex != null) {
+				_style.foreground(argbHex.substring(2));
+			}
+		}
+
+		switch (style.getAlignmentEnum()) {
+		case LEFT:
+			_style.leftAligned();
+			break;
+		case RIGHT:
+			_style.rightAligned();
+			break;
+		case CENTER:
+			_style.centerAligned();
+			break;
+		case JUSTIFY:
+			_style.justifyAligned();
+			break;
+		}
+
+	}
+
+	@Override
+	public void endElement(String uri, String localName, String qName)
+			throws SAXException {
+		if ("row".equals(qName)) {
+			// element was a row
+			boolean next = _callback.row(_rowNumber, _rowValues, _styles);
+			if (!next) {
+				throw new XlsxStopParsingException();
+			}
+			_rowValues.clear();
+			_styles.clear();
+		} else if ("c".equals(qName)) {
+			// element was a cell
+
+			_inCell = false;
+
+			while (_rowValues.size() < _columnNumber) {
+				_rowValues.add(null);
+				_styles.add(Style.NO_STYLE);
+			}
+
+			_rowValues.add(createValue());
+			_styles.add(_style.create());
+			_value.setLength(0);
+			_style.reset();
+		} else if (_inFormula && "f".equals(qName)) {
+			// skip the actual formula line
+			_inFormula = false;
+		}
+	}
+
+	private String createValue() {
+		if (_value.length() == 0) {
+			return null;
+		}
+
+		switch (_dataType) {
+
+		case BOOL:
+			char first = _value.charAt(0);
+			return first == '0' ? "false" : "true";
+		case ERROR:
+			logger.warn("Error-cell occurred: {}", _value);
+			return _value.toString();
+		case FORMULA:
+			return _value.toString();
+		case INLINESTR:
+			XSSFRichTextString rtsi = new XSSFRichTextString(_value.toString());
+			return rtsi.toString();
+		case SSTINDEX:
+			String sstIndex = _value.toString();
+			int idx = Integer.parseInt(sstIndex);
+			XSSFRichTextString rtss = new XSSFRichTextString(
+					_sharedStringTable.getEntryAt(idx));
+			return rtss.toString();
+		case NUMBER:
+			final String numberString = _value.toString();
+			if (_formatString != null) {
+				DataFormatter formatter = getDataFormatter();
+				if (HSSFDateUtil.isADateFormat(_formatIndex, _formatString)) {
+					Date date = DateUtil.getJavaDate(Double
+							.parseDouble(numberString));
+					return DateUtils.createDateFormat().format(date);
+				}
+				return formatter.formatRawCellContents(
+						Double.parseDouble(numberString), _formatIndex,
+						_formatString);
+			} else {
+				if (numberString.endsWith(".0")) {
+					// xlsx only stores doubles, so integers get ".0" appended
+					// to them
+					return numberString.substring(0, numberString.length() - 2);
+				}
+				return numberString;
+			}
+		default:
+			logger.error("Unsupported data type: {}", _dataType);
+			return "";
+		}
+	}
+
+	private DataFormatter getDataFormatter() {
+		return new DataFormatter();
+	}
+
+	@Override
+	public void characters(char[] ch, int start, int length)
+			throws SAXException {
+		if (_inCell && !_inFormula) {
+			_value.append(ch, start, length);
+		}
+	}
+
+	/**
+	 * Converts an Excel column name like "C" to a zero-based index.
+	 * 
+	 * @param name
+	 * @return Index corresponding to the specified name
+	 */
+	private int nameToColumn(String name) {
+		int column = -1;
+		for (int i = 0; i < name.length(); ++i) {
+			int c = name.charAt(i);
+			column = (column + 1) * 26 + c - 'A';
+		}
+		return column;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/XlsxSpreadsheetReaderDelegate.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/XlsxSpreadsheetReaderDelegate.java b/excel/src/main/java/org/apache/metamodel/excel/XlsxSpreadsheetReaderDelegate.java
new file mode 100644
index 0000000..dadd978
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/XlsxSpreadsheetReaderDelegate.java
@@ -0,0 +1,192 @@
+/**
+ * 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.eobjects.metamodel.excel;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.xssf.eventusermodel.XSSFReader;
+import org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.data.RowPublisherDataSet;
+import org.eobjects.metamodel.data.Style;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.ColumnType;
+import org.eobjects.metamodel.schema.MutableColumn;
+import org.eobjects.metamodel.schema.MutableSchema;
+import org.eobjects.metamodel.schema.MutableTable;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+import org.eobjects.metamodel.util.AlphabeticSequence;
+import org.eobjects.metamodel.util.FileHelper;
+import org.eobjects.metamodel.util.Ref;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+
+/**
+ * {@link SpreadsheetReaderDelegate} implementation for the "new" XLSX format.
+ * This implementation is very efficient as it uses SAX XML parsing which does
+ * not bloat memory usage in the same way that POI's user model does.
+ * 
+ * @author Kasper Sørensen
+ */
+final class XlsxSpreadsheetReaderDelegate implements SpreadsheetReaderDelegate {
+
+    private static final Logger logger = LoggerFactory.getLogger(XlsxSpreadsheetReaderDelegate.class);
+
+    private final ExcelConfiguration _configuration;
+    private final Map<String, String> _tableNamesToInternalIds;
+
+    public XlsxSpreadsheetReaderDelegate(ExcelConfiguration configuration) {
+        _configuration = configuration;
+        _tableNamesToInternalIds = new HashMap<String, String>();
+    }
+
+    @Override
+    public DataSet executeQuery(InputStream inputStream, Table table, Column[] columns, int maxRows) throws Exception {
+        final OPCPackage pkg = OPCPackage.open(inputStream);
+        final XSSFReader xssfReader = new XSSFReader(pkg);
+        final String relationshipId = _tableNamesToInternalIds.get(table.getName());
+
+        return buildDataSet(columns, maxRows, relationshipId, xssfReader);
+    }
+
+    @Override
+    public Schema createSchema(InputStream inputStream, String schemaName) throws Exception {
+        final MutableSchema schema = new MutableSchema(schemaName);
+        final OPCPackage pkg = OPCPackage.open(inputStream);
+        final XSSFReader xssfReader = new XSSFReader(pkg);
+
+        final XlsxWorkbookToTablesHandler workbookToTables = new XlsxWorkbookToTablesHandler(schema,
+                _tableNamesToInternalIds);
+        buildTables(xssfReader, workbookToTables);
+
+        for (Entry<String, String> entry : _tableNamesToInternalIds.entrySet()) {
+
+            final String tableName = entry.getKey();
+            final String relationshipId = entry.getValue();
+
+            final MutableTable table = (MutableTable) schema.getTableByName(tableName);
+
+            buildColumns(table, relationshipId, xssfReader);
+        }
+        return schema;
+    }
+
+    @Override
+    public void notifyTablesModified(Ref<InputStream> inputStreamRef) {
+        InputStream inputStream = inputStreamRef.get();
+        final XlsxWorkbookToTablesHandler workbookToTables = new XlsxWorkbookToTablesHandler(null,
+                _tableNamesToInternalIds);
+        try {
+            final OPCPackage pkg = OPCPackage.open(inputStream);
+            final XSSFReader xssfReader = new XSSFReader(pkg);
+            buildTables(xssfReader, workbookToTables);
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        } finally {
+            FileHelper.safeClose(inputStream);
+        }
+    }
+
+    private DataSet buildDataSet(final Column[] columns, int maxRows, final String relationshipId,
+            final XSSFReader xssfReader) throws Exception {
+
+        List<SelectItem> selectItems = new ArrayList<SelectItem>(columns.length);
+        for (Column column : columns) {
+            selectItems.add(new SelectItem(column));
+        }
+        final XlsxRowPublisherAction publishAction = new XlsxRowPublisherAction(_configuration, columns,
+                relationshipId, xssfReader);
+
+        return new RowPublisherDataSet(selectItems.toArray(new SelectItem[selectItems.size()]), maxRows, publishAction);
+    }
+
+    private void buildColumns(final MutableTable table, final String relationshipId, final XSSFReader xssfReader)
+            throws Exception {
+        final InputStream sheetData = xssfReader.getSheet(relationshipId);
+
+        final XlsxRowCallback rowCallback = new XlsxRowCallback() {
+            @Override
+            public boolean row(int rowNumber, List<String> values, List<Style> styles) {
+                final int columnNameLineNumber = _configuration.getColumnNameLineNumber();
+                if (columnNameLineNumber == ExcelConfiguration.NO_COLUMN_NAME_LINE) {
+                    AlphabeticSequence alphabeticSequence = new AlphabeticSequence();
+                    List<String> generatedColumnNames = new ArrayList<String>(values.size());
+                    for (String originalColumnName : values) {
+                        String columnName = alphabeticSequence.next();
+                        if (originalColumnName == null) {
+                            columnName = null;
+                        }
+                        generatedColumnNames.add(columnName);
+                    }
+                    buildColumns(table, generatedColumnNames);
+                    return false;
+                } else {
+                    final int zeroBasedLineNumber = columnNameLineNumber - 1;
+                    if (rowNumber >= zeroBasedLineNumber) {
+                        buildColumns(table, values);
+                        return false;
+                    }
+                }
+                return true;
+            }
+        };
+        final XlsxSheetToRowsHandler handler = new XlsxSheetToRowsHandler(rowCallback, xssfReader, _configuration);
+
+        final XMLReader sheetParser = ExcelUtils.createXmlReader();
+        sheetParser.setContentHandler(handler);
+        try {
+            sheetParser.parse(new InputSource(sheetData));
+        } catch (XlsxStopParsingException e) {
+            logger.debug("Parsing stop signal thrown");
+        } finally {
+            FileHelper.safeClose(sheetData);
+        }
+    }
+
+    protected void buildColumns(final MutableTable table, final List<String> columnNames) {
+        int columnNumber = 0;
+        for (String columnName : columnNames) {
+            if (columnName != null || !_configuration.isSkipEmptyColumns()) {
+                if (columnName == null) {
+                    columnName = "[Column " + (columnNumber + 1) + "]";
+                }
+                table.addColumn(new MutableColumn(columnName, ColumnType.VARCHAR, table, columnNumber, true));
+            }
+            columnNumber++;
+        }
+    }
+
+    private void buildTables(final XSSFReader xssfReader, final XlsxWorkbookToTablesHandler workbookToTables)
+            throws Exception {
+        final InputStream workbookData = xssfReader.getWorkbookData();
+        final XMLReader workbookParser = ExcelUtils.createXmlReader();
+        workbookParser.setContentHandler(workbookToTables);
+        workbookParser.parse(new InputSource(workbookData));
+        FileHelper.safeClose(workbookData);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/XlsxStopParsingException.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/XlsxStopParsingException.java b/excel/src/main/java/org/apache/metamodel/excel/XlsxStopParsingException.java
new file mode 100644
index 0000000..47d8078
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/XlsxStopParsingException.java
@@ -0,0 +1,33 @@
+/**
+ * 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.eobjects.metamodel.excel;
+
+import org.xml.sax.SAXException;
+
+/**
+ * Exception thrown when all elements of interest in a spreadsheet have been
+ * parsed.
+ * 
+ * @author Kasper Sørensen
+ */
+final class XlsxStopParsingException extends SAXException {
+
+	private static final long serialVersionUID = 1L;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/XlsxWorkbookToTablesHandler.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/XlsxWorkbookToTablesHandler.java b/excel/src/main/java/org/apache/metamodel/excel/XlsxWorkbookToTablesHandler.java
new file mode 100644
index 0000000..fa65bf8
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/XlsxWorkbookToTablesHandler.java
@@ -0,0 +1,66 @@
+/**
+ * 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.eobjects.metamodel.excel;
+
+import java.util.Map;
+
+import org.eobjects.metamodel.schema.MutableSchema;
+import org.eobjects.metamodel.schema.MutableTable;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+import org.eobjects.metamodel.schema.TableType;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * XML handler for transforming a workbook document into {@link Table}s in a
+ * MetaModel {@link Schema}.
+ * 
+ * @author Kasper Sørensen
+ */
+final class XlsxWorkbookToTablesHandler extends DefaultHandler {
+
+	private final MutableSchema _schema;
+	private final Map<String, String> _tableNamesToRelationshipIds;
+
+	public XlsxWorkbookToTablesHandler(MutableSchema schema,
+			Map<String, String> tableNamesToRelationshipIds) {
+		_schema = schema;
+		_tableNamesToRelationshipIds = tableNamesToRelationshipIds;
+	}
+
+	@Override
+	public void startElement(String uri, String localName, String qName,
+			Attributes attributes) throws SAXException {
+		if ("sheet".equals(qName)) {
+			String name = attributes.getValue("name");
+			assert name != null;
+			String relationId = attributes.getValue("r:id");
+			assert relationId != null;
+
+			if (_schema != null) {
+				MutableTable table = new MutableTable(name, TableType.TABLE,
+						_schema);
+				_schema.addTable(table);
+			}
+			_tableNamesToRelationshipIds.put(name, relationId);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/ZeroBasedRowIterator.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/ZeroBasedRowIterator.java b/excel/src/main/java/org/apache/metamodel/excel/ZeroBasedRowIterator.java
new file mode 100644
index 0000000..d897ec4
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/ZeroBasedRowIterator.java
@@ -0,0 +1,58 @@
+/**
+ * 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.eobjects.metamodel.excel;
+
+import java.util.Iterator;
+
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+
+/**
+ * An iterator implementation that iterates from the first logical (as opposed
+ * to physical, which is the default in POI) row in a spreadsheet.
+ * 
+ * @author Kasper Sørensen
+ */
+final class ZeroBasedRowIterator implements Iterator<Row> {
+
+	private final Sheet _sheet;
+	private volatile int _rowNumber;
+
+	public ZeroBasedRowIterator(Sheet sheet) {
+		_sheet = sheet;
+		_rowNumber = -1;
+	}
+
+	@Override
+	public boolean hasNext() {
+		return _rowNumber < _sheet.getLastRowNum();
+	}
+
+	@Override
+	public Row next() {
+		_rowNumber++;
+		return _sheet.getRow(_rowNumber);
+	}
+
+	@Override
+	public void remove() {
+		throw new UnsupportedOperationException("remove() is not supported");
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/package-info.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/package-info.java b/excel/src/main/java/org/apache/metamodel/excel/package-info.java
new file mode 100644
index 0000000..9bf3d30
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/package-info.java
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+/**
+ * Module package for MS Excel spreadsheet files
+ */
+package org.eobjects.metamodel.excel;
+

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/eobjects/metamodel/excel/DefaultSpreadsheetReaderDelegate.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/eobjects/metamodel/excel/DefaultSpreadsheetReaderDelegate.java b/excel/src/main/java/org/eobjects/metamodel/excel/DefaultSpreadsheetReaderDelegate.java
deleted file mode 100644
index dc4a331..0000000
--- a/excel/src/main/java/org/eobjects/metamodel/excel/DefaultSpreadsheetReaderDelegate.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/**
- * 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.eobjects.metamodel.excel;
-
-import java.io.InputStream;
-import java.util.Iterator;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.eobjects.metamodel.data.DataSet;
-import org.eobjects.metamodel.data.EmptyDataSet;
-import org.eobjects.metamodel.data.MaxRowsDataSet;
-import org.eobjects.metamodel.schema.Column;
-import org.eobjects.metamodel.schema.ColumnType;
-import org.eobjects.metamodel.schema.MutableColumn;
-import org.eobjects.metamodel.schema.MutableSchema;
-import org.eobjects.metamodel.schema.MutableTable;
-import org.eobjects.metamodel.schema.Schema;
-import org.eobjects.metamodel.schema.Table;
-import org.eobjects.metamodel.util.AlphabeticSequence;
-import org.eobjects.metamodel.util.Ref;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The default {@link SpreadsheetReaderDelegate}, which uses POI's main user
- * model to read spreadsheets: the Workbook class.
- * 
- * @author Kasper Sørensen
- */
-final class DefaultSpreadsheetReaderDelegate implements SpreadsheetReaderDelegate {
-
-    private static final Logger logger = LoggerFactory.getLogger(DefaultSpreadsheetReaderDelegate.class);
-
-    private final ExcelConfiguration _configuration;
-
-    public DefaultSpreadsheetReaderDelegate(ExcelConfiguration configuration) {
-        _configuration = configuration;
-    }
-
-    @Override
-    public Schema createSchema(InputStream inputStream, String schemaName) {
-        final MutableSchema schema = new MutableSchema(schemaName);
-        final Workbook wb = ExcelUtils.readWorkbook(inputStream);
-
-        for (int i = 0; i < wb.getNumberOfSheets(); i++) {
-            final Sheet currentSheet = wb.getSheetAt(i);
-            final MutableTable table = createTable(wb, currentSheet);
-            table.setSchema(schema);
-            schema.addTable(table);
-        }
-
-        return schema;
-    }
-
-    @Override
-    public DataSet executeQuery(InputStream inputStream, Table table, Column[] columns, int maxRows) {
-        final Workbook wb = ExcelUtils.readWorkbook(inputStream);
-        final Sheet sheet = wb.getSheet(table.getName());
-
-        if (sheet == null || sheet.getPhysicalNumberOfRows() == 0) {
-            return new EmptyDataSet(columns);
-        }
-
-        DataSet dataSet = ExcelUtils.getDataSet(wb, sheet, table, _configuration);
-
-        if (maxRows > 0) {
-            dataSet = new MaxRowsDataSet(dataSet, maxRows);
-        }
-        return dataSet;
-    }
-
-    @Override
-    public void notifyTablesModified(Ref<InputStream> inputStreamRef) {
-        // do nothing
-    }
-
-    private MutableTable createTable(final Workbook wb, final Sheet sheet) {
-        final MutableTable table = new MutableTable(sheet.getSheetName());
-
-        if (sheet.getPhysicalNumberOfRows() <= 0) {
-            // no physical rows in sheet
-            return table;
-        }
-
-        final Iterator<Row> rowIterator = ExcelUtils.getRowIterator(sheet, _configuration, false);
-
-        if (!rowIterator.hasNext()) {
-            // no physical rows in sheet
-            return table;
-        }
-
-
-        Row row = null;
-
-        if (_configuration.isSkipEmptyLines()) {
-            while (row == null && rowIterator.hasNext()) {
-                row = rowIterator.next();
-            }
-        } else {
-            row = rowIterator.next();
-        }
-
-        final int columnNameLineNumber = _configuration.getColumnNameLineNumber();
-        if (columnNameLineNumber == ExcelConfiguration.NO_COLUMN_NAME_LINE) {
-
-            // get to the first non-empty line (no matter if lines are skipped
-            // or not we need to read ahead to figure out how many columns there
-            // are!)
-            while (row == null && rowIterator.hasNext()) {
-                row = rowIterator.next();
-            }
-
-            // build columns by using alphabetic sequences
-            // (A,B,C...)
-            AlphabeticSequence sequence = new AlphabeticSequence();
-
-            final int offset = getColumnOffset(row);
-            for (int i = 0; i < offset; i++) {
-                sequence.next();
-            }
-
-            for (int j = offset; j < row.getLastCellNum(); j++) {
-                Column column = new MutableColumn(sequence.next(), ColumnType.VARCHAR, table, j, true);
-                table.addColumn(column);
-            }
-        } else {
-
-            boolean hasColumns = true;
-
-            // iterate to the column name line number (if above 1)
-            for (int j = 1; j < columnNameLineNumber; j++) {
-                if (rowIterator.hasNext()) {
-                    row = rowIterator.next();
-                } else {
-                    hasColumns = false;
-                    break;
-                }
-            }
-
-            if (hasColumns) {
-                createColumns(table, wb, row);
-            }
-        }
-
-        return table;
-    }
-
-    /**
-     * Builds columns based on row/cell values.
-     * 
-     * @param table
-     * @param wb
-     * @param row
-     */
-    private void createColumns(MutableTable table, Workbook wb, Row row) {
-        if (row == null) {
-            logger.warn("Cannot create columns based on null row!");
-            return;
-        }
-        final short rowLength = row.getLastCellNum();
-
-        final int offset = getColumnOffset(row);
-
-        // build columns based on cell values.
-        for (int j = offset; j < rowLength; j++) {
-            Cell cell = row.getCell(j);
-            String columnName = ExcelUtils.getCellValue(wb, cell);
-            if (columnName == null || "".equals(columnName)) {
-                columnName = "[Column " + (j + 1) + "]";
-            }
-            Column column = new MutableColumn(columnName, ColumnType.VARCHAR, table, j, true);
-            table.addColumn(column);
-        }
-    }
-
-    /**
-     * Gets the column offset (first column to include). This is dependent on
-     * the row used for column processing and whether the skip empty columns
-     * property is set.
-     * 
-     * @param row
-     * @return
-     */
-    private int getColumnOffset(Row row) {
-        final int offset;
-        if (_configuration.isSkipEmptyColumns()) {
-            offset = row.getFirstCellNum();
-        } else {
-            offset = 0;
-        }
-        return offset;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelConfiguration.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelConfiguration.java b/excel/src/main/java/org/eobjects/metamodel/excel/ExcelConfiguration.java
deleted file mode 100644
index 6ea490c..0000000
--- a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelConfiguration.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * 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.eobjects.metamodel.excel;
-
-import java.io.Serializable;
-import java.util.List;
-
-import org.eobjects.metamodel.util.BaseObject;
-
-/**
- * Represents the configuration for reading/parsing Excel spreadsheets.
- * 
- * @see ExcelDataContext
- * 
- * @author Kasper Sørensen
- */
-public final class ExcelConfiguration extends BaseObject implements
-		Serializable {
-
-	private static final long serialVersionUID = 1L;
-
-	public static final int NO_COLUMN_NAME_LINE = 0;
-	public static final int DEFAULT_COLUMN_NAME_LINE = 1;
-
-	private final int columnNameLineNumber;
-	private final boolean skipEmptyLines;
-	private final boolean skipEmptyColumns;
-
-	public ExcelConfiguration() {
-		this(DEFAULT_COLUMN_NAME_LINE, true, false);
-	}
-
-	public ExcelConfiguration(int columnNameLineNumber, boolean skipEmptyLines,
-			boolean skipEmptyColumns) {
-		this.columnNameLineNumber = columnNameLineNumber;
-		this.skipEmptyLines = skipEmptyLines;
-		this.skipEmptyColumns = skipEmptyColumns;
-	}
-
-	/**
-	 * The line number (1 based) from which to get the names of the columns.
-	 * Note that this line number is affected by the skipEmptyLines property! If
-	 * skipEmptyLines is set to true, the line numbers will begin from the first
-	 * non-empty line.
-	 * 
-	 * @return the line number of the column headers/names.
-	 */
-	public int getColumnNameLineNumber() {
-		return columnNameLineNumber;
-	}
-
-	/**
-	 * Defines if empty lines in the excel spreadsheet should be skipped while
-	 * reading the spreadsheet.
-	 * 
-	 * @return a boolean indicating whether or not to skip empty lines.
-	 */
-	public boolean isSkipEmptyLines() {
-		return skipEmptyLines;
-	}
-
-	/**
-	 * Defines if empty columns in the excel spreadsheet should be skipped while
-	 * reading the spreadsheet.
-	 * 
-	 * @return a boolean indicating whether or not to skip empty columns.
-	 */
-	public boolean isSkipEmptyColumns() {
-		return skipEmptyColumns;
-	}
-
-	@Override
-	protected void decorateIdentity(List<Object> identifiers) {
-		identifiers.add(columnNameLineNumber);
-		identifiers.add(skipEmptyLines);
-		identifiers.add(skipEmptyColumns);
-	}
-
-	@Override
-	public String toString() {
-		return "ExcelConfiguration[columnNameLineNumber="
-				+ columnNameLineNumber + ", skipEmptyLines=" + skipEmptyLines
-				+ ", skipEmptyColumns=" + skipEmptyColumns + "]";
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDataContext.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDataContext.java b/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDataContext.java
deleted file mode 100644
index 6726d8b..0000000
--- a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDataContext.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/**
- * 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.eobjects.metamodel.excel;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PushbackInputStream;
-
-import org.apache.poi.POIXMLDocument;
-import org.eobjects.metamodel.DataContext;
-import org.eobjects.metamodel.MetaModelException;
-import org.eobjects.metamodel.QueryPostprocessDataContext;
-import org.eobjects.metamodel.UpdateScript;
-import org.eobjects.metamodel.UpdateableDataContext;
-import org.eobjects.metamodel.data.DataSet;
-import org.eobjects.metamodel.schema.Column;
-import org.eobjects.metamodel.schema.MutableSchema;
-import org.eobjects.metamodel.schema.Schema;
-import org.eobjects.metamodel.schema.Table;
-import org.eobjects.metamodel.util.FileHelper;
-import org.eobjects.metamodel.util.FileResource;
-import org.eobjects.metamodel.util.LazyRef;
-import org.eobjects.metamodel.util.Ref;
-import org.eobjects.metamodel.util.Resource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * {@link DataContext} implementation to use for Excel spreadsheets.
- * 
- * This DataContext supports both the "old" .xls format and the "new" .xlsx
- * format, and saves the user the trouble of figuring out which one to use,
- * simply by detecting it at runtime and delegating to the appropriate
- * implementation.
- */
-public final class ExcelDataContext extends QueryPostprocessDataContext implements UpdateableDataContext {
-
-    private static final Logger logger = LoggerFactory.getLogger(ExcelDataContext.class);
-
-    private final Object WRITE_LOCK = new Object();
-
-    private final Resource _resource;
-    private final ExcelConfiguration _configuration;
-    private SpreadsheetReaderDelegate _spreadsheetReaderDelegate;
-
-    /**
-     * Constructs an Excel DataContext based on a file, with default
-     * configuration
-     * 
-     * @param file
-     */
-    public ExcelDataContext(File file) {
-        this(file, new ExcelConfiguration());
-    }
-
-    /**
-     * Constructs an Excel DataContext based on a resource and a custom
-     * configuration.
-     * 
-     * @param file
-     * @param configuration
-     */
-    public ExcelDataContext(File file, ExcelConfiguration configuration) {
-        if (file == null) {
-            throw new IllegalArgumentException("File cannot be null");
-        }
-        if (configuration == null) {
-            throw new IllegalArgumentException("ExcelConfiguration cannot be null");
-        }
-        if (file.exists() && !file.canRead()) {
-            throw new IllegalArgumentException("Cannot read from file");
-        }
-        _resource = new FileResource(file);
-        _configuration = configuration;
-    }
-
-    public ExcelDataContext(Resource resource, ExcelConfiguration configuration) {
-        if (resource == null) {
-            throw new IllegalArgumentException("Resource cannot be null");
-        }
-        if (configuration == null) {
-            throw new IllegalArgumentException("ExcelConfiguration cannot be null");
-        }
-        _resource = resource;
-        _configuration = configuration;
-    }
-
-    /**
-     * Gets the Excel configuration used.
-     * 
-     * @return an excel configuration.
-     */
-    public ExcelConfiguration getConfiguration() {
-        return _configuration;
-    }
-
-    /**
-     * Gets the Excel file being read.
-     * 
-     * @return a file.
-     * @deprecated
-     */
-    @Deprecated
-    public File getFile() {
-        if (_resource instanceof FileResource) {
-            return ((FileResource) _resource).getFile();
-        }
-        return null;
-    }
-
-    /**
-     * Gets the Excel resource being read
-     * 
-     * @return
-     */
-    public Resource getResource() {
-        return _resource;
-    }
-
-    @Override
-    protected String getMainSchemaName() throws MetaModelException {
-        return _resource.getName();
-    }
-
-    @Override
-    public DataSet materializeMainSchemaTable(Table table, Column[] columns, int maxRows) {
-
-        Ref<InputStream> inputStreamRef = getInputStreamRef();
-        InputStream inputStream = null;
-        try {
-            SpreadsheetReaderDelegate delegate = getSpreadsheetReaderDelegate(inputStreamRef);
-            inputStream = inputStreamRef.get();
-            DataSet dataSet = delegate.executeQuery(inputStream, table, columns, maxRows);
-            return dataSet;
-        } catch (Exception e) {
-            if (e instanceof RuntimeException) {
-                throw (RuntimeException) e;
-            }
-            throw new MetaModelException("Unexpected exception while materializing main schema table", e);
-        } finally {
-            FileHelper.safeClose(inputStream);
-        }
-    }
-
-    @Override
-    protected Schema getMainSchema() throws MetaModelException {
-        if (!_resource.isExists()) {
-            logger.info("Resource does not exist, returning empty schema");
-            return new MutableSchema(getMainSchemaName());
-        }
-        Ref<InputStream> inputStreamRef = getInputStreamRef();
-        InputStream inputStream = null;
-        try {
-            SpreadsheetReaderDelegate delegate = getSpreadsheetReaderDelegate(inputStreamRef);
-            inputStream = inputStreamRef.get();
-            Schema schema = delegate.createSchema(inputStream, getMainSchemaName());
-            assert getMainSchemaName().equals(schema.getName());
-            return schema;
-        } catch (Exception e) {
-            if (e instanceof RuntimeException) {
-                throw (RuntimeException) e;
-            }
-            throw new MetaModelException("Unexpected exception while building main schema", e);
-        } finally {
-            FileHelper.safeClose(inputStream);
-        }
-    }
-
-    /**
-     * Convenient method for testing and inspecting internal state.
-     * 
-     * @return the class of the spreadsheet reader delegate.
-     */
-    protected Class<? extends SpreadsheetReaderDelegate> getSpreadsheetReaderDelegateClass() {
-        if (_spreadsheetReaderDelegate != null) {
-            return _spreadsheetReaderDelegate.getClass();
-        }
-        return null;
-    }
-
-    private SpreadsheetReaderDelegate getSpreadsheetReaderDelegate(Ref<InputStream> inputStream) throws MetaModelException {
-        if (_spreadsheetReaderDelegate == null) {
-            synchronized (this) {
-                if (_spreadsheetReaderDelegate == null) {
-                    try {
-                        if (POIXMLDocument.hasOOXMLHeader(inputStream.get())) {
-                            _spreadsheetReaderDelegate = new XlsxSpreadsheetReaderDelegate(_configuration);
-                        } else {
-                            _spreadsheetReaderDelegate = new DefaultSpreadsheetReaderDelegate(_configuration);
-                        }
-                    } catch (IOException e) {
-                        logger.error("Could not identify spreadsheet type, using default", e);
-                        _spreadsheetReaderDelegate = new DefaultSpreadsheetReaderDelegate(_configuration);
-                    }
-                }
-            }
-        }
-        return _spreadsheetReaderDelegate;
-    }
-
-    private InputStream getInputStream() throws MetaModelException {
-        InputStream inputStream = _resource.read();
-        if (!inputStream.markSupported()) {
-            inputStream = new PushbackInputStream(inputStream, 8);
-        }
-        return inputStream;
-    }
-
-    private LazyRef<InputStream> getInputStreamRef() throws MetaModelException {
-        final LazyRef<InputStream> inputStreamRef = new LazyRef<InputStream>() {
-            @Override
-            public InputStream fetch() {
-                InputStream inputStream = getInputStream();
-                return inputStream;
-            }
-        };
-        return inputStreamRef;
-    }
-
-    protected void notifyTablesModified() {
-        LazyRef<InputStream> inputStreamRef = getInputStreamRef();
-        try {
-            getSpreadsheetReaderDelegate(inputStreamRef).notifyTablesModified(inputStreamRef);
-        } finally {
-            if (inputStreamRef.isFetched()) {
-                FileHelper.safeClose(inputStreamRef.get());
-            }
-        }
-    }
-
-    @Override
-    public void executeUpdate(UpdateScript update) {
-        ExcelUpdateCallback updateCallback = new ExcelUpdateCallback(this);
-        synchronized (WRITE_LOCK) {
-            try {
-                update.run(updateCallback);
-            } finally {
-                updateCallback.close();
-            }
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDeleteBuilder.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDeleteBuilder.java b/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDeleteBuilder.java
deleted file mode 100644
index cd2a0cc..0000000
--- a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDeleteBuilder.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * 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.eobjects.metamodel.excel;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.eobjects.metamodel.MetaModelException;
-import org.eobjects.metamodel.MetaModelHelper;
-import org.eobjects.metamodel.data.DataSetHeader;
-import org.eobjects.metamodel.data.DefaultRow;
-import org.eobjects.metamodel.data.SimpleDataSetHeader;
-import org.eobjects.metamodel.delete.AbstractRowDeletionBuilder;
-import org.eobjects.metamodel.query.SelectItem;
-import org.eobjects.metamodel.schema.Table;
-
-final class ExcelDeleteBuilder extends AbstractRowDeletionBuilder {
-
-    private final ExcelUpdateCallback _updateCallback;
-
-    public ExcelDeleteBuilder(ExcelUpdateCallback updateCallback, Table table) {
-        super(table);
-        _updateCallback = updateCallback;
-    }
-
-    @Override
-    public void execute() throws MetaModelException {
-        // close the update callback will flush any changes
-        _updateCallback.close();
-
-        // read the workbook without streaming, since this will not wrap it in a
-        // streaming workbook implementation (which do not support random
-        // accessing rows).
-        final Workbook workbook = _updateCallback.getWorkbook(false);
-
-        final String tableName = getTable().getName();
-        final SelectItem[] selectItems = MetaModelHelper.createSelectItems(getTable().getColumns());
-        final DataSetHeader header = new SimpleDataSetHeader(selectItems);
-        final Sheet sheet = workbook.getSheet(tableName);
-
-        final Iterator<Row> rowIterator = ExcelUtils.getRowIterator(sheet, _updateCallback.getConfiguration(), true);
-        final List<Row> rowsToDelete = new ArrayList<Row>();
-        while (rowIterator.hasNext()) {
-            final Row excelRow = rowIterator.next();
-            final DefaultRow row = ExcelUtils.createRow(workbook, excelRow, header);
-
-            final boolean deleteRow = deleteRow(row);
-            if (deleteRow) {
-                rowsToDelete.add(excelRow);
-            }
-        }
-
-        // reverse the list to not mess up any row numbers
-        Collections.reverse(rowsToDelete);
-
-        for (Row row : rowsToDelete) {
-            sheet.removeRow(row);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDropTableBuilder.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDropTableBuilder.java b/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDropTableBuilder.java
deleted file mode 100644
index abcb222..0000000
--- a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelDropTableBuilder.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/**
- * 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.eobjects.metamodel.excel;
-
-import org.eobjects.metamodel.MetaModelException;
-import org.eobjects.metamodel.drop.AbstractTableDropBuilder;
-import org.eobjects.metamodel.drop.TableDropBuilder;
-import org.eobjects.metamodel.schema.MutableSchema;
-import org.eobjects.metamodel.schema.Table;
-
-final class ExcelDropTableBuilder extends AbstractTableDropBuilder implements TableDropBuilder {
-
-    private ExcelUpdateCallback _updateCallback;
-
-    public ExcelDropTableBuilder(ExcelUpdateCallback updateCallback, Table table) {
-        super(table);
-        _updateCallback = updateCallback;
-    }
-
-    @Override
-    public void execute() throws MetaModelException {
-        final Table table = getTable();
-        _updateCallback.removeSheet(table.getName());
-        final MutableSchema schema = (MutableSchema) table.getSchema();
-        schema.removeTable(table);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelInsertBuilder.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelInsertBuilder.java b/excel/src/main/java/org/eobjects/metamodel/excel/ExcelInsertBuilder.java
deleted file mode 100644
index 24bf3b1..0000000
--- a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelInsertBuilder.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/**
- * 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.eobjects.metamodel.excel;
-
-import java.util.Date;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.Row;
-import org.eobjects.metamodel.data.Style;
-import org.eobjects.metamodel.data.Style.Color;
-import org.eobjects.metamodel.data.Style.SizeUnit;
-import org.eobjects.metamodel.data.Style.TextAlignment;
-import org.eobjects.metamodel.insert.AbstractRowInsertionBuilder;
-import org.eobjects.metamodel.insert.RowInsertionBuilder;
-import org.eobjects.metamodel.schema.Column;
-import org.eobjects.metamodel.schema.Table;
-import org.eobjects.metamodel.util.LazyRef;
-
-/**
- * {@link RowInsertionBuilder} for excel spreadsheets.
- * 
- * @author Kasper Sørensen
- */
-final class ExcelInsertBuilder extends
-		AbstractRowInsertionBuilder<ExcelUpdateCallback> {
-
-	public ExcelInsertBuilder(ExcelUpdateCallback updateCallback, Table table) {
-		super(updateCallback, table);
-	}
-
-	@Override
-	public void execute() {
-		final Object[] values = getValues();
-		final Style[] styles = getStyles();
-
-		final Row row = getUpdateCallback().createRow(getTable().getName());
-
-		final Column[] columns = getColumns();
-		for (int i = 0; i < columns.length; i++) {
-			Object value = values[i];
-			if (value != null) {
-				int columnNumber = columns[i].getColumnNumber();
-				Cell cell = row.createCell(columnNumber);
-
-				// use a lazyref and the isFetched method to only create style
-				// if nescesary
-				LazyRef<CellStyle> cellStyle = new LazyRef<CellStyle>() {
-					@Override
-					protected CellStyle fetch() {
-						return getUpdateCallback().createCellStyle();
-					}
-				};
-
-				if (value instanceof Number) {
-					cell.setCellValue(((Number) value).doubleValue());
-				} else if (value instanceof Boolean) {
-					cell.setCellValue((Boolean) value);
-				} else if (value instanceof Date) {
-					cell.setCellValue((Date) value);
-				} else {
-					cell.setCellValue(value.toString());
-				}
-
-				Style style = styles[i];
-				if (style != null && !Style.NO_STYLE.equals(style)) {
-					LazyRef<Font> font = new LazyRef<Font>() {
-						@Override
-						protected Font fetch() {
-							return getUpdateCallback().createFont();
-						}
-
-					};
-					if (style.isBold()) {
-						font.get().setBoldweight(Font.BOLDWEIGHT_BOLD);
-					}
-					if (style.isItalic()) {
-						font.get().setItalic(true);
-					}
-					if (style.isUnderline()) {
-						font.get().setUnderline(Font.U_SINGLE);
-					}
-					if (style.getFontSize() != null) {
-						Integer fontSize = style.getFontSize();
-						SizeUnit sizeUnit = style.getFontSizeUnit();
-						if (sizeUnit == SizeUnit.PERCENT) {
-							fontSize = convertFontPercentageToPt(fontSize);
-						}
-						font.get().setFontHeightInPoints(fontSize.shortValue());
-					}
-					Color foregroundColor = style.getForegroundColor();
-					if (foregroundColor != null) {
-						short index = getUpdateCallback().getColorIndex(
-								foregroundColor);
-						font.get().setColor(index);
-					}
-					if (font.isFetched()) {
-						cellStyle.get().setFont(font.get());
-					}
-					if (style.getAlignment() != null) {
-						cellStyle.get().setAlignment(
-								getAlignment(style.getAlignment()));
-					}
-
-					final Color backgroundColor = style.getBackgroundColor();
-					if (backgroundColor != null) {
-						cellStyle.get().setFillPattern(
-								CellStyle.SOLID_FOREGROUND);
-						cellStyle.get().setFillForegroundColor(
-								getUpdateCallback().getColorIndex(
-										backgroundColor));
-					}
-				}
-
-				if (value instanceof Date) {
-					if (cellStyle.isFetched()) {
-						cellStyle.get().setDataFormat(
-								getUpdateCallback().getDateCellFormat());
-					} else {
-						cellStyle = new LazyRef<CellStyle>() {
-							@Override
-							protected CellStyle fetch() {
-								return getUpdateCallback().getDateCellStyle();
-							}
-						};
-						// trigger the fetch
-						cellStyle.get();
-					}
-				}
-
-				if (cellStyle.isFetched()) {
-					cell.setCellStyle(cellStyle.get());
-				}
-			}
-		}
-	}
-
-	/**
-	 * Converts a percentage based font size to excel "pt" scale.
-	 * 
-	 * @param percentage
-	 * @return
-	 */
-	private Integer convertFontPercentageToPt(Integer percentage) {
-		Double d = percentage.intValue() * 11.0 / 100;
-		return d.intValue();
-	}
-
-	private short getAlignment(TextAlignment alignment) {
-		switch (alignment) {
-		case LEFT:
-			return CellStyle.ALIGN_LEFT;
-		case RIGHT:
-			return CellStyle.ALIGN_RIGHT;
-		case CENTER:
-			return CellStyle.ALIGN_CENTER;
-		case JUSTIFY:
-			return CellStyle.ALIGN_JUSTIFY;
-		default:
-			throw new IllegalArgumentException("Unknown alignment type: "
-					+ alignment);
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelTableCreationBuilder.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelTableCreationBuilder.java b/excel/src/main/java/org/eobjects/metamodel/excel/ExcelTableCreationBuilder.java
deleted file mode 100644
index a031fde..0000000
--- a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelTableCreationBuilder.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * 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.eobjects.metamodel.excel;
-
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.eobjects.metamodel.create.AbstractTableCreationBuilder;
-import org.eobjects.metamodel.create.TableCreationBuilder;
-import org.eobjects.metamodel.schema.Column;
-import org.eobjects.metamodel.schema.MutableSchema;
-import org.eobjects.metamodel.schema.MutableTable;
-import org.eobjects.metamodel.schema.Schema;
-import org.eobjects.metamodel.schema.Table;
-
-/**
- * {@link TableCreationBuilder} implementation for Excel spreadsheets.
- * 
- * @author Kasper Sørensen
- */
-final class ExcelTableCreationBuilder extends AbstractTableCreationBuilder<ExcelUpdateCallback> {
-
-    public ExcelTableCreationBuilder(ExcelUpdateCallback updateCallback, Schema schema, String name) {
-        super(updateCallback, schema, name);
-    }
-
-    @Override
-    public Table execute() {
-        final ExcelUpdateCallback updateCallback = getUpdateCallback();
-        final MutableTable table = getTable();
-
-        final Sheet sheet = updateCallback.createSheet(table.getName());
-
-        final int lineNumber = updateCallback.getConfiguration().getColumnNameLineNumber();
-        if (lineNumber != ExcelConfiguration.NO_COLUMN_NAME_LINE) {
-            final int zeroBasedLineNumber = lineNumber - 1;
-            final Row row = sheet.createRow(zeroBasedLineNumber);
-            final Column[] columns = table.getColumns();
-            for (int i = 0; i < columns.length; i++) {
-                final Column column = columns[i];
-                final int columnNumber = column.getColumnNumber();
-                row.createCell(columnNumber).setCellValue(column.getName());
-            }
-        }
-
-        final MutableSchema schema = (MutableSchema) table.getSchema();
-        schema.addTable((MutableTable) table);
-        return table;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelUpdateCallback.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelUpdateCallback.java b/excel/src/main/java/org/eobjects/metamodel/excel/ExcelUpdateCallback.java
deleted file mode 100644
index 9564ba9..0000000
--- a/excel/src/main/java/org/eobjects/metamodel/excel/ExcelUpdateCallback.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/**
- * 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.eobjects.metamodel.excel;
-
-import org.apache.poi.hssf.usermodel.HSSFPalette;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.hssf.util.HSSFColor;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.xssf.streaming.SXSSFSheet;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.eobjects.metamodel.AbstractUpdateCallback;
-import org.eobjects.metamodel.UpdateCallback;
-import org.eobjects.metamodel.create.TableCreationBuilder;
-import org.eobjects.metamodel.data.DataSet;
-import org.eobjects.metamodel.data.Style.Color;
-import org.eobjects.metamodel.delete.RowDeletionBuilder;
-import org.eobjects.metamodel.drop.TableDropBuilder;
-import org.eobjects.metamodel.insert.RowInsertionBuilder;
-import org.eobjects.metamodel.schema.Schema;
-import org.eobjects.metamodel.schema.Table;
-
-final class ExcelUpdateCallback extends AbstractUpdateCallback implements UpdateCallback {
-
-    private final ExcelDataContext _dataContext;
-    private final ExcelConfiguration _configuration;
-    private boolean _sheetsModified;
-    private Workbook _workbook;
-    private Short _dateCellFormat;
-    private CellStyle _dateCellStyle;
-
-    public ExcelUpdateCallback(ExcelDataContext dataContext) {
-        super(dataContext);
-        _sheetsModified = false;
-        _configuration = dataContext.getConfiguration();
-        _dataContext = dataContext;
-    }
-
-    @Override
-    public TableCreationBuilder createTable(Schema schema, String name) throws IllegalArgumentException,
-            IllegalStateException {
-        return new ExcelTableCreationBuilder(this, schema, name);
-    }
-
-    @Override
-    public RowInsertionBuilder insertInto(Table table) throws IllegalArgumentException, IllegalStateException {
-        return new ExcelInsertBuilder(this, table);
-    }
-
-    protected ExcelConfiguration getConfiguration() {
-        return _configuration;
-    }
-
-    @Override
-    public ExcelDataContext getDataContext() {
-        return _dataContext;
-    }
-
-    protected void close() {
-        if (_workbook != null) {
-            ExcelUtils.writeWorkbook(_dataContext, _workbook);
-
-            _workbook = null;
-            _dateCellFormat = null;
-            _dateCellStyle = null;
-        }
-        if (_sheetsModified) {
-            _dataContext.notifyTablesModified();
-            _sheetsModified = false;
-        }
-    }
-
-    protected Workbook getWorkbook(boolean streamingAllowed) {
-        if (_workbook == null || (!streamingAllowed && _workbook instanceof SXSSFWorkbook)) {
-            if (_workbook != null) {
-                ExcelUtils.writeWorkbook(_dataContext, _workbook);
-            }
-            _workbook = ExcelUtils.readWorkbook(_dataContext);
-            if (streamingAllowed && _workbook instanceof XSSFWorkbook) {
-                _workbook = new SXSSFWorkbook((XSSFWorkbook) _workbook);
-            }
-        }
-        return _workbook;
-    }
-
-    protected Sheet createSheet(String name) {
-        Sheet sheet = getWorkbook(true).createSheet(name);
-        _sheetsModified = true;
-        return sheet;
-    }
-
-    protected void removeSheet(String name) {
-        int index = getWorkbook(true).getSheetIndex(name);
-        if (index != -1) {
-            getWorkbook(true).removeSheetAt(index);
-            _sheetsModified = true;
-        }
-    }
-
-    protected Row createRow(String name) {
-        if (_sheetsModified) {
-            close();
-        }
-        Sheet sheet = getWorkbook(true).getSheet(name);
-        int lastRowNum = getLastRowNum(sheet);
-        Row row = sheet.createRow(lastRowNum + 1);
-        return row;
-    }
-
-    private int getLastRowNum(Sheet sheet) {
-        final int lastRowNum = sheet.getLastRowNum();
-        if (lastRowNum == 0 && sheet instanceof SXSSFSheet) {
-            // streaming sheets have bad behaviour in this scenario - since no
-            // rows are in cache, it will return 0!
-            DataSet ds = _dataContext.query().from(sheet.getSheetName()).selectCount().execute();
-            ds.next();
-            final Number count = (Number) ds.getRow().getValue(0);
-            final int columnNameLineNumber = _configuration.getColumnNameLineNumber();
-            int oneBasedResult = count.intValue()
-                    + (columnNameLineNumber == ExcelConfiguration.NO_COLUMN_NAME_LINE ? 0 : columnNameLineNumber);
-            return oneBasedResult - 1;
-        }
-        return lastRowNum;
-    }
-
-    /**
-     * Creates a new cell style in the spreadsheet
-     * 
-     * @return
-     */
-    public CellStyle createCellStyle() {
-        Workbook workbook = getWorkbook(true);
-        return workbook.createCellStyle();
-    }
-
-    public Font createFont() {
-        Workbook workbook = getWorkbook(true);
-        return workbook.createFont();
-    }
-
-    protected Sheet getSheet(String name) {
-        return getWorkbook(true).getSheet(name);
-    }
-
-    /**
-     * Gets the index identifier for the date format
-     * 
-     * @return
-     */
-    public short getDateCellFormat() {
-        if (_dateCellFormat == null) {
-            Workbook workbook = getWorkbook(true);
-            _dateCellFormat = workbook.getCreationHelper().createDataFormat().getFormat("m/d/yy h:mm");
-        }
-        return _dateCellFormat;
-    }
-
-    /**
-     * Gets a shared, reusable cell style for "pure date" cells (eg. no other
-     * styling applied)
-     * 
-     * @return
-     */
-    public CellStyle getDateCellStyle() {
-        if (_dateCellStyle == null) {
-            _dateCellStyle = createCellStyle();
-            _dateCellStyle.setDataFormat(getDateCellFormat());
-        }
-        return _dateCellStyle;
-    }
-
-    public short getColorIndex(Color color) {
-        Workbook workbook = getWorkbook(true);
-        if (workbook instanceof HSSFWorkbook) {
-            HSSFPalette palette = ((HSSFWorkbook) workbook).getCustomPalette();
-            byte r = toRgb(color.getRed());
-            byte g = toRgb(color.getGreen());
-            byte b = toRgb(color.getBlue());
-
-            HSSFColor index = palette.findColor(r, g, b);
-            if (index == null) {
-                index = palette.findSimilarColor(r, g, b);
-            }
-            return index.getIndex();
-        }
-        throw new IllegalStateException("Unexpected workbook type: " + workbook.getClass());
-    }
-
-    private byte toRgb(int i) {
-        assert i >= 0;
-        assert i <= 255;
-
-        if (i > 127) {
-            i = i - 256;
-        }
-        return (byte) i;
-    }
-
-    @Override
-    public boolean isDropTableSupported() {
-        return true;
-    }
-
-    @Override
-    public TableDropBuilder dropTable(Table table) throws UnsupportedOperationException {
-        return new ExcelDropTableBuilder(this, table);
-    }
-
-    @Override
-    public boolean isDeleteSupported() {
-        return true;
-    }
-
-    @Override
-    public RowDeletionBuilder deleteFrom(Table table) throws UnsupportedOperationException {
-        return new ExcelDeleteBuilder(this, table);
-    }
-}