SHARE
TWEET

Untitled

a guest Oct 14th, 2019 83 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package com.facebook.presto.scuba.optimization;
  2.  
  3. import com.facebook.presto.spi.function.FunctionMetadata;
  4. import com.facebook.presto.spi.function.ScalarFunction;
  5. import com.facebook.presto.spi.function.ScalarOperator;
  6. import com.facebook.presto.spi.function.SqlType;
  7. import com.facebook.presto.spi.type.TypeSignature;
  8. import com.google.common.collect.ImmutableList;
  9. import com.google.common.collect.ImmutableMap;
  10. import com.google.common.collect.ImmutableSet;
  11.  
  12. import java.lang.annotation.Annotation;
  13. import java.lang.invoke.MethodHandle;
  14. import java.lang.invoke.MethodHandles;
  15. import java.lang.reflect.Method;
  16. import java.lang.reflect.Modifier;
  17. import java.lang.reflect.Parameter;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.Set;
  21. import java.util.stream.Stream;
  22.  
  23. import static com.facebook.presto.scuba.optimization.ScubaScalarHeader.fromAnnotatedElement;
  24. import static com.facebook.presto.spi.function.FunctionKind.SCALAR;
  25. import static com.facebook.presto.spi.type.TypeSignature.parseTypeSignature;
  26. import static com.google.common.base.Preconditions.checkArgument;
  27. import static java.lang.String.format;
  28. import static java.util.Objects.requireNonNull;
  29.  
  30. public class ScubaScalarFromAnnotationsParser
  31. {
  32.     private ScubaScalarFromAnnotationsParser()
  33.     {
  34.     }
  35.  
  36.     public static Map<FunctionMetadata, MethodHandle> parseFunctionDefinitions(Class<?> clazz)
  37.     {
  38.         ImmutableMap.Builder<FunctionMetadata, MethodHandle> translatorBuilder = ImmutableMap.builder();
  39.         for (ScalarHeaderAndMethods methods : findScalarsFromSetClass(clazz)) {
  40.             translatorBuilder.putAll(scalarToFunctionMetadata(methods));
  41.         }
  42.  
  43.         return translatorBuilder.build();
  44.     }
  45.  
  46.     public static TypeSignature removeTypeParameters(TypeSignature typeSignature)
  47.     {
  48.         return new TypeSignature(typeSignature.getBase());
  49.     }
  50.  
  51.     public static FunctionMetadata removeTypeParameters(FunctionMetadata metadata)
  52.     {
  53.         ImmutableList.Builder<TypeSignature> argumentsBuilder = ImmutableList.builder();
  54.         for (TypeSignature typeSignature : metadata.getArgumentTypes()) {
  55.             argumentsBuilder.add(removeTypeParameters(typeSignature));
  56.         }
  57.  
  58.         if (metadata.getOperatorType().isPresent()) {
  59.             return new FunctionMetadata(
  60.                     metadata.getOperatorType().get(),
  61.                     argumentsBuilder.build(),
  62.                     metadata.getReturnType(),
  63.                     metadata.getFunctionKind(),
  64.                     metadata.isDeterministic(),
  65.                     metadata.isCalledOnNullInput());
  66.         }
  67.         else {
  68.             return new FunctionMetadata(
  69.                     metadata.getName(),
  70.                     argumentsBuilder.build(),
  71.                     metadata.getReturnType(),
  72.                     metadata.getFunctionKind(),
  73.                     metadata.isDeterministic(),
  74.                     metadata.isCalledOnNullInput());
  75.         }
  76.     }
  77.  
  78.     private static MethodHandle getMethodHandle(Method method)
  79.     {
  80.         try {
  81.             return MethodHandles.lookup().unreflect(method);
  82.         }
  83.         catch (IllegalAccessException e) {
  84.             throw new RuntimeException(e);
  85.         }
  86.     }
  87.  
  88.     private static List<ScalarHeaderAndMethods> findScalarsFromSetClass(Class<?> clazz)
  89.     {
  90.         ImmutableList.Builder<ScalarHeaderAndMethods> builder = ImmutableList.builder();
  91.         for (Method method : findPublicMethodsWithAnnotation(clazz, SqlType.class, ScalarFunction.class, ScalarOperator.class)) {
  92.             boolean annotationCondition = (method.getAnnotation(ScalarFunction.class) != null) || (method.getAnnotation(ScalarOperator.class) != null);
  93.             checkArgument(annotationCondition, format("Method [%s] annotated with @SqlType is missing @ScalarFunction or @ScalarOperator", method));
  94.  
  95.             for (ScubaScalarHeader header : fromAnnotatedElement(method)) {
  96.                 builder.add(new ScalarHeaderAndMethods(header, ImmutableSet.of(method)));
  97.             }
  98.         }
  99.         List<ScalarHeaderAndMethods> methods = builder.build();
  100.         checkArgument(!methods.isEmpty(), "Class [%s] does not have any methods annotated with @ScalarFunction or @ScalarOperator", clazz.getName());
  101.  
  102.         return methods;
  103.     }
  104.  
  105.     private static Map<FunctionMetadata, MethodHandle> scalarToFunctionMetadata(ScalarHeaderAndMethods scalar)
  106.     {
  107.         ScubaScalarHeader header = scalar.getHeader();
  108.  
  109.         ImmutableMap.Builder<FunctionMetadata, MethodHandle> metadataBuilder = ImmutableMap.builder();
  110.         for (Method method : scalar.getMethods()) {
  111.             FunctionMetadata metadata = methodToFunctionMetadata(header, method);
  112.             metadataBuilder.put(removeTypeParameters(metadata), getMethodHandle(method));
  113.         }
  114.  
  115.         return metadataBuilder.build();
  116.     }
  117.  
  118.     private static FunctionMetadata methodToFunctionMetadata(ScubaScalarHeader header, Method method)
  119.     {
  120.         requireNonNull(header, "header is null");
  121.  
  122.         // return type
  123.         SqlType annotatedReturnType = method.getAnnotation(SqlType.class);
  124.         checkArgument(annotatedReturnType != null, format("Method [%s] is missing @SqlType annotation", method));
  125.         TypeSignature returnType = parseTypeSignature(annotatedReturnType.value(), ImmutableSet.of());
  126.  
  127.         // argument type
  128.         ImmutableList.Builder<TypeSignature> argumentTypes = new ImmutableList.Builder<>();
  129.         for (Parameter parameter : method.getParameters()) {
  130.             Annotation[] annotations = parameter.getAnnotations();
  131.  
  132.             SqlType type = Stream.of(annotations)
  133.                     .filter(SqlType.class::isInstance)
  134.                     .map(SqlType.class::cast)
  135.                     .findFirst()
  136.                     .orElseThrow(() -> new IllegalArgumentException(format("Method [%s] is missing @SqlType annotation for parameter", method)));
  137.             TypeSignature typeSignature = parseTypeSignature(type.value(), ImmutableSet.of());
  138.             argumentTypes.add(typeSignature);
  139.         }
  140.  
  141.         if (header.getOperatorType().isPresent()) {
  142.             return new FunctionMetadata(header.getOperatorType().get(), argumentTypes.build(), returnType, SCALAR, header.isDeterministic(), header.isCalledOnNullInput());
  143.         }
  144.         else {
  145.             return new FunctionMetadata(header.getName(), argumentTypes.build(), returnType, SCALAR, header.isDeterministic(), header.isCalledOnNullInput());
  146.         }
  147.     }
  148.  
  149.     @SafeVarargs
  150.     private static Set<Method> findPublicMethodsWithAnnotation(Class<?> clazz, Class<? extends Annotation>... annotationClasses)
  151.     {
  152.         ImmutableSet.Builder<Method> methods = ImmutableSet.builder();
  153.         for (Method method : clazz.getDeclaredMethods()) {
  154.             for (Annotation annotation : method.getAnnotations()) {
  155.                 for (Class<?> annotationClass : annotationClasses) {
  156.                     if (annotationClass.isInstance(annotation)) {
  157.                         checkArgument(Modifier.isPublic(method.getModifiers()), "Method [%s] annotated with @%s must be public", method, annotationClass.getSimpleName());
  158.                         methods.add(method);
  159.                     }
  160.                 }
  161.             }
  162.         }
  163.         return methods.build();
  164.     }
  165.  
  166.     private static class ScalarHeaderAndMethods
  167.     {
  168.         private final ScubaScalarHeader header;
  169.         private final Set<Method> methods;
  170.  
  171.         public ScalarHeaderAndMethods(ScubaScalarHeader header, Set<Method> methods)
  172.         {
  173.             this.header = requireNonNull(header, "header is null");
  174.             this.methods = requireNonNull(methods, "methods are null");
  175.         }
  176.  
  177.         public ScubaScalarHeader getHeader()
  178.         {
  179.             return header;
  180.         }
  181.  
  182.         public Set<Method> getMethods()
  183.         {
  184.             return methods;
  185.         }
  186.     }
  187. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top