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/22 10:10:27 UTC

[14/64] [partial] Hard rename of all 'org/eobjects' folders to 'org/apache'.

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/csv/src/test/java/org/eobjects/metamodel/csv/DefaultExampleValueGenerator.java
----------------------------------------------------------------------
diff --git a/csv/src/test/java/org/eobjects/metamodel/csv/DefaultExampleValueGenerator.java b/csv/src/test/java/org/eobjects/metamodel/csv/DefaultExampleValueGenerator.java
deleted file mode 100644
index d836fef..0000000
--- a/csv/src/test/java/org/eobjects/metamodel/csv/DefaultExampleValueGenerator.java
+++ /dev/null
@@ -1,31 +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.csv;
-
-import org.junit.Ignore;
-
-@Ignore
-final class DefaultExampleValueGenerator implements ExampleValueGenerator {
-
-	@Override
-	public String generate(int row, int col) {
-		return "r" + row + "c" + col;
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/csv/src/test/java/org/eobjects/metamodel/csv/ExampleDataGenerator.java
----------------------------------------------------------------------
diff --git a/csv/src/test/java/org/eobjects/metamodel/csv/ExampleDataGenerator.java b/csv/src/test/java/org/eobjects/metamodel/csv/ExampleDataGenerator.java
deleted file mode 100644
index e2da7bf..0000000
--- a/csv/src/test/java/org/eobjects/metamodel/csv/ExampleDataGenerator.java
+++ /dev/null
@@ -1,96 +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.csv;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-
-import org.junit.Ignore;
-
-/**
- * Simple program used for creating large CSV datasets for performance/memory
- * testing
- */
-@Ignore
-class ExampleDataGenerator {
-
-	private final int _rows;
-	private final int _cols;
-	private final ExampleValueGenerator _valueGenerator;
-	
-	public static void main(String[] args) {
-		// Convenience main method. Customize if needed.
-		ExampleDataGenerator gen = new ExampleDataGenerator(374635, 4, new RandomizedExampleValueGenerator(3));
-		gen.createFile( new File("test1.csv"));
-		gen.createFile( new File("test2.csv"));
-		gen.createFile( new File("test3.csv"));
-	}
-
-	public ExampleDataGenerator(int rows, int cols) {
-		this(rows, cols, new DefaultExampleValueGenerator());
-	}
-
-	public ExampleDataGenerator(int rows, int cols,
-			ExampleValueGenerator valueGenerator) {
-		_rows = rows;
-		_cols = cols;
-		_valueGenerator = valueGenerator;
-	}
-
-	public void createFile(File file) {
-		BufferedWriter writer = null;
-		try {
-			writer = new BufferedWriter(new FileWriter(file));
-
-			for (int j = 0; j < _cols; j++) {
-				if (j != 0) {
-					writer.write(',');
-				}
-				writer.write("col" + j);
-			}
-
-			for (int i = 0; i < _rows; i++) {
-				if (i % 500000 == 0) {
-					System.out.println("i: " + i);
-				}
-				writer.write('\n');
-				for (int j = 0; j < _cols; j++) {
-					if (j != 0) {
-						writer.write(',');
-					}
-					final String value = _valueGenerator.generate(i, j);
-					writer.write(value);
-				}
-			}
-
-		} catch (Exception e) {
-			e.printStackTrace();
-		} finally {
-			if (writer != null) {
-				try {
-					writer.close();
-				} catch (IOException e) {
-					e.printStackTrace();
-				}
-			}
-		}
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/csv/src/test/java/org/eobjects/metamodel/csv/ExampleValueGenerator.java
----------------------------------------------------------------------
diff --git a/csv/src/test/java/org/eobjects/metamodel/csv/ExampleValueGenerator.java b/csv/src/test/java/org/eobjects/metamodel/csv/ExampleValueGenerator.java
deleted file mode 100644
index 9e45e98..0000000
--- a/csv/src/test/java/org/eobjects/metamodel/csv/ExampleValueGenerator.java
+++ /dev/null
@@ -1,27 +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.csv;
-
-import org.junit.Ignore;
-
-@Ignore
-interface ExampleValueGenerator {
-
-	public String generate(int row, int col);
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/csv/src/test/java/org/eobjects/metamodel/csv/RandomizedExampleValueGenerator.java
----------------------------------------------------------------------
diff --git a/csv/src/test/java/org/eobjects/metamodel/csv/RandomizedExampleValueGenerator.java b/csv/src/test/java/org/eobjects/metamodel/csv/RandomizedExampleValueGenerator.java
deleted file mode 100644
index 2a6dfaa..0000000
--- a/csv/src/test/java/org/eobjects/metamodel/csv/RandomizedExampleValueGenerator.java
+++ /dev/null
@@ -1,92 +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.csv;
-
-import java.util.Random;
-
-import org.junit.Ignore;
-
-@Ignore
-final class RandomizedExampleValueGenerator implements ExampleValueGenerator {
-
-	private final char[] diacriticChars = new char[] { 'æ', 'ø', 'å', 'ä', 'õ',
-			'â', 'á', 'í', 'ì', 'ẽ', 'ŝ', 'é', 'ç' };
-	private final char[] strangeChars = new char[] { '*', '.', '~', '`', '@',
-			'[', ']', '#', '-' };
-	private final Random random = new Random();
-	private final int letterMin = 'a';
-	private final int letterMax = 'z';
-	private final int letterDiff = letterMax - letterMin;
-	private final int _tokenLength;
-
-	public RandomizedExampleValueGenerator() {
-		this(20);
-	}
-
-	public RandomizedExampleValueGenerator(int tokenLength) {
-		_tokenLength = tokenLength;
-	}
-
-	@Override
-	public String generate(int row, int col) {
-		int length = random.nextInt(_tokenLength);
-		if (length < 3) {
-			if (random.nextInt(1000) == 0) {
-				length = 0;
-			} else {
-				length = 1 + random.nextInt(5);
-			}
-		}
-		char[] chars = new char[length];
-		for (int i = 0; i < length; i++) {
-			chars[i] = nextChar();
-		}
-		return String.valueOf(chars);
-	}
-
-	private char nextChar() {
-		int unusualCharRandom = random.nextInt(10000);
-		if (unusualCharRandom < 91) {
-			return ' ';
-		} else if (unusualCharRandom < 109) {
-			return getRandom(diacriticChars);
-		} else if (unusualCharRandom < 113) {
-			return getRandom(strangeChars);
-		}
-		final int r = random.nextInt(letterDiff);
-		char c = (char) (r + letterMin);
-		if (random.nextInt(6) == 0) {
-			c = Character.toUpperCase(c);
-		}
-		return c;
-	}
-
-	private char getRandom(char[] chars) {
-		final int index = random.nextInt(chars.length);
-		return chars[index];
-	}
-
-	public static void main(String[] args) {
-		RandomizedExampleValueGenerator gen = new RandomizedExampleValueGenerator();
-		for (int i = 0; i < 1000; i++) {
-			System.out.println(gen.generate(0, 0));
-		}
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/csv/src/test/java/org/eobjects/metamodel/csv/UnicodeWriterTest.java
----------------------------------------------------------------------
diff --git a/csv/src/test/java/org/eobjects/metamodel/csv/UnicodeWriterTest.java b/csv/src/test/java/org/eobjects/metamodel/csv/UnicodeWriterTest.java
deleted file mode 100644
index a82b732..0000000
--- a/csv/src/test/java/org/eobjects/metamodel/csv/UnicodeWriterTest.java
+++ /dev/null
@@ -1,51 +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.csv;
-
-import static org.junit.Assert.assertEquals;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.Writer;
-
-import org.eobjects.metamodel.util.UnicodeWriter;
-import org.junit.Test;
-
-public class UnicodeWriterTest {
-
-    @Test
-    public void test() throws IOException {
-        File file = new File("target/unicodeWriterTest.txt");
-        Writer writer = new UnicodeWriter(file, "UTF-8");
-        writer.write("Hello");
-        writer.close();
-
-        FileInputStream is = new FileInputStream(file);
-        byte[] bytes = new byte[100];
-        assertEquals(8, is.read(bytes));
-
-        assertEquals(UnicodeWriter.UTF8_BOM[0], bytes[0]);
-        assertEquals(UnicodeWriter.UTF8_BOM[1], bytes[1]);
-        assertEquals(UnicodeWriter.UTF8_BOM[2], bytes[2]);
-        assertEquals((byte) 'H', bytes[3]);
-        
-        is.close();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/csv/src/test/java/org/eobjects/metamodel/intercept/InterceptionCsvIntegrationTest.java
----------------------------------------------------------------------
diff --git a/csv/src/test/java/org/eobjects/metamodel/intercept/InterceptionCsvIntegrationTest.java b/csv/src/test/java/org/eobjects/metamodel/intercept/InterceptionCsvIntegrationTest.java
deleted file mode 100644
index 6e587d2..0000000
--- a/csv/src/test/java/org/eobjects/metamodel/intercept/InterceptionCsvIntegrationTest.java
+++ /dev/null
@@ -1,85 +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.intercept;
-
-import java.io.File;
-import java.util.Arrays;
-
-import junit.framework.TestCase;
-
-import org.eobjects.metamodel.UpdateCallback;
-import org.eobjects.metamodel.UpdateScript;
-import org.eobjects.metamodel.UpdateableDataContext;
-import org.eobjects.metamodel.create.TableCreationBuilder;
-import org.eobjects.metamodel.csv.CsvDataContext;
-import org.eobjects.metamodel.data.DataSet;
-import org.eobjects.metamodel.insert.RowInsertionBuilder;
-import org.eobjects.metamodel.schema.Table;
-
-public class InterceptionCsvIntegrationTest extends TestCase {
-
-	public void testScenario() throws Exception {
-		final UpdateableDataContext source = new CsvDataContext(new File(
-				"target/test_interception_scenario.txt"));
-		final InterceptableDataContext dc = Interceptors.intercept(source);
-
-		dc.addTableCreationInterceptor(new TableCreationInterceptor() {
-			@Override
-			public TableCreationBuilder intercept(TableCreationBuilder input) {
-				return input.withColumn("foobar");
-			}
-		});
-
-		dc.addRowInsertionInterceptor(new RowInsertionInterceptor() {
-			@Override
-			public RowInsertionBuilder intercept(RowInsertionBuilder input) {
-				return input.value("foobar", "elite!");
-			}
-		});
-
-		dc.executeUpdate(new UpdateScript() {
-			@Override
-			public void run(UpdateCallback callback) {
-				Table table = callback
-						.createTable(dc.getDefaultSchema(), "table")
-						.withColumn("col1").withColumn("col2").execute();
-
-				callback.insertInto(table).value("col1", "hello")
-						.value("col2", "world").execute();
-				callback.insertInto(table).value("col1", "123")
-						.value("col2", "567").execute();
-			}
-		});
-
-		assertEquals("[test_interception_scenario]",
-				Arrays.toString(dc.getDefaultSchema().getTableNames()));
-		Table table = dc.getDefaultSchema().getTables()[0];
-		assertEquals("[col1, col2, foobar]",
-				Arrays.toString(table.getColumnNames()));
-
-		DataSet ds = dc.query().from(table).select(table.getColumns())
-				.execute();
-		assertTrue(ds.next());
-		assertEquals("Row[values=[hello, world, elite!]]", ds.getRow()
-				.toString());
-		assertTrue(ds.next());
-		assertEquals("Row[values=[123, 567, elite!]]", ds.getRow().toString());
-		assertFalse(ds.next());
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/DefaultSpreadsheetReaderDelegate.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/DefaultSpreadsheetReaderDelegate.java b/excel/src/main/java/org/apache/metamodel/excel/DefaultSpreadsheetReaderDelegate.java
new file mode 100644
index 0000000..f4c6dd7
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/DefaultSpreadsheetReaderDelegate.java
@@ -0,0 +1,212 @@
+/**
+ * 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/apache/metamodel/excel/ExcelConfiguration.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/ExcelConfiguration.java b/excel/src/main/java/org/apache/metamodel/excel/ExcelConfiguration.java
new file mode 100644
index 0000000..b63140c
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/ExcelConfiguration.java
@@ -0,0 +1,101 @@
+/**
+ * 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/apache/metamodel/excel/ExcelDataContext.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/ExcelDataContext.java b/excel/src/main/java/org/apache/metamodel/excel/ExcelDataContext.java
new file mode 100644
index 0000000..6726d8b
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/ExcelDataContext.java
@@ -0,0 +1,259 @@
+/**
+ * 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/apache/metamodel/excel/ExcelDeleteBuilder.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/ExcelDeleteBuilder.java b/excel/src/main/java/org/apache/metamodel/excel/ExcelDeleteBuilder.java
new file mode 100644
index 0000000..4b9308c
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/ExcelDeleteBuilder.java
@@ -0,0 +1,81 @@
+/**
+ * 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/apache/metamodel/excel/ExcelDropTableBuilder.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/ExcelDropTableBuilder.java b/excel/src/main/java/org/apache/metamodel/excel/ExcelDropTableBuilder.java
new file mode 100644
index 0000000..b303622
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/ExcelDropTableBuilder.java
@@ -0,0 +1,44 @@
+/**
+ * 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/apache/metamodel/excel/ExcelInsertBuilder.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/ExcelInsertBuilder.java b/excel/src/main/java/org/apache/metamodel/excel/ExcelInsertBuilder.java
new file mode 100644
index 0000000..3a61a2f
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/ExcelInsertBuilder.java
@@ -0,0 +1,181 @@
+/**
+ * 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/apache/metamodel/excel/ExcelTableCreationBuilder.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/ExcelTableCreationBuilder.java b/excel/src/main/java/org/apache/metamodel/excel/ExcelTableCreationBuilder.java
new file mode 100644
index 0000000..7a579e5
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/ExcelTableCreationBuilder.java
@@ -0,0 +1,65 @@
+/**
+ * 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/apache/metamodel/excel/ExcelUpdateCallback.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/ExcelUpdateCallback.java b/excel/src/main/java/org/apache/metamodel/excel/ExcelUpdateCallback.java
new file mode 100644
index 0000000..533a878
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/ExcelUpdateCallback.java
@@ -0,0 +1,238 @@
+/**
+ * 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);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/ExcelUtils.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/ExcelUtils.java b/excel/src/main/java/org/apache/metamodel/excel/ExcelUtils.java
new file mode 100644
index 0000000..e31d61d
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/ExcelUtils.java
@@ -0,0 +1,419 @@
+/**
+ * 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.io.OutputStream;
+import java.text.NumberFormat;
+import java.util.Date;
+import java.util.Iterator;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
+import org.apache.poi.hssf.usermodel.HSSFFont;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.hssf.util.HSSFColor;
+import org.apache.poi.ss.formula.FormulaParseException;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Color;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.FontUnderline;
+import org.apache.poi.ss.usermodel.FormulaError;
+import org.apache.poi.ss.usermodel.FormulaEvaluator;
+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.ss.usermodel.WorkbookFactory;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFColor;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.eobjects.metamodel.MetaModelException;
+import org.eobjects.metamodel.MetaModelHelper;
+import org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.data.DataSetHeader;
+import org.eobjects.metamodel.data.DefaultRow;
+import org.eobjects.metamodel.data.EmptyDataSet;
+import org.eobjects.metamodel.data.Style;
+import org.eobjects.metamodel.data.Style.SizeUnit;
+import org.eobjects.metamodel.data.StyleBuilder;
+import org.eobjects.metamodel.query.SelectItem;
+import org.eobjects.metamodel.schema.Table;
+import org.eobjects.metamodel.util.Action;
+import org.eobjects.metamodel.util.DateUtils;
+import org.eobjects.metamodel.util.FormatHelper;
+import org.eobjects.metamodel.util.Func;
+import org.eobjects.metamodel.util.Resource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.XMLReader;
+
+/**
+ * Convenience/reusable methods for Excel workbook handling.
+ * 
+ * @author Kasper Sørensen
+ */
+final class ExcelUtils {
+
+    private static final Logger logger = LoggerFactory.getLogger(ExcelUtils.class);
+
+    private static final NumberFormat _numberFormat = FormatHelper.getUiNumberFormat();
+
+    private ExcelUtils() {
+        // prevent instantiation
+    }
+
+    public static XMLReader createXmlReader() {
+        try {
+            SAXParserFactory saxFactory = SAXParserFactory.newInstance();
+            SAXParser saxParser = saxFactory.newSAXParser();
+            XMLReader sheetParser = saxParser.getXMLReader();
+            return sheetParser;
+        } catch (Exception e) {
+            throw new MetaModelException(e);
+        }
+    }
+
+    /**
+     * Initializes a workbook instance based on a inputstream.
+     * 
+     * @return a workbook instance based on the inputstream.
+     */
+    public static Workbook readWorkbook(InputStream inputStream) {
+        try {
+            return WorkbookFactory.create(inputStream);
+        } catch (Exception e) {
+            logger.error("Could not open workbook", e);
+            throw new IllegalStateException("Could not open workbook", e);
+        }
+    }
+
+    public static Workbook readWorkbook(Resource resource) {
+        return resource.read(new Func<InputStream, Workbook>() {
+            @Override
+            public Workbook eval(InputStream inputStream) {
+                return readWorkbook(inputStream);
+            }
+        });
+    }
+
+    public static boolean isXlsxFile(Resource resource) {
+        if (resource == null) {
+            return false;
+        }
+        return resource.getName().toLowerCase().endsWith(".xlsx");
+    }
+
+    /**
+     * Initializes a workbook instance based on a {@link ExcelDataContext}.
+     * 
+     * @return a workbook instance based on the ExcelDataContext.
+     */
+    public static Workbook readWorkbook(ExcelDataContext dataContext) {
+        Resource resource = dataContext.getResource();
+        if (!resource.isExists()) {
+            if (isXlsxFile(resource)) {
+                return new SXSSFWorkbook(1000);
+            } else {
+                return new HSSFWorkbook();
+            }
+        }
+        return readWorkbook(resource);
+    }
+
+    public static void writeWorkbook(ExcelDataContext dataContext, final Workbook wb) {
+        final Resource resource = dataContext.getResource();
+        resource.write(new Action<OutputStream>() {
+            @Override
+            public void run(OutputStream outputStream) throws Exception {
+                wb.write(outputStream);
+            }
+        });
+    }
+
+    public static String getCellValue(Workbook wb, Cell cell) {
+        if (cell == null) {
+            return null;
+        }
+
+        final String cellCoordinate = "(" + cell.getRowIndex() + "," + cell.getColumnIndex() + ")";
+
+        final String result;
+
+        switch (cell.getCellType()) {
+        case Cell.CELL_TYPE_BLANK:
+            result = null;
+            break;
+        case Cell.CELL_TYPE_BOOLEAN:
+            result = Boolean.toString(cell.getBooleanCellValue());
+            break;
+        case Cell.CELL_TYPE_ERROR:
+            String errorResult;
+            try {
+                byte errorCode = cell.getErrorCellValue();
+                FormulaError formulaError = FormulaError.forInt(errorCode);
+                errorResult = formulaError.getString();
+            } catch (RuntimeException e) {
+                logger.debug("Getting error code for {} failed!: {}", cellCoordinate, e.getMessage());
+                if (cell instanceof XSSFCell) {
+                    // hack to get error string, which is available
+                    String value = ((XSSFCell) cell).getErrorCellString();
+                    errorResult = value;
+                } else {
+                    logger.error("Couldn't handle unexpected error scenario in cell: " + cellCoordinate, e);
+                    throw e;
+                }
+            }
+            result = errorResult;
+            break;
+        case Cell.CELL_TYPE_FORMULA:
+            // result = cell.getCellFormula();
+            result = getFormulaCellValue(wb, cell);
+            break;
+        case Cell.CELL_TYPE_NUMERIC:
+            if (HSSFDateUtil.isCellDateFormatted(cell)) {
+                Date date = cell.getDateCellValue();
+                if (date == null) {
+                    result = null;
+                } else {
+                    result = DateUtils.createDateFormat().format(date);
+                }
+            } else {
+                // TODO: Consider not formatting it, but simple using
+                // Double.toString(...)
+                result = _numberFormat.format(cell.getNumericCellValue());
+            }
+            break;
+        case Cell.CELL_TYPE_STRING:
+            result = cell.getRichStringCellValue().getString();
+            break;
+        default:
+            throw new IllegalStateException("Unknown cell type: " + cell.getCellType());
+        }
+
+        logger.debug("cell {} resolved to value: {}", cellCoordinate, result);
+
+        return result;
+    }
+
+    private static String getFormulaCellValue(Workbook wb, Cell cell) {
+        // first try with a cached/precalculated value
+        try {
+            double numericCellValue = cell.getNumericCellValue();
+            // TODO: Consider not formatting it, but simple using
+            // Double.toString(...)
+            return _numberFormat.format(numericCellValue);
+        } catch (Exception e) {
+            if (logger.isInfoEnabled()) {
+                logger.info("Failed to fetch cached/precalculated formula value of cell: " + cell, e);
+            }
+        }
+
+        // evaluate cell first, if possible
+        try {
+            if (logger.isInfoEnabled()) {
+                logger.info("cell({},{}) is a formula. Attempting to evaluate: {}",
+                        new Object[] { cell.getRowIndex(), cell.getColumnIndex(), cell.getCellFormula() });
+            }
+
+            final FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
+
+            // calculates the formula and puts it's value back into the cell
+            final Cell evaluatedCell = evaluator.evaluateInCell(cell);
+
+            return getCellValue(wb, evaluatedCell);
+        } catch (RuntimeException e) {
+            logger.warn("Exception occurred while evaluating formula at position ({},{}): {}", new Object[] { cell.getRowIndex(),
+                    cell.getColumnIndex(), e.getMessage() });
+            // Some exceptions we simply log - result will be then be the
+            // actual formula
+            if (e instanceof FormulaParseException) {
+                logger.error("Parse exception occurred while evaluating cell formula: " + cell, e);
+            } else if (e instanceof IllegalArgumentException) {
+                logger.error("Illegal formula argument occurred while evaluating cell formula: " + cell, e);
+            } else {
+                logger.error("Unexpected exception occurred while evaluating cell formula: " + cell, e);
+            }
+        }
+
+        // last resort: return the string formula
+        return cell.getCellFormula();
+    }
+
+    public static Style getCellStyle(Workbook workbook, Cell cell) {
+        if (cell == null) {
+            return Style.NO_STYLE;
+        }
+        final CellStyle cellStyle = cell.getCellStyle();
+
+        final short fontIndex = cellStyle.getFontIndex();
+        final Font font = workbook.getFontAt(fontIndex);
+        final StyleBuilder styleBuilder = new StyleBuilder();
+
+        // Font bold, italic, underline
+        if (font.getBoldweight() >= Font.BOLDWEIGHT_BOLD) {
+            styleBuilder.bold();
+        }
+        if (font.getItalic()) {
+            styleBuilder.italic();
+        }
+        if (font.getUnderline() != FontUnderline.NONE.getByteValue()) {
+            styleBuilder.underline();
+        }
+
+        // Font size
+        final Font stdFont = workbook.getFontAt((short) 0);
+        final short fontSize = font.getFontHeightInPoints();
+        if (stdFont.getFontHeightInPoints() != fontSize) {
+            styleBuilder.fontSize(fontSize, SizeUnit.PT);
+        }
+
+        // Font color
+        final short colorIndex = font.getColor();
+        if (font instanceof HSSFFont) {
+            if (colorIndex != HSSFFont.COLOR_NORMAL) {
+                final HSSFWorkbook wb = (HSSFWorkbook) workbook;
+                HSSFColor color = wb.getCustomPalette().getColor(colorIndex);
+                if (color != null) {
+                    short[] triplet = color.getTriplet();
+                    styleBuilder.foreground(triplet);
+                }
+            }
+        } else if (font instanceof XSSFFont) {
+            XSSFFont xssfFont = (XSSFFont) font;
+
+            XSSFColor color = xssfFont.getXSSFColor();
+            if (color != null) {
+                String argbHex = color.getARGBHex();
+                if (argbHex != null) {
+                    styleBuilder.foreground(argbHex.substring(2));
+                }
+            }
+        } else {
+            throw new IllegalStateException("Unexpected font type: " + (font == null ? "null" : font.getClass()) + ")");
+        }
+
+        // Background color
+        if (cellStyle.getFillPattern() == 1) {
+            Color color = cellStyle.getFillForegroundColorColor();
+            if (color instanceof HSSFColor) {
+                short[] triplet = ((HSSFColor) color).getTriplet();
+                if (triplet != null) {
+                    styleBuilder.background(triplet);
+                }
+            } else if (color instanceof XSSFColor) {
+                String argb = ((XSSFColor) color).getARGBHex();
+                if (argb != null) {
+                    styleBuilder.background(argb.substring(2));
+                }
+            } else {
+                throw new IllegalStateException("Unexpected color type: " + (color == null ? "null" : color.getClass()) + ")");
+            }
+        }
+
+        // alignment
+        switch (cellStyle.getAlignment()) {
+        case CellStyle.ALIGN_LEFT:
+            styleBuilder.leftAligned();
+            break;
+        case CellStyle.ALIGN_RIGHT:
+            styleBuilder.rightAligned();
+            break;
+        case CellStyle.ALIGN_CENTER:
+            styleBuilder.centerAligned();
+            break;
+        case CellStyle.ALIGN_JUSTIFY:
+            styleBuilder.justifyAligned();
+            break;
+        }
+
+        return styleBuilder.create();
+    }
+
+    public static Iterator<Row> getRowIterator(Sheet sheet, ExcelConfiguration configuration, boolean jumpToDataRows) {
+        final Iterator<Row> iterator;
+        if (configuration.isSkipEmptyLines()) {
+            iterator = sheet.rowIterator();
+        } else {
+            iterator = new ZeroBasedRowIterator(sheet);
+        }
+
+        if (jumpToDataRows) {
+            final int columnNameLineNumber = configuration.getColumnNameLineNumber();
+            if (columnNameLineNumber != ExcelConfiguration.NO_COLUMN_NAME_LINE) {
+                // iterate past the column headers
+                if (iterator.hasNext()) {
+                    iterator.next();
+                }
+                for (int i = 1; i < columnNameLineNumber; i++) {
+                    if (iterator.hasNext()) {
+                        iterator.next();
+                    } else {
+                        // no more rows!
+                        break;
+                    }
+                }
+            }
+        }
+
+        return iterator;
+    }
+
+    /**
+     * Creates a MetaModel row based on an Excel row
+     * 
+     * @param workbook
+     * @param row
+     * @param selectItems
+     *            select items of the columns in the table
+     * @return
+     */
+    public static DefaultRow createRow(Workbook workbook, Row row, DataSetHeader header) {
+        final int size = header.size();
+        final String[] values = new String[size];
+        final Style[] styles = new Style[size];
+        if (row != null) {
+            for (int i = 0; i < size; i++) {
+                final int columnNumber = header.getSelectItem(i).getColumn().getColumnNumber();
+                final Cell cell = row.getCell(columnNumber);
+                final String value = ExcelUtils.getCellValue(workbook, cell);
+                final Style style = ExcelUtils.getCellStyle(workbook, cell);
+                values[i] = value;
+                styles[i] = style;
+            }
+        }
+
+        return new DefaultRow(header, values, styles);
+    }
+
+    public static DataSet getDataSet(Workbook workbook, Sheet sheet, Table table, ExcelConfiguration configuration) {
+        final SelectItem[] selectItems = MetaModelHelper.createSelectItems(table.getColumns());
+        final Iterator<Row> rowIterator = getRowIterator(sheet, configuration, true);
+        if (!rowIterator.hasNext()) {
+            // no more rows!
+            return new EmptyDataSet(selectItems);
+        }
+
+        final DataSet dataSet = new XlsDataSet(selectItems, workbook, rowIterator);
+        return dataSet;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/SpreadsheetReaderDelegate.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/SpreadsheetReaderDelegate.java b/excel/src/main/java/org/apache/metamodel/excel/SpreadsheetReaderDelegate.java
new file mode 100644
index 0000000..9cdbe42
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/SpreadsheetReaderDelegate.java
@@ -0,0 +1,45 @@
+/**
+ * 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 org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.schema.Schema;
+import org.eobjects.metamodel.schema.Table;
+import org.eobjects.metamodel.util.Ref;
+
+/**
+ * Delegate for spreadsheet-implementation specific operations in an
+ * {@link ExcelDataContext}.
+ * 
+ * @author Kasper Sørensen
+ */
+interface SpreadsheetReaderDelegate {
+
+	public void notifyTablesModified(Ref<InputStream> inputStreamRef);
+
+	public Schema createSchema(InputStream inputStream, String schemaName)
+			throws Exception;
+
+	public DataSet executeQuery(InputStream inputStream, Table table,
+			Column[] columns, int maxRows) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/XlsDataSet.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/XlsDataSet.java b/excel/src/main/java/org/apache/metamodel/excel/XlsDataSet.java
new file mode 100644
index 0000000..133233f
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/XlsDataSet.java
@@ -0,0 +1,78 @@
+/**
+ * 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.Workbook;
+import org.eobjects.metamodel.data.AbstractDataSet;
+import org.eobjects.metamodel.data.DataSet;
+import org.eobjects.metamodel.data.Row;
+import org.eobjects.metamodel.query.SelectItem;
+
+/**
+ * Stream {@link DataSet} implementation for Excel support.
+ * 
+ * @author Kasper Sørensen
+ */
+final class XlsDataSet extends AbstractDataSet {
+
+	private final Iterator<org.apache.poi.ss.usermodel.Row> _rowIterator;
+	private final Workbook _workbook;
+
+	private volatile org.apache.poi.ss.usermodel.Row _row;
+	private volatile boolean _closed;
+
+	/**
+	 * Creates an XLS dataset
+	 * 
+	 * @param selectItems
+	 *            the selectitems representing the columns of the table
+	 * @param workbook
+	 * @param rowIterator
+	 */
+	public XlsDataSet(SelectItem[] selectItems, Workbook workbook,
+			Iterator<org.apache.poi.ss.usermodel.Row> rowIterator) {
+	    super(selectItems);
+		_workbook = workbook;
+		_rowIterator = rowIterator;
+		_closed = false;
+	}
+
+	@Override
+	public boolean next() {
+		if (_rowIterator.hasNext()) {
+			_row = _rowIterator.next();
+			return true;
+		} else {
+			_row = null;
+			_closed = true;
+			return false;
+		}
+	}
+
+	@Override
+	public Row getRow() {
+		if (_closed) {
+			return null;
+		}
+
+		return ExcelUtils.createRow(_workbook, _row, getHeader());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/XlsxRowCallback.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/XlsxRowCallback.java b/excel/src/main/java/org/apache/metamodel/excel/XlsxRowCallback.java
new file mode 100644
index 0000000..630a512
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/XlsxRowCallback.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 java.util.List;
+
+import org.eobjects.metamodel.data.Style;
+
+/**
+ * Callback for read rows in an XLSX spreadsheet.
+ * 
+ * @author Kasper Sørensen
+ */
+interface XlsxRowCallback {
+
+	public boolean row(int rowNumber, List<String> values, List<Style> styles);
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/e2e2b37a/excel/src/main/java/org/apache/metamodel/excel/XlsxRowPublisherAction.java
----------------------------------------------------------------------
diff --git a/excel/src/main/java/org/apache/metamodel/excel/XlsxRowPublisherAction.java b/excel/src/main/java/org/apache/metamodel/excel/XlsxRowPublisherAction.java
new file mode 100644
index 0000000..85bbd58
--- /dev/null
+++ b/excel/src/main/java/org/apache/metamodel/excel/XlsxRowPublisherAction.java
@@ -0,0 +1,103 @@
+/**
+ * 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.List;
+
+import org.apache.poi.xssf.eventusermodel.XSSFReader;
+import org.eobjects.metamodel.data.RowPublisher;
+import org.eobjects.metamodel.data.Style;
+import org.eobjects.metamodel.schema.Column;
+import org.eobjects.metamodel.util.Action;
+import org.eobjects.metamodel.util.FileHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+
+class XlsxRowPublisherAction implements Action<RowPublisher> {
+
+	private static final Logger logger = LoggerFactory
+			.getLogger(XlsxRowPublisherAction.class);
+
+	private final ExcelConfiguration _configuration;
+	private final Column[] _columns;
+	private final String _relationshipId;
+	private final XSSFReader _xssfReader;
+
+	public XlsxRowPublisherAction(ExcelConfiguration configuration,
+			Column[] columns, String relationshipId, XSSFReader xssfReader) {
+		_configuration = configuration;
+		_columns = columns;
+		_relationshipId = relationshipId;
+		_xssfReader = xssfReader;
+	}
+
+	@Override
+	public void run(final RowPublisher publisher) 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) {
+				if (_configuration.getColumnNameLineNumber() != ExcelConfiguration.NO_COLUMN_NAME_LINE) {
+					final int zeroBasedLineNumber = _configuration.getColumnNameLineNumber() - 1;
+                    if (rowNumber <= zeroBasedLineNumber) {
+						// skip header rows
+						return true;
+					}
+				}
+
+				Object[] rowData = new Object[_columns.length];
+				Style[] styleData = new Style[_columns.length];
+				for (int i = 0; i < _columns.length; i++) {
+					int columnNumber = _columns[i].getColumnNumber();
+					if (columnNumber < values.size()) {
+						rowData[i] = values.get(columnNumber);
+						styleData[i] = styles.get(columnNumber);
+					} else {
+						rowData[i] = null;
+						styleData[i] = Style.NO_STYLE;
+					}
+				}
+
+				return publisher.publish(rowData, styleData);
+			}
+		};
+		final XlsxSheetToRowsHandler handler = new XlsxSheetToRowsHandler(
+				rowCallback, _xssfReader, _configuration);
+
+		final XMLReader sheetParser = ExcelUtils.createXmlReader();
+		sheetParser.setContentHandler(handler);
+		sheetParser.setErrorHandler(handler);
+		try {
+			sheetParser.parse(new InputSource(sheetData));
+		} catch (XlsxStopParsingException e) {
+			logger.debug("Parsing stop signal thrown");
+		} catch (Exception e) {
+			logger.warn("Unexpected error occurred while parsing", e);
+			throw e;
+		} finally {
+			publisher.finished();
+			FileHelper.safeClose(sheetData);
+		}
+	}
+}
\ No newline at end of file