/* * Copyright 2011-2015 the original author or authors. * * Licensed 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.springframework.data.hadoop.hbase; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.HTableInterface; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.springframework.dao.DataAccessException; import org.springframework.util.Assert; import java.io.IOException; import java.util.List; /** * Central class for accessing the HBase API. Simplifies the use of HBase and helps to avoid common errors. * It executes core HBase workflow, leaving application code to invoke actions and extract results. * * @author Costin Leau * @author Shaun Elliott */ public class HbaseTemplate extends HbaseAccessor implements HbaseOperations { private boolean autoFlush = true; public HbaseTemplate() { } public HbaseTemplate(Configuration configuration) { setConfiguration(configuration); afterPropertiesSet(); } @Override public <T> T execute(String tableName, TableCallback<T> action) { Assert.notNull(action, "Callback object must not be null"); Assert.notNull(tableName, "No table specified"); HTableInterface table = getTable(tableName); try { boolean previousFlushSetting = applyFlushSetting(table); T result = action.doInTable(table); flushIfNecessary(table, previousFlushSetting); return result; } catch (Throwable th) { if (th instanceof Error) { throw ((Error) th); } if (th instanceof RuntimeException) { throw ((RuntimeException) th); } throw convertHbaseAccessException((Exception) th); } finally { releaseTable(tableName, table); } } private HTableInterface getTable(String tableName) { return HbaseUtils.getHTable(tableName, getConfiguration(), getCharset(), getTableFactory()); } private void releaseTable(String tableName, HTableInterface table) { HbaseUtils.releaseTable(tableName, table, getTableFactory()); } @SuppressWarnings("deprecation") private boolean applyFlushSetting(HTableInterface table) { boolean autoFlush = table.isAutoFlush(); if (table instanceof HTable) { ((HTable) table).setAutoFlush(this.autoFlush); } return autoFlush; } @SuppressWarnings("deprecation") private void restoreFlushSettings(HTableInterface table, boolean oldFlush) { if (table instanceof HTable) { if (table.isAutoFlush() != oldFlush) { ((HTable) table).setAutoFlush(oldFlush); } } } private void flushIfNecessary(HTableInterface table, boolean oldFlush) throws IOException { // TODO: check whether we can consider or not a table scope table.flushCommits(); restoreFlushSettings(table, oldFlush); } public DataAccessException convertHbaseAccessException(Exception ex) { return HbaseUtils.convertHbaseException(ex); } @Override public <T> T find(String tableName, String family, final ResultsExtractor<T> action) { Scan scan = new Scan(); scan.addFamily(family.getBytes(getCharset())); return find(tableName, scan, action); } @Override public <T> T find(String tableName, String family, String qualifier, final ResultsExtractor<T> action) { Scan scan = new Scan(); scan.addColumn(family.getBytes(getCharset()), qualifier.getBytes(getCharset())); return find(tableName, scan, action); } @Override public <T> T find(String tableName, final Scan scan, final ResultsExtractor<T> action) { return execute(tableName, new TableCallback<T>() { @Override public T doInTable(HTableInterface htable) throws Throwable { ResultScanner scanner = htable.getScanner(scan); try { return action.extractData(scanner); } finally { scanner.close(); } } }); } @Override public <T> List<T> find(String tableName, String family, final RowMapper<T> action) { Scan scan = new Scan(); scan.addFamily(family.getBytes(getCharset())); return find(tableName, scan, action); } @Override public <T> List<T> find(String tableName, String family, String qualifier, final RowMapper<T> action) { Scan scan = new Scan(); scan.addColumn(family.getBytes(getCharset()), qualifier.getBytes(getCharset())); return find(tableName, scan, action); } @Override public <T> List<T> find(String tableName, final Scan scan, final RowMapper<T> action) { return find(tableName, scan, new RowMapperResultsExtractor<T>(action)); } @Override public <T> T get(String tableName, String rowName, final RowMapper<T> mapper) { return get(tableName, rowName, null, null, mapper); } @Override public <T> T get(String tableName, String rowName, String familyName, final RowMapper<T> mapper) { return get(tableName, rowName, familyName, null, mapper); } @Override public <T> T get(String tableName, final String rowName, final String familyName, final String qualifier, final RowMapper<T> mapper) { return execute(tableName, new TableCallback<T>() { @Override public T doInTable(HTableInterface htable) throws Throwable { Get get = new Get(rowName.getBytes(getCharset())); if (familyName != null) { byte[] family = familyName.getBytes(getCharset()); if (qualifier != null) { get.addColumn(family, qualifier.getBytes(getCharset())); } else { get.addFamily(family); } } Result result = htable.get(get); return mapper.mapRow(result, 0); } }); } @Override public void put(String tableName, final String rowName, final String familyName, final String qualifier, final byte[] value) { Assert.hasLength(rowName); Assert.hasLength(familyName); Assert.hasLength(qualifier); Assert.notNull(value); execute(tableName, new TableCallback<Object>() { @Override public Object doInTable(HTableInterface htable) throws Throwable { Put put = new Put(rowName.getBytes(getCharset())).add(familyName.getBytes(getCharset()), qualifier.getBytes(getCharset()), value); htable.put(put); return null; } }); } @Override public void delete(String tableName, final String rowName, final String familyName) { delete(tableName, rowName, familyName, null); } @Override public void delete(String tableName, final String rowName, final String familyName, final String qualifier) { Assert.hasLength(rowName); Assert.hasLength(familyName); execute(tableName, new TableCallback<Object>() { @Override public Object doInTable(HTableInterface htable) throws Throwable { Delete delete = new Delete(rowName.getBytes(getCharset())); byte[] family = familyName.getBytes(getCharset()); if (qualifier != null) { delete.deleteColumn(family, qualifier.getBytes(getCharset())); } else { delete.deleteFamily(family); } htable.delete(delete); return null; } }); } /** * Sets the auto flush. * * @param autoFlush The autoFlush to set. */ public void setAutoFlush(boolean autoFlush) { this.autoFlush = autoFlush; } }