Try harder to acquire class mapping 91/76991/4
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 15 Oct 2018 12:44:48 +0000 (14:44 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 23 Oct 2018 09:00:34 +0000 (11:00 +0200)
We can perform a third try when we failed to load an augmentation
using TCCL by installing the candidate class classloader as the TCCL.

This can help in situations where we are invoked from a context where
the TCCL is not set up to actually see binding classes properly.

JIRA: MDSAL-379
Change-Id: I56d65494cbce32aee0592e3f0799a2bf283e6d17
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java

index 9dcd71387447c76f8cbd7a95568e96ae353f9a6e..e7961a546a5a32c45510bef6f8df87df4d6d8589 100644 (file)
@@ -33,8 +33,10 @@ import java.util.concurrent.ConcurrentMap;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.generator.api.ClassLoadingStrategy;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.model.api.Type;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
 import org.opendaylight.yangtools.yang.binding.Augmentable;
 import org.opendaylight.yangtools.yang.binding.Augmentation;
 import org.opendaylight.yangtools.yang.binding.AugmentationHolder;
@@ -283,14 +285,40 @@ abstract class DataObjectCodecContext<D extends DataObject, T extends DataNodeCo
     }
 
     private @Nullable DataContainerCodecPrototype<?> augmentationByClass(final @NonNull Class<?> childClass) {
-        final DataContainerCodecPrototype<?> firstTry = augmentationByClassOrEquivalentClass(childClass);
-        if (firstTry != null) {
-            return firstTry;
+        DataContainerCodecPrototype<?> lookup = augmentationByClassOrEquivalentClass(childClass);
+        if (lookup != null || !isPotentialAugmentation(childClass)) {
+            return lookup;
         }
+
+        // Attempt to reload all augmentations using TCCL and lookup again
         reloadAllAugmentations();
+        lookup = augmentationByClassOrEquivalentClass(childClass);
+        if (lookup != null) {
+            return lookup;
+        }
+
+        // Still no result, this can be caused by TCCL not being set up properly -- try the class's ClassLoader
+        // if it is present;
+        final ClassLoader loader = childClass.getClassLoader();
+        if (loader == null) {
+            return null;
+        }
+
+        LOG.debug("Class {} not loaded via TCCL, attempting to recover", childClass);
+        ClassLoaderUtils.runWithClassLoader(loader, this::reloadAllAugmentations);
         return augmentationByClassOrEquivalentClass(childClass);
     }
 
+    private boolean isPotentialAugmentation(final Class<?> childClass) {
+        final JavaTypeName name = JavaTypeName.create(childClass);
+        for (Type type : possibleAugmentations.values()) {
+            if (name.equals(type.getIdentifier())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private @Nullable DataContainerCodecPrototype<?> augmentationByClassOrEquivalentClass(
             final @NonNull Class<?> childClass) {
         final DataContainerCodecPrototype<?> childProto = byStreamAugmented.get(childClass);