/*
* Copyright 2012 NGDATA nv
*
* 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.lilyproject.repository.impl;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.ngdata.lily.security.hbase.client.AuthEnabledHTable;
import com.ngdata.lily.security.hbase.client.AuthorizationContextProvider;
import org.apache.hadoop.hbase.client.HTableInterface;
import org.apache.hadoop.hbase.util.Bytes;
import org.lilyproject.repository.api.IdGenerator;
import org.lilyproject.repository.api.LRepository;
import org.lilyproject.repository.api.RecordFactory;
import org.lilyproject.repository.api.Repository;
import org.lilyproject.repository.api.RepositoryException;
import org.lilyproject.repository.api.RepositoryManager;
import org.lilyproject.repository.api.RepositoryUnavailableException;
import org.lilyproject.repository.api.TypeManager;
import org.lilyproject.repository.model.api.RepositoryModel;
import org.lilyproject.util.hbase.LilyHBaseSchema;
import org.lilyproject.util.hbase.LilyHBaseSchema.Table;
import org.lilyproject.util.hbase.RepoAndTableUtil;
import org.lilyproject.util.io.Closer;
/**
* Handles thread-safe creation and caching of Repository objects.
*/
public abstract class AbstractRepositoryManager implements RepositoryManager {
private final Map<RepoTableKey, Repository> repositoryCache = Maps.newHashMap();
private final TypeManager typeManager;
private final IdGenerator idGenerator;
private final RecordFactory recordFactory;
private final RepositoryModel repositoryModel;
private final AuthorizationContextProvider authzCtxProvider = new DRAuthorizationContextProvider();
/**
* For NGDATA's hbase authorization layer: unique name for the application, in order to
* identify the relevant set of permissions.
*/
private static final String PERMISSION_APP_NAME = "hbase-dr";
/**
* For NGDATA's hbase authorization layer: default permissions that ensure the system columns are
* always visible by the Lily Data Repository.
*/
private static final Set<String> DEFAULT_PERMISSIONS = ImmutableSet.of(
PERMISSION_APP_NAME + ":rw#row:defer&column:qualifier:bin_starts_with:"
+ Bytes.toStringBinary(new byte[]{LilyHBaseSchema.RecordColumn.SYSTEM_PREFIX}));
/**
* For NGDATA's hbase authorization layer: the types of permissions for which access needs to be granted.
*/
private static final Set<String> ROW_PERMISSION_TYPES = ImmutableSet.of("row_labels", "row_recordtype");
public AbstractRepositoryManager(TypeManager typeManager, IdGenerator idGenerator, RecordFactory recordFactory,
RepositoryModel repositoryModel) {
this.typeManager = typeManager;
this.idGenerator = idGenerator;
this.recordFactory = recordFactory;
this.repositoryModel = repositoryModel;
}
protected HTableInterface wrapWithAuthorization(HTableInterface htable) {
return new AuthEnabledHTable(authzCtxProvider, false, PERMISSION_APP_NAME, DEFAULT_PERMISSIONS, htable);
}
protected TypeManager getTypeManager() {
return typeManager;
}
protected IdGenerator getIdGenerator() {
return idGenerator;
}
protected RecordFactory getRecordFactory() {
return recordFactory;
}
/**
* Create a new Repository object for the repository cache.
*/
protected abstract Repository createRepository(RepoTableKey key) throws InterruptedException, RepositoryException;
@Override
public LRepository getDefaultRepository() throws InterruptedException, RepositoryException {
return getRepository(RepoAndTableUtil.DEFAULT_REPOSITORY);
}
@Override
public LRepository getRepository(String repositoryName) throws InterruptedException, RepositoryException {
return getRepository(repositoryName, Table.RECORD.name);
}
public Repository getRepository(String repositoryName, String tableName)
throws InterruptedException, RepositoryException {
if (!repositoryModel.repositoryExistsAndActive(repositoryName)) {
throw new RepositoryUnavailableException("Repository does not exist or is not active: " + repositoryName);
}
RepoTableKey key = new RepoTableKey(repositoryName, tableName);
if (!repositoryCache.containsKey(key)) {
synchronized (repositoryCache) {
if (!repositoryCache.containsKey(key)) {
repositoryCache.put(key, createRepository(key));
}
}
}
return repositoryCache.get(key);
}
@Override
public synchronized void close() throws IOException {
if (shouldCloseRepositories()) {
for (Repository repository : repositoryCache.values()) {
Closer.close(repository);
}
}
repositoryCache.clear();
Closer.close(typeManager);
}
protected boolean shouldCloseRepositories() {
return true;
}
}