/* * 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.repository.remote; import org.apache.avro.AvroRemoteException; import org.apache.avro.ipc.Transceiver; import org.apache.avro.ipc.specific.SpecificRequestor; import org.apache.commons.logging.LogFactory; import org.lilyproject.avro.AvroConverter; import org.lilyproject.avro.AvroFieldType; import org.lilyproject.avro.AvroGenericException; import org.lilyproject.avro.AvroLily; import org.lilyproject.avro.AvroRepositoryException; import org.lilyproject.avro.AvroTypeBucket; import org.lilyproject.avro.NettyTransceiverFactory; import org.lilyproject.repository.api.FieldType; import org.lilyproject.repository.api.IOTypeException; import org.lilyproject.repository.api.IdGenerator; import org.lilyproject.repository.api.QName; import org.lilyproject.repository.api.RecordType; import org.lilyproject.repository.api.RepositoryException; import org.lilyproject.repository.api.Scope; import org.lilyproject.repository.api.TypeBucket; import org.lilyproject.repository.api.TypeException; import org.lilyproject.repository.api.TypeManager; import org.lilyproject.repository.api.ValueType; import org.lilyproject.repository.impl.AbstractTypeManager; import org.lilyproject.repository.impl.SchemaCache; import org.lilyproject.util.Pair; import org.lilyproject.util.io.Closer; import org.lilyproject.util.zookeeper.ZooKeeperItf; import java.io.IOException; import java.lang.reflect.UndeclaredThrowableException; import java.net.InetSocketAddress; import java.util.List; import javax.annotation.PreDestroy; // ATTENTION: when adding new methods, do not forget to add handling for UndeclaredThrowableException! This is // necessary because, at the time of this writing, Avro did not include IOException in its generated // interfaces. public class RemoteTypeManager extends AbstractTypeManager implements TypeManager { private AvroLily lilyProxy; private AvroConverter converter; private Transceiver client; public RemoteTypeManager(InetSocketAddress address, AvroConverter converter, IdGenerator idGenerator, ZooKeeperItf zooKeeper, SchemaCache schemaCache) throws IOException { this(address, converter, idGenerator, zooKeeper, schemaCache, false); } public RemoteTypeManager(InetSocketAddress address, AvroConverter converter, IdGenerator idGenerator, ZooKeeperItf zooKeeper, SchemaCache schemaCache, boolean keepAlive) throws IOException { super(zooKeeper); super.schemaCache = schemaCache; log = LogFactory.getLog(getClass()); this.converter = converter; //TODO idGenerator should not be available or used in the remote implementation this.idGenerator = idGenerator; //client = new HttpTransceiver(new URL("http://" + address.getHostName() + ":" + address.getPort() + "/")); client = NettyTransceiverFactory.create(address, keepAlive); lilyProxy = SpecificRequestor.getClient(AvroLily.class, client); registerDefaultValueTypes(); } @Override @PreDestroy public void close() throws IOException { Closer.close(client); } @Override public RecordType createRecordType(RecordType recordType) throws RepositoryException, InterruptedException { try { RecordType newRecordType = converter.convert(lilyProxy.createRecordType(converter.convert(recordType)), this); updateRecordTypeCache(newRecordType.clone()); return newRecordType; } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroGenericException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public RecordType createOrUpdateRecordType(RecordType recordType) throws RepositoryException, InterruptedException { return createOrUpdateRecordType(recordType, false); } @Override public RecordType createOrUpdateRecordType(RecordType recordType, boolean refreshSubtypes) throws RepositoryException, InterruptedException { try { RecordType newRecordType = converter.convert(lilyProxy.createOrUpdateRecordType(converter.convert(recordType), refreshSubtypes), this); updateRecordTypeCache(newRecordType.clone()); return newRecordType; } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroGenericException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public RecordType updateRecordType(RecordType recordType) throws RepositoryException, InterruptedException { return updateRecordType(recordType, false); } @Override public RecordType updateRecordType(RecordType recordType, boolean refreshSubtypes) throws RepositoryException, InterruptedException { try { RecordType newRecordType = converter.convert( lilyProxy.updateRecordType(converter.convert(recordType), refreshSubtypes), this); updateRecordTypeCache(newRecordType); return newRecordType; } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroGenericException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public FieldType createFieldType(ValueType valueType, QName name, Scope scope) throws RepositoryException, InterruptedException { return createFieldType(newFieldType(valueType, name, scope)); } @Override public FieldType createFieldType(String valueType, QName name, Scope scope) throws RepositoryException, InterruptedException { return createFieldType(newFieldType(getValueType(valueType), name, scope)); } @Override public FieldType createFieldType(FieldType fieldType) throws RepositoryException, InterruptedException { try { AvroFieldType avroFieldType = converter.convert(fieldType); AvroFieldType createFieldType = lilyProxy.createFieldType(avroFieldType); FieldType newFieldType = converter.convert(createFieldType, this); updateFieldTypeCache(newFieldType); return newFieldType; } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroGenericException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public FieldType createOrUpdateFieldType(FieldType fieldType) throws RepositoryException, InterruptedException { try { FieldType newFieldType = converter.convert(lilyProxy.createOrUpdateFieldType(converter.convert(fieldType)), this); updateFieldTypeCache(newFieldType); return newFieldType; } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroGenericException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public FieldType updateFieldType(FieldType fieldType) throws RepositoryException, InterruptedException { try { FieldType newFieldType = converter.convert(lilyProxy.updateFieldType(converter.convert(fieldType)), this); updateFieldTypeCache(newFieldType); return newFieldType; } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroGenericException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public List<FieldType> getFieldTypesWithoutCache() throws RepositoryException, InterruptedException { try { return converter.convertAvroFieldTypes(lilyProxy.getFieldTypesWithoutCache(), this); } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public List<RecordType> getRecordTypesWithoutCache() throws RepositoryException, InterruptedException { try { return converter.convertAvroRecordTypes(lilyProxy.getRecordTypesWithoutCache(), this); } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public Pair<List<FieldType>, List<RecordType>> getTypesWithoutCache() throws RepositoryException, InterruptedException { try { return converter.convertAvroFieldAndRecordTypes(lilyProxy.getTypesWithoutCache(), this); } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public TypeBucket getTypeBucketWithoutCache(String bucketId) throws RepositoryException, InterruptedException { try { AvroTypeBucket avroTypeBucket = lilyProxy.getTypeBucketWithoutCache(bucketId); return converter.convertAvroTypeBucket(avroTypeBucket, this); } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public void disableSchemaCacheRefresh() throws RepositoryException, InterruptedException { try { lilyProxy.disableSchemaCacheRefresh(); } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public void enableSchemaCacheRefresh() throws RepositoryException, InterruptedException { try { lilyProxy.enableSchemaCacheRefresh(); } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public boolean isSchemaCacheRefreshEnabled() throws RepositoryException, InterruptedException { try { return lilyProxy.isSchemaCacheRefreshEnabled(); } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } @Override public void triggerSchemaCacheRefresh() throws RepositoryException, InterruptedException { try { lilyProxy.triggerSchemaCacheRefresh(); } catch (AvroRepositoryException e) { throw converter.convert(e); } catch (AvroRemoteException e) { throw handleAvroRemoteException(e); } catch (UndeclaredThrowableException e) { throw handleUndeclaredTypeThrowable(e); } } private RuntimeException handleAvroRemoteException(AvroRemoteException e) throws TypeException { // AvroRemoteException's are exceptions which are not declared in the avro protocol and // which are not RuntimeException's. if (e.getCause() instanceof IOException) { throw new IOTypeException(e.getCause()); } else { throw converter.convert(e); } } private RuntimeException handleUndeclaredTypeThrowable(UndeclaredThrowableException e) throws TypeException { if (e.getCause() instanceof IOException) { throw new IOTypeException(e.getCause()); } else { throw e; } } }