com.hazelcast.org.apache.calcite.rel.metadata.ProxyingMetadataHandlerProvider Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you 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.hazelcast.org.apache.calcite.rel.metadata;
import com.hazelcast.org.apache.calcite.rel.RelNode;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* A MetadataHandlerProvider built on a RelMetadataProvider.
*
* Uses proxies to call the underlying metadata provider.
*/
public class ProxyingMetadataHandlerProvider implements MetadataHandlerProvider {
private final RelMetadataProvider provider;
/**
* Create a proxying handler provider.
* @param provider The provider this will operate against.
*/
public ProxyingMetadataHandlerProvider(RelMetadataProvider provider) {
this.provider = provider;
}
@SuppressWarnings("deprecation")
@Override public > MH handler(Class handlerClass) {
Type[] types = handlerClass.getGenericInterfaces();
if (types.length != 1 || !(types[0] instanceof ParameterizedType)) {
throw new UnsupportedOperationException("Unexpected failure. " + handlerClass);
}
ParameterizedType pType = (ParameterizedType) types[0];
if (pType.getRawType() != MetadataHandler.class) {
throw new UnsupportedOperationException("Unexpected failure. " + handlerClass);
}
Class> metadataType = (Class>) pType.getActualTypeArguments()[0];
final Field field;
final MetadataDef> def;
try {
field = metadataType.getField("DEF");
def = Objects.requireNonNull((MetadataDef>) field.get(null),
() -> "Unexpected failure. " + handlerClass);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
List methods = def.methods;
Map methodMap = methods.stream()
.collect(Collectors.toMap(Method::getName, f -> f));
InvocationHandler handler = (proxy, method, args) -> {
Method metadataMethod = Objects.requireNonNull(methodMap.get(method.getName()),
() -> "Not supported: " + method);
RelNode rel = Objects.requireNonNull((RelNode) args[0], "rel must be non null");
RelMetadataQuery mq = Objects.requireNonNull((RelMetadataQuery) args[1],
"mq must be non null");
// using deprecated RelMetadataProvider method here as the non-deprecated methods completely
// sidestep the purpose of RelMetadataProvider reflection-based functionality.
UnboundMetadata metadata = provider.apply(
(Class extends RelNode>) rel.getClass(),
(Class extends Metadata>) metadataType);
if (metadata == null) {
Method handlerMethod = Arrays.stream(handlerClass.getMethods())
.filter(m -> m.getName().equals(metadataMethod.getName()))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unable to find method."));
throw new IllegalArgumentException(
String.format(Locale.ROOT, "No handler for "
+ "method [%s] applied to argument of type [%s]; we recommend you create a "
+ "catch-all (RelNode) handler", handlerMethod, rel.getClass()));
}
Metadata bound = Objects.requireNonNull(metadata, "expected defined metadata")
.bind(rel, mq);
Object[] abbreviatedArgs = new Object[args.length - 2];
System.arraycopy(args, 2, abbreviatedArgs, 0, abbreviatedArgs.length);
try {
return metadataMethod.invoke(bound, abbreviatedArgs);
} catch (InvocationTargetException ex) {
if (ex.getCause() instanceof CyclicMetadataException) {
throw (CyclicMetadataException) ex.getCause();
}
throw new RuntimeException(ex.getCause());
}
};
return (MH) Proxy.newProxyInstance(
handlerClass.getClassLoader(),
new Class[]{handlerClass},
handler);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy