METAMODEL-1205: Fixed CassandraUnit, Guava, Hadoop for JDK9+
[metamodel.git] / hbase / src / main / java / org / apache / metamodel / hbase / HBaseTable.java
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.metamodel.hbase;
20
21 import java.util.List;
22 import java.util.Set;
23 import java.util.stream.Collectors;
24
25 import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
26 import org.apache.metamodel.MetaModelException;
27 import org.apache.metamodel.schema.Column;
28 import org.apache.metamodel.schema.ColumnType;
29 import org.apache.metamodel.schema.MutableSchema;
30 import org.apache.metamodel.schema.MutableTable;
31 import org.apache.metamodel.schema.TableType;
32 import org.apache.metamodel.util.SimpleTableDef;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37 * Table implementation for HBase
38 */
39 final class HBaseTable extends MutableTable {
40
41 private static final long serialVersionUID = 1L;
42 private static final Logger logger = LoggerFactory.getLogger(HBaseTable.class);
43
44 private final transient HBaseDataContext _dataContext;
45 private final transient ColumnType _defaultRowKeyColumnType;
46
47 /**
48 * Creates an HBaseTable. If the tableDef variable doesn't include the ID-column (see
49 * {@link HBaseDataContext#FIELD_ID}). Then it's first added.
50 *
51 * @param dataContext
52 * @param tableDef Table definition. The tableName, columnNames and columnTypes variables are used.
53 * @param schema {@link MutableSchema} where the table belongs to.
54 * @param defaultRowKeyColumnType This variable determines the {@link ColumnType}, used when the tableDef doesn't
55 * include the ID column (see {@link HBaseDataContext#FIELD_ID}).
56 */
57 public HBaseTable(final HBaseDataContext dataContext, final SimpleTableDef tableDef, final MutableSchema schema,
58 final ColumnType defaultRowKeyColumnType) {
59 super(tableDef.getName(), TableType.TABLE, schema);
60 _dataContext = dataContext;
61 _defaultRowKeyColumnType = defaultRowKeyColumnType;
62 addColumns(tableDef);
63 }
64
65 /**
66 * Add multiple columns to this table
67 *
68 * @param tableDef
69 */
70 private void addColumns(final SimpleTableDef tableDef) {
71 // Add the columns
72 final String[] columnNames = tableDef.getColumnNames();
73 if (columnNames == null || columnNames.length == 0) {
74 logger.info("No user-defined columns specified for table {}. Columns will be auto-detected.");
75 } else {
76 final ColumnType[] columnTypes = tableDef.getColumnTypes();
77
78 // Find the ID-Column
79 int indexOfIDColumn = getIndexOfIdColumn(columnNames);
80 boolean idColumnFound = indexOfIDColumn != -1;
81
82 // ColumnNumbers start from 1
83 if (idColumnFound) {
84 addColumn(HBaseDataContext.FIELD_ID, columnTypes[indexOfIDColumn], indexOfIDColumn + 1);
85 } else {
86 addColumn(HBaseDataContext.FIELD_ID, _defaultRowKeyColumnType, 1);
87 }
88
89 // Add the other columns
90 for (int i = 0; i < columnNames.length; i++) {
91 if (!HBaseDataContext.FIELD_ID.equals(columnNames[i])) {
92 if (idColumnFound) {
93 addColumn(columnNames[i], columnTypes[i], i + 1);
94 } else {
95 addColumn(columnNames[i], columnTypes[i], i + 2);
96 }
97 }
98 }
99 }
100 }
101
102 /**
103 * Returns the index of the ID-column (see {@link HBaseDataContext#FIELD_ID}) in an array of columnNames. When no
104 * ID-column is found, then -1 is returned.
105 *
106 * @param columnNames
107 * @return {@link Integer}
108 */
109 private static int getIndexOfIdColumn(final String[] columnNames) {
110 for (int i = 0; i < columnNames.length; i++) {
111 if (HBaseDataContext.FIELD_ID.equals(columnNames[i])) {
112 return i;
113 }
114 }
115 return -1;
116 }
117
118 /**
119 * Add a column to this table
120 *
121 * @param columnName
122 * @param columnType
123 * @param columnNumber
124 */
125 private void addColumn(final String columnName, final ColumnType columnType, final int columnNumber) {
126 addColumn(new HBaseColumn(columnName, null, this, columnNumber, columnType));
127 }
128
129 @Override
130 protected synchronized List<Column> getColumnsInternal() {
131 final List<Column> columnsInternal = super.getColumnsInternal();
132 if (columnsInternal.isEmpty() && _dataContext != null) {
133 try (final org.apache.hadoop.hbase.client.Table table = _dataContext.getHTable(getName())) {
134 // Add the ID-Column (with columnNumber = 1)
135 addColumn(HBaseDataContext.FIELD_ID, _defaultRowKeyColumnType, 1);
136
137 // What about timestamp?
138
139 // Add the other column (with columnNumbers starting from 2)
140 final ColumnFamilyDescriptor[] columnFamilies = table.getDescriptor().getColumnFamilies();
141 for (int i = 0; i < columnFamilies.length; i++) {
142 addColumn(columnFamilies[i].getNameAsString(), HBaseColumn.DEFAULT_COLUMN_TYPE_FOR_COLUMN_FAMILIES,
143 i + 2);
144 }
145 } catch (Exception e) {
146 throw new MetaModelException("Could not resolve table ", e);
147 }
148 }
149 return columnsInternal;
150 }
151
152 /**
153 * Returns the column families for this HBase table.
154 *
155 * @return {@link Set}<{@link String}> of columnFamilies
156 */
157 Set<String> getColumnFamilies() {
158 return getColumnsInternal().stream().map(column -> (HBaseColumn) column).map(HBaseColumn::getColumnFamily)
159 .distinct().collect(Collectors.toSet());
160 }
161 }