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>