Expand class customization capabilities
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / loader / LeafCodecClassLoader.java
index fdf29037614afb3e8c30281b34a1f2eb55da2663..eebeb6c8184474738f618b89e29b7ba23618a7b2 100644 (file)
@@ -10,7 +10,14 @@ package org.opendaylight.mdsal.binding.dom.codec.loader;
 import static com.google.common.base.Verify.verify;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.collect.ImmutableSet;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 import org.eclipse.jdt.annotation.NonNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 // A leaf class loader, binding together a root class loader and some other class loader
 final class LeafCodecClassLoader extends CodecClassLoader {
@@ -18,8 +25,15 @@ final class LeafCodecClassLoader extends CodecClassLoader {
         verify(registerAsParallelCapable());
     }
 
-    private final @NonNull ClassLoader target;
+    private static final Logger LOG = LoggerFactory.getLogger(LeafCodecClassLoader.class);
+
     private final @NonNull RootCodecClassLoader root;
+    private final @NonNull ClassLoader target;
+
+    @SuppressWarnings("rawtypes")
+    private static final AtomicReferenceFieldUpdater<LeafCodecClassLoader, ImmutableSet> DEPENDENCIES_UPDATER =
+            AtomicReferenceFieldUpdater.newUpdater(LeafCodecClassLoader.class, ImmutableSet.class, "dependencies");
+    private volatile ImmutableSet<LeafCodecClassLoader> dependencies = ImmutableSet.of();
 
     LeafCodecClassLoader(final RootCodecClassLoader root, final ClassLoader target) {
         super(root);
@@ -29,7 +43,20 @@ final class LeafCodecClassLoader extends CodecClassLoader {
 
     @Override
     protected Class<?> findClass(final String name) throws ClassNotFoundException {
-        return target.loadClass(name);
+        try {
+            return target.loadClass(name);
+        } catch (ClassNotFoundException e) {
+            LOG.trace("Class {} not found in target, looking through dependencies", name);
+            for (LeafCodecClassLoader loader : dependencies) {
+                final Class<?> loaded = loader.findLoadedClass(name);
+                if (loaded != null) {
+                    LOG.trace("Class {} found in dependency {}", name, loader);
+                    return loaded;
+                }
+            }
+
+            throw e;
+        }
     }
 
     @Override
@@ -37,4 +64,19 @@ final class LeafCodecClassLoader extends CodecClassLoader {
         final ClassLoader bindingTarget = bindingClass.getClassLoader();
         return target.equals(bindingTarget) ? this : root.findClassLoader(bindingClass);
     }
+
+    @Override
+    void appendLoaders(final Set<LeafCodecClassLoader> newLoaders) {
+        while (true) {
+            final ImmutableSet<LeafCodecClassLoader> local = dependencies;
+            final List<LeafCodecClassLoader> builder = new ArrayList<>(local.size() + newLoaders.size());
+            builder.addAll(local);
+            builder.addAll(newLoaders);
+            final ImmutableSet<LeafCodecClassLoader> updated = ImmutableSet.copyOf(builder);
+            if (local.equals(updated) || DEPENDENCIES_UPDATER.compareAndSet(this, local, updated)) {
+                // No need for an update or the update was successful
+                return;
+            }
+        }
+    }
 }