X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-spec-util%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fspec%2Freflect%2FBindingReflections.java;h=2a0cbed23da3be91ff41ca4f0cb0b21f546abfb5;hb=6087dda3aa2e148c5046fb2d8e7b0f75a5eee844;hp=0da11d9945ee1a20c8528f765321f964848193ca;hpb=d90adcf214a8f17ae5de22cf8964cbb2a9963972;p=mdsal.git diff --git a/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java b/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java index 0da11d9945..2a0cbed23d 100644 --- a/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java +++ b/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java @@ -9,6 +9,7 @@ package org.opendaylight.mdsal.binding.spec.reflect; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.Beta; import com.google.common.cache.CacheBuilder; @@ -16,11 +17,11 @@ 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; @@ -28,15 +29,18 @@ 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.eclipse.jdt.annotation.NonNull; 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; @@ -55,7 +59,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); @@ -66,6 +70,15 @@ public final class BindingReflections { .expireAfterAccess(EXPIRATION_TIME, TimeUnit.SECONDS) .build(new ClassToQNameLoader()); + private static final LoadingCache> MODULE_INFO_CACHE = + CacheBuilder.newBuilder().weakKeys().weakValues().build( + new CacheLoader>() { + @Override + public ImmutableSet load(final ClassLoader key) { + return loadModuleInfos(key); + } + }); + private BindingReflections() { throw new UnsupportedOperationException("Utility class."); } @@ -81,7 +94,9 @@ public final class BindingReflections { */ public static Class> findAugmentationTarget( final Class> augmentation) { - return ClassLoaderUtils.findFirstGenericArgument(augmentation, Augmentation.class); + final Optional>> opt = ClassLoaderUtils.findFirstGenericArgument(augmentation, + Augmentation.class); + return opt.orElse(null); } /** @@ -93,12 +108,12 @@ public final class BindingReflections { * @return Parent class, e.g. class of which the childClass is ChildOf. */ public static Class findHierarchicalParent(final Class> 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. @@ -106,7 +121,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; } @@ -151,8 +166,8 @@ public final class BindingReflections { public static Optional> 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); } @@ -176,8 +191,10 @@ public final class BindingReflections { return Optional.empty(); } - public static QName getQName(final Class context) { - return findQName(context); + public static @NonNull QName getQName(final Class bindingClass) { + final Optional qname = CLASS_TO_QNAME.getUnchecked(requireNonNull(bindingClass)); + checkState(qname.isPresent(), "Failed to resolve QName of %s", bindingClass); + return qname.get(); } /** @@ -201,7 +218,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. @@ -327,9 +344,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. + *

+ * 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 loadModuleInfos(final ClassLoader loader) { @@ -344,6 +362,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. + * + *

+ * {@link YangModuleInfo} are discovered using {@link ServiceLoader} for {@link YangModelBindingProvider}. + * {@link YangModelBindingProvider} are simple classes which holds only pointers to actual instance + * {@link YangModuleInfo}. + * + *

+ * 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 cacheModuleInfos(final ClassLoader loader) { + return MODULE_INFO_CACHE.getUnchecked(loader); + } + private static void collectYangModuleInfo(final YangModuleInfo moduleInfo, final Builder moduleInfoSet) { moduleInfoSet.add(moduleInfo); @@ -418,7 +457,7 @@ public final class BindingReflections { return getChildrenClassToMethod(type, BindingMapping.NONNULL_PREFIX); } - @SuppressWarnings({ "unchecked", "rawtypes", "checkstyle:illegalCatch" }) + @SuppressWarnings("checkstyle:illegalCatch") private static Optional> getYangModeledReturnType(final Method method, final String prefix) { final String methodName = method.getName(); @@ -426,18 +465,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) { /* @@ -451,6 +486,14 @@ public final class BindingReflections { return Optional.empty(); } + private static Optional> optionalCast(final Class type) { + return DataContainer.class.isAssignableFrom(type) ? optionalDataContainer(type) : Optional.empty(); + } + + private static Optional> optionalDataContainer(final Class type) { + return Optional.of(type.asSubclass(DataContainer.class)); + } + private static class ClassToQNameLoader extends CacheLoader, Optional> { @Override @@ -547,6 +590,9 @@ public final class BindingReflections { * @return Map of augmentations if read was successful, otherwise empty map. */ public static Map>, Augmentation> getAugmentations(final Augmentable input) { + if (input instanceof AugmentationHolder) { + return ((AugmentationHolder) input).augmentations(); + } return AugmentationFieldGetter.getGetter(input.getClass()).getAugmentations(input); } @@ -580,8 +626,8 @@ public final class BindingReflections { */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static boolean isSubstitutionFor(final Class potential, final Class target) { - HashSet subImplemented = Sets.newHashSet(potential.getInterfaces()); - HashSet targetImplemented = Sets.newHashSet(target.getInterfaces()); + Set subImplemented = new HashSet<>(Arrays.asList(potential.getInterfaces())); + Set targetImplemented = new HashSet<>(Arrays.asList(target.getInterfaces())); if (!subImplemented.equals(targetImplemented)) { return false; }