Merge branch 'master' into 5.x
authorkaspersorensen <i.am.kasper.sorensen@gmail.com>
Mon, 16 May 2016 03:40:06 +0000 (20:40 -0700)
committerkaspersorensen <i.am.kasper.sorensen@gmail.com>
Mon, 16 May 2016 03:51:27 +0000 (20:51 -0700)
Conflicts:
CHANGES.md
cassandra/pom.xml
core/pom.xml
couchdb/pom.xml
csv/pom.xml
elasticsearch/common/pom.xml
elasticsearch/native/pom.xml
elasticsearch/native/src/main/java/org/apache/metamodel/elasticsearch/nativeclient/ElasticSearchDataContext.java
elasticsearch/pom.xml
elasticsearch/rest/pom.xml
elasticsearch/rest/src/main/java/org/apache/metamodel/elasticsearch/rest/ElasticSearchRestDataContext.java
excel/pom.xml
fixedwidth/pom.xml
full/pom.xml
hadoop/pom.xml
hbase/pom.xml
jdbc/pom.xml
json/pom.xml
mongodb/pom.xml
mongodb/src/main/java/org/apache/metamodel/mongodb/MongoDbDataContext.java
neo4j/pom.xml
openoffice/pom.xml
pojo/pom.xml
pom.xml
salesforce/pom.xml
spring/pom.xml
sugarcrm/pom.xml
xml/pom.xml

31 files changed:
1  2 
.travis.yml
CHANGES.md
core/src/main/java/org/apache/metamodel/schema/naming/AlphabeticColumnNamingStrategy.java
core/src/main/java/org/apache/metamodel/schema/naming/ColumnNamingContext.java
core/src/main/java/org/apache/metamodel/schema/naming/ColumnNamingContextImpl.java
core/src/main/java/org/apache/metamodel/schema/naming/ColumnNamingStrategies.java
core/src/main/java/org/apache/metamodel/schema/naming/ColumnNamingStrategy.java
core/src/main/java/org/apache/metamodel/schema/naming/CustomColumnNamingStrategy.java
core/src/main/java/org/apache/metamodel/schema/naming/DelegatingIntrinsicSwitchColumnNamingStrategy.java
core/src/main/java/org/apache/metamodel/schema/naming/UniqueColumnNamingStrategy.java
elasticsearch/native/src/main/java/org/apache/metamodel/elasticsearch/nativeclient/ElasticSearchDataContext.java
elasticsearch/rest/pom.xml
elasticsearch/rest/src/main/java/org/apache/metamodel/elasticsearch/rest/ElasticSearchRestDataContext.java
elasticsearch/rest/src/main/java/org/apache/metamodel/elasticsearch/rest/JestElasticSearchUpdateCallback.java
excel/src/main/java/org/apache/metamodel/excel/ExcelDataContext.java
fixedwidth/pom.xml
fixedwidth/src/main/java/org/apache/metamodel/fixedwidth/FixedWidthColumnSpec.java
fixedwidth/src/main/java/org/apache/metamodel/fixedwidth/FixedWidthConfiguration.java
fixedwidth/src/main/java/org/apache/metamodel/fixedwidth/FixedWidthConfigurationReader.java
fixedwidth/src/test/java/org/apache/metamodel/fixedwidth/FixedWidthConfigurationReaderTest.java
fixedwidth/src/test/resources/metadata_spec1/data.txt
fixedwidth/src/test/resources/metadata_spec1/sas-formatfile-metadata.txt
fixedwidth/src/test/resources/metadata_spec1/sas-input-metadata.txt
full/pom.xml
mongodb/common/pom.xml
mongodb/mongo2/pom.xml
mongodb/mongo2/src/main/java/org/apache/metamodel/mongodb/mongo2/MongoDbDataContext.java
mongodb/mongo3/pom.xml
mongodb/mongo3/src/main/java/org/apache/metamodel/mongodb/mongo3/MongoDbDataContext.java
mongodb/pom.xml
pom.xml

diff --cc .travis.yml
Simple merge
diff --cc CHANGES.md
@@@ -1,8 -1,25 +1,30 @@@
 +### Apache MetaModel 5.0
 +
 + * [METAMODEL-6] - Added update summary containing information about changes on returning UpdateableDataContext.executeUpdate(..)
 + * [METAMODEL-222] - Added support for Java 8 lambdas, removed support for Java 7.
 +
+ ### Apache MetaModel 4.5.3 (work in progress)
+  * [METAMODEL-235] - Fixed a bug related to handling of null or missing values in ElasticSearch using REST client.
+  * [METAMODEL-225] - Fixed support for nested objects and arrays in ElasticSearch using REST client.
+  * [METAMODEL-244] - Added ColumnNamingStrategies concept which allows custom column naming and column name overriding.
+  * [METAMODEL-242] - Fixed issue when de-serializing old enum-instances of FunctionType.
+  * [METAMODEL-247] - Added FixedWidthConfigurationReader for reading fixed width file metadata from external files.
+  * [METAMODEL-159] - DataContextFactory misses methods to create HBase and POJO data contexts.
+  * [METAMODEL-252] - Fixed a bug that caused JDBC updates to unnecessarily refresh schema objects.
+  * [METAMODEL-1082] - Improved performance of batch ElasticSearch operations by using bulk API.
+ ### Apache MetaModel 4.5.2
+  * [METAMODEL-236] - Made OperatorType and FunctionType Serializable to ensure that serialization of Query is possible.
+ ### Apache MetaModel 4.5.1
+  * [METAMODEL-227] - Fix for respecting CSV escape character also when no quote character is set.
+  * [METAMODEL-183] - MongoDB module split into three: common, Mongo2 and Mongo3 to allow use of either old or new MongoDB API.
+  * [METAMODEL-231] - Fixed a bug causing the Neo4j to represent the same table multiple times within a schema.
+  * [METAMODEL-228] - Fixed a bug causing Number.class to not be converted to ColumnType.NUMBER.
  ### Apache MetaModel 4.5.0
  
   * [METAMODEL-212] - New module for ElasticSearch via REST client.
index 0000000,f6575c7..34498de
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,43 +1,43 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.schema.naming;\r
 -\r
 -import org.apache.metamodel.util.AlphabeticSequence;\r
 -\r
 -public class AlphabeticColumnNamingStrategy implements ColumnNamingStrategy {\r
 -\r
 -    private static final long serialVersionUID = 1L;\r
 -\r
 -    @Override\r
 -    public ColumnNamingSession startColumnNamingSession() {\r
 -        return new ColumnNamingSession() {\r
 -            private final AlphabeticSequence seq = new AlphabeticSequence();\r
 -\r
 -            @Override\r
 -            public String getNextColumnName(ColumnNamingContext ctx) {\r
 -                return seq.next();\r
 -            }\r
 -\r
 -            @Override\r
 -            public void close() {\r
 -            }\r
 -        };\r
 -    }\r
 -\r
 -}\r
++/**
++ * 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.apache.metamodel.schema.naming;
++
++import org.apache.metamodel.util.AlphabeticSequence;
++
++public class AlphabeticColumnNamingStrategy implements ColumnNamingStrategy {
++
++    private static final long serialVersionUID = 1L;
++
++    @Override
++    public ColumnNamingSession startColumnNamingSession() {
++        return new ColumnNamingSession() {
++            private final AlphabeticSequence seq = new AlphabeticSequence();
++
++            @Override
++            public String getNextColumnName(ColumnNamingContext ctx) {
++                return seq.next();
++            }
++
++            @Override
++            public void close() {
++            }
++        };
++    }
++
++}
index 0000000,b613913..b43ad87
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,52 +1,52 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */package org.apache.metamodel.schema.naming;\r
 -\r
 -import org.apache.metamodel.schema.Table;\r
 -\r
 -/**\r
 - * Defines the context for naming a single column in a\r
 - * {@link ColumnNamingStrategy} session.\r
 - */\r
 -public interface ColumnNamingContext {\r
 -\r
 -    /**\r
 -     * Gets the index of the column being named.\r
 -     * \r
 -     * @return\r
 -     */\r
 -    public int getColumnIndex();\r
 -\r
 -    /**\r
 -     * Gets the {@link Table} that the column is to pertain to. If the table is\r
 -     * not yet available then this may return null.\r
 -     * \r
 -     * @return\r
 -     */\r
 -    public Table getTable();\r
 -\r
 -    /**\r
 -     * Gets the intrinsic column name, if this is defined in the datastore\r
 -     * itself. This may be in the form of a header or such. Sometimes intrinsic\r
 -     * column names exist only for some columns and sometimes there may be\r
 -     * duplicate names or other anomalies which are often discouraged.\r
 -     * \r
 -     * @return\r
 -     */\r
 -    public String getIntrinsicColumnName();\r
 -}\r
++/**
++ * 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.apache.metamodel.schema.naming;
++
++import org.apache.metamodel.schema.Table;
++
++/**
++ * Defines the context for naming a single column in a
++ * {@link ColumnNamingStrategy} session.
++ */
++public interface ColumnNamingContext {
++
++    /**
++     * Gets the index of the column being named.
++     * 
++     * @return
++     */
++    public int getColumnIndex();
++
++    /**
++     * Gets the {@link Table} that the column is to pertain to. If the table is
++     * not yet available then this may return null.
++     * 
++     * @return
++     */
++    public Table getTable();
++
++    /**
++     * Gets the intrinsic column name, if this is defined in the datastore
++     * itself. This may be in the form of a header or such. Sometimes intrinsic
++     * column names exist only for some columns and sometimes there may be
++     * duplicate names or other anomalies which are often discouraged.
++     * 
++     * @return
++     */
++    public String getIntrinsicColumnName();
++}
index 0000000,cc7a24e..ec77440
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,64 +1,64 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.schema.naming;\r
 -\r
 -import org.apache.metamodel.schema.Table;\r
 -\r
 -public class ColumnNamingContextImpl implements ColumnNamingContext {\r
 -\r
 -    private final int columnIndex;\r
 -    private final Table table;\r
 -    private final String intrinsicColumnName;\r
 -\r
 -    /**\r
 -     * \r
 -     * @param table\r
 -     * @param intrinsicColumnName\r
 -     * @param columnIndex\r
 -     */\r
 -    public ColumnNamingContextImpl(Table table, String intrinsicColumnName, int columnIndex) {\r
 -        this.table = table;\r
 -        this.intrinsicColumnName = intrinsicColumnName;\r
 -        this.columnIndex = columnIndex;\r
 -    }\r
 -\r
 -    /**\r
 -     * \r
 -     * @param columnIndex\r
 -     */\r
 -    public ColumnNamingContextImpl(int columnIndex) {\r
 -        this(null, null, columnIndex);\r
 -    }\r
 -\r
 -    @Override\r
 -    public int getColumnIndex() {\r
 -        return columnIndex;\r
 -    }\r
 -\r
 -    @Override\r
 -    public Table getTable() {\r
 -        return table;\r
 -    }\r
 -\r
 -    @Override\r
 -    public String getIntrinsicColumnName() {\r
 -        return intrinsicColumnName;\r
 -    }\r
 -\r
 -}\r
++/**
++ * 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.apache.metamodel.schema.naming;
++
++import org.apache.metamodel.schema.Table;
++
++public class ColumnNamingContextImpl implements ColumnNamingContext {
++
++    private final int columnIndex;
++    private final Table table;
++    private final String intrinsicColumnName;
++
++    /**
++     * 
++     * @param table
++     * @param intrinsicColumnName
++     * @param columnIndex
++     */
++    public ColumnNamingContextImpl(Table table, String intrinsicColumnName, int columnIndex) {
++        this.table = table;
++        this.intrinsicColumnName = intrinsicColumnName;
++        this.columnIndex = columnIndex;
++    }
++
++    /**
++     * 
++     * @param columnIndex
++     */
++    public ColumnNamingContextImpl(int columnIndex) {
++        this(null, null, columnIndex);
++    }
++
++    @Override
++    public int getColumnIndex() {
++        return columnIndex;
++    }
++
++    @Override
++    public Table getTable() {
++        return table;
++    }
++
++    @Override
++    public String getIntrinsicColumnName() {
++        return intrinsicColumnName;
++    }
++
++}
index 0000000,0696376..f0da83a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,45 +1,45 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.schema.naming;\r
 -\r
 -import java.util.List;\r
 -\r
 -/**\r
 - * Constructors and common utilities for {@link ColumnNamingStrategy} objects.\r
 - */\r
 -public class ColumnNamingStrategies {\r
 -\r
 -    private static final DelegatingIntrinsicSwitchColumnNamingStrategy DEFAULT_STRATEGY = new DelegatingIntrinsicSwitchColumnNamingStrategy(\r
 -            new UniqueColumnNamingStrategy(), new AlphabeticColumnNamingStrategy());\r
 -\r
 -    private ColumnNamingStrategies() {\r
 -    }\r
 -\r
 -    public static ColumnNamingStrategy defaultStrategy() {\r
 -        return DEFAULT_STRATEGY;\r
 -    }\r
 -\r
 -    public static ColumnNamingStrategy customNames(List<String> columnNames) {\r
 -        return new CustomColumnNamingStrategy(columnNames);\r
 -    }\r
 -\r
 -    public static ColumnNamingStrategy customNames(String ... columnNames) {\r
 -        return new CustomColumnNamingStrategy(columnNames);\r
 -    }\r
 -}\r
++/**
++ * 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.apache.metamodel.schema.naming;
++
++import java.util.List;
++
++/**
++ * Constructors and common utilities for {@link ColumnNamingStrategy} objects.
++ */
++public class ColumnNamingStrategies {
++
++    private static final DelegatingIntrinsicSwitchColumnNamingStrategy DEFAULT_STRATEGY = new DelegatingIntrinsicSwitchColumnNamingStrategy(
++            new UniqueColumnNamingStrategy(), new AlphabeticColumnNamingStrategy());
++
++    private ColumnNamingStrategies() {
++    }
++
++    public static ColumnNamingStrategy defaultStrategy() {
++        return DEFAULT_STRATEGY;
++    }
++
++    public static ColumnNamingStrategy customNames(List<String> columnNames) {
++        return new CustomColumnNamingStrategy(columnNames);
++    }
++
++    public static ColumnNamingStrategy customNames(String ... columnNames) {
++        return new CustomColumnNamingStrategy(columnNames);
++    }
++}
index 0000000,6ccccbf..27e85ea
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,31 +1,31 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.schema.naming;\r
 -\r
 -import java.io.Serializable;\r
 -\r
 -/**\r
 - * A strategy that defines how columns are logically named. Such strategies are\r
 - * mostly used when a particular datastore is not itself intrinsically\r
 - * specifying the column name.\r
 - */\r
 -public interface ColumnNamingStrategy extends Serializable {\r
 -    \r
 -    public ColumnNamingSession startColumnNamingSession();\r
 -}\r
++/**
++ * 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.apache.metamodel.schema.naming;
++
++import java.io.Serializable;
++
++/**
++ * A strategy that defines how columns are logically named. Such strategies are
++ * mostly used when a particular datastore is not itself intrinsically
++ * specifying the column name.
++ */
++public interface ColumnNamingStrategy extends Serializable {
++    
++    public ColumnNamingSession startColumnNamingSession();
++}
index 0000000,e6cc706..39397d7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,62 +1,62 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.schema.naming;\r
 -\r
 -import java.util.Arrays;\r
 -import java.util.Iterator;\r
 -import java.util.List;\r
 -\r
 -/**\r
 - * A {@link ColumnNamingStrategy} that allows the user to supply his own list of\r
 - * custom column names.\r
 - */\r
 -public class CustomColumnNamingStrategy implements ColumnNamingStrategy {\r
 -\r
 -    private static final long serialVersionUID = 1L;\r
 -\r
 -    private final List<String> columnNames;\r
 -\r
 -    public CustomColumnNamingStrategy(List<String> columnNames) {\r
 -        this.columnNames = columnNames;\r
 -    }\r
 -\r
 -    public CustomColumnNamingStrategy(String... columnNames) {\r
 -        this(Arrays.asList(columnNames));\r
 -    }\r
 -\r
 -    @Override\r
 -    public ColumnNamingSession startColumnNamingSession() {\r
 -        final Iterator<String> iterator = columnNames.iterator();\r
 -        return new ColumnNamingSession() {\r
 -\r
 -            @Override\r
 -            public String getNextColumnName(ColumnNamingContext ctx) {\r
 -                if (iterator.hasNext()) {\r
 -                    return iterator.next();\r
 -                }\r
 -                return null;\r
 -            }\r
 -\r
 -            @Override\r
 -            public void close() {\r
 -            }\r
 -        };\r
 -    }\r
 -\r
 -}\r
++/**
++ * 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.apache.metamodel.schema.naming;
++
++import java.util.Arrays;
++import java.util.Iterator;
++import java.util.List;
++
++/**
++ * A {@link ColumnNamingStrategy} that allows the user to supply his own list of
++ * custom column names.
++ */
++public class CustomColumnNamingStrategy implements ColumnNamingStrategy {
++
++    private static final long serialVersionUID = 1L;
++
++    private final List<String> columnNames;
++
++    public CustomColumnNamingStrategy(List<String> columnNames) {
++        this.columnNames = columnNames;
++    }
++
++    public CustomColumnNamingStrategy(String... columnNames) {
++        this(Arrays.asList(columnNames));
++    }
++
++    @Override
++    public ColumnNamingSession startColumnNamingSession() {
++        final Iterator<String> iterator = columnNames.iterator();
++        return new ColumnNamingSession() {
++
++            @Override
++            public String getNextColumnName(ColumnNamingContext ctx) {
++                if (iterator.hasNext()) {
++                    return iterator.next();
++                }
++                return null;
++            }
++
++            @Override
++            public void close() {
++            }
++        };
++    }
++
++}
index 0000000,e18cb3a..35a0f39
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,60 +1,60 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.schema.naming;\r
 -\r
 -/**\r
 - * A {@link ColumnNamingStrategy} that switches between two other\r
 - * {@link ColumnNamingStrategy} delegates depending on the availability of a\r
 - * intrinsic column name.\r
 - */\r
 -public class DelegatingIntrinsicSwitchColumnNamingStrategy implements ColumnNamingStrategy {\r
 -\r
 -    private static final long serialVersionUID = 1L;\r
 -    private final ColumnNamingStrategy intrinsicStrategy;\r
 -    private final ColumnNamingStrategy nonIntrinsicStrategy;\r
 -\r
 -    public DelegatingIntrinsicSwitchColumnNamingStrategy(ColumnNamingStrategy intrinsicStrategy,\r
 -            ColumnNamingStrategy nonIntrinsicStrategy) {\r
 -        this.intrinsicStrategy = intrinsicStrategy;\r
 -        this.nonIntrinsicStrategy = nonIntrinsicStrategy;\r
 -    }\r
 -\r
 -    @Override\r
 -    public ColumnNamingSession startColumnNamingSession() {\r
 -        final ColumnNamingSession intrinsicSession = intrinsicStrategy.startColumnNamingSession();\r
 -        final ColumnNamingSession nonIntrinsicSession = nonIntrinsicStrategy.startColumnNamingSession();\r
 -        return new ColumnNamingSession() {\r
 -\r
 -            @Override\r
 -            public String getNextColumnName(ColumnNamingContext ctx) {\r
 -                final String intrinsicColumnName = ctx.getIntrinsicColumnName();\r
 -                if (intrinsicColumnName == null || intrinsicColumnName.isEmpty()) {\r
 -                    return nonIntrinsicSession.getNextColumnName(ctx);\r
 -                }\r
 -                return intrinsicSession.getNextColumnName(ctx);\r
 -            }\r
 -\r
 -            @Override\r
 -            public void close() {\r
 -                intrinsicSession.close();\r
 -                nonIntrinsicSession.close();\r
 -            }\r
 -        };\r
 -    }\r
 -}\r
++/**
++ * 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.apache.metamodel.schema.naming;
++
++/**
++ * A {@link ColumnNamingStrategy} that switches between two other
++ * {@link ColumnNamingStrategy} delegates depending on the availability of a
++ * intrinsic column name.
++ */
++public class DelegatingIntrinsicSwitchColumnNamingStrategy implements ColumnNamingStrategy {
++
++    private static final long serialVersionUID = 1L;
++    private final ColumnNamingStrategy intrinsicStrategy;
++    private final ColumnNamingStrategy nonIntrinsicStrategy;
++
++    public DelegatingIntrinsicSwitchColumnNamingStrategy(ColumnNamingStrategy intrinsicStrategy,
++            ColumnNamingStrategy nonIntrinsicStrategy) {
++        this.intrinsicStrategy = intrinsicStrategy;
++        this.nonIntrinsicStrategy = nonIntrinsicStrategy;
++    }
++
++    @Override
++    public ColumnNamingSession startColumnNamingSession() {
++        final ColumnNamingSession intrinsicSession = intrinsicStrategy.startColumnNamingSession();
++        final ColumnNamingSession nonIntrinsicSession = nonIntrinsicStrategy.startColumnNamingSession();
++        return new ColumnNamingSession() {
++
++            @Override
++            public String getNextColumnName(ColumnNamingContext ctx) {
++                final String intrinsicColumnName = ctx.getIntrinsicColumnName();
++                if (intrinsicColumnName == null || intrinsicColumnName.isEmpty()) {
++                    return nonIntrinsicSession.getNextColumnName(ctx);
++                }
++                return intrinsicSession.getNextColumnName(ctx);
++            }
++
++            @Override
++            public void close() {
++                intrinsicSession.close();
++                nonIntrinsicSession.close();
++            }
++        };
++    }
++}
index 0000000,d4d21dd..9321998
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,62 +1,62 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.schema.naming;\r
 -\r
 -import java.util.HashSet;\r
 -import java.util.Set;\r
 -\r
 -/**\r
 - * A {@link ColumnNamingStrategy} that uses the intrinsic column names, but\r
 - * ensures that all column names are unique. When duplicate names are\r
 - * encountered a number will be appended yielding column names like "name",\r
 - * "name_2", "name_3" etc.\r
 - */\r
 -public class UniqueColumnNamingStrategy implements ColumnNamingStrategy {\r
 -\r
 -    private static final long serialVersionUID = 1L;\r
 -\r
 -    @Override\r
 -    public ColumnNamingSession startColumnNamingSession() {\r
 -        return new ColumnNamingSession() {\r
 -\r
 -            private final Set<String> names = new HashSet<>();\r
 -\r
 -            @Override\r
 -            public String getNextColumnName(ColumnNamingContext ctx) {\r
 -                final String intrinsicName = ctx.getIntrinsicColumnName();\r
 -                boolean unique = names.add(intrinsicName);\r
 -                if (unique) {\r
 -                    return intrinsicName;\r
 -                }\r
 -\r
 -                String newName = null;\r
 -                for (int i = 2; !unique; i++) {\r
 -                    newName = intrinsicName + '_' + i;\r
 -                    unique = names.add(newName);\r
 -                }\r
 -                return newName;\r
 -            }\r
 -\r
 -            @Override\r
 -            public void close() {\r
 -            }\r
 -        };\r
 -    }\r
 -\r
 -}\r
++/**
++ * 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.apache.metamodel.schema.naming;
++
++import java.util.HashSet;
++import java.util.Set;
++
++/**
++ * A {@link ColumnNamingStrategy} that uses the intrinsic column names, but
++ * ensures that all column names are unique. When duplicate names are
++ * encountered a number will be appended yielding column names like "name",
++ * "name_2", "name_3" etc.
++ */
++public class UniqueColumnNamingStrategy implements ColumnNamingStrategy {
++
++    private static final long serialVersionUID = 1L;
++
++    @Override
++    public ColumnNamingSession startColumnNamingSession() {
++        return new ColumnNamingSession() {
++
++            private final Set<String> names = new HashSet<>();
++
++            @Override
++            public String getNextColumnName(ColumnNamingContext ctx) {
++                final String intrinsicName = ctx.getIntrinsicColumnName();
++                boolean unique = names.add(intrinsicName);
++                if (unique) {
++                    return intrinsicName;
++                }
++
++                String newName = null;
++                for (int i = 2; !unique; i++) {
++                    newName = intrinsicName + '_' + i;
++                    unique = names.add(newName);
++                }
++                return newName;
++            }
++
++            @Override
++            public void close() {
++            }
++        };
++    }
++
++}
Simple merge
@@@ -358,11 -354,11 +359,12 @@@ public class ElasticSearchRestDataConte
      }
  
      @Override
 -    public void executeUpdate(UpdateScript update) {
 +    public UpdateSummary executeUpdate(UpdateScript update) {
-         final JestElasticSearchUpdateCallback callback = new JestElasticSearchUpdateCallback(this);
+         final boolean isBatch = update instanceof BatchUpdateScript;
+         final JestElasticSearchUpdateCallback callback = new JestElasticSearchUpdateCallback(this, isBatch);
          update.run(callback);
          callback.onExecuteUpdateFinished();
 +        return callback.getUpdateSummary();
      }
  
      /**
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.elasticsearch.rest;\r
 -\r
 -import java.util.List;\r
 -\r
 -import org.apache.metamodel.AbstractUpdateCallback;\r
 -import org.apache.metamodel.MetaModelException;\r
 -import org.apache.metamodel.UpdateCallback;\r
 -import org.apache.metamodel.create.TableCreationBuilder;\r
 -import org.apache.metamodel.delete.RowDeletionBuilder;\r
 -import org.apache.metamodel.drop.TableDropBuilder;\r
 -import org.apache.metamodel.insert.RowInsertionBuilder;\r
 -import org.apache.metamodel.schema.Schema;\r
 -import org.apache.metamodel.schema.Table;\r
 -import org.elasticsearch.action.bulk.BulkRequest;\r
 -import org.slf4j.Logger;\r
 -import org.slf4j.LoggerFactory;\r
 -\r
 -import io.searchbox.action.Action;\r
 -import io.searchbox.action.BulkableAction;\r
 -import io.searchbox.client.JestResult;\r
 -import io.searchbox.core.Bulk;\r
 -import io.searchbox.core.Bulk.Builder;\r
 -import io.searchbox.core.BulkResult;\r
 -import io.searchbox.core.BulkResult.BulkResultItem;\r
 -import io.searchbox.indices.Refresh;\r
 -\r
 -/**\r
 - * {@link UpdateCallback} implementation for\r
 - * {@link ElasticSearchRestDataContext}.\r
 - */\r
 -final class JestElasticSearchUpdateCallback extends AbstractUpdateCallback {\r
 -\r
 -    private static final Logger logger = LoggerFactory.getLogger(JestElasticSearchUpdateCallback.class);\r
 -\r
 -    private static final int BULK_BUFFER_SIZE = 1000;\r
 -\r
 -    private Bulk.Builder bulkBuilder;\r
 -    private int bulkActionCount = 0;\r
 -    private final boolean isBatch;\r
 -\r
 -    public JestElasticSearchUpdateCallback(ElasticSearchRestDataContext dataContext, boolean isBatch) {\r
 -        super(dataContext);\r
 -        this.isBatch = isBatch;\r
 -    }\r
 -\r
 -    private boolean isBatch() {\r
 -        return isBatch;\r
 -    }\r
 -\r
 -    @Override\r
 -    public ElasticSearchRestDataContext getDataContext() {\r
 -        return (ElasticSearchRestDataContext) super.getDataContext();\r
 -    }\r
 -\r
 -    @Override\r
 -    public TableCreationBuilder createTable(Schema schema, String name) throws IllegalArgumentException,\r
 -            IllegalStateException {\r
 -        return new JestElasticSearchCreateTableBuilder(this, schema, name);\r
 -    }\r
 -\r
 -    @Override\r
 -    public boolean isDropTableSupported() {\r
 -        return true;\r
 -    }\r
 -\r
 -    @Override\r
 -    public TableDropBuilder dropTable(Table table) throws IllegalArgumentException, IllegalStateException,\r
 -            UnsupportedOperationException {\r
 -        return new JestElasticSearchDropTableBuilder(this, table);\r
 -    }\r
 -\r
 -    @Override\r
 -    public RowInsertionBuilder insertInto(Table table) throws IllegalArgumentException, IllegalStateException,\r
 -            UnsupportedOperationException {\r
 -        return new JestElasticSearchInsertBuilder(this, table);\r
 -    }\r
 -\r
 -    @Override\r
 -    public boolean isDeleteSupported() {\r
 -        return true;\r
 -    }\r
 -\r
 -    @Override\r
 -    public RowDeletionBuilder deleteFrom(Table table) throws IllegalArgumentException, IllegalStateException,\r
 -            UnsupportedOperationException {\r
 -        return new JestElasticSearchDeleteBuilder(this, table);\r
 -    }\r
 -\r
 -    public void onExecuteUpdateFinished() {\r
 -        if (isBatch()) {\r
 -            flushBulkActions();\r
 -        }\r
 -\r
 -        final String indexName = getDataContext().getIndexName();\r
 -        final Refresh refresh = new Refresh.Builder().addIndex(indexName).build();\r
 -\r
 -        JestClientExecutor.execute(getDataContext().getElasticSearchClient(), refresh, false);\r
 -    }\r
 -\r
 -    private void flushBulkActions() {\r
 -        if (bulkBuilder == null || bulkActionCount == 0) {\r
 -            // nothing to flush\r
 -            return;\r
 -        }\r
 -        final Bulk bulk = getBulkBuilder().build();\r
 -        logger.info("Flushing {} actions to ElasticSearch index {}", bulkActionCount, getDataContext().getIndexName());\r
 -        executeBlocking(bulk);\r
 -\r
 -        bulkActionCount = 0;\r
 -        bulkBuilder = null;\r
 -    }\r
 -\r
 -    public void execute(Action<?> action) {\r
 -        if (isBatch() && action instanceof BulkableAction) {\r
 -            final Bulk.Builder bulkBuilder = getBulkBuilder();\r
 -            bulkBuilder.addAction((BulkableAction<?>) action);\r
 -            bulkActionCount++;\r
 -            if (bulkActionCount == BULK_BUFFER_SIZE) {\r
 -                flushBulkActions();\r
 -            }\r
 -        } else {\r
 -            executeBlocking(action);\r
 -        }\r
 -    }\r
 -\r
 -    private void executeBlocking(Action<?> action) {\r
 -        final JestResult result = JestClientExecutor.execute(getDataContext().getElasticSearchClient(), action);\r
 -        if (!result.isSucceeded()) {\r
 -            if (result instanceof BulkResult) {\r
 -                final List<BulkResultItem> failedItems = ((BulkResult) result).getFailedItems();\r
 -                for (int i = 0; i < failedItems.size(); i++) {\r
 -                    final BulkResultItem failedItem = failedItems.get(i);\r
 -                    logger.error("Bulk failed with item no. {} of {}: id={} op={} status={} error={}", i+1, failedItems.size(), failedItem.id, failedItem.operation, failedItem.status, failedItem.error);\r
 -                }\r
 -            }\r
 -            throw new MetaModelException(result.getResponseCode() + " - " + result.getErrorMessage());\r
 -        }\r
 -    }\r
 -\r
 -    private Builder getBulkBuilder() {\r
 -        if (bulkBuilder == null) {\r
 -            bulkBuilder = new Bulk.Builder();\r
 -            bulkBuilder.defaultIndex(getDataContext().getIndexName());\r
 -        }\r
 -        return bulkBuilder;\r
 -    }\r
 -}\r
 +/**
 + * 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.apache.metamodel.elasticsearch.rest;
 +
- import io.searchbox.indices.Refresh;
++import java.util.List;
++
 +import org.apache.metamodel.AbstractUpdateCallback;
++import org.apache.metamodel.MetaModelException;
 +import org.apache.metamodel.UpdateCallback;
 +import org.apache.metamodel.create.TableCreationBuilder;
 +import org.apache.metamodel.delete.RowDeletionBuilder;
 +import org.apache.metamodel.drop.TableDropBuilder;
 +import org.apache.metamodel.insert.RowInsertionBuilder;
 +import org.apache.metamodel.schema.Schema;
 +import org.apache.metamodel.schema.Table;
++import org.elasticsearch.action.bulk.BulkRequest;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++import io.searchbox.action.Action;
++import io.searchbox.action.BulkableAction;
++import io.searchbox.client.JestResult;
++import io.searchbox.core.Bulk;
++import io.searchbox.core.Bulk.Builder;
++import io.searchbox.core.BulkResult;
++import io.searchbox.core.BulkResult.BulkResultItem;
++import io.searchbox.indices.Refresh;
 +
 +/**
-  * {@link UpdateCallback} implementation for {@link ElasticSearchRestDataContext}.
++ * {@link UpdateCallback} implementation for
++ * {@link ElasticSearchRestDataContext}.
 + */
 +final class JestElasticSearchUpdateCallback extends AbstractUpdateCallback {
-     public JestElasticSearchUpdateCallback(ElasticSearchRestDataContext dataContext) {
++
++    private static final Logger logger = LoggerFactory.getLogger(JestElasticSearchUpdateCallback.class);
++
++    private static final int BULK_BUFFER_SIZE = 1000;
++
++    private Bulk.Builder bulkBuilder;
++    private int bulkActionCount = 0;
++    private final boolean isBatch;
++
++    public JestElasticSearchUpdateCallback(ElasticSearchRestDataContext dataContext, boolean isBatch) {
 +        super(dataContext);
++        this.isBatch = isBatch;
++    }
++
++    private boolean isBatch() {
++        return isBatch;
 +    }
 +
 +    @Override
 +    public ElasticSearchRestDataContext getDataContext() {
 +        return (ElasticSearchRestDataContext) super.getDataContext();
 +    }
 +
 +    @Override
 +    public TableCreationBuilder createTable(Schema schema, String name) throws IllegalArgumentException,
 +            IllegalStateException {
 +        return new JestElasticSearchCreateTableBuilder(this, schema, name);
 +    }
 +
 +    @Override
 +    public boolean isDropTableSupported() {
 +        return true;
 +    }
 +
 +    @Override
 +    public TableDropBuilder dropTable(Table table) throws IllegalArgumentException, IllegalStateException,
 +            UnsupportedOperationException {
 +        return new JestElasticSearchDropTableBuilder(this, table);
 +    }
 +
 +    @Override
 +    public RowInsertionBuilder insertInto(Table table) throws IllegalArgumentException, IllegalStateException,
 +            UnsupportedOperationException {
 +        return new JestElasticSearchInsertBuilder(this, table);
 +    }
 +
 +    @Override
 +    public boolean isDeleteSupported() {
 +        return true;
 +    }
 +
 +    @Override
 +    public RowDeletionBuilder deleteFrom(Table table) throws IllegalArgumentException, IllegalStateException,
 +            UnsupportedOperationException {
 +        return new JestElasticSearchDeleteBuilder(this, table);
 +    }
 +
 +    public void onExecuteUpdateFinished() {
++        if (isBatch()) {
++            flushBulkActions();
++        }
++
 +        final String indexName = getDataContext().getIndexName();
-         Refresh refresh = new Refresh.Builder().addIndex(indexName).build();
++        final Refresh refresh = new Refresh.Builder().addIndex(indexName).build();
 +
 +        JestClientExecutor.execute(getDataContext().getElasticSearchClient(), refresh, false);
 +    }
++
++    private void flushBulkActions() {
++        if (bulkBuilder == null || bulkActionCount == 0) {
++            // nothing to flush
++            return;
++        }
++        final Bulk bulk = getBulkBuilder().build();
++        logger.info("Flushing {} actions to ElasticSearch index {}", bulkActionCount, getDataContext().getIndexName());
++        executeBlocking(bulk);
++
++        bulkActionCount = 0;
++        bulkBuilder = null;
++    }
++
++    public void execute(Action<?> action) {
++        if (isBatch() && action instanceof BulkableAction) {
++            final Bulk.Builder bulkBuilder = getBulkBuilder();
++            bulkBuilder.addAction((BulkableAction<?>) action);
++            bulkActionCount++;
++            if (bulkActionCount == BULK_BUFFER_SIZE) {
++                flushBulkActions();
++            }
++        } else {
++            executeBlocking(action);
++        }
++    }
++
++    private void executeBlocking(Action<?> action) {
++        final JestResult result = JestClientExecutor.execute(getDataContext().getElasticSearchClient(), action);
++        if (!result.isSucceeded()) {
++            if (result instanceof BulkResult) {
++                final List<BulkResultItem> failedItems = ((BulkResult) result).getFailedItems();
++                for (int i = 0; i < failedItems.size(); i++) {
++                    final BulkResultItem failedItem = failedItems.get(i);
++                    logger.error("Bulk failed with item no. {} of {}: id={} op={} status={} error={}", i+1, failedItems.size(), failedItem.id, failedItem.operation, failedItem.status, failedItem.error);
++                }
++            }
++            throw new MetaModelException(result.getResponseCode() + " - " + result.getErrorMessage());
++        }
++    }
++
++    private Builder getBulkBuilder() {
++        if (bulkBuilder == null) {
++            bulkBuilder = new Bulk.Builder();
++            bulkBuilder.defaultIndex(getDataContext().getIndexName());
++        }
++        return bulkBuilder;
++    }
 +}
@@@ -1,46 -1,52 +1,52 @@@
 -<?xml version="1.0" encoding="UTF-8" ?>\r
 -<!--\r
 -Licensed to the Apache Software Foundation (ASF) under one\r
 -or more contributor license agreements.  See the NOTICE file\r
 -distributed with this work for additional information\r
 -regarding copyright ownership.  The ASF licenses this file\r
 -to you under the Apache License, Version 2.0 (the\r
 -"License"); you may not use this file except in compliance\r
 -with the License.  You may obtain a copy of the License at\r
 -\r
 -  http://www.apache.org/licenses/LICENSE-2.0\r
 -\r
 -Unless required by applicable law or agreed to in writing,\r
 -software distributed under the License is distributed on an\r
 -"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 -KIND, either express or implied.  See the License for the\r
 -specific language governing permissions and limitations\r
 -under the License.\r
 --->\r
 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">\r
 -      <parent>\r
 -              <artifactId>MetaModel</artifactId>\r
 -              <groupId>org.apache.metamodel</groupId>\r
 -              <version>4.5.3-SNAPSHOT</version>\r
 -      </parent>\r
 -      <modelVersion>4.0.0</modelVersion>\r
 -      <artifactId>MetaModel-fixedwidth</artifactId>\r
 -      <name>MetaModel module for fixed width value files</name>\r
 -      <dependencies>\r
 -              <dependency>\r
 -                      <groupId>org.apache.metamodel</groupId>\r
 -                      <artifactId>MetaModel-core</artifactId>\r
 -                      <version>${project.version}</version>\r
 -              </dependency>\r
 -              <dependency>\r
 -                      <groupId>org.apache.metamodel</groupId>\r
 -                      <artifactId>MetaModel-csv</artifactId>\r
 -                      <version>${project.version}</version>\r
 -                      <optional>true</optional>\r
 -              </dependency>\r
 -              <dependency>\r
 -                      <groupId>org.slf4j</groupId>\r
 -                      <artifactId>slf4j-nop</artifactId>\r
 -                      <scope>test</scope>\r
 -              </dependency>\r
 -              <dependency>\r
 -                      <groupId>junit</groupId>\r
 -                      <artifactId>junit</artifactId>\r
 -                      <scope>test</scope>\r
 -              </dependency>\r
 -      </dependencies>\r
 -</project>\r
 +<?xml version="1.0" encoding="UTF-8" ?>
 +<!--
 +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.
 +-->
 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 +      <parent>
 +              <artifactId>MetaModel</artifactId>
 +              <groupId>org.apache.metamodel</groupId>
 +              <version>5.0-SNAPSHOT</version>
 +      </parent>
 +      <modelVersion>4.0.0</modelVersion>
 +      <artifactId>MetaModel-fixedwidth</artifactId>
 +      <name>MetaModel module for fixed width value files</name>
 +      <dependencies>
 +              <dependency>
 +                      <groupId>org.apache.metamodel</groupId>
 +                      <artifactId>MetaModel-core</artifactId>
 +                      <version>${project.version}</version>
 +              </dependency>
++        <dependency>
++      <groupId>org.apache.metamodel</groupId>
++      <artifactId>MetaModel-csv</artifactId>
++      <version>${project.version}</version>
++      <optional>true</optional>
++    </dependency>
 +              <dependency>
 +                      <groupId>org.slf4j</groupId>
 +                      <artifactId>slf4j-nop</artifactId>
 +                      <scope>test</scope>
 +              </dependency>
 +              <dependency>
 +                      <groupId>junit</groupId>
 +                      <artifactId>junit</artifactId>
 +                      <scope>test</scope>
 +              </dependency>
 +      </dependencies>
 +</project>
index 0000000,65ec219..f9d62df
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,45 +1,45 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.fixedwidth;\r
 -\r
 -import org.apache.metamodel.util.HasName;\r
 -\r
 -/**\r
 - * Represents the specification of a single column for a\r
 - * {@link FixedWidthDataContext}.\r
 - */\r
 -public final class FixedWidthColumnSpec implements HasName {\r
 -\r
 -    private final String name;\r
 -    private final int width;\r
 -\r
 -    public FixedWidthColumnSpec(String name, int width) {\r
 -        this.name = name;\r
 -        this.width = width;\r
 -    }\r
 -\r
 -    @Override\r
 -    public String getName() {\r
 -        return name;\r
 -    }\r
 -\r
 -    public int getWidth() {\r
 -        return width;\r
 -    }\r
 -}\r
++/**
++ * 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.apache.metamodel.fixedwidth;
++
++import org.apache.metamodel.util.HasName;
++
++/**
++ * Represents the specification of a single column for a
++ * {@link FixedWidthDataContext}.
++ */
++public final class FixedWidthColumnSpec implements HasName {
++
++    private final String name;
++    private final int width;
++
++    public FixedWidthColumnSpec(String name, int width) {
++        this.name = name;
++        this.width = width;
++    }
++
++    @Override
++    public String getName() {
++        return name;
++    }
++
++    public int getWidth() {
++        return width;
++    }
++}
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.fixedwidth;\r
 -\r
 -import java.io.Serializable;\r
 -import java.util.Arrays;\r
 -import java.util.List;\r
 -\r
 -import org.apache.metamodel.data.DataSet;\r
 -import org.apache.metamodel.schema.naming.ColumnNamingStrategies;\r
 -import org.apache.metamodel.schema.naming.ColumnNamingStrategy;\r
 -import org.apache.metamodel.util.BaseObject;\r
 -import org.apache.metamodel.util.CollectionUtils;\r
 -import org.apache.metamodel.util.FileHelper;\r
 -import org.apache.metamodel.util.HasNameMapper;\r
 -\r
 -/**\r
 - * Configuration of metadata about a fixed width values datacontext.\r
 - */\r
 -public final class FixedWidthConfiguration extends BaseObject implements\r
 -              Serializable {\r
 -\r
 -      private static final long serialVersionUID = 1L;\r
 -\r
 -      public static final int NO_COLUMN_NAME_LINE = 0;\r
 -      public static final int DEFAULT_COLUMN_NAME_LINE = 1;\r
 -\r
 -      private final String encoding;\r
 -      private final int fixedValueWidth;\r
 -      private final int[] valueWidths;\r
 -      private final int columnNameLineNumber;\r
 -      private final boolean failOnInconsistentLineWidth;\r
 -      private final ColumnNamingStrategy columnNamingStrategy;\r
 -\r
 -      public FixedWidthConfiguration(int fixedValueWidth) {\r
 -              this(DEFAULT_COLUMN_NAME_LINE, FileHelper.DEFAULT_ENCODING,\r
 -                              fixedValueWidth);\r
 -      }\r
 -\r
 -      public FixedWidthConfiguration(int[] valueWidth) {\r
 -              this(DEFAULT_COLUMN_NAME_LINE, FileHelper.DEFAULT_ENCODING, valueWidth,\r
 -                              false);\r
 -      }\r
 -\r
 -    public FixedWidthConfiguration(int columnNameLineNumber, String encoding, int fixedValueWidth) {\r
 -        this(columnNameLineNumber, encoding, fixedValueWidth, false);\r
 -    }\r
 -\r
 -    public FixedWidthConfiguration(int columnNameLineNumber, String encoding, int fixedValueWidth,\r
 -            boolean failOnInconsistentLineWidth) {\r
 -        this.encoding = encoding;\r
 -        this.fixedValueWidth = fixedValueWidth;\r
 -        this.columnNameLineNumber = columnNameLineNumber;\r
 -        this.failOnInconsistentLineWidth = failOnInconsistentLineWidth;\r
 -        this.columnNamingStrategy = null;\r
 -        this.valueWidths = new int[0];\r
 -    }\r
 -\r
 -    public FixedWidthConfiguration(int columnNameLineNumber, String encoding,\r
 -            int[] valueWidths, boolean failOnInconsistentLineWidth) {\r
 -        this(columnNameLineNumber, null, encoding, valueWidths, failOnInconsistentLineWidth);\r
 -    }\r
 -    \r
 -    public FixedWidthConfiguration(int columnNameLineNumber, ColumnNamingStrategy columnNamingStrategy, String encoding,\r
 -            int[] valueWidths, boolean failOnInconsistentLineWidth) {\r
 -        this.encoding = encoding;\r
 -        this.fixedValueWidth = -1;\r
 -        this.columnNameLineNumber = columnNameLineNumber;\r
 -        this.failOnInconsistentLineWidth = failOnInconsistentLineWidth;\r
 -        this.columnNamingStrategy = columnNamingStrategy;\r
 -        this.valueWidths = valueWidths;\r
 -    }\r
 -    \r
 -    public FixedWidthConfiguration(String encoding, List<FixedWidthColumnSpec> columnSpecs) {\r
 -        this(encoding, columnSpecs, false);\r
 -    }\r
 -\r
 -    public FixedWidthConfiguration(String encoding, List<FixedWidthColumnSpec> columnSpecs,\r
 -            boolean failOnInconsistentLineWidth) {\r
 -        this.encoding = encoding;\r
 -        this.fixedValueWidth = -1;\r
 -        this.columnNameLineNumber = NO_COLUMN_NAME_LINE;\r
 -        this.columnNamingStrategy = ColumnNamingStrategies.customNames(CollectionUtils.map(columnSpecs,\r
 -                new HasNameMapper()));\r
 -        this.valueWidths = new int[columnSpecs.size()];\r
 -        for (int i = 0; i < valueWidths.length; i++) {\r
 -            valueWidths[i] = columnSpecs.get(i).getWidth();\r
 -        }\r
 -        this.failOnInconsistentLineWidth = failOnInconsistentLineWidth;\r
 -    }\r
 -\r
 -    /**\r
 -       * The line number (1 based) from which to get the names of the columns.\r
 -       * \r
 -       * @return an int representing the line number of the column headers/names.\r
 -       */\r
 -      public int getColumnNameLineNumber() {\r
 -              return columnNameLineNumber;\r
 -      }\r
 -      \r
 -      /**\r
 -       * Gets a {@link ColumnNamingStrategy} to use if needed.\r
 -       * @return\r
 -       */\r
 -      public ColumnNamingStrategy getColumnNamingStrategy() {\r
 -          if (columnNamingStrategy == null) {\r
 -              return ColumnNamingStrategies.defaultStrategy();\r
 -          }\r
 -        return columnNamingStrategy;\r
 -    }\r
 -\r
 -      /**\r
 -       * Gets the file encoding to use for reading the file.\r
 -       * \r
 -       * @return the text encoding to use for reading the file.\r
 -       */\r
 -      public String getEncoding() {\r
 -              return encoding;\r
 -      }\r
 -\r
 -      /**\r
 -       * Gets the width of each value within the fixed width value file.\r
 -       * \r
 -       * @return the fixed width to use when parsing the file.\r
 -       */\r
 -      public int getFixedValueWidth() {\r
 -              return fixedValueWidth;\r
 -      }\r
 -\r
 -      public int[] getValueWidths() {\r
 -              return valueWidths;\r
 -      }\r
 -\r
 -      /**\r
 -       * Determines if the {@link DataSet#next()} should throw an exception in\r
 -       * case of inconsistent line width in the fixed width value file.\r
 -       * \r
 -       * @return a boolean indicating whether or not to fail on inconsistent line\r
 -       *         widths.\r
 -       */\r
 -      public boolean isFailOnInconsistentLineWidth() {\r
 -              return failOnInconsistentLineWidth;\r
 -      }\r
 -\r
 -      @Override\r
 -      protected void decorateIdentity(List<Object> identifiers) {\r
 -              identifiers.add(columnNameLineNumber);\r
 -              identifiers.add(encoding);\r
 -              identifiers.add(fixedValueWidth);\r
 -              identifiers.add(valueWidths);\r
 -              identifiers.add(failOnInconsistentLineWidth);\r
 -      }\r
 -\r
 -      @Override\r
 -      public String toString() {\r
 -              return "FixedWidthConfiguration[encoding=" + encoding\r
 -                              + ", fixedValueWidth=" + fixedValueWidth + ", valueWidths="\r
 -                              + Arrays.toString(valueWidths) + ", columnNameLineNumber="\r
 -                              + columnNameLineNumber + ", failOnInconsistentLineWidth="\r
 -                              + failOnInconsistentLineWidth + "]";\r
 -      }\r
 -\r
 -      public boolean isConstantValueWidth() {\r
 -              return fixedValueWidth != -1;\r
 -      }\r
 -\r
 -      public int getValueWidth(int columnIndex) {\r
 -              if (isConstantValueWidth()) {\r
 -                      return fixedValueWidth;\r
 -              }\r
 -              return valueWidths[columnIndex];\r
 -      }\r
 -}\r
 +/**
 + * 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.apache.metamodel.fixedwidth;
 +
 +import java.io.Serializable;
 +import java.util.Arrays;
 +import java.util.List;
 +
 +import org.apache.metamodel.data.DataSet;
++import org.apache.metamodel.schema.naming.ColumnNamingStrategies;
++import org.apache.metamodel.schema.naming.ColumnNamingStrategy;
 +import org.apache.metamodel.util.BaseObject;
++import org.apache.metamodel.util.CollectionUtils;
 +import org.apache.metamodel.util.FileHelper;
++import org.apache.metamodel.util.HasNameMapper;
 +
 +/**
 + * Configuration of metadata about a fixed width values datacontext.
 + */
 +public final class FixedWidthConfiguration 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 String encoding;
 +      private final int fixedValueWidth;
 +      private final int[] valueWidths;
 +      private final int columnNameLineNumber;
 +      private final boolean failOnInconsistentLineWidth;
++      private final ColumnNamingStrategy columnNamingStrategy;
 +
 +      public FixedWidthConfiguration(int fixedValueWidth) {
 +              this(DEFAULT_COLUMN_NAME_LINE, FileHelper.DEFAULT_ENCODING,
 +                              fixedValueWidth);
 +      }
 +
 +      public FixedWidthConfiguration(int[] valueWidth) {
 +              this(DEFAULT_COLUMN_NAME_LINE, FileHelper.DEFAULT_ENCODING, valueWidth,
 +                              false);
 +      }
 +
-       public FixedWidthConfiguration(int columnNameLineNumber, String encoding,
-                       int fixedValueWidth) {
-               this(columnNameLineNumber, encoding, fixedValueWidth, false);
-       }
-       public FixedWidthConfiguration(int columnNameLineNumber, String encoding,
-                       int fixedValueWidth, boolean failOnInconsistentLineWidth) {
-               this.encoding = encoding;
-               this.fixedValueWidth = fixedValueWidth;
-               this.columnNameLineNumber = columnNameLineNumber;
-               this.failOnInconsistentLineWidth = failOnInconsistentLineWidth;
-               this.valueWidths = new int[0];
-       }
-       public FixedWidthConfiguration(int columnNameLineNumber, String encoding,
-                       int[] valueWidths, boolean failOnInconsistentLineWidth) {
-               this.encoding = encoding;
-               this.fixedValueWidth = -1;
-               this.columnNameLineNumber = columnNameLineNumber;
-               this.failOnInconsistentLineWidth = failOnInconsistentLineWidth;
-               this.valueWidths = valueWidths;
-       }
-       /**
++    public FixedWidthConfiguration(int columnNameLineNumber, String encoding, int fixedValueWidth) {
++        this(columnNameLineNumber, encoding, fixedValueWidth, false);
++    }
++
++    public FixedWidthConfiguration(int columnNameLineNumber, String encoding, int fixedValueWidth,
++            boolean failOnInconsistentLineWidth) {
++        this.encoding = encoding;
++        this.fixedValueWidth = fixedValueWidth;
++        this.columnNameLineNumber = columnNameLineNumber;
++        this.failOnInconsistentLineWidth = failOnInconsistentLineWidth;
++        this.columnNamingStrategy = null;
++        this.valueWidths = new int[0];
++    }
++
++    public FixedWidthConfiguration(int columnNameLineNumber, String encoding,
++            int[] valueWidths, boolean failOnInconsistentLineWidth) {
++        this(columnNameLineNumber, null, encoding, valueWidths, failOnInconsistentLineWidth);
++    }
++    
++    public FixedWidthConfiguration(int columnNameLineNumber, ColumnNamingStrategy columnNamingStrategy, String encoding,
++            int[] valueWidths, boolean failOnInconsistentLineWidth) {
++        this.encoding = encoding;
++        this.fixedValueWidth = -1;
++        this.columnNameLineNumber = columnNameLineNumber;
++        this.failOnInconsistentLineWidth = failOnInconsistentLineWidth;
++        this.columnNamingStrategy = columnNamingStrategy;
++        this.valueWidths = valueWidths;
++    }
++    
++    public FixedWidthConfiguration(String encoding, List<FixedWidthColumnSpec> columnSpecs) {
++        this(encoding, columnSpecs, false);
++    }
++
++    public FixedWidthConfiguration(String encoding, List<FixedWidthColumnSpec> columnSpecs,
++            boolean failOnInconsistentLineWidth) {
++        this.encoding = encoding;
++        this.fixedValueWidth = -1;
++        this.columnNameLineNumber = NO_COLUMN_NAME_LINE;
++        this.columnNamingStrategy = ColumnNamingStrategies.customNames(CollectionUtils.map(columnSpecs,
++                new HasNameMapper()));
++        this.valueWidths = new int[columnSpecs.size()];
++        for (int i = 0; i < valueWidths.length; i++) {
++            valueWidths[i] = columnSpecs.get(i).getWidth();
++        }
++        this.failOnInconsistentLineWidth = failOnInconsistentLineWidth;
++    }
++
++    /**
 +       * The line number (1 based) from which to get the names of the columns.
 +       * 
 +       * @return an int representing the line number of the column headers/names.
 +       */
 +      public int getColumnNameLineNumber() {
 +              return columnNameLineNumber;
 +      }
++      
++      /**
++       * Gets a {@link ColumnNamingStrategy} to use if needed.
++       * @return
++       */
++      public ColumnNamingStrategy getColumnNamingStrategy() {
++          if (columnNamingStrategy == null) {
++              return ColumnNamingStrategies.defaultStrategy();
++          }
++        return columnNamingStrategy;
++    }
 +
 +      /**
 +       * Gets the file encoding to use for reading the file.
 +       * 
 +       * @return the text encoding to use for reading the file.
 +       */
 +      public String getEncoding() {
 +              return encoding;
 +      }
 +
 +      /**
 +       * Gets the width of each value within the fixed width value file.
 +       * 
 +       * @return the fixed width to use when parsing the file.
 +       */
 +      public int getFixedValueWidth() {
 +              return fixedValueWidth;
 +      }
 +
 +      public int[] getValueWidths() {
 +              return valueWidths;
 +      }
 +
 +      /**
 +       * Determines if the {@link DataSet#next()} should throw an exception in
 +       * case of inconsistent line width in the fixed width value file.
 +       * 
 +       * @return a boolean indicating whether or not to fail on inconsistent line
 +       *         widths.
 +       */
 +      public boolean isFailOnInconsistentLineWidth() {
 +              return failOnInconsistentLineWidth;
 +      }
 +
 +      @Override
 +      protected void decorateIdentity(List<Object> identifiers) {
 +              identifiers.add(columnNameLineNumber);
 +              identifiers.add(encoding);
 +              identifiers.add(fixedValueWidth);
 +              identifiers.add(valueWidths);
 +              identifiers.add(failOnInconsistentLineWidth);
 +      }
 +
 +      @Override
 +      public String toString() {
 +              return "FixedWidthConfiguration[encoding=" + encoding
 +                              + ", fixedValueWidth=" + fixedValueWidth + ", valueWidths="
 +                              + Arrays.toString(valueWidths) + ", columnNameLineNumber="
 +                              + columnNameLineNumber + ", failOnInconsistentLineWidth="
 +                              + failOnInconsistentLineWidth + "]";
 +      }
 +
 +      public boolean isConstantValueWidth() {
 +              return fixedValueWidth != -1;
 +      }
 +
 +      public int getValueWidth(int columnIndex) {
 +              if (isConstantValueWidth()) {
 +                      return fixedValueWidth;
 +              }
 +              return valueWidths[columnIndex];
 +      }
 +}
index 0000000,9154e5e..3c8d14c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,180 +1,180 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.fixedwidth;\r
 -\r
 -import java.io.BufferedReader;\r
 -import java.io.InputStream;\r
 -import java.io.InputStreamReader;\r
 -import java.util.ArrayList;\r
 -import java.util.HashMap;\r
 -import java.util.LinkedHashMap;\r
 -import java.util.List;\r
 -import java.util.Map;\r
 -import java.util.Map.Entry;\r
 -import java.util.regex.Matcher;\r
 -import java.util.regex.Pattern;\r
 -\r
 -import org.apache.metamodel.csv.CsvConfiguration;\r
 -import org.apache.metamodel.csv.CsvDataContext;\r
 -import org.apache.metamodel.data.DataSet;\r
 -import org.apache.metamodel.schema.Table;\r
 -import org.apache.metamodel.util.Action;\r
 -import org.apache.metamodel.util.Resource;\r
 -import org.slf4j.Logger;\r
 -import org.slf4j.LoggerFactory;\r
 -\r
 -/**\r
 - * Object capable of reading fixed width metadata from external sources and\r
 - * thereby producing an appropriate {@link FixedWidthConfiguration} to use with\r
 - * a {@link FixedWidthDataContext}.\r
 - */\r
 -public class FixedWidthConfigurationReader {\r
 -\r
 -    private static final Logger logger = LoggerFactory.getLogger(FixedWidthConfigurationReader.class);\r
 -\r
 -    // example: @1 COL1 $char1.\r
 -    private final Pattern PATTERN_SAS_INPUT_LINE = Pattern.compile("\\@(\\d+) (.+) .*?(\\d+)\\.");\r
 -\r
 -    // example: COL1 "Record type"\r
 -    private final Pattern PATTERN_SAS_LABEL_LINE = Pattern.compile("(.+) \\\"(.+)\\\"");\r
 -\r
 -    /**\r
 -     * Reads a {@link FixedWidthConfiguration} based on a SAS 'format file',\r
 -     * <a href=\r
 -     * "http://support.sas.com/documentation/cdl/en/etlug/67323/HTML/default/viewer.htm#p0h03yig7fp1qan1arghp3lwjqi6.htm">\r
 -     * described here</a>.\r
 -     * \r
 -     * @param encoding\r
 -     * @param resource\r
 -     *            the format file resource\r
 -     * @param failOnInconsistentLineWidth\r
 -     * @return a {@link FixedWidthConfiguration} object to use\r
 -     */\r
 -    public FixedWidthConfiguration readFromSasFormatFile(String encoding, Resource resource,\r
 -            boolean failOnInconsistentLineWidth) {\r
 -        final List<FixedWidthColumnSpec> columnSpecs = new ArrayList<>();\r
 -\r
 -        final CsvDataContext dataContext = new CsvDataContext(resource, new CsvConfiguration());\r
 -        final Table table = dataContext.getDefaultSchema().getTable(0);\r
 -        try (final DataSet dataSet = dataContext.query().from(table).select("Name", "BeginPosition", "EndPosition")\r
 -                .execute()) {\r
 -            while (dataSet.next()) {\r
 -                final String name = (String) dataSet.getRow().getValue(0);\r
 -                final int beginPosition = Integer.parseInt((String) dataSet.getRow().getValue(1));\r
 -                final int endPosition = Integer.parseInt((String) dataSet.getRow().getValue(2));\r
 -                final int width = 1 + endPosition - beginPosition;\r
 -                columnSpecs.add(new FixedWidthColumnSpec(name, width));\r
 -            }\r
 -        }\r
 -\r
 -        return new FixedWidthConfiguration(encoding, columnSpecs, failOnInconsistentLineWidth);\r
 -    }\r
 -\r
 -    /**\r
 -     * Reads a {@link FixedWidthConfiguration} based on a SAS INPUT declaration.\r
 -     * The reader method also optionally will look for a LABEL defintion for\r
 -     * column naming.\r
 -     * \r
 -     * @param encoding\r
 -     * @param resource\r
 -     *            the format file resource\r
 -     * @param failOnInconsistentLineWidth\r
 -     * @return a {@link FixedWidthConfiguration} object to use\r
 -     */\r
 -    public FixedWidthConfiguration readFromSasInputDefinition(String encoding, Resource resource,\r
 -            boolean failOnInconsistentLineWidth) {\r
 -\r
 -        final Map<String, Integer> inputWidthDeclarations = new LinkedHashMap<>();\r
 -        final Map<String, String> labelDeclarations = new HashMap<>();\r
 -\r
 -        resource.read(new Action<InputStream>() {\r
 -\r
 -            private boolean inInputSection = false;\r
 -            private boolean inLabelSection = false;\r
 -\r
 -            @Override\r
 -            public void run(InputStream in) throws Exception {\r
 -                try (final BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {\r
 -                    for (String line = reader.readLine(); line != null; line = reader.readLine()) {\r
 -                        processLine(line);\r
 -                    }\r
 -                }\r
 -            }\r
 -\r
 -            private void processLine(String line) {\r
 -                line = line.trim();\r
 -                if (line.isEmpty()) {\r
 -                    return;\r
 -                }\r
 -                if (";".equals(line)) {\r
 -                    inInputSection = false;\r
 -                    inLabelSection = false;\r
 -                    return;\r
 -                } else if ("INPUT".equals(line)) {\r
 -                    inInputSection = true;\r
 -                    return;\r
 -                } else if ("LABEL".equals(line)) {\r
 -                    inLabelSection = true;\r
 -                    return;\r
 -                }\r
 -\r
 -                if (inInputSection) {\r
 -                    final Matcher matcher = PATTERN_SAS_INPUT_LINE.matcher(line);\r
 -                    if (matcher.matches()) {\r
 -                        final String positionSpec = matcher.group(1);\r
 -                        final String nameSpec = matcher.group(2);\r
 -                        final int width = Integer.parseInt(matcher.group(3));\r
 -                        logger.debug("Parsed INPUT line \"{}\": position={}, name={}, width={}", line, positionSpec,\r
 -                                nameSpec, width);\r
 -                        inputWidthDeclarations.put(nameSpec, width);\r
 -                    } else {\r
 -                        logger.debug("Failed to parse/recognize INPUT line \"{}\"", line);\r
 -                    }\r
 -                } else if (inLabelSection) {\r
 -                    final Matcher matcher = PATTERN_SAS_LABEL_LINE.matcher(line);\r
 -                    if (matcher.matches()) {\r
 -                        final String nameSpec = matcher.group(1);\r
 -                        final String labelSpec = matcher.group(2);\r
 -                        logger.debug("Parsed LABEL line \"{}\": name={}, label={}", line, nameSpec, labelSpec);\r
 -                        labelDeclarations.put(nameSpec, labelSpec);\r
 -                    } else {\r
 -                        logger.debug("Failed to parse/recognize LABEL line \"{}\"", line);\r
 -                    }\r
 -                }\r
 -\r
 -                if (line.endsWith(";")) {\r
 -                    inInputSection = false;\r
 -                    inLabelSection = false;\r
 -                }\r
 -            }\r
 -        });\r
 -\r
 -        final List<FixedWidthColumnSpec> columnSpecs = new ArrayList<>();\r
 -        for (Entry<String, Integer> entry : inputWidthDeclarations.entrySet()) {\r
 -            final String columnKey = entry.getKey();\r
 -            final Integer columnWidth = entry.getValue();\r
 -            final String columnLabel = labelDeclarations.get(columnKey);\r
 -            final String columnName = columnLabel == null ? columnKey : columnLabel;\r
 -            columnSpecs.add(new FixedWidthColumnSpec(columnName, columnWidth));\r
 -        }\r
 -\r
 -        return new FixedWidthConfiguration(encoding, columnSpecs, failOnInconsistentLineWidth);\r
 -    }\r
 -\r
 -}\r
++/**
++ * 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.apache.metamodel.fixedwidth;
++
++import java.io.BufferedReader;
++import java.io.InputStream;
++import java.io.InputStreamReader;
++import java.util.ArrayList;
++import java.util.HashMap;
++import java.util.LinkedHashMap;
++import java.util.List;
++import java.util.Map;
++import java.util.Map.Entry;
++import java.util.regex.Matcher;
++import java.util.regex.Pattern;
++
++import org.apache.metamodel.csv.CsvConfiguration;
++import org.apache.metamodel.csv.CsvDataContext;
++import org.apache.metamodel.data.DataSet;
++import org.apache.metamodel.schema.Table;
++import org.apache.metamodel.util.Action;
++import org.apache.metamodel.util.Resource;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++/**
++ * Object capable of reading fixed width metadata from external sources and
++ * thereby producing an appropriate {@link FixedWidthConfiguration} to use with
++ * a {@link FixedWidthDataContext}.
++ */
++public class FixedWidthConfigurationReader {
++
++    private static final Logger logger = LoggerFactory.getLogger(FixedWidthConfigurationReader.class);
++
++    // example: @1 COL1 $char1.
++    private final Pattern PATTERN_SAS_INPUT_LINE = Pattern.compile("\\@(\\d+) (.+) .*?(\\d+)\\.");
++
++    // example: COL1 "Record type"
++    private final Pattern PATTERN_SAS_LABEL_LINE = Pattern.compile("(.+) \\\"(.+)\\\"");
++
++    /**
++     * Reads a {@link FixedWidthConfiguration} based on a SAS 'format file',
++     * <a href=
++     * "http://support.sas.com/documentation/cdl/en/etlug/67323/HTML/default/viewer.htm#p0h03yig7fp1qan1arghp3lwjqi6.htm">
++     * described here</a>.
++     * 
++     * @param encoding
++     * @param resource
++     *            the format file resource
++     * @param failOnInconsistentLineWidth
++     * @return a {@link FixedWidthConfiguration} object to use
++     */
++    public FixedWidthConfiguration readFromSasFormatFile(String encoding, Resource resource,
++            boolean failOnInconsistentLineWidth) {
++        final List<FixedWidthColumnSpec> columnSpecs = new ArrayList<>();
++
++        final CsvDataContext dataContext = new CsvDataContext(resource, new CsvConfiguration());
++        final Table table = dataContext.getDefaultSchema().getTable(0);
++        try (final DataSet dataSet = dataContext.query().from(table).select("Name", "BeginPosition", "EndPosition")
++                .execute()) {
++            while (dataSet.next()) {
++                final String name = (String) dataSet.getRow().getValue(0);
++                final int beginPosition = Integer.parseInt((String) dataSet.getRow().getValue(1));
++                final int endPosition = Integer.parseInt((String) dataSet.getRow().getValue(2));
++                final int width = 1 + endPosition - beginPosition;
++                columnSpecs.add(new FixedWidthColumnSpec(name, width));
++            }
++        }
++
++        return new FixedWidthConfiguration(encoding, columnSpecs, failOnInconsistentLineWidth);
++    }
++
++    /**
++     * Reads a {@link FixedWidthConfiguration} based on a SAS INPUT declaration.
++     * The reader method also optionally will look for a LABEL defintion for
++     * column naming.
++     * 
++     * @param encoding
++     * @param resource
++     *            the format file resource
++     * @param failOnInconsistentLineWidth
++     * @return a {@link FixedWidthConfiguration} object to use
++     */
++    public FixedWidthConfiguration readFromSasInputDefinition(String encoding, Resource resource,
++            boolean failOnInconsistentLineWidth) {
++
++        final Map<String, Integer> inputWidthDeclarations = new LinkedHashMap<>();
++        final Map<String, String> labelDeclarations = new HashMap<>();
++
++        resource.read(new Action<InputStream>() {
++
++            private boolean inInputSection = false;
++            private boolean inLabelSection = false;
++
++            @Override
++            public void run(InputStream in) throws Exception {
++                try (final BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
++                    for (String line = reader.readLine(); line != null; line = reader.readLine()) {
++                        processLine(line);
++                    }
++                }
++            }
++
++            private void processLine(String line) {
++                line = line.trim();
++                if (line.isEmpty()) {
++                    return;
++                }
++                if (";".equals(line)) {
++                    inInputSection = false;
++                    inLabelSection = false;
++                    return;
++                } else if ("INPUT".equals(line)) {
++                    inInputSection = true;
++                    return;
++                } else if ("LABEL".equals(line)) {
++                    inLabelSection = true;
++                    return;
++                }
++
++                if (inInputSection) {
++                    final Matcher matcher = PATTERN_SAS_INPUT_LINE.matcher(line);
++                    if (matcher.matches()) {
++                        final String positionSpec = matcher.group(1);
++                        final String nameSpec = matcher.group(2);
++                        final int width = Integer.parseInt(matcher.group(3));
++                        logger.debug("Parsed INPUT line \"{}\": position={}, name={}, width={}", line, positionSpec,
++                                nameSpec, width);
++                        inputWidthDeclarations.put(nameSpec, width);
++                    } else {
++                        logger.debug("Failed to parse/recognize INPUT line \"{}\"", line);
++                    }
++                } else if (inLabelSection) {
++                    final Matcher matcher = PATTERN_SAS_LABEL_LINE.matcher(line);
++                    if (matcher.matches()) {
++                        final String nameSpec = matcher.group(1);
++                        final String labelSpec = matcher.group(2);
++                        logger.debug("Parsed LABEL line \"{}\": name={}, label={}", line, nameSpec, labelSpec);
++                        labelDeclarations.put(nameSpec, labelSpec);
++                    } else {
++                        logger.debug("Failed to parse/recognize LABEL line \"{}\"", line);
++                    }
++                }
++
++                if (line.endsWith(";")) {
++                    inInputSection = false;
++                    inLabelSection = false;
++                }
++            }
++        });
++
++        final List<FixedWidthColumnSpec> columnSpecs = new ArrayList<>();
++        for (Entry<String, Integer> entry : inputWidthDeclarations.entrySet()) {
++            final String columnKey = entry.getKey();
++            final Integer columnWidth = entry.getValue();
++            final String columnLabel = labelDeclarations.get(columnKey);
++            final String columnName = columnLabel == null ? columnKey : columnLabel;
++            columnSpecs.add(new FixedWidthColumnSpec(columnName, columnWidth));
++        }
++
++        return new FixedWidthConfiguration(encoding, columnSpecs, failOnInconsistentLineWidth);
++    }
++
++}
index 0000000,eb57233..c34b294
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,89 +1,89 @@@
 -/**\r
 - * Licensed to the Apache Software Foundation (ASF) under one\r
 - * or more contributor license agreements.  See the NOTICE file\r
 - * distributed with this work for additional information\r
 - * regarding copyright ownership.  The ASF licenses this file\r
 - * to you under the Apache License, Version 2.0 (the\r
 - * "License"); you may not use this file except in compliance\r
 - * with the License.  You may obtain a copy of the License at\r
 - *\r
 - *   http://www.apache.org/licenses/LICENSE-2.0\r
 - *\r
 - * Unless required by applicable law or agreed to in writing,\r
 - * software distributed under the License is distributed on an\r
 - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
 - * KIND, either express or implied.  See the License for the\r
 - * specific language governing permissions and limitations\r
 - * under the License.\r
 - */\r
 -package org.apache.metamodel.fixedwidth;\r
 -\r
 -import static org.junit.Assert.*;\r
 -\r
 -import java.util.Arrays;\r
 -\r
 -import org.apache.metamodel.DataContext;\r
 -import org.apache.metamodel.data.DataSet;\r
 -import org.apache.metamodel.schema.Table;\r
 -import org.apache.metamodel.util.FileResource;\r
 -import org.apache.metamodel.util.Resource;\r
 -import org.junit.Test;\r
 -\r
 -public class FixedWidthConfigurationReaderTest {\r
 -\r
 -    private final FileResource dataResource = new FileResource("src/test/resources/metadata_spec1/data.txt");\r
 -\r
 -    @Test\r
 -    public void testReadConfigurationFromSasFormatFile() throws Exception {\r
 -        final FixedWidthConfigurationReader reader = new FixedWidthConfigurationReader();\r
 -        final Resource resource = new FileResource("src/test/resources/metadata_spec1/sas-formatfile-metadata.txt");\r
 -        assertTrue(resource.isExists());\r
 -\r
 -        final FixedWidthConfiguration configuration = reader.readFromSasFormatFile("UTF8", resource, false);\r
 -        assertEquals("[1, 20, 2]", Arrays.toString(configuration.getValueWidths()));\r
 -\r
 -        final FixedWidthDataContext dataContext = new FixedWidthDataContext(dataResource, configuration);\r
 -\r
 -        performAssertionsOnSpec1(dataContext);\r
 -    }\r
 -    \r
 -    @Test\r
 -    public void testReadConfigurationFromSasInputMetadata() throws Exception {\r
 -        final FixedWidthConfigurationReader reader = new FixedWidthConfigurationReader();\r
 -        final Resource resource = new FileResource("src/test/resources/metadata_spec1/sas-input-metadata.txt");\r
 -        assertTrue(resource.isExists());\r
 -\r
 -        final FixedWidthConfiguration configuration = reader.readFromSasInputDefinition("UTF8", resource, false);\r
 -        assertEquals("[1, 20, 2]", Arrays.toString(configuration.getValueWidths()));\r
 -\r
 -        final FixedWidthDataContext dataContext = new FixedWidthDataContext(dataResource, configuration);\r
 -\r
 -        performAssertionsOnSpec1(dataContext);\r
 -    }\r
 -\r
 -    /**\r
 -     * Shared assertions section once the 'metadata_spec1' {@link DataContext}\r
 -     * has been loaded.\r
 -     * \r
 -     * @param dataContext\r
 -     */\r
 -    private void performAssertionsOnSpec1(FixedWidthDataContext dataContext) {\r
 -        final Table table = dataContext.getDefaultSchema().getTable(0);\r
 -        final String[] columnNames = table.getColumnNames();\r
 -        assertEquals("[Record type, Description, Initials]", Arrays.toString(columnNames));\r
 -\r
 -        try (final DataSet dataSet = dataContext.query().from(table).selectAll().execute()) {\r
 -            assertTrue(dataSet.next());\r
 -            assertEquals("Row[values=[P, Kasper Sorensen, KS]]", dataSet.getRow().toString());\r
 -            assertTrue(dataSet.next());\r
 -            assertEquals("Row[values=[C, Human Inference, HI]]", dataSet.getRow().toString());\r
 -            assertTrue(dataSet.next());\r
 -            assertEquals("Row[values=[P, Ankit Kumar, AK]]", dataSet.getRow().toString());\r
 -            assertTrue(dataSet.next());\r
 -            assertEquals("Row[values=[C, Stratio, S]]", dataSet.getRow().toString());\r
 -            assertTrue(dataSet.next());\r
 -            assertEquals("Row[values=[U, Unknown, ]]", dataSet.getRow().toString());\r
 -            assertFalse(dataSet.next());\r
 -        }\r
 -    }\r
 -}\r
++/**
++ * 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.apache.metamodel.fixedwidth;
++
++import static org.junit.Assert.*;
++
++import java.util.Arrays;
++
++import org.apache.metamodel.DataContext;
++import org.apache.metamodel.data.DataSet;
++import org.apache.metamodel.schema.Table;
++import org.apache.metamodel.util.FileResource;
++import org.apache.metamodel.util.Resource;
++import org.junit.Test;
++
++public class FixedWidthConfigurationReaderTest {
++
++    private final FileResource dataResource = new FileResource("src/test/resources/metadata_spec1/data.txt");
++
++    @Test
++    public void testReadConfigurationFromSasFormatFile() throws Exception {
++        final FixedWidthConfigurationReader reader = new FixedWidthConfigurationReader();
++        final Resource resource = new FileResource("src/test/resources/metadata_spec1/sas-formatfile-metadata.txt");
++        assertTrue(resource.isExists());
++
++        final FixedWidthConfiguration configuration = reader.readFromSasFormatFile("UTF8", resource, false);
++        assertEquals("[1, 20, 2]", Arrays.toString(configuration.getValueWidths()));
++
++        final FixedWidthDataContext dataContext = new FixedWidthDataContext(dataResource, configuration);
++
++        performAssertionsOnSpec1(dataContext);
++    }
++    
++    @Test
++    public void testReadConfigurationFromSasInputMetadata() throws Exception {
++        final FixedWidthConfigurationReader reader = new FixedWidthConfigurationReader();
++        final Resource resource = new FileResource("src/test/resources/metadata_spec1/sas-input-metadata.txt");
++        assertTrue(resource.isExists());
++
++        final FixedWidthConfiguration configuration = reader.readFromSasInputDefinition("UTF8", resource, false);
++        assertEquals("[1, 20, 2]", Arrays.toString(configuration.getValueWidths()));
++
++        final FixedWidthDataContext dataContext = new FixedWidthDataContext(dataResource, configuration);
++
++        performAssertionsOnSpec1(dataContext);
++    }
++
++    /**
++     * Shared assertions section once the 'metadata_spec1' {@link DataContext}
++     * has been loaded.
++     * 
++     * @param dataContext
++     */
++    private void performAssertionsOnSpec1(FixedWidthDataContext dataContext) {
++        final Table table = dataContext.getDefaultSchema().getTable(0);
++        final String[] columnNames = table.getColumnNames();
++        assertEquals("[Record type, Description, Initials]", Arrays.toString(columnNames));
++
++        try (final DataSet dataSet = dataContext.query().from(table).selectAll().execute()) {
++            assertTrue(dataSet.next());
++            assertEquals("Row[values=[P, Kasper Sorensen, KS]]", dataSet.getRow().toString());
++            assertTrue(dataSet.next());
++            assertEquals("Row[values=[C, Human Inference, HI]]", dataSet.getRow().toString());
++            assertTrue(dataSet.next());
++            assertEquals("Row[values=[P, Ankit Kumar, AK]]", dataSet.getRow().toString());
++            assertTrue(dataSet.next());
++            assertEquals("Row[values=[C, Stratio, S]]", dataSet.getRow().toString());
++            assertTrue(dataSet.next());
++            assertEquals("Row[values=[U, Unknown, ]]", dataSet.getRow().toString());
++            assertFalse(dataSet.next());
++        }
++    }
++}
index 0000000,785a539..ac055c9
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,5 +1,5 @@@
 -PKasper Sorensen     KS\r
 -CHuman Inference     HI\r
 -PAnkit Kumar         AK\r
 -CStratio             S \r
 -UUnknown               \r
++PKasper Sorensen     KS
++CHuman Inference     HI
++PAnkit Kumar         AK
++CStratio             S 
++UUnknown               
index 0000000,9bbe411..38b0e04
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,4 +1,4 @@@
 -Name,SASColumnType,BeginPosition,EndPosition,ReadFlag,Desc,SASFormat,SASInformat\r
 -Record type,C,1,1,y,Record Type,$char.,$char.\r
 -Description,C,2,21,y,Description of record,$char.,$char.\r
 -Initials,C,22,23,y,Initials of record,,\r
++Name,SASColumnType,BeginPosition,EndPosition,ReadFlag,Desc,SASFormat,SASInformat
++Record type,C,1,1,y,Record Type,$char.,$char.
++Description,C,2,21,y,Description of record,$char.,$char.
++Initials,C,22,23,y,Initials of record,,
index 0000000,f12e418..6839a9b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,19 +1,19 @@@
 -INPUT\r
 -\r
 -   @1 COL1 $char1.\r
 -\r
 -   @2 COL2 $char20.\r
 -\r
 -   @22 COL3 $char2.\r
 -   \r
 -;\r
 -\r
 -LABEL\r
 -\r
 -   COL1 "Record type"\r
 -\r
 -   COL2 "Description"\r
 -\r
 -   COL3 "Initials"\r
 -\r
 -;\r
++INPUT
++
++   @1 COL1 $char1.
++
++   @2 COL2 $char20.
++
++   @22 COL3 $char2.
++   
++;
++
++LABEL
++
++   COL1 "Record type"
++
++   COL2 "Description"
++
++   COL3 "Initials"
++
++;
diff --cc full/pom.xml
Simple merge
index 0000000,850d2f7..9675d9e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,67 +1,67 @@@
 -              <version>4.5.3-SNAPSHOT</version>
+ <?xml version="1.0" encoding="UTF-8" ?>
+ <!--
+ 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.
+ -->
+ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <parent>
+               <artifactId>MetaModel-mongodb</artifactId>
+               <groupId>org.apache.metamodel</groupId>
++              <version>5.0-SNAPSHOT</version>
+       </parent>
+       <modelVersion>4.0.0</modelVersion>
+       <artifactId>MetaModel-mongodb-common</artifactId>
+       <name>MetaModel module for MongoDB commons</name>
+       
+       <dependencies>
+               <dependency>
+                       <groupId>org.apache.metamodel</groupId>
+                       <artifactId>MetaModel-core</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.mongodb</groupId>
+                       <artifactId>mongo-java-driver</artifactId>
+                       <version>3.1.0</version>
+                       <scope>provided</scope>
+               </dependency>
+               <!-- Test dependencies -->
+               <dependency>
+                       <groupId>org.apache.metamodel</groupId>
+                       <artifactId>MetaModel-jdbc</artifactId>
+                       <version>${project.version}</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.derby</groupId>
+                       <artifactId>derby</artifactId>
+                       <version>10.8.1.2</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>slf4j-nop</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+       </dependencies>
+ </project>
index 0000000,4905102..8cd2540
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,70 +1,70 @@@
 -              <version>4.5.3-SNAPSHOT</version>
+ <?xml version="1.0" encoding="UTF-8" ?>
+ <!--
+ 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.
+ -->
+ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <parent>
+               <artifactId>MetaModel-mongodb</artifactId>
+               <groupId>org.apache.metamodel</groupId>
++              <version>5.0-SNAPSHOT</version>
+       </parent>
+       <modelVersion>4.0.0</modelVersion>
+       <artifactId>MetaModel-mongodb-mongo2</artifactId>
+       <name>MetaModel module for MongoDB 2.x</name>
+       <dependencies>
+               <dependency>
+                       <groupId>org.apache.metamodel</groupId>
+                       <artifactId>MetaModel-core</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+             <groupId>org.apache.metamodel</groupId>
+             <artifactId>MetaModel-mongodb-common</artifactId>
+             <version>${project.version}</version>
+         </dependency>
+               <dependency>
+                       <groupId>org.mongodb</groupId>
+                       <artifactId>mongo-java-driver</artifactId>
+                       <version>2.14.0</version>
+               </dependency>
+               <!-- Test dependencies -->
+               <dependency>
+                       <groupId>org.apache.metamodel</groupId>
+                       <artifactId>MetaModel-jdbc</artifactId>
+                       <version>${project.version}</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.derby</groupId>
+                       <artifactId>derby</artifactId>
+                       <version>10.8.1.2</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>slf4j-nop</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+       </dependencies>
+ </project>
@@@ -468,10 -469,9 +470,9 @@@ public class MongoDbDataContext extend
  
      /**
       * Executes an update with a specific {@link WriteConcernAdvisor}.
-      * @return 
       */
 -    public void executeUpdate(UpdateScript update, WriteConcernAdvisor writeConcernAdvisor) {
 +    public UpdateSummary executeUpdate(UpdateScript update, WriteConcernAdvisor writeConcernAdvisor) {
-         final MongoDbUpdateCallback callback = new MongoDbUpdateCallback(this, writeConcernAdvisor);
+         MongoDbUpdateCallback callback = new MongoDbUpdateCallback(this, writeConcernAdvisor);
          try {
              update.run(callback);
          } finally {
      /**
       * Executes an update with a specific {@link WriteConcern}.
       */
--    public void executeUpdate(UpdateScript update, WriteConcern writeConcern) {
--        executeUpdate(update, new SimpleWriteConcernAdvisor(writeConcern));
++    public UpdateSummary executeUpdate(UpdateScript update, WriteConcern writeConcern) {
++        return executeUpdate(update, new SimpleWriteConcernAdvisor(writeConcern));
      }
  
      @Override
index 0000000,ae53158..4ff4fd7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,70 +1,70 @@@
 -              <version>4.5.3-SNAPSHOT</version>
+ <?xml version="1.0" encoding="UTF-8" ?>
+ <!--
+ 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.
+ -->
+ <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <parent>
+               <artifactId>MetaModel-mongodb</artifactId>
+               <groupId>org.apache.metamodel</groupId>
++              <version>5.0-SNAPSHOT</version>
+       </parent>
+       <modelVersion>4.0.0</modelVersion>
+       <artifactId>MetaModel-mongodb-mongo3</artifactId>
+       <name>MetaModel module for MongoDB 3.x</name>
+       <dependencies>
+               <dependency>
+                       <groupId>org.apache.metamodel</groupId>
+                       <artifactId>MetaModel-core</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+               <dependency>
+             <groupId>org.apache.metamodel</groupId>
+             <artifactId>MetaModel-mongodb-common</artifactId>
+             <version>${project.version}</version>
+         </dependency>
+               <dependency>
+                       <groupId>org.mongodb</groupId>
+                       <artifactId>mongo-java-driver</artifactId>
+                       <version>3.1.0</version>
+               </dependency>
+               <!-- Test dependencies -->
+               <dependency>
+                       <groupId>org.apache.metamodel</groupId>
+                       <artifactId>MetaModel-jdbc</artifactId>
+                       <version>${project.version}</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.derby</groupId>
+                       <artifactId>derby</artifactId>
+                       <version>10.8.1.2</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>slf4j-nop</artifactId>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <scope>test</scope>
+               </dependency>
+       </dependencies>
+ </project>
index 0000000,fbc9047..cf89f39
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,545 +1,547 @@@
 -    public void executeUpdate(UpdateScript update, WriteConcernAdvisor writeConcernAdvisor) {
+ /**
+  * 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.apache.metamodel.mongodb.mongo3;
+ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.HashSet;
+ import java.util.List;
+ import java.util.Map.Entry;
+ import java.util.Set;
+ import java.util.SortedMap;
+ import java.util.TreeMap;
+ import java.util.regex.Pattern;
+ import org.apache.metamodel.DataContext;
+ import org.apache.metamodel.MetaModelException;
+ import org.apache.metamodel.QueryPostprocessDataContext;
+ import org.apache.metamodel.UpdateScript;
++import org.apache.metamodel.UpdateSummary;
+ import org.apache.metamodel.UpdateableDataContext;
+ import org.apache.metamodel.data.DataSet;
+ import org.apache.metamodel.data.DataSetHeader;
+ import org.apache.metamodel.data.InMemoryDataSet;
+ import org.apache.metamodel.data.Row;
+ import org.apache.metamodel.data.SimpleDataSetHeader;
+ import org.apache.metamodel.mongodb.common.MongoDBUtils;
+ import org.apache.metamodel.query.FilterItem;
+ import org.apache.metamodel.query.FromItem;
+ import org.apache.metamodel.query.OperatorType;
+ import org.apache.metamodel.query.Query;
+ import org.apache.metamodel.query.SelectItem;
+ import org.apache.metamodel.schema.Column;
+ import org.apache.metamodel.schema.ColumnType;
+ import org.apache.metamodel.schema.ColumnTypeImpl;
+ import org.apache.metamodel.schema.MutableColumn;
+ import org.apache.metamodel.schema.MutableSchema;
+ import org.apache.metamodel.schema.MutableTable;
+ import org.apache.metamodel.schema.Schema;
+ import org.apache.metamodel.schema.Table;
+ import org.apache.metamodel.util.SimpleTableDef;
+ import org.bson.Document;
+ import org.bson.types.ObjectId;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ import com.mongodb.DB;
+ import com.mongodb.WriteConcern;
+ import com.mongodb.client.FindIterable;
+ import com.mongodb.client.MongoCollection;
+ import com.mongodb.client.MongoCursor;
+ import com.mongodb.client.MongoDatabase;
+ import com.mongodb.client.MongoIterable;
+ /**
+  * DataContext implementation for MongoDB.
+  *
+  * Since MongoDB has no schema, a virtual schema will be used in this
+  * DataContext. This implementation supports either automatic discovery of a
+  * schema or manual specification of a schema, through the
+  * {@link SimpleTableDef} class.
+  */
+ public class MongoDbDataContext extends QueryPostprocessDataContext implements UpdateableDataContext {
+     private static final Logger logger = LoggerFactory.getLogger(MongoDbDataSet.class);
+     private final MongoDatabase _mongoDb;
+     private final SimpleTableDef[] _tableDefs;
+     private WriteConcernAdvisor _writeConcernAdvisor;
+     private Schema _schema;
+     /**
+      * Constructs a {@link MongoDbDataContext}. This constructor accepts a
+      * custom array of {@link SimpleTableDef}s which allows the user to define
+      * his own view on the collections in the database.
+      *
+      * @param mongoDb
+      *            the mongo db connection
+      * @param tableDefs
+      *            an array of {@link SimpleTableDef}s, which define the table
+      *            and column model of the mongo db collections. (consider using
+      *            {@link #detectSchema(MongoDatabase)} or {@link #detectTable(MongoDatabase, String)}
+      *            ).
+      */
+     public MongoDbDataContext(MongoDatabase mongoDb, SimpleTableDef... tableDefs) {
+         _mongoDb = mongoDb;
+         _tableDefs = tableDefs;
+         _schema = null;
+     }
+     /**
+      * Constructs a {@link MongoDbDataContext} and automatically detects the
+      * schema structure/view on all collections (see {@link #detectSchema(MongoDatabase)}).
+      *
+      * @param mongoDb
+      *            the mongo db connection
+      */
+     public MongoDbDataContext(MongoDatabase mongoDb) {
+         this(mongoDb, detectSchema(mongoDb));
+     }
+     /**
+      * Performs an analysis of the available collections in a Mongo {@link DB}
+      * instance and tries to detect the table's structure based on the first
+      * 1000 documents in each collection.
+      *
+      * @param mongoDb
+      *            the mongo db to inspect
+      * @return a mutable schema instance, useful for further fine tuning by the
+      *         user.
+      * @see #detectTable(MongoDatabase, String)
+      */
+     public static SimpleTableDef[] detectSchema(MongoDatabase mongoDb) {
+         MongoIterable<String> collectionNames = mongoDb.listCollectionNames();
+         List<SimpleTableDef> result = new ArrayList<>();
+         for (String collectionName : collectionNames) {
+             SimpleTableDef table = detectTable(mongoDb, collectionName);
+             result.add(table);
+         }
+         return result.toArray(new SimpleTableDef[0]);
+     }
+     /**
+      * Performs an analysis of an available collection in a Mongo {@link DB}
+      * instance and tries to detect the table structure based on the first 1000
+      * documents in the collection.
+      *
+      * @param mongoDb
+      *            the mongo DB
+      * @param collectionName
+      *            the name of the collection
+      * @return a table definition for mongo db.
+      */
+     public static SimpleTableDef detectTable(MongoDatabase mongoDb, String collectionName) {
+         
+         final MongoCollection<Document> collection = mongoDb.getCollection(collectionName);
+         final FindIterable<Document> iterable = collection.find().limit(1000);
+         final SortedMap<String, Set<Class<?>>> columnsAndTypes = new TreeMap<String, Set<Class<?>>>();
+         for (Document document : iterable) {
+             Set<String> keysInObject = document.keySet();
+             for (String key : keysInObject) {
+                 Set<Class<?>> types = columnsAndTypes.get(key);
+                 if (types == null) {
+                     types = new HashSet<Class<?>>();
+                     columnsAndTypes.put(key, types);
+                 }
+                 Object value = document.get(key);
+                 if (value != null) {
+                     types.add(value.getClass());
+                 }
+             }
+         }
+            
+         final String[] columnNames = new String[columnsAndTypes.size()];
+         final ColumnType[] columnTypes = new ColumnType[columnsAndTypes.size()];
+         int i = 0;
+         for (Entry<String, Set<Class<?>>> columnAndTypes : columnsAndTypes.entrySet()) {
+             final String columnName = columnAndTypes.getKey();
+             final Set<Class<?>> columnTypeSet = columnAndTypes.getValue();
+             final Class<?> columnType;
+             if (columnTypeSet.size() == 1) {
+                 columnType = columnTypeSet.iterator().next();
+             } else {
+                 columnType = Object.class;
+             }
+             columnNames[i] = columnName;
+             if (columnType == ObjectId.class) {
+                 columnTypes[i] = ColumnType.ROWID;
+             } else {
+                 columnTypes[i] = ColumnTypeImpl.convertColumnType(columnType);
+             }
+             i++;
+         }
+         return new SimpleTableDef(collectionName, columnNames, columnTypes);
+     }
+     @Override
+     protected Schema getMainSchema() throws MetaModelException {
+         if (_schema == null) {
+             MutableSchema schema = new MutableSchema(getMainSchemaName());
+             for (SimpleTableDef tableDef : _tableDefs) {
+                 MutableTable table = tableDef.toTable().setSchema(schema);
+                 Column[] rowIdColumns = table.getColumnsOfType(ColumnType.ROWID);
+                 for (Column column : rowIdColumns) {
+                     if (column instanceof MutableColumn) {
+                         ((MutableColumn) column).setPrimaryKey(true);
+                     }
+                 }
+                 schema.addTable(table);
+             }
+             _schema = schema;
+         }
+         return _schema;
+     }
+     @Override
+     protected String getMainSchemaName() throws MetaModelException {
+         return _mongoDb.getName();
+     }
+     @Override
+     protected Number executeCountQuery(Table table, List<FilterItem> whereItems, boolean functionApproximationAllowed) {
+         final MongoCollection<Document> collection = _mongoDb.getCollection(table.getName());
+         final Document query = createMongoDbQuery(table, whereItems);
+         logger.info("Executing MongoDB 'count' query: {}", query);
+         final long count = collection.count(query);
+         return count;
+     }
+     @Override
+     protected Row executePrimaryKeyLookupQuery(Table table, List<SelectItem> selectItems, Column primaryKeyColumn,
+             Object keyValue) {
+         final MongoCollection<Document> collection = _mongoDb.getCollection(table.getName());
+         List<FilterItem> whereItems = new ArrayList<FilterItem>();
+         SelectItem selectItem = new SelectItem(primaryKeyColumn);
+         FilterItem primaryKeyWhereItem = new FilterItem(selectItem, OperatorType.EQUALS_TO, keyValue);
+         whereItems.add(primaryKeyWhereItem);
+         final Document query = createMongoDbQuery(table, whereItems);
+         final Document resultDoc = collection.find(query).first();
+         DataSetHeader header = new SimpleDataSetHeader(selectItems);
+         Row row = MongoDBUtils.toRow(resultDoc, header);
+         return row;
+     }
+     @Override
+     public DataSet executeQuery(Query query) {
+         // Check for queries containing only simple selects and where clauses,
+         // or if it is a COUNT(*) query.
+         // if from clause only contains a main schema table
+         List<FromItem> fromItems = query.getFromClause().getItems();
+         if (fromItems.size() == 1 && fromItems.get(0).getTable() != null
+                 && fromItems.get(0).getTable().getSchema() == _schema) {
+             final Table table = fromItems.get(0).getTable();
+             // if GROUP BY, HAVING and ORDER BY clauses are not specified
+             if (query.getGroupByClause().isEmpty() && query.getHavingClause().isEmpty()
+                     && query.getOrderByClause().isEmpty()) {
+                 final List<FilterItem> whereItems = query.getWhereClause().getItems();
+                 // if all of the select items are "pure" column selection
+                 boolean allSelectItemsAreColumns = true;
+                 List<SelectItem> selectItems = query.getSelectClause().getItems();
+                 // if it is a
+                 // "SELECT [columns] FROM [table] WHERE [conditions]"
+                 // query.
+                 for (SelectItem selectItem : selectItems) {
+                     if (selectItem.getFunction() != null || selectItem.getColumn() == null) {
+                         allSelectItemsAreColumns = false;
+                         break;
+                     }
+                 }
+                 if (allSelectItemsAreColumns) {
+                     logger.debug("Query can be expressed in full MongoDB, no post processing needed.");
+                     // prepare for a non-post-processed query
+                     Column[] columns = new Column[selectItems.size()];
+                     for (int i = 0; i < columns.length; i++) {
+                         columns[i] = selectItems.get(i).getColumn();
+                     }
+                     // checking if the query is a primary key lookup query
+                     if (whereItems.size() == 1) {
+                         final FilterItem whereItem = whereItems.get(0);
+                         final SelectItem selectItem = whereItem.getSelectItem();
+                         if (!whereItem.isCompoundFilter() && selectItem != null && selectItem.getColumn() != null) {
+                             final Column column = selectItem.getColumn();
+                             if (column.isPrimaryKey() && OperatorType.EQUALS_TO.equals(whereItem.getOperator())) {
+                                 logger.debug("Query is a primary key lookup query. Trying executePrimaryKeyLookupQuery(...)");
+                                 final Object operand = whereItem.getOperand();
+                                 final Row row = executePrimaryKeyLookupQuery(table, selectItems, column, operand);
+                                 if (row == null) {
+                                     logger.debug("DataContext did not return any primary key lookup query results. Proceeding "
+                                             + "with manual lookup.");
+                                 } else {
+                                     final DataSetHeader header = new SimpleDataSetHeader(selectItems);
+                                     return new InMemoryDataSet(header, row);
+                                 }
+                             }
+                         }
+                     }
+                     int firstRow = (query.getFirstRow() == null ? 1 : query.getFirstRow());
+                     int maxRows = (query.getMaxRows() == null ? -1 : query.getMaxRows());
+                     final DataSet dataSet = materializeMainSchemaTableInternal(table, columns, whereItems, firstRow,
+                             maxRows, false);
+                     return dataSet;
+                 }
+             }
+         }
+         logger.debug("Query will be simplified for MongoDB and post processed.");
+         return super.executeQuery(query);
+     }
+     private DataSet materializeMainSchemaTableInternal(Table table, Column[] columns, List<FilterItem> whereItems,
+             int firstRow, int maxRows, boolean queryPostProcessed) {
+         final MongoCollection<Document> collection = _mongoDb.getCollection(table.getName());
+         final Document query = createMongoDbQuery(table, whereItems);
+         logger.info("Executing MongoDB 'find' query: {}", query);
+         FindIterable<Document> iterable = collection.find(query);
+         if (maxRows > 0) {
+             iterable = iterable.limit(maxRows);
+         }
+         if (firstRow > 1) {
+             final int skip = firstRow - 1;
+             iterable = iterable.skip(skip);
+         }
+         MongoCursor<Document> cursor = iterable.iterator();
+         return new MongoDbDataSet(cursor, columns, queryPostProcessed);
+     }
+     protected Document createMongoDbQuery(Table table, List<FilterItem> whereItems) {
+         assert _schema == table.getSchema();
+         final Document query = new Document();
+         if (whereItems != null && !whereItems.isEmpty()) {
+             for (FilterItem item : whereItems) {
+                 convertToCursorObject(query, item);
+             }
+         }
+         return query;
+     }
+     private static Object convertArrayToList(Object arr) {
+         if (arr instanceof boolean[]) {
+             return Arrays.asList((boolean[])arr);
+         } else if (arr instanceof byte[]) {
+             return Arrays.asList((byte[])arr);
+         } else if (arr instanceof short[]) {
+             return Arrays.asList((short[])arr);
+         } else if (arr instanceof char[]) {
+             return Arrays.asList((char[])arr);
+         } else if (arr instanceof int[]) {
+             return Arrays.asList((int[])arr);
+         } else if (arr instanceof long[]) {
+             return Arrays.asList((long[])arr);
+         } else if (arr instanceof float[]) {
+             return Arrays.asList((float[])arr);
+         } else if (arr instanceof double[]) {
+             return Arrays.asList((double[])arr);
+         } else if (arr instanceof Object[]) {
+             return Arrays.asList((Object[])arr);
+         }
+         // It's not an array.
+         return null;
+     }
+     
+     private void convertToCursorObject(Document query, FilterItem item) {
+         if (item.isCompoundFilter()) {
+             List<Document> orList = new ArrayList<Document>();
+             final FilterItem[] childItems = item.getChildItems();
+             for (FilterItem childItem : childItems) {
+                 Document childDoc = new Document();
+                 convertToCursorObject(childDoc, childItem);
+                 orList.add(childDoc);
+             }
+             query.put("$or", orList);
+         } else {
+             final Column column = item.getSelectItem().getColumn();
+             final String columnName = column.getName();
+             final String operatorName = getOperatorName(item);
+             Object operand = item.getOperand();
+             if (ObjectId.isValid(String.valueOf(operand))) {
+                 operand = new ObjectId(String.valueOf(operand));
+             } else if (operand != null && operand.getClass().isArray()){
+                 operand = convertArrayToList(operand);
+             }
+             final Document existingFilterObject = (Document) query.get(columnName);
+             if (existingFilterObject == null) {
+                 if (operatorName == null) {
+                     if (OperatorType.LIKE.equals(item.getOperator())) {
+                         query.put(columnName, turnOperandIntoRegExp(operand));
+                     } else {
+                         query.put(columnName, operand);
+                     }
+                 } else {
+                     query.put(columnName, new Document(operatorName, operand));
+                 }
+             } else {
+                 if (operatorName == null) {
+                     throw new IllegalStateException("Cannot retrieve records for a column with two EQUALS_TO operators");
+                 } else {
+                     existingFilterObject.append(operatorName, operand);
+                 }
+             }
+         }
+     }
+     private String getOperatorName(FilterItem item) {
+         final OperatorType operator = item.getOperator();
+         if (OperatorType.EQUALS_TO.equals(operator)) {
+             return null;
+         }
+         if (OperatorType.LIKE.equals(operator)) {
+             return null;
+         }
+         if (OperatorType.LESS_THAN.equals(operator)) {
+             return "$lt";
+         }
+         if (OperatorType.LESS_THAN_OR_EQUAL.equals(operator)) {
+             return "$lte";
+         }
+         if (OperatorType.GREATER_THAN.equals(operator)) {
+             return "$gt";
+         }
+         if (OperatorType.GREATER_THAN_OR_EQUAL.equals(operator)) {
+             return "$gte";
+         }
+         if (OperatorType.DIFFERENT_FROM.equals(operator)) {
+             return "$ne";
+         }
+         if (OperatorType.IN.equals(operator)) {
+             return "$in";
+         }
+         throw new IllegalStateException("Unsupported operator type: " + operator);
+     }
+     private Pattern turnOperandIntoRegExp(Object operand) {
+         StringBuilder operandAsRegExp = new StringBuilder(replaceWildCardLikeChars(operand.toString()));
+         operandAsRegExp.insert(0, "^").append("$");
+         return Pattern.compile(operandAsRegExp.toString(), Pattern.CASE_INSENSITIVE);
+     }
+     private String replaceWildCardLikeChars(String operand) {
+         return operand.replaceAll("%", ".*");
+     }
+     @Override
+     protected DataSet materializeMainSchemaTable(Table table, Column[] columns, int maxRows) {
+         return materializeMainSchemaTableInternal(table, columns, null, 1, maxRows, true);
+     }
+     @Override
+     protected DataSet materializeMainSchemaTable(Table table, Column[] columns, int firstRow, int maxRows) {
+         return materializeMainSchemaTableInternal(table, columns, null, firstRow, maxRows, true);
+     }
+     /**
+      * Executes an update with a specific {@link WriteConcernAdvisor}.
+      */
 -    public void executeUpdate(UpdateScript update, WriteConcern writeConcern) {
 -        executeUpdate(update, new SimpleWriteConcernAdvisor(writeConcern));
++    public UpdateSummary executeUpdate(UpdateScript update, WriteConcernAdvisor writeConcernAdvisor) {
+         MongoDbUpdateCallback callback = new MongoDbUpdateCallback(this, writeConcernAdvisor);
+         try {
+             update.run(callback);
+         } finally {
+             callback.close();
+         }
++        return callback.getUpdateSummary();
+     }
+     /**
+      * Executes an update with a specific {@link WriteConcern}.
+      */
 -    public void executeUpdate(UpdateScript update) {
 -        executeUpdate(update, getWriteConcernAdvisor());
++    public UpdateSummary executeUpdate(UpdateScript update, WriteConcern writeConcern) {
++        return executeUpdate(update, new SimpleWriteConcernAdvisor(writeConcern));
+     }
+     @Override
++    public UpdateSummary executeUpdate(UpdateScript update) {
++        return executeUpdate(update, getWriteConcernAdvisor());
+     }
+     /**
+      * Gets the {@link WriteConcernAdvisor} to use on
+      * {@link #executeUpdate(UpdateScript)} calls.
+      */
+     public WriteConcernAdvisor getWriteConcernAdvisor() {
+         if (_writeConcernAdvisor == null) {
+             return new DefaultWriteConcernAdvisor();
+         }
+         return _writeConcernAdvisor;
+     }
+     /**
+      * Sets a global {@link WriteConcern} advisor to use on
+      * {@link #executeUpdate(UpdateScript)}.
+      */
+     public void setWriteConcernAdvisor(WriteConcernAdvisor writeConcernAdvisor) {
+         _writeConcernAdvisor = writeConcernAdvisor;
+     }
+     /**
+      * Gets the {@link DB} instance that this {@link DataContext} is backed by.
+      * @return 
+      */
+     public MongoDatabase getMongoDb() {
+         return _mongoDb;
+     }
+     protected void addTable(MutableTable table) {
+         if (_schema instanceof MutableSchema) {
+             MutableSchema mutableSchema = (MutableSchema) _schema;
+             mutableSchema.addTable(table);
+         } else {
+             throw new UnsupportedOperationException("Schema is not mutable");
+         }
+     }
+ }
diff --cc mongodb/pom.xml
Simple merge
diff --cc pom.xml
Simple merge