/*
* This is a common dao with basic CRUD operations and is not limited to any
* persistent layer implementation
*
* Copyright (C) 2010 Imran M Yousuf (imyousuf@smartitengineering.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.smartitengineering.dao.impl.hbase.spi.impl;
import com.google.inject.Inject;
import com.smartitengineering.dao.impl.hbase.spi.AsyncExecutorService;
import com.smartitengineering.dao.impl.hbase.spi.ExecutorService;
import com.smartitengineering.dao.impl.hbase.spi.LockAttainer;
import com.smartitengineering.dao.impl.hbase.spi.ObjectRowConverter;
import com.smartitengineering.dao.impl.hbase.spi.SchemaInfoProvider;
import com.smartitengineering.domain.PersistentDTO;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.RowLock;
import org.apache.hadoop.hbase.util.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author imyousuf
*/
public abstract class AbstractObjectRowConverter<T extends PersistentDTO<? extends PersistentDTO, ? extends Comparable, Long>, IdType>
implements ObjectRowConverter<T> {
@Inject
private SchemaInfoProvider<T, IdType> infoProvider;
@Inject
private LockAttainer<T, IdType> lockAttainer;
protected final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public LinkedHashMap<String, Put> objectToRows(final T instance, final ExecutorService service,
boolean pessimisticLock) {
final AsyncExecutorService executorService;
if (service instanceof AsyncExecutorService) {
executorService = (AsyncExecutorService) service;
}
else {
executorService = null;
}
if (logger.isDebugEnabled()) {
logger.debug("Executor service " + executorService + " " + executorService);
}
LinkedHashMap<String, Put> puts = new LinkedHashMap<String, Put>();
String[] tables = getTablesToAttainLock();
Map<String, RowLock> map = getLocks(executorService, instance, pessimisticLock, tables);
if (tables != null) {
for (String table : tables) {
try {
if (logger.isDebugEnabled()) {
logger.debug(new StringBuilder("Working with table ").append(table).toString());
logger.debug(new StringBuilder("Future ").append(map.get(table)).toString());
}
RowLock lock = map.get(table);
final Put put;
if (lock == null) {
logger.info("Creating put without lock");
put = new Put(infoProvider.getRowIdFromRow(instance));
}
else {
if (logger.isInfoEnabled()) {
logger.info("Creating put with lock " + lock.getLockId());
}
put = new Put(infoProvider.getRowIdFromRow(instance), lock);
}
final byte[] family = infoProvider.getVersionColumnFamily();
final byte[] qualifier = infoProvider.getVersionColumnQualifier();
if (family != null && qualifier != null && instance.getVersion() != null) {
put.add(family, qualifier, Bytes.toBytes(instance.getVersion()));
}
getPutForTable(instance, service, put);
puts.put(table, put);
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
return puts;
}
protected Map<String, RowLock> getLocks(AsyncExecutorService executorService, final T instance,
boolean pessimisticLock, String... tables) {
logger.info("Attempting to get locks");
if (pessimisticLock) {
return lockAttainer.getLock(instance, tables);
}
else {
return Collections.emptyMap();
}
}
@Override
public LinkedHashMap<String, Delete> objectToDeleteableRows(T instance, ExecutorService service,
boolean pessimisticLock) {
AsyncExecutorService executorService;
if (service instanceof AsyncExecutorService) {
executorService = (AsyncExecutorService) service;
}
else {
executorService = null;
}
LinkedHashMap<String, Delete> deletes = new LinkedHashMap<String, Delete>();
String[] tables = getTablesToAttainLock();
Map<String, RowLock> map = getLocks(executorService, instance, pessimisticLock, tables);
if (tables != null) {
for (String table : tables) {
try {
RowLock lock = map.get(table);
final Delete delete;
if (lock == null) {
delete = new Delete(infoProvider.getRowIdFromRow(instance));
}
else {
delete = new Delete(infoProvider.getRowIdFromRow(instance), HConstants.LATEST_TIMESTAMP, lock);
}
getDeleteForTable(instance, service, delete);
deletes.put(table, delete);
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
return deletes;
}
protected SchemaInfoProvider<T, IdType> getInfoProvider() {
return infoProvider;
}
protected void addColumn(String family, String column, String value, Put put) {
addColumn(Bytes.toBytes(family), Bytes.toBytes(column), value, put);
}
protected void addColumn(byte[] family, byte[] column, String value, Put put) {
addColumn(family, column, Bytes.toBytes(value), put);
}
protected void addColumn(String family, String column, Long value, Put put) {
addColumn(Bytes.toBytes(family), Bytes.toBytes(column), value, put);
}
protected void addColumn(byte[] family, byte[] column, Long value, Put put) {
addColumn(family, column, Bytes.toBytes(value), put);
}
protected void addColumn(String family, String column, Integer value, Put put) {
addColumn(Bytes.toBytes(family), Bytes.toBytes(column), value, put);
}
protected void addColumn(byte[] family, byte[] column, Integer value, Put put) {
addColumn(family, column, Bytes.toBytes(value), put);
}
protected void addColumn(String family, String column, Double value, Put put) {
addColumn(Bytes.toBytes(family), Bytes.toBytes(column), value, put);
}
protected void addColumn(byte[] family, byte[] column, Double value, Put put) {
addColumn(family, column, Bytes.toBytes(value), put);
}
protected void addColumn(String family, String column, Boolean value, Put put) {
addColumn(Bytes.toBytes(family), Bytes.toBytes(column), value, put);
}
protected void addColumn(byte[] family, byte[] column, Boolean value, Put put) {
addColumn(family, column, Bytes.toBytes(value), put);
}
protected void addColumn(byte[] family, byte[] column, byte[] value, Put put) {
put.add(family, column, value);
}
protected void populateVersion(T instance, Result row) {
byte[] verFam = getInfoProvider().getVersionColumnFamily();
byte[] verQual = getInfoProvider().getVersionColumnQualifier();
if (verFam != null && verQual != null && row.containsColumn(verFam, verQual)) {
instance.setVersion(Long.valueOf(Bytes.toLong(row.getValue(verFam, verQual))));
}
}
protected abstract String[] getTablesToAttainLock();
protected abstract void getPutForTable(T instance, ExecutorService service, Put put);
protected abstract void getDeleteForTable(T instance, ExecutorService service, Delete put);
}