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

git commit: Added draft module for Apache HBase.

Updated Branches:
  refs/heads/hbase-module [created] eba65a052


Added draft module for Apache HBase.

Project: http://git-wip-us.apache.org/repos/asf/incubator-metamodel/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-metamodel/commit/eba65a05
Tree: http://git-wip-us.apache.org/repos/asf/incubator-metamodel/tree/eba65a05
Diff: http://git-wip-us.apache.org/repos/asf/incubator-metamodel/diff/eba65a05

Branch: refs/heads/hbase-module
Commit: eba65a052065aea521e7d2159b94ab07de9fb528
Parents: a767740
Author: kasper <ka...@192.168.0.165>
Authored: Tue Jul 30 11:12:52 2013 +0200
Committer: kasper <ka...@192.168.0.165>
Committed: Tue Jul 30 11:12:52 2013 +0200

----------------------------------------------------------------------
 hbase/pom.xml                                   |  56 ++++++
 .../org/apache/metamodel/hbase/ByteUtils.java   | 114 +++++++++++
 .../metamodel/hbase/HBaseConfiguration.java     | 107 ++++++++++
 .../metamodel/hbase/HBaseDataContext.java       | 199 +++++++++++++++++++
 .../apache/metamodel/hbase/HBaseDataSet.java    |  77 +++++++
 .../apache/metamodel/hbase/HBaseFamilyMap.java  | 116 +++++++++++
 .../org/apache/metamodel/hbase/HBaseRow.java    |  89 +++++++++
 .../org/apache/metamodel/hbase/HBaseTable.java  | 129 ++++++++++++
 .../apache/metamodel/hbase/package-info.java    |  22 ++
 .../metamodel/hbase/HBaseDataContextTest.java   | 159 +++++++++++++++
 pom.xml                                         |   1 +
 11 files changed, 1069 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/hbase/pom.xml
----------------------------------------------------------------------
diff --git a/hbase/pom.xml b/hbase/pom.xml
new file mode 100644
index 0000000..382d116
--- /dev/null
+++ b/hbase/pom.xml
@@ -0,0 +1,56 @@
+<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>3.4.4</version>
+	</parent>
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>MetaModel-hbase</artifactId>
+	<name>MetaModel module for Apache HBase</name>
+
+	<properties>
+		<hbase.version>0.95.1-hadoop1</hbase.version>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.metamodel</groupId>
+			<artifactId>MetaModel-core</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.hbase</groupId>
+			<artifactId>hbase-client</artifactId>
+			<version>${hbase.version}</version>
+			<exclusions>
+				<exclusion>
+					<artifactId>log4j</artifactId>
+					<groupId>log4j</groupId>
+				</exclusion>
+				<exclusion>
+					<artifactId>commons-logging</artifactId>
+					<groupId>commons-logging</groupId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>jcl-over-slf4j</artifactId>
+		</dependency>
+		<dependency>
+		    <groupId>org.slf4j</groupId>
+		    <artifactId>slf4j-log4j12</artifactId>
+		    <scope>provided</scope>
+		</dependency>
+
+		<!-- Test dependencies -->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+
+	</dependencies>
+
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/hbase/src/main/java/org/apache/metamodel/hbase/ByteUtils.java
----------------------------------------------------------------------
diff --git a/hbase/src/main/java/org/apache/metamodel/hbase/ByteUtils.java b/hbase/src/main/java/org/apache/metamodel/hbase/ByteUtils.java
new file mode 100644
index 0000000..0a4d1bf
--- /dev/null
+++ b/hbase/src/main/java/org/apache/metamodel/hbase/ByteUtils.java
@@ -0,0 +1,114 @@
+/**
+ * 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.hbase;
+
+import java.math.BigDecimal;
+
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.metamodel.MetaModelException;
+
+/**
+ * Util class for Converting Object values to Bytes
+ * 
+ */
+public class ByteUtils {
+
+	public static byte[] toBytes(Object o) {
+		if (o != null) {
+			return toBytes(o, o.getClass());
+		}
+		return null;
+	}
+
+	public static byte[] toBytes(Object value, Class<?> klass) {
+		if (klass.isAssignableFrom(String.class)) {
+			return Bytes.toBytes(value.toString());
+		} else if (klass.equals(int.class)
+				|| klass.isAssignableFrom(Integer.class)) {
+			return Bytes.toBytes(value instanceof Integer ? (Integer) value
+					: new Integer(value.toString()));
+		} else if (klass.equals(long.class)
+				|| klass.isAssignableFrom(Long.class)) {
+			return Bytes.toBytes(value instanceof Long ? (Long) value
+					: new Long(value.toString()));
+		} else if (klass.equals(boolean.class)
+				|| klass.isAssignableFrom(Boolean.class)) {
+			return Bytes.toBytes(value instanceof Boolean ? (Boolean) value
+					: new Boolean(value.toString()));
+		} else if (klass.equals(double.class)
+				|| klass.isAssignableFrom(Double.class)) {
+			return Bytes.toBytes(value instanceof Double ? (Double) value
+					: new Double(value.toString()));
+		} else if (klass.equals(float.class)
+				|| klass.isAssignableFrom(Float.class)) {
+			return Bytes.toBytes(value instanceof Float ? (Float) value
+					: new Float(value.toString()));
+		} else if (klass.equals(short.class)
+				|| klass.isAssignableFrom(Short.class)) {
+			return Bytes.toBytes(value instanceof Short ? (Short) value
+					: new Short(value.toString()));
+		} else if (klass.equals(BigDecimal.class)) {
+			return Bytes
+					.toBytes(value instanceof BigDecimal ? (BigDecimal) value
+							: new BigDecimal(value.toString()));
+		} else {
+			throw new MetaModelException(
+					"Could not find a suitable Type to assign value for give type "
+							+ klass.getName());
+		}
+	}
+
+	/**
+	 * Builds Object from Bytes Picked from Hbase.
+	 * 
+	 * @param b
+	 * @param klass
+	 * @return
+	 */
+	public static Object toObject(byte[] b, Class<?> klass) {
+
+		if (klass.isAssignableFrom(String.class)) {
+			return Bytes.toString(b);
+		} else if (klass.equals(int.class)
+				|| klass.isAssignableFrom(Integer.class)) {
+			return Bytes.toInt(b);
+		} else if (klass.equals(long.class)
+				|| klass.isAssignableFrom(Long.class)) {
+			return Bytes.toLong(b);
+		} else if (klass.equals(boolean.class)
+				|| klass.isAssignableFrom(Boolean.class)) {
+			return Bytes.toBoolean(b);
+		} else if (klass.equals(double.class)
+				|| klass.isAssignableFrom(Double.class)) {
+			return Bytes.toDouble(b);
+		} else if (klass.equals(float.class)
+				|| klass.isAssignableFrom(Float.class)) {
+			return Bytes.toFloat(b);
+		} else if (klass.equals(short.class)
+				|| klass.isAssignableFrom(Short.class)) {
+			return Bytes.toShort(b);
+		} else if (klass.equals(BigDecimal.class)) {
+			return Bytes.toBigDecimal(b);
+		} else {
+			throw new MetaModelException("Could Not find a suitable Type for "
+					+ klass.getName());
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/hbase/src/main/java/org/apache/metamodel/hbase/HBaseConfiguration.java
----------------------------------------------------------------------
diff --git a/hbase/src/main/java/org/apache/metamodel/hbase/HBaseConfiguration.java b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseConfiguration.java
new file mode 100644
index 0000000..b3782d5
--- /dev/null
+++ b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseConfiguration.java
@@ -0,0 +1,107 @@
+/**
+ * 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.hbase;
+
+import java.io.Serializable;
+import java.util.List;
+
+import org.apache.metamodel.schema.ColumnType;
+import org.apache.metamodel.util.BaseObject;
+import org.apache.metamodel.util.SimpleTableDef;
+
+/**
+ * Represents the configuration of MetaModel's HBase adaptor.
+ */
+public class HBaseConfiguration extends BaseObject implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    public static final String DEFAULT_SCHEMA_NAME = "HBase";
+    public static final String DEFAULT_ZOOKEEPER_HOSTNAME = "127.0.0.1";
+    public static final int DEFAULT_ZOOKEEPER_PORT = 2181;
+
+    private final String _schemaName;
+    private final int _zookeeperPort;
+    private final String _zookeeperHostname;
+    private final SimpleTableDef[] _tableDefinitions;
+    private final ColumnType _defaultRowKeyType;
+
+    /**
+     * Creates a {@link HBaseConfiguration} using default values.
+     */
+    public HBaseConfiguration() {
+        this(DEFAULT_ZOOKEEPER_HOSTNAME, DEFAULT_ZOOKEEPER_PORT);
+    }
+
+    public HBaseConfiguration(String zookeeperHostname, int zookeeperPort) {
+        this(DEFAULT_SCHEMA_NAME, zookeeperHostname, zookeeperPort, null, ColumnType.BINARY);
+    }
+    
+    public HBaseConfiguration(String zookeeperHostname, int zookeeperPort, ColumnType defaultRowKeyType) {
+        this(DEFAULT_SCHEMA_NAME, zookeeperHostname, zookeeperPort, null, defaultRowKeyType);
+    }
+
+    /**
+     * Creates a {@link HBaseConfiguration} using detailed configuration
+     * properties.
+     * 
+     * @param schemaName
+     * @param zookeeperHostname
+     * @param zookeeperPort
+     * @param tableDefinitions
+     * @param defaultRowKeyType
+     */
+    public HBaseConfiguration(String schemaName, String zookeeperHostname, int zookeeperPort,
+            SimpleTableDef[] tableDefinitions, ColumnType defaultRowKeyType) {
+        _schemaName = schemaName;
+        _zookeeperHostname = zookeeperHostname;
+        _zookeeperPort = zookeeperPort;
+        _tableDefinitions = tableDefinitions;
+        _defaultRowKeyType = defaultRowKeyType;
+    }
+
+    public String getSchemaName() {
+        return _schemaName;
+    }
+
+    public String getZookeeperHostname() {
+        return _zookeeperHostname;
+    }
+
+    public int getZookeeperPort() {
+        return _zookeeperPort;
+    }
+
+    public SimpleTableDef[] getTableDefinitions() {
+        return _tableDefinitions;
+    }
+    
+    public ColumnType getDefaultRowKeyType() {
+        return _defaultRowKeyType;
+    }
+
+    @Override
+    protected void decorateIdentity(List<Object> list) {
+        list.add(_schemaName);
+        list.add(_zookeeperHostname);
+        list.add(_zookeeperPort);
+        list.add(_tableDefinitions);
+        list.add(_defaultRowKeyType);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/hbase/src/main/java/org/apache/metamodel/hbase/HBaseDataContext.java
----------------------------------------------------------------------
diff --git a/hbase/src/main/java/org/apache/metamodel/hbase/HBaseDataContext.java b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseDataContext.java
new file mode 100644
index 0000000..b4da5d0
--- /dev/null
+++ b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseDataContext.java
@@ -0,0 +1,199 @@
+/**
+ * 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.hbase;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HTableInterface;
+import org.apache.hadoop.hbase.client.HTablePool;
+import org.apache.hadoop.hbase.client.ResultScanner;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.metamodel.DataContext;
+import org.apache.metamodel.MetaModelException;
+import org.apache.metamodel.QueryPostprocessDataContext;
+import org.apache.metamodel.data.DataSet;
+import org.apache.metamodel.query.FilterItem;
+import org.apache.metamodel.schema.Column;
+import org.apache.metamodel.schema.MutableSchema;
+import org.apache.metamodel.schema.Schema;
+import org.apache.metamodel.schema.Table;
+import org.apache.metamodel.util.FileHelper;
+import org.apache.metamodel.util.SimpleTableDef;
+
+/**
+ * MetaModel adaptor for Apache HBase.
+ */
+public class HBaseDataContext extends QueryPostprocessDataContext {
+
+    public static final String FIELD_ID = "_id";
+
+    private final HBaseConfiguration _configuration;
+    private final HBaseAdmin _admin;
+    private final HTablePool _tablePool;
+
+    /**
+     * Creates a {@link HBaseDataContext}.
+     * 
+     * @param configuration
+     */
+    public HBaseDataContext(HBaseConfiguration configuration) {
+        Configuration config = createConfig(configuration);
+        _configuration = configuration;
+        _admin = createHbaseAdmin(config);
+        _tablePool = new HTablePool(config, 100);
+    }
+
+    /**
+     * Creates a {@link HBaseDataContext}.
+     * 
+     * @param configuration
+     * @param admin
+     * @param hTablePool
+     */
+    public HBaseDataContext(HBaseConfiguration configuration, HBaseAdmin admin, HTablePool hTablePool) {
+        _configuration = configuration;
+        _tablePool = hTablePool;
+        _admin = admin;
+    }
+
+    private HBaseAdmin createHbaseAdmin(Configuration config) {
+        try {
+            return new HBaseAdmin(config);
+        } catch (Exception e) {
+            if (e instanceof RuntimeException) {
+                throw (RuntimeException) e;
+            }
+            throw new MetaModelException(e);
+        }
+    }
+
+    private Configuration createConfig(HBaseConfiguration configuration) {
+        Configuration config = org.apache.hadoop.hbase.HBaseConfiguration.create();
+        config.set("hbase.zookeeper.quorum", configuration.getZookeeperHostname());
+        config.set("hbase.zookeeper.property.clientPort", Integer.toString(configuration.getZookeeperPort()));
+        return config;
+    }
+
+    public HTablePool getTablePool() {
+        return _tablePool;
+    }
+
+    /**
+     * Gets the HBaseAdmin used by this {@link DataContext}
+     * 
+     * @return
+     */
+    public HBaseAdmin getHBaseAdmin() {
+        return _admin;
+    }
+
+    @Override
+    protected Schema getMainSchema() throws MetaModelException {
+        final MutableSchema schema = new MutableSchema(_configuration.getSchemaName());
+
+        try {
+            SimpleTableDef[] tableDefinitions = _configuration.getTableDefinitions();
+            if (tableDefinitions == null) {
+                final HTableDescriptor[] tables = _admin.listTables();
+                tableDefinitions = new SimpleTableDef[tables.length];
+                for (int i = 0; i < tables.length; i++) {
+                    SimpleTableDef emptyTableDef = new SimpleTableDef(tables[i].getNameAsString(), new String[0]);
+                    tableDefinitions[i] = emptyTableDef;
+                }
+            }
+
+            for (SimpleTableDef tableDef : tableDefinitions) {
+                schema.addTable(new HBaseTable(tableDef, schema, _admin, _configuration.getDefaultRowKeyType()));
+            }
+
+            return schema;
+        } catch (Exception e) {
+            throw new MetaModelException(e);
+        }
+    }
+
+    /**
+     * Gets the {@link HBaseConfiguration} that is used in this datacontext.
+     * 
+     * @return
+     */
+    public HBaseConfiguration getConfiguration() {
+        return _configuration;
+    }
+
+    @Override
+    protected String getMainSchemaName() throws MetaModelException {
+        return _configuration.getSchemaName();
+    }
+
+    @Override
+    protected Number executeCountQuery(Table table, List<FilterItem> whereItems, boolean functionApproximationAllowed) {
+        if (whereItems != null && !whereItems.isEmpty()) {
+            return null;
+        }
+
+        long result = 0;
+        final HTableInterface hTable = _tablePool.getTable(table.getName());
+        try {
+            ResultScanner scanner = hTable.getScanner(new Scan());
+            try {
+                while (scanner.next() != null) {
+                    result++;
+                }                
+            } finally {
+                scanner.close();
+            }
+            return result;
+        } catch (IOException e) {
+            throw new MetaModelException(e);
+        }
+    }
+
+    @Override
+    protected DataSet materializeMainSchemaTable(Table table, Column[] columns, int maxRows) {
+        final Scan scan = new Scan();
+        for (Column column : columns) {
+            if (!column.isPrimaryKey()) {
+                final int colonIndex = column.getName().indexOf(':');
+                if (colonIndex != -1) {
+                    String family = column.getName().substring(0, colonIndex);
+                    scan.addFamily(family.getBytes());
+                } else {
+                    scan.addFamily(column.getName().getBytes());
+                }
+            }
+        }
+
+        scan.setMaxResultSize(maxRows);
+
+        final HTableInterface hTable = _tablePool.getTable(table.getName());
+        try {
+            final ResultScanner scanner = hTable.getScanner(scan);
+            return new HBaseDataSet(columns, scanner, hTable);
+        } catch (Exception e) {
+            FileHelper.safeClose(hTable);
+            throw new MetaModelException(e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/hbase/src/main/java/org/apache/metamodel/hbase/HBaseDataSet.java
----------------------------------------------------------------------
diff --git a/hbase/src/main/java/org/apache/metamodel/hbase/HBaseDataSet.java b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseDataSet.java
new file mode 100644
index 0000000..699774d
--- /dev/null
+++ b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseDataSet.java
@@ -0,0 +1,77 @@
+/**
+ * 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.hbase;
+
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.client.HTableInterface;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.client.ResultScanner;
+import org.apache.metamodel.MetaModelException;
+import org.apache.metamodel.data.AbstractDataSet;
+import org.apache.metamodel.data.Row;
+import org.apache.metamodel.schema.Column;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class HBaseDataSet extends AbstractDataSet {
+
+    private static final Logger logger = LoggerFactory.getLogger(HBaseDataSet.class);
+
+    private final ResultScanner _scanner;
+    private final HTableInterface _hTable;
+    private volatile Result _nextResult;
+
+    public HBaseDataSet(Column[] columns, ResultScanner scanner, HTableInterface hTable) {
+        super(columns);
+        _scanner = scanner;
+        _hTable = hTable;
+    }
+
+    @Override
+    public void close() {
+        super.close();
+        try {
+            _scanner.close();
+        } catch (Exception e) {
+            logger.warn("Failed to close ResultScanner", e);
+        }
+        try {
+            _hTable.close();
+        } catch (Exception e) {
+            logger.warn("Failed to close HTable", e);
+        }
+    }
+
+    @Override
+    public boolean next() {
+        try {
+            _nextResult = _scanner.next();
+        } catch (IOException e) {
+            throw new MetaModelException(e);
+        }
+        return _nextResult != null;
+    }
+
+    @Override
+    public Row getRow() {
+        return new HBaseRow(getHeader(), _nextResult);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/hbase/src/main/java/org/apache/metamodel/hbase/HBaseFamilyMap.java
----------------------------------------------------------------------
diff --git a/hbase/src/main/java/org/apache/metamodel/hbase/HBaseFamilyMap.java b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseFamilyMap.java
new file mode 100644
index 0000000..38a6848
--- /dev/null
+++ b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseFamilyMap.java
@@ -0,0 +1,116 @@
+/**
+ * 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.hbase;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.Set;
+
+public class HBaseFamilyMap implements Map<Object, Object> {
+
+    private final NavigableMap<byte[], byte[]> _map;
+
+    public HBaseFamilyMap(NavigableMap<byte[], byte[]> map) {
+        _map = map;
+    }
+
+    @Override
+    public int size() {
+        return _map.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return _map.isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        return _map.containsKey(ByteUtils.toBytes(key));
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        return _map.containsValue(ByteUtils.toBytes(value));
+    }
+
+    @Override
+    public Object get(Object key) {
+        return _map.get(ByteUtils.toBytes(key));
+    }
+
+    @Override
+    public Object put(Object key, Object value) {
+        throw new UnsupportedOperationException("HBase row value map is immutable");
+    }
+
+    @Override
+    public Object remove(Object key) {
+        throw new UnsupportedOperationException("HBase row value map is immutable");
+    }
+
+    @Override
+    public void putAll(Map<? extends Object, ? extends Object> m) {
+        throw new UnsupportedOperationException("HBase row value map is immutable");
+    }
+
+    @Override
+    public void clear() {
+        throw new UnsupportedOperationException("HBase row value map is immutable");
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Set<Object> keySet() {
+        Set<?> keySet = _map.keySet();
+        return (Set<Object>) keySet;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Collection<Object> values() {
+        Collection<?> values = _map.values();
+        return (Collection<Object>) values;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Set<java.util.Map.Entry<Object, Object>> entrySet() {
+        final Set<?> entrySet = _map.entrySet();
+        return (Set<java.util.Map.Entry<Object, Object>>) entrySet;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        for (java.util.Map.Entry<byte[], byte[]> entry : _map.entrySet()) {
+            if (sb.length() > 1) {
+                sb.append(',');
+            }
+            sb.append(Arrays.toString(entry.getKey()));
+            sb.append('=');
+            sb.append(Arrays.toString(entry.getValue()));
+        }
+        sb.append('}');
+        return sb.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/hbase/src/main/java/org/apache/metamodel/hbase/HBaseRow.java
----------------------------------------------------------------------
diff --git a/hbase/src/main/java/org/apache/metamodel/hbase/HBaseRow.java b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseRow.java
new file mode 100644
index 0000000..b091ae1
--- /dev/null
+++ b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseRow.java
@@ -0,0 +1,89 @@
+/**
+ * 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.hbase;
+
+import java.util.NavigableMap;
+
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.metamodel.data.AbstractRow;
+import org.apache.metamodel.data.DataSetHeader;
+import org.apache.metamodel.data.Row;
+import org.apache.metamodel.data.Style;
+import org.apache.metamodel.schema.Column;
+
+/**
+ * Row implementation around a HBase result
+ */
+final class HBaseRow extends AbstractRow implements Row {
+
+    private static final long serialVersionUID = 1L;
+
+    private final DataSetHeader _header;
+    private final Result _result;
+
+    public HBaseRow(DataSetHeader header, Result result) {
+        _header = header;
+        _result = result;
+    }
+
+    @Override
+    protected DataSetHeader getHeader() {
+        return _header;
+    }
+
+    @Override
+    public Object getValue(int index) throws IndexOutOfBoundsException {
+        final Column column = _header.getSelectItem(index).getColumn();
+        final String name = column.getName();
+        if (HBaseDataContext.FIELD_ID.equals(name)) {
+            byte[] rowKey = _result.getRow();
+            if (column.getType().isLiteral()) {
+                return Bytes.toString(rowKey);
+            }
+            return rowKey;
+        }
+
+        final int colonIndex = name.indexOf(':');
+        if (colonIndex != -1) {
+            byte[] family = name.substring(0, colonIndex).getBytes();
+            byte[] qualifier = name.substring(colonIndex + 1).getBytes();
+            byte[] value = _result.getValue(family, qualifier);
+            if (value == null) {
+                return null;
+            }
+            if (column.getType().isLiteral()) {
+                return Bytes.toString(value);
+            }
+            return value;
+        } else {
+            final NavigableMap<byte[], byte[]> map = _result.getFamilyMap(name.getBytes());
+            if (map == null || map.isEmpty()) {
+                return map;
+            }
+            return new HBaseFamilyMap(map);
+        }
+    }
+
+    @Override
+    public Style getStyle(int index) throws IndexOutOfBoundsException {
+        return Style.NO_STYLE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/hbase/src/main/java/org/apache/metamodel/hbase/HBaseTable.java
----------------------------------------------------------------------
diff --git a/hbase/src/main/java/org/apache/metamodel/hbase/HBaseTable.java b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseTable.java
new file mode 100644
index 0000000..b79acac
--- /dev/null
+++ b/hbase/src/main/java/org/apache/metamodel/hbase/HBaseTable.java
@@ -0,0 +1,129 @@
+/**
+ * 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.hbase;
+
+import java.util.List;
+
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.metamodel.MetaModelException;
+import org.apache.metamodel.schema.Column;
+import org.apache.metamodel.schema.ColumnType;
+import org.apache.metamodel.schema.MutableColumn;
+import org.apache.metamodel.schema.MutableSchema;
+import org.apache.metamodel.schema.MutableTable;
+import org.apache.metamodel.schema.TableType;
+import org.apache.metamodel.util.SimpleTableDef;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Table implementation for HBase
+ */
+final class HBaseTable extends MutableTable {
+
+    private static final long serialVersionUID = 1L;
+    private static final Logger logger = LoggerFactory.getLogger(HBaseTable.class);
+
+    private final transient HBaseAdmin _admin;
+    private final transient ColumnType _defaultRowKeyColumnType;
+
+    public HBaseTable(SimpleTableDef tableDef, MutableSchema schema, HBaseAdmin admin,
+            ColumnType defaultRowKeyColumnType) {
+        super(tableDef.getName(), TableType.TABLE, schema);
+        _admin = admin;
+        _defaultRowKeyColumnType = defaultRowKeyColumnType;
+
+        final String[] columnNames = tableDef.getColumnNames();
+        if (columnNames == null || columnNames.length == 0) {
+            logger.info("No user-defined columns specified for table {}. Columns will be auto-detected.");
+        } else {
+
+            final ColumnType[] types = tableDef.getColumnTypes();
+            int columnNumber = 1;
+
+            for (int i = 0; i < columnNames.length; i++) {
+                String columnName = columnNames[i];
+                if (HBaseDataContext.FIELD_ID.equals(columnName)) {
+                    final ColumnType type = types[i];
+                    final MutableColumn idColumn = new MutableColumn(HBaseDataContext.FIELD_ID, type)
+                            .setPrimaryKey(true).setColumnNumber(columnNumber).setTable(this);
+                    addColumn(idColumn);
+                    columnNumber++;
+                }
+            }
+
+            if (columnNumber == 1) {
+                // insert a default definition of the id column
+                final MutableColumn idColumn = new MutableColumn(HBaseDataContext.FIELD_ID,
+                        defaultRowKeyColumnType).setPrimaryKey(true).setColumnNumber(columnNumber).setTable(this);
+                addColumn(idColumn);
+                columnNumber++;
+            }
+
+            for (int i = 0; i < columnNames.length; i++) {
+                final String columnName = columnNames[i];
+
+                if (!HBaseDataContext.FIELD_ID.equals(columnName)) {
+                    final ColumnType type = types[i];
+                    final MutableColumn column = new MutableColumn(columnName, type);
+                    column.setTable(this);
+                    column.setColumnNumber(columnNumber);
+                    columnNumber++;
+                    addColumn(column);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected List<Column> getColumnsInternal() {
+        final List<Column> columnsInternal = super.getColumnsInternal();
+        if (columnsInternal.isEmpty() && _admin != null) {
+            try {
+                HTableDescriptor tableDescriptor = _admin.getTableDescriptor(getName().getBytes());
+                int columnNumber = 1;
+
+                final MutableColumn idColumn = new MutableColumn(HBaseDataContext.FIELD_ID,
+                        _defaultRowKeyColumnType).setPrimaryKey(true).setColumnNumber(columnNumber).setTable(this);
+                addColumn(idColumn);
+                columnNumber++;
+
+                // What about timestamp?
+
+                final HColumnDescriptor[] columnFamilies = tableDescriptor.getColumnFamilies();
+                for (int i = 0; i < columnFamilies.length; i++) {
+                    final HColumnDescriptor columnDescriptor = columnFamilies[i];
+                    final String columnFamilyName = columnDescriptor.getNameAsString();
+                    // HBase column families are always unstructured maps.
+                    final ColumnType type = ColumnType.MAP;
+                    final MutableColumn column = new MutableColumn(columnFamilyName, type);
+                    column.setTable(this);
+                    column.setColumnNumber(columnNumber);
+                    columnNumber++;
+                    addColumn(column);
+                }
+            } catch (Exception e) {
+                throw new MetaModelException("Could not resolve table ", e);
+            }
+        }
+        return columnsInternal;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/hbase/src/main/java/org/apache/metamodel/hbase/package-info.java
----------------------------------------------------------------------
diff --git a/hbase/src/main/java/org/apache/metamodel/hbase/package-info.java b/hbase/src/main/java/org/apache/metamodel/hbase/package-info.java
new file mode 100644
index 0000000..f373be0
--- /dev/null
+++ b/hbase/src/main/java/org/apache/metamodel/hbase/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/**
+ * Module package for Apache HBase
+ */
+package org.apache.metamodel.hbase;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/hbase/src/test/java/org/apache/metamodel/hbase/HBaseDataContextTest.java
----------------------------------------------------------------------
diff --git a/hbase/src/test/java/org/apache/metamodel/hbase/HBaseDataContextTest.java b/hbase/src/test/java/org/apache/metamodel/hbase/HBaseDataContextTest.java
new file mode 100644
index 0000000..0782231
--- /dev/null
+++ b/hbase/src/test/java/org/apache/metamodel/hbase/HBaseDataContextTest.java
@@ -0,0 +1,159 @@
+/**
+ * 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.hbase;
+
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
+import org.apache.hadoop.hbase.client.HTableInterface;
+import org.apache.hadoop.hbase.client.HTablePool;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.metamodel.data.DataSet;
+import org.apache.metamodel.schema.ColumnType;
+import org.apache.metamodel.schema.Table;
+import org.apache.metamodel.util.SimpleTableDef;
+
+public class HBaseDataContextTest extends TestCase {
+
+    private static final String EXAMPLE_TABLE_NAME = "table_for_junit";
+
+    private final String hostname = HBaseConfiguration.DEFAULT_ZOOKEEPER_HOSTNAME;
+    private final int port = HBaseConfiguration.DEFAULT_ZOOKEEPER_PORT;
+
+    private HBaseDataContext _dataContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        _dataContext = new HBaseDataContext(new HBaseConfiguration(hostname, port, ColumnType.VARCHAR));
+        createTableNatively();
+    }
+
+    public void testCreateInsertQueryAndDrop() throws Exception {
+        // test the schema exploration
+        final Table table = _dataContext.getDefaultSchema().getTableByName(EXAMPLE_TABLE_NAME);
+        assertNotNull(table);
+
+        assertEquals("[_id, bar, foo]", Arrays.toString(table.getColumnNames()));
+        assertEquals(ColumnType.MAP, table.getColumn(1).getType());
+
+        // insert two records
+        insertRecordsNatively();
+
+        // query using regular configuration
+        final DataSet dataSet1 = _dataContext.query().from(EXAMPLE_TABLE_NAME).selectAll().execute();
+        try {
+            assertTrue(dataSet1.next());
+            assertEquals(
+                    "Row[values=[junit1, {[104, 101, 121]=[121, 111],[104, 105]=[116, 104, 101, 114, 101]}, {[104, 101, 108, 108, 111]=[119, 111, 114, 108, 100]}]]",
+                    dataSet1.getRow().toString());
+            assertTrue(dataSet1.next());
+            assertEquals("Row[values=[junit2, {[98, 97, 104]=[1, 2, 3],[104, 105]=[121, 111, 117]}, {}]]", dataSet1
+                    .getRow().toString());
+            assertFalse(dataSet1.next());
+        } finally {
+            dataSet1.close();
+        }
+
+        // query using custom table definitions
+        final String[] columnNames = new String[] { "foo", "bar:hi", "bar:hey" };
+        final ColumnType[] columnTypes = new ColumnType[] { ColumnType.MAP, ColumnType.VARCHAR, ColumnType.VARCHAR };
+        final SimpleTableDef[] tableDefinitions = new SimpleTableDef[] { new SimpleTableDef(EXAMPLE_TABLE_NAME,
+                columnNames, columnTypes) };
+        _dataContext = new HBaseDataContext(new HBaseConfiguration("SCH", hostname, port, tableDefinitions,
+                ColumnType.VARCHAR));
+
+        final DataSet dataSet2 = _dataContext.query().from(EXAMPLE_TABLE_NAME).select("foo", "bar:hi", "bar:hey")
+                .execute();
+        try {
+            assertTrue(dataSet2.next());
+            assertEquals("Row[values=[{[104, 101, 108, 108, 111]=[119, 111, 114, 108, 100]}, there, yo]]", dataSet2
+                    .getRow().toString());
+            assertTrue(dataSet2.next());
+            assertEquals("Row[values=[{}, you, null]]", dataSet2.getRow().toString());
+            assertFalse(dataSet2.next());
+        } finally {
+            dataSet2.close();
+        }
+
+        // query count
+        final DataSet dataSet3 = _dataContext.query().from(EXAMPLE_TABLE_NAME).selectCount().execute();
+        try {
+            assertTrue(dataSet3.next());
+            assertEquals("Row[values=[2]]", dataSet3.getRow().toString());
+            assertFalse(dataSet3.next());
+        } finally {
+            dataSet3.close();
+        }
+
+        // query only id
+        final DataSet dataSet4 = _dataContext.query().from(EXAMPLE_TABLE_NAME)
+                .select(HBaseDataContext.FIELD_ID).execute();
+        try {
+            assertTrue(dataSet4.next());
+            assertEquals("Row[values=[junit1]]", dataSet4.getRow().toString());
+            assertTrue(dataSet4.next());
+            assertEquals("Row[values=[junit2]]", dataSet4.getRow().toString());
+            assertFalse(dataSet4.next());
+        } finally {
+            dataSet4.close();
+        }
+    }
+
+    private void insertRecordsNatively() throws Exception {
+        final HTablePool tablePool = _dataContext.getTablePool();
+        final HTableInterface hTable = tablePool.getTable(EXAMPLE_TABLE_NAME);
+        try {
+            final Put put1 = new Put("junit1".getBytes());
+            put1.add("foo".getBytes(), "hello".getBytes(), "world".getBytes());
+            put1.add("bar".getBytes(), "hi".getBytes(), "there".getBytes());
+            put1.add("bar".getBytes(), "hey".getBytes(), "yo".getBytes());
+
+            final Put put2 = new Put("junit2".getBytes());
+            put2.add("bar".getBytes(), "bah".getBytes(), new byte[] { 1, 2, 3 });
+            put2.add("bar".getBytes(), "hi".getBytes(), "you".getBytes());
+
+            hTable.batch(Arrays.asList(put1, put2));
+        } finally {
+            hTable.close();
+            tablePool.closeTablePool(EXAMPLE_TABLE_NAME);
+            tablePool.close();
+        }
+    }
+
+    private void createTableNatively() throws Exception {
+        // check if the table exists
+        if (_dataContext.getHBaseAdmin().isTableAvailable(EXAMPLE_TABLE_NAME)) {
+            // table already exists
+            return;
+        }
+
+        HBaseAdmin admin = _dataContext.getHBaseAdmin();
+        System.out.println("Creating table");
+        final HTableDescriptor tableDescriptor = new HTableDescriptor(EXAMPLE_TABLE_NAME.getBytes());
+        tableDescriptor.addFamily(new HColumnDescriptor("foo".getBytes()));
+        tableDescriptor.addFamily(new HColumnDescriptor("bar".getBytes()));
+        admin.createTable(tableDescriptor);
+        System.out.println("Created table");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/eba65a05/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 2cff794..92f4106 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,7 @@
 		<module>xml</module>
 		<module>access</module>
 		<module>jdbc</module>
+		<module>hbase</module>
 		<module>mongodb</module>
 		<module>couchdb</module>
 		<module>openoffice</module>