Remove unneeded checkstyle supressions
[mdsal.git] / binding / mdsal-binding-spec-util / src / main / java / org / opendaylight / mdsal / binding / spec / reflect / BindingReflections.java
index 020906cfb3cfeab74a34455810aa96e28efe2c6b..8b6b6c42114094a3e8df7a435ac4c0930ee6a093 100644 (file)
@@ -38,6 +38,7 @@ 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;
@@ -67,6 +68,15 @@ public final class BindingReflections {
             .expireAfterAccess(EXPIRATION_TIME, TimeUnit.SECONDS)
             .build(new ClassToQNameLoader());
 
+    private static final LoadingCache<ClassLoader, ImmutableSet<YangModuleInfo>> MODULE_INFO_CACHE =
+            CacheBuilder.newBuilder().weakKeys().weakValues().build(
+                new CacheLoader<ClassLoader, ImmutableSet<YangModuleInfo>>() {
+                    @Override
+                    public ImmutableSet<YangModuleInfo> load(final ClassLoader key) {
+                        return loadModuleInfos(key);
+                    }
+                });
+
     private BindingReflections() {
         throw new UnsupportedOperationException("Utility class.");
     }
@@ -82,7 +92,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);
     }
 
     /**
@@ -94,7 +106,7 @@ 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);
     }
 
     /**
@@ -107,7 +119,7 @@ public final class BindingReflections {
      */
     public static Class<?> findHierarchicalParent(final DataObject child) {
         if (child instanceof ChildOf) {
-            return ClassLoaderUtils.findFirstGenericArgument(child.implementedInterface(), ChildOf.class);
+            return ClassLoaderUtils.findFirstGenericArgument(child.implementedInterface(), ChildOf.class).orElse(null);
         }
         return null;
     }
@@ -152,8 +164,8 @@ public final class BindingReflections {
     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);
         }
@@ -177,6 +189,7 @@ public final class BindingReflections {
         return Optional.empty();
     }
 
+    // FIXME: 4.0.0: check that the QName is actually resolved, i.e. guarantee @NonNull here
     public static QName getQName(final Class<? extends BaseIdentity> context) {
         return findQName(context);
     }
@@ -328,9 +341,10 @@ public final class BindingReflections {
      * When {@link YangModuleInfo} is available, all dependencies are recursively collected into returning set by
      * collecting results of {@link YangModuleInfo#getImportedModules()}.
      *
-     * @param loader
-     *            Classloader for which {@link YangModuleInfo} should be
-     *            retrieved.
+     * <p>
+     * Consider using {@link #cacheModuleInfos(ClassLoader)} if the classloader is known to be immutable.
+     *
+     * @param loader Classloader for which {@link YangModuleInfo} should be retrieved.
      * @return Set of {@link YangModuleInfo} available for supplied classloader.
      */
     public static ImmutableSet<YangModuleInfo> loadModuleInfos(final ClassLoader loader) {
@@ -345,6 +359,27 @@ public final class BindingReflections {
         return moduleInfoSet.build();
     }
 
+    /**
+     * Loads {@link YangModuleInfo} instances available on supplied {@link ClassLoader}, assuming the set of available
+     * information does not change. Subsequent accesses may return cached values.
+     *
+     * <p>
+     * {@link YangModuleInfo} are discovered using {@link ServiceLoader} for {@link YangModelBindingProvider}.
+     * {@link YangModelBindingProvider} are simple classes which holds only pointers to actual instance
+     * {@link YangModuleInfo}.
+     *
+     * <p>
+     * When {@link YangModuleInfo} is available, all dependencies are recursively collected into returning set by
+     * collecting results of {@link YangModuleInfo#getImportedModules()}.
+     *
+     * @param loader Class loader for which {@link YangModuleInfo} should be retrieved.
+     * @return Set of {@link YangModuleInfo} available for supplied classloader.
+     */
+    @Beta
+    public static ImmutableSet<YangModuleInfo> cacheModuleInfos(final ClassLoader loader) {
+        return MODULE_INFO_CACHE.getUnchecked(loader);
+    }
+
     private static void collectYangModuleInfo(final YangModuleInfo moduleInfo,
             final Builder<YangModuleInfo> moduleInfoSet) {
         moduleInfoSet.add(moduleInfo);
@@ -419,7 +454,7 @@ public final class BindingReflections {
         return getChildrenClassToMethod(type, BindingMapping.NONNULL_PREFIX);
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes", "checkstyle:illegalCatch" })
+    @SuppressWarnings("checkstyle:illegalCatch")
     private static Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method,
             final String prefix) {
         final String methodName = method.getName();
@@ -427,18 +462,14 @@ public final class BindingReflections {
             return Optional.empty();
         }
 
-        Class returnType = method.getReturnType();
+        final Class<?> returnType = method.getReturnType();
         if (DataContainer.class.isAssignableFrom(returnType)) {
-            return Optional.of(returnType);
-        }
-        if (List.class.isAssignableFrom(returnType)) {
+            return optionalDataContainer(returnType);
+        } else 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.empty();
+                    return ClassLoaderUtils.getFirstGenericParameter(method.getGenericReturnType()).flatMap(
+                        result -> result instanceof Class ? optionalCast((Class<?>) result) : Optional.empty());
                 });
             } catch (Exception e) {
                 /*
@@ -452,6 +483,14 @@ public final class BindingReflections {
         return Optional.empty();
     }
 
+    private static Optional<Class<? extends DataContainer>> optionalCast(final Class<?> type) {
+        return DataContainer.class.isAssignableFrom(type) ? optionalDataContainer(type) : Optional.empty();
+    }
+
+    private static Optional<Class<? extends DataContainer>> optionalDataContainer(final Class<?> type) {
+        return Optional.of(type.asSubclass(DataContainer.class));
+    }
+
     private static class ClassToQNameLoader extends CacheLoader<Class<?>, Optional<QName>> {
 
         @Override
@@ -548,6 +587,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);
     }