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:57 UTC
[14/61] [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