Speed up BindingReflections.getAugmentations()
[mdsal.git] / binding / mdsal-binding-spec-util / src / main / java / org / opendaylight / mdsal / binding / spec / reflect / BindingReflections.java
index c4a0d34abf85c2ebd15ef9ab76ef3baa291fa229..5875f17b91a3e5e5464e7ce160a8e71763c95e62 100644 (file)
@@ -10,32 +10,35 @@ package org.opendaylight.mdsal.binding.spec.reflect;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 
-import com.google.common.base.Optional;
+import com.google.common.annotations.Beta;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSet.Builder;
-import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.ServiceLoader;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import javax.annotation.RegEx;
+import org.checkerframework.checker.regex.qual.Regex;
 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
 import org.opendaylight.yangtools.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.binding.Action;
 import org.opendaylight.yangtools.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.AugmentationHolder;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.ChildOf;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
@@ -54,7 +57,7 @@ public final class BindingReflections {
 
     private static final long EXPIRATION_TIME = 60;
 
-    @RegEx
+    @Regex
     private static final String ROOT_PACKAGE_PATTERN_STRING =
             "(org.opendaylight.yang.gen.v1.[a-z0-9_\\.]*\\.(?:rev[0-9][0-9][0-1][0-9][0-3][0-9]|norev))";
     private static final Pattern ROOT_PACKAGE_PATTERN = Pattern.compile(ROOT_PACKAGE_PATTERN_STRING);
@@ -80,7 +83,9 @@ public final class BindingReflections {
      */
     public static Class<? extends Augmentable<?>> findAugmentationTarget(
             final Class<? extends Augmentation<?>> augmentation) {
-        return ClassLoaderUtils.findFirstGenericArgument(augmentation, Augmentation.class);
+        final Optional<Class<Augmentable<?>>> opt = ClassLoaderUtils.findFirstGenericArgument(augmentation,
+            Augmentation.class);
+        return opt.orElse(null);
     }
 
     /**
@@ -92,12 +97,12 @@ public final class BindingReflections {
      * @return Parent class, e.g. class of which the childClass is ChildOf.
      */
     public static Class<?> findHierarchicalParent(final Class<? extends ChildOf<?>> childClass) {
-        return ClassLoaderUtils.findFirstGenericArgument(childClass, ChildOf.class);
+        return ClassLoaderUtils.findFirstGenericArgument(childClass, ChildOf.class).orElse(null);
     }
 
     /**
      * Find data hierarchy parent from concrete Data class. This method is shorthand which gets DataObject class by
-     * invoking {@link DataObject#getImplementedInterface()} and uses {@link #findHierarchicalParent(Class)}.
+     * invoking {@link DataObject#implementedInterface()} and uses {@link #findHierarchicalParent(Class)}.
      *
      * @param child
      *            Child object for which the parent needs to be located.
@@ -105,7 +110,7 @@ public final class BindingReflections {
      */
     public static Class<?> findHierarchicalParent(final DataObject child) {
         if (child instanceof ChildOf) {
-            return ClassLoaderUtils.findFirstGenericArgument(child.getImplementedInterface(), ChildOf.class);
+            return ClassLoaderUtils.findFirstGenericArgument(child.implementedInterface(), ChildOf.class).orElse(null);
         }
         return null;
     }
@@ -119,7 +124,7 @@ public final class BindingReflections {
      *         have name. May return null if QName is not present.
      */
     public static QName findQName(final Class<?> dataType) {
-        return CLASS_TO_QNAME.getUnchecked(dataType).orNull();
+        return CLASS_TO_QNAME.getUnchecked(dataType).orElse(null);
     }
 
     /**
@@ -136,7 +141,7 @@ public final class BindingReflections {
                 // resolveRpcInputClass() check.While RpcMethodInvoker counts with one argument for
                 // non input type and two arguments for input type, resolveRpcInputClass() counting
                 // with zero for non input and one for input type
-                && possibleMethod.getParameterTypes().length <= 2;
+                && possibleMethod.getParameterCount() <= 2;
     }
 
     /**
@@ -144,18 +149,18 @@ public final class BindingReflections {
      *
      * @param targetMethod
      *            method to scan
-     * @return Optional.absent() if result type could not be get, or return type is Void.
+     * @return Optional.empty() if result type could not be get, or return type is Void.
      */
     @SuppressWarnings("rawtypes")
     public static Optional<Class<?>> resolveRpcOutputClass(final Method targetMethod) {
         checkState(isRpcMethod(targetMethod), "Supplied method is not a RPC invocation method");
         Type futureType = targetMethod.getGenericReturnType();
-        Type rpcResultType = ClassLoaderUtils.getFirstGenericParameter(futureType);
-        Type rpcResultArgument = ClassLoaderUtils.getFirstGenericParameter(rpcResultType);
+        Type rpcResultType = ClassLoaderUtils.getFirstGenericParameter(futureType).orElse(null);
+        Type rpcResultArgument = ClassLoaderUtils.getFirstGenericParameter(rpcResultType).orElse(null);
         if (rpcResultArgument instanceof Class && !Void.class.equals(rpcResultArgument)) {
             return Optional.of((Class) rpcResultArgument);
         }
-        return Optional.absent();
+        return Optional.empty();
     }
 
     /**
@@ -163,7 +168,7 @@ public final class BindingReflections {
      *
      * @param targetMethod
      *            method to scan
-     * @return Optional.absent() if RPC has no input, RPC input type otherwise.
+     * @return Optional.empty() if RPC has no input, RPC input type otherwise.
      */
     @SuppressWarnings("rawtypes")
     public static Optional<Class<? extends DataContainer>> resolveRpcInputClass(final Method targetMethod) {
@@ -172,7 +177,7 @@ public final class BindingReflections {
                 return Optional.of(clazz);
             }
         }
-        return Optional.absent();
+        return Optional.empty();
     }
 
     public static QName getQName(final Class<? extends BaseIdentity> context) {
@@ -200,7 +205,7 @@ public final class BindingReflections {
     }
 
     /**
-     * Returns root package name for suplied package.
+     * Returns root package name for supplied package.
      *
      * @param pkg
      *            Package for which find model root package.
@@ -240,20 +245,6 @@ public final class BindingReflections {
         }
     }
 
-    /**
-     * Extract a QNameModule from YangModuleInfo.
-     *
-     * @param modInfo Module info
-     * @return QNameModule for the module
-     * @throws NullPointerException in modInfo is null
-     *
-     * @deprecated Use {@code YangModuleInfo.getName().getModule()} instead.
-     */
-    @Deprecated
-    public static QNameModule getQNameModule(final YangModuleInfo modInfo) {
-        return modInfo.getName().getModule();
-    }
-
     /**
      * Returns instance of {@link YangModuleInfo} of declaring model for specific class.
      *
@@ -297,7 +288,7 @@ public final class BindingReflections {
      */
     public static boolean isNotificationCallback(final Method method) {
         checkArgument(method != null);
-        if (method.getName().startsWith("on") && method.getParameterTypes().length == 1) {
+        if (method.getName().startsWith("on") && method.getParameterCount() == 1) {
             Class<?> potentialNotification = method.getParameterTypes()[0];
             if (isNotification(potentialNotification)
                     && method.getName().equals("on" + potentialNotification.getSimpleName())) {
@@ -392,7 +383,8 @@ public final class BindingReflections {
         checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type must be derived from DataContainer");
         List<Class<? extends DataObject>> ret = new LinkedList<>();
         for (Method method : type.getMethods()) {
-            Optional<Class<? extends DataContainer>> entity = getYangModeledReturnType(method);
+            Optional<Class<? extends DataContainer>> entity = getYangModeledReturnType(method,
+                BindingMapping.GETTER_PREFIX);
             if (entity.isPresent()) {
                 ret.add((Class<? extends DataObject>) entity.get());
             }
@@ -408,12 +400,16 @@ public final class BindingReflections {
      * @return Iterable of all data children, which have YANG modeled entity
      */
     public static Map<Class<?>, Method> getChildrenClassToMethod(final Class<?> type) {
+        return getChildrenClassToMethod(type, BindingMapping.GETTER_PREFIX);
+    }
+
+    private static Map<Class<?>, Method> getChildrenClassToMethod(final Class<?> type, final String prefix) {
         checkArgument(type != null, "Target type must not be null");
         checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type %s must be derived from DataContainer",
             type);
         Map<Class<?>, Method> ret = new HashMap<>();
         for (Method method : type.getMethods()) {
-            Optional<Class<? extends DataContainer>> entity = getYangModeledReturnType(method);
+            Optional<Class<? extends DataContainer>> entity = getYangModeledReturnType(method, prefix);
             if (entity.isPresent()) {
                 ret.put(entity.get(), method);
             }
@@ -421,25 +417,29 @@ public final class BindingReflections {
         return ret;
     }
 
+    @Beta
+    public static Map<Class<?>, Method> getChildrenClassToNonnullMethod(final Class<?> type) {
+        return getChildrenClassToMethod(type, BindingMapping.NONNULL_PREFIX);
+    }
+
     @SuppressWarnings({ "unchecked", "rawtypes", "checkstyle:illegalCatch" })
-    private static Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method) {
-        if ("getClass".equals(method.getName()) || !method.getName().startsWith("get")
-                || method.getParameterTypes().length > 0) {
-            return Optional.absent();
+    private static Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method,
+            final String prefix) {
+        final String methodName = method.getName();
+        if ("getClass".equals(methodName) || !methodName.startsWith(prefix) || method.getParameterCount() > 0) {
+            return Optional.empty();
         }
 
         Class returnType = method.getReturnType();
         if (DataContainer.class.isAssignableFrom(returnType)) {
             return Optional.of(returnType);
-        } else if (List.class.isAssignableFrom(returnType)) {
+        }
+        if (List.class.isAssignableFrom(returnType)) {
             try {
                 return ClassLoaderUtils.callWithClassLoader(method.getDeclaringClass().getClassLoader(), () -> {
-                    Type listResult = ClassLoaderUtils.getFirstGenericParameter(method.getGenericReturnType());
-                    if (listResult instanceof Class
-                            && DataContainer.class.isAssignableFrom((Class) listResult)) {
-                        return Optional.of((Class) listResult);
-                    }
-                    return Optional.absent();
+                    return ClassLoaderUtils.getFirstGenericParameter(method.getGenericReturnType()).flatMap(
+                        result -> result instanceof Class && DataContainer.class.isAssignableFrom((Class) result)
+                            ? Optional.of((Class) result) : Optional.empty());
                 });
             } catch (Exception e) {
                 /*
@@ -450,7 +450,7 @@ public final class BindingReflections {
                 LOG.debug("Unable to find YANG modeled return type for {}", method, e);
             }
         }
-        return Optional.absent();
+        return Optional.empty();
     }
 
     private static class ClassToQNameLoader extends CacheLoader<Class<?>, Optional<QName>> {
@@ -487,7 +487,7 @@ public final class BindingReflections {
                  */
                 LOG.debug("Unexpected exception during extracting QName for {}", key, e);
             }
-            return Optional.absent();
+            return Optional.empty();
         }
 
         /**
@@ -540,22 +540,6 @@ public final class BindingReflections {
         }
     }
 
-    /**
-     * Given a {@link YangModuleInfo}, create a QName representing it. The QName is formed by reusing the module's
-     * namespace and revision using the module's name as the QName's local name.
-     *
-     * @param moduleInfo
-     *            module information
-     * @return QName representing the module
-     *
-     * @deprecated Use {@link YangModuleInfo#getName()} instead.
-     */
-    @Deprecated
-    public static QName getModuleQName(final YangModuleInfo moduleInfo) {
-        checkArgument(moduleInfo != null, "moduleInfo must not be null.");
-        return moduleInfo.getName();
-    }
-
     /**
      * Extracts augmentation from Binding DTO field using reflection.
      *
@@ -565,6 +549,9 @@ public final class BindingReflections {
      * @return Map of augmentations if read was successful, otherwise empty map.
      */
     public static Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAugmentations(final Augmentable<?> input) {
+        if (input instanceof AugmentationHolder) {
+            return ((AugmentationHolder) input).augmentations();
+        }
         return AugmentationFieldGetter.getGetter(input.getClass()).getAugmentations(input);
     }
 
@@ -598,8 +585,8 @@ public final class BindingReflections {
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     public static boolean isSubstitutionFor(final Class potential, final Class target) {
-        HashSet<Class> subImplemented = Sets.newHashSet(potential.getInterfaces());
-        HashSet<Class> targetImplemented = Sets.newHashSet(target.getInterfaces());
+        Set<Class> subImplemented = new HashSet<>(Arrays.asList(potential.getInterfaces()));
+        Set<Class> targetImplemented = new HashSet<>(Arrays.asList(target.getInterfaces()));
         if (!subImplemented.equals(targetImplemented)) {
             return false;
         }