/* * 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 com.facebook.presto.metadata; import com.facebook.presto.connector.informationSchema.InformationSchemaHandleResolver; import com.facebook.presto.connector.system.SystemHandleResolver; import com.facebook.presto.spi.ColumnHandle; import com.facebook.presto.spi.ConnectorHandleResolver; import com.facebook.presto.spi.ConnectorIndexHandle; import com.facebook.presto.spi.ConnectorInsertTableHandle; import com.facebook.presto.spi.ConnectorOutputTableHandle; import com.facebook.presto.spi.ConnectorSplit; import com.facebook.presto.spi.ConnectorTableHandle; import com.facebook.presto.spi.ConnectorTableLayoutHandle; import com.facebook.presto.spi.connector.ConnectorPartitioningHandle; import com.facebook.presto.spi.connector.ConnectorTransactionHandle; import com.facebook.presto.split.EmptySplitHandleResolver; import javax.inject.Inject; import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; import java.util.function.Supplier; import static com.facebook.presto.operator.ExchangeOperator.REMOTE_CONNECTOR_ID; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static java.util.Objects.requireNonNull; public class HandleResolver { private final ConcurrentMap<String, MaterializedHandleResolver> handleResolvers = new ConcurrentHashMap<>(); @Inject public HandleResolver() { handleResolvers.put(REMOTE_CONNECTOR_ID.toString(), new MaterializedHandleResolver(new RemoteHandleResolver())); handleResolvers.put("$system", new MaterializedHandleResolver(new SystemHandleResolver())); handleResolvers.put("$info_schema", new MaterializedHandleResolver(new InformationSchemaHandleResolver())); handleResolvers.put("$empty", new MaterializedHandleResolver(new EmptySplitHandleResolver())); } public void addConnectorName(String name, ConnectorHandleResolver resolver) { requireNonNull(name, "name is null"); requireNonNull(resolver, "resolver is null"); MaterializedHandleResolver existingResolver = handleResolvers.putIfAbsent(name, new MaterializedHandleResolver(resolver)); checkState(existingResolver == null || existingResolver.equals(resolver), "Connector '%s' is already assigned to resolver: %s", name, existingResolver); } public String getId(ConnectorTableHandle tableHandle) { return getId(tableHandle, MaterializedHandleResolver::getTableHandleClass); } public String getId(ConnectorTableLayoutHandle handle) { return getId(handle, MaterializedHandleResolver::getTableLayoutHandleClass); } public String getId(ColumnHandle columnHandle) { return getId(columnHandle, MaterializedHandleResolver::getColumnHandleClass); } public String getId(ConnectorSplit split) { return getId(split, MaterializedHandleResolver::getSplitClass); } public String getId(ConnectorIndexHandle indexHandle) { return getId(indexHandle, MaterializedHandleResolver::getIndexHandleClass); } public String getId(ConnectorOutputTableHandle outputHandle) { return getId(outputHandle, MaterializedHandleResolver::getOutputTableHandleClass); } public String getId(ConnectorInsertTableHandle insertHandle) { return getId(insertHandle, MaterializedHandleResolver::getInsertTableHandleClass); } public String getId(ConnectorPartitioningHandle partitioningHandle) { return getId(partitioningHandle, MaterializedHandleResolver::getPartitioningHandleClass); } public String getId(ConnectorTransactionHandle transactionHandle) { return getId(transactionHandle, MaterializedHandleResolver::getTransactionHandleClass); } public Class<? extends ConnectorTableHandle> getTableHandleClass(String id) { return resolverFor(id).getTableHandleClass().orElseThrow(() -> new IllegalArgumentException("No resolver for " + id)); } public Class<? extends ConnectorTableLayoutHandle> getTableLayoutHandleClass(String id) { return resolverFor(id).getTableLayoutHandleClass().orElseThrow(() -> new IllegalArgumentException("No resolver for " + id)); } public Class<? extends ColumnHandle> getColumnHandleClass(String id) { return resolverFor(id).getColumnHandleClass().orElseThrow(() -> new IllegalArgumentException("No resolver for " + id)); } public Class<? extends ConnectorSplit> getSplitClass(String id) { return resolverFor(id).getSplitClass().orElseThrow(() -> new IllegalArgumentException("No resolver for " + id)); } public Class<? extends ConnectorIndexHandle> getIndexHandleClass(String id) { return resolverFor(id).getIndexHandleClass().orElseThrow(() -> new IllegalArgumentException("No resolver for " + id)); } public Class<? extends ConnectorOutputTableHandle> getOutputTableHandleClass(String id) { return resolverFor(id).getOutputTableHandleClass().orElseThrow(() -> new IllegalArgumentException("No resolver for " + id)); } public Class<? extends ConnectorInsertTableHandle> getInsertTableHandleClass(String id) { return resolverFor(id).getInsertTableHandleClass().orElseThrow(() -> new IllegalArgumentException("No resolver for " + id)); } public Class<? extends ConnectorPartitioningHandle> getPartitioningHandleClass(String id) { return resolverFor(id).getPartitioningHandleClass().orElseThrow(() -> new IllegalArgumentException("No resolver for " + id)); } public Class<? extends ConnectorTransactionHandle> getTransactionHandleClass(String id) { return resolverFor(id).getTransactionHandleClass().orElseThrow(() -> new IllegalArgumentException("No resolver for " + id)); } private MaterializedHandleResolver resolverFor(String id) { MaterializedHandleResolver resolver = handleResolvers.get(id); checkArgument(resolver != null, "No handle resolver for connector: %s", id); return resolver; } private <T> String getId(T handle, Function<MaterializedHandleResolver, Optional<Class<? extends T>>> getter) { for (Entry<String, MaterializedHandleResolver> entry : handleResolvers.entrySet()) { try { if (getter.apply(entry.getValue()).map(clazz -> clazz.isInstance(handle)).orElse(false)) { return entry.getKey(); } } catch (UnsupportedOperationException ignored) { } } throw new IllegalArgumentException("No connector for handle: " + handle); } private static class MaterializedHandleResolver { private final Optional<Class<? extends ConnectorTableHandle>> tableHandle; private final Optional<Class<? extends ConnectorTableLayoutHandle>> layoutHandle; private final Optional<Class<? extends ColumnHandle>> columnHandle; private final Optional<Class<? extends ConnectorSplit>> split; private final Optional<Class<? extends ConnectorIndexHandle>> indexHandle; private final Optional<Class<? extends ConnectorOutputTableHandle>> outputTableHandle; private final Optional<Class<? extends ConnectorInsertTableHandle>> insertTableHandle; private final Optional<Class<? extends ConnectorPartitioningHandle>> partitioningHandle; private final Optional<Class<? extends ConnectorTransactionHandle>> transactionHandle; public MaterializedHandleResolver(ConnectorHandleResolver resolver) { tableHandle = getHandleClass(resolver::getTableHandleClass); layoutHandle = getHandleClass(resolver::getTableLayoutHandleClass); columnHandle = getHandleClass(resolver::getColumnHandleClass); split = getHandleClass(resolver::getSplitClass); indexHandle = getHandleClass(resolver::getIndexHandleClass); outputTableHandle = getHandleClass(resolver::getOutputTableHandleClass); insertTableHandle = getHandleClass(resolver::getInsertTableHandleClass); partitioningHandle = getHandleClass(resolver::getPartitioningHandleClass); transactionHandle = getHandleClass(resolver::getTransactionHandleClass); } private static <T> Optional<Class<? extends T>> getHandleClass(Supplier<Class<? extends T>> callable) { try { return Optional.of(callable.get()); } catch (UnsupportedOperationException e) { return Optional.empty(); } } public Optional<Class<? extends ConnectorTableHandle>> getTableHandleClass() { return tableHandle; } public Optional<Class<? extends ConnectorTableLayoutHandle>> getTableLayoutHandleClass() { return layoutHandle; } public Optional<Class<? extends ColumnHandle>> getColumnHandleClass() { return columnHandle; } public Optional<Class<? extends ConnectorSplit>> getSplitClass() { return split; } public Optional<Class<? extends ConnectorIndexHandle>> getIndexHandleClass() { return indexHandle; } public Optional<Class<? extends ConnectorOutputTableHandle>> getOutputTableHandleClass() { return outputTableHandle; } public Optional<Class<? extends ConnectorInsertTableHandle>> getInsertTableHandleClass() { return insertTableHandle; } public Optional<Class<? extends ConnectorPartitioningHandle>> getPartitioningHandleClass() { return partitioningHandle; } public Optional<Class<? extends ConnectorTransactionHandle>> getTransactionHandleClass() { return transactionHandle; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } MaterializedHandleResolver that = (MaterializedHandleResolver) o; return Objects.equals(tableHandle, that.tableHandle) && Objects.equals(layoutHandle, that.layoutHandle) && Objects.equals(columnHandle, that.columnHandle) && Objects.equals(split, that.split) && Objects.equals(indexHandle, that.indexHandle) && Objects.equals(outputTableHandle, that.outputTableHandle) && Objects.equals(insertTableHandle, that.insertTableHandle) && Objects.equals(partitioningHandle, that.partitioningHandle) && Objects.equals(transactionHandle, that.transactionHandle); } @Override public int hashCode() { return Objects.hash(tableHandle, layoutHandle, columnHandle, split, indexHandle, outputTableHandle, insertTableHandle, partitioningHandle, transactionHandle); } } }