/*
* Copyright 2010 Outerthought bvba
*
* 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.avro;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import com.google.common.annotations.VisibleForTesting;
import org.apache.avro.AvroRemoteException;
import org.lilyproject.repository.api.LRepository;
import org.lilyproject.repository.api.LTable;
import org.lilyproject.repository.api.Record;
import org.lilyproject.repository.api.RecordId;
import org.lilyproject.repository.api.RepositoryException;
import org.lilyproject.repository.api.RepositoryManager;
import org.lilyproject.repository.api.RepositoryTable;
import org.lilyproject.repository.api.TableManager;
import org.lilyproject.repository.api.TypeBucket;
import org.lilyproject.repository.api.TypeManager;
import org.lilyproject.repository.spi.AuthorizationContextHolder;
public class AvroLilyImpl implements AvroLily {
private final RepositoryManager repositoryManager;
private final TypeManager typeManager;
private AvroConverter converter;
public AvroLilyImpl(RepositoryManager repositoryManager, TypeManager typeManager) {
this.repositoryManager = repositoryManager;
this.typeManager = typeManager;
this.converter = new AvroConverter();
}
@VisibleForTesting
public void setAvroConverter(AvroConverter converter) {
this.converter = converter;
}
@Override
public ByteBuffer create(AvroAuthzContext authzContext, ByteBuffer record, String repositoryName, String tableName)
throws AvroRepositoryException, AvroInterruptedException {
try {
AuthorizationContextHolder.setCurrentContext(converter.convert(authzContext));
LRepository repository = repositoryManager.getRepository(repositoryName);
LTable table = repository.getTable(tableName);
return converter.convert(table.create(converter.convertRecord(record, repository)), repository);
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
} finally {
AuthorizationContextHolder.clearContext();
}
}
@Override
public ByteBuffer createOrUpdate(AvroAuthzContext authzContext, ByteBuffer record, String repositoryName,
String tableName, boolean useLatestRecordType)
throws AvroRepositoryException, AvroInterruptedException {
try {
AuthorizationContextHolder.setCurrentContext(converter.convert(authzContext));
LRepository repository = repositoryManager.getRepository(repositoryName);
LTable table = repository.getTable(tableName);
return converter.convert(
table.createOrUpdate(converter.convertRecord(record, repository), useLatestRecordType), repository);
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
} finally {
AuthorizationContextHolder.clearContext();
}
}
@Override
public ByteBuffer delete(AvroAuthzContext authzContext, ByteBuffer recordId, String repositoryName,
String tableName, List<AvroMutationCondition> conditions, Map<String,String> attributes)
throws AvroRepositoryException, AvroInterruptedException {
try {
AuthorizationContextHolder.setCurrentContext(converter.convert(authzContext));
LRepository repository = repositoryManager.getRepository(repositoryName);
LTable table = repository.getTable(tableName);
RecordId decodedRecordId = converter.convertAvroRecordId(recordId, repository);
Record record = null;
if (attributes == null) {
record = table.delete(decodedRecordId, converter.convertFromAvro(conditions, repository));
} else if (conditions == null) {
Record toDelete = table.newRecord(decodedRecordId);
toDelete.setAttributes(attributes);
table.delete(toDelete);
} else {
// There is no API call where a full record and MutationConditions can be supplied, so
// something has gone wrong if we get here
throw new IllegalStateException("Cannot delete a full record with MutationConditions");
}
return record == null ? null : converter.convert(record, repository);
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
} finally {
AuthorizationContextHolder.clearContext();
}
}
@Override
public ByteBuffer update(AvroAuthzContext authzContext, ByteBuffer record, String repositoryName, String tableName,
boolean updateVersion, boolean useLatestRecordType, List<AvroMutationCondition> conditions)
throws AvroRemoteException {
try {
AuthorizationContextHolder.setCurrentContext(converter.convert(authzContext));
LRepository repository = repositoryManager.getRepository(repositoryName);
LTable table = repository.getTable(tableName);
return converter.convert(table.update(converter.convertRecord(record, repository), updateVersion,
useLatestRecordType, converter.convertFromAvro(conditions, repository)), repository);
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
} finally {
AuthorizationContextHolder.clearContext();
}
}
// TODO since this is a pure-read method, the client should do it directly rather than going
// over to lily-server.
@Override
public List<String> getVariants(AvroAuthzContext authzContext, ByteBuffer recordId, String repositoryName,
String tableName) throws AvroRepositoryException, AvroInterruptedException {
try {
AuthorizationContextHolder.setCurrentContext(converter.convert(authzContext));
LRepository repository = repositoryManager.getRepository(repositoryName);
LTable table = repository.getTable(tableName);
return converter.convert(table.getVariants(converter.convertAvroRecordId(recordId, repository)));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
} finally {
AuthorizationContextHolder.clearContext();
}
}
@Override
public AvroFieldType createFieldType(AvroFieldType avroFieldType)
throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convert(typeManager.createFieldType(converter.convert(avroFieldType, typeManager)));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroRecordType createRecordType(AvroRecordType avroRecordType)
throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convert(typeManager.createRecordType(converter.convert(avroRecordType, typeManager)));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroRecordType createOrUpdateRecordType(AvroRecordType avroRecordType, boolean refreshSubtypes)
throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convert(typeManager.createOrUpdateRecordType(
converter.convert(avroRecordType, typeManager), refreshSubtypes));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroRecordType getRecordTypeById(AvroSchemaId id, long avroVersion)
throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convert(
typeManager.getRecordTypeById(converter.convert(id), converter.convertAvroVersion(avroVersion)));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroRecordType getRecordTypeByName(AvroQName name, long avroVersion)
throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convert(typeManager
.getRecordTypeByName(converter.convert(name), converter.convertAvroVersion(avroVersion)));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroRecordType updateRecordType(AvroRecordType recordType, boolean refreshSubtypes)
throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convert(
typeManager.updateRecordType(converter.convert(recordType, typeManager), refreshSubtypes));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroFieldType updateFieldType(AvroFieldType fieldType)
throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convert(typeManager.updateFieldType(converter.convert(fieldType, typeManager)));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroFieldType createOrUpdateFieldType(AvroFieldType fieldType) throws AvroRepositoryException,
AvroInterruptedException {
try {
return converter.convert(typeManager.createOrUpdateFieldType(converter.convert(fieldType, typeManager)));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroFieldType getFieldTypeById(AvroSchemaId id) throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convert(typeManager.getFieldTypeById(converter.convert(id)));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroFieldType getFieldTypeByName(AvroQName name) throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convert(typeManager.getFieldTypeByName(converter.convert(name)));
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public List<AvroFieldType> getFieldTypes() throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convertFieldTypes(typeManager.getFieldTypes());
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public List<AvroRecordType> getRecordTypes() throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convertRecordTypes(typeManager.getRecordTypes());
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public List<AvroFieldType> getFieldTypesWithoutCache() throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convertFieldTypes(typeManager.getFieldTypesWithoutCache());
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public List<AvroRecordType> getRecordTypesWithoutCache() throws AvroRepositoryException, AvroInterruptedException {
try {
return converter.convertRecordTypes(typeManager.getRecordTypesWithoutCache());
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroFieldAndRecordTypes getTypesWithoutCache()
throws AvroRepositoryException,
AvroInterruptedException {
try {
return converter.convertFieldAndRecordTypes(typeManager.getTypesWithoutCache());
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public AvroTypeBucket getTypeBucketWithoutCache(String bucketId)
throws AvroRepositoryException, AvroInterruptedException {
try {
TypeBucket typeBucket = typeManager.getTypeBucketWithoutCache(bucketId);
return converter.convertTypeBucket(typeBucket);
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public Object disableSchemaCacheRefresh() throws AvroRepositoryException, AvroInterruptedException {
try {
typeManager.disableSchemaCacheRefresh();
return null;
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public Object enableSchemaCacheRefresh() throws AvroRepositoryException, AvroInterruptedException {
try {
typeManager.enableSchemaCacheRefresh();
return null;
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public boolean isSchemaCacheRefreshEnabled() throws AvroRepositoryException, AvroInterruptedException {
try {
return typeManager.isSchemaCacheRefreshEnabled();
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public Object triggerSchemaCacheRefresh() throws AvroRepositoryException, AvroInterruptedException {
try {
typeManager.triggerSchemaCacheRefresh();
return null;
} catch (RepositoryException e) {
throw converter.convert(e);
} catch (InterruptedException e) {
throw converter.convert(e);
}
}
@Override
public Object createTable(String repository, AvroTableCreateDescriptor tableCreateDescriptor)
throws AvroInterruptedException, AvroIOException, AvroRepositoryException {
try {
TableManager tableMgr = repositoryManager.getRepository(repository).getTableManager();
tableMgr.createTable(converter.convert(tableCreateDescriptor));
return null;
} catch (InterruptedException e) {
throw converter.convert(e);
} catch (IOException e) {
throw converter.convert(e);
} catch (RepositoryException e) {
throw converter.convert(e);
}
}
@Override
public Object dropTable(String repositoryName, String name)
throws AvroInterruptedException, AvroIOException, AvroRepositoryException {
try {
TableManager tableMgr = repositoryManager.getRepository(repositoryName).getTableManager();
tableMgr.dropTable(name);
return null;
} catch (InterruptedException e) {
throw converter.convert(e);
} catch (IOException e) {
throw converter.convert(e);
} catch (RepositoryException e) {
throw converter.convert(e);
}
}
@Override
public List<String> getTables(String repositoryName)
throws AvroInterruptedException, AvroIOException, AvroRepositoryException {
try {
TableManager tableMgr = repositoryManager.getRepository(repositoryName).getTableManager();
List<String> tables = new ArrayList<String>();
for (RepositoryTable table : tableMgr.getTables()) {
tables.add(table.getName());
}
return tables;
} catch (InterruptedException e) {
throw converter.convert(e);
} catch (IOException e) {
throw converter.convert(e);
} catch (RepositoryException e) {
throw converter.convert(e);
}
}
@Override
public boolean tableExists(String repositoryName, String name)
throws AvroInterruptedException, AvroIOException, AvroRepositoryException {
try {
TableManager tableMgr = repositoryManager.getRepository(repositoryName).getTableManager();
return tableMgr.tableExists(name);
} catch (InterruptedException e) {
throw converter.convert(e);
} catch (IOException e) {
throw converter.convert(e);
} catch (RepositoryException e) {
throw converter.convert(e);
}
}
}