Expand class customization capabilities
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / loader / LeafCodecClassLoader.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.binding.dom.codec.loader;
9
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.collect.ImmutableSet;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Set;
17 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 // A leaf class loader, binding together a root class loader and some other class loader
23 final class LeafCodecClassLoader extends CodecClassLoader {
24     static {
25         verify(registerAsParallelCapable());
26     }
27
28     private static final Logger LOG = LoggerFactory.getLogger(LeafCodecClassLoader.class);
29
30     private final @NonNull RootCodecClassLoader root;
31     private final @NonNull ClassLoader target;
32
33     @SuppressWarnings("rawtypes")
34     private static final AtomicReferenceFieldUpdater<LeafCodecClassLoader, ImmutableSet> DEPENDENCIES_UPDATER =
35             AtomicReferenceFieldUpdater.newUpdater(LeafCodecClassLoader.class, ImmutableSet.class, "dependencies");
36     private volatile ImmutableSet<LeafCodecClassLoader> dependencies = ImmutableSet.of();
37
38     LeafCodecClassLoader(final RootCodecClassLoader root, final ClassLoader target) {
39         super(root);
40         this.root = requireNonNull(root);
41         this.target = requireNonNull(target);
42     }
43
44     @Override
45     protected Class<?> findClass(final String name) throws ClassNotFoundException {
46         try {
47             return target.loadClass(name);
48         } catch (ClassNotFoundException e) {
49             LOG.trace("Class {} not found in target, looking through dependencies", name);
50             for (LeafCodecClassLoader loader : dependencies) {
51                 final Class<?> loaded = loader.findLoadedClass(name);
52                 if (loaded != null) {
53                     LOG.trace("Class {} found in dependency {}", name, loader);
54                     return loaded;
55                 }
56             }
57
58             throw e;
59         }
60     }
61
62     @Override
63     CodecClassLoader findClassLoader(final Class<?> bindingClass) {
64         final ClassLoader bindingTarget = bindingClass.getClassLoader();
65         return target.equals(bindingTarget) ? this : root.findClassLoader(bindingClass);
66     }
67
68     @Override
69     void appendLoaders(final Set<LeafCodecClassLoader> newLoaders) {
70         while (true) {
71             final ImmutableSet<LeafCodecClassLoader> local = dependencies;
72             final List<LeafCodecClassLoader> builder = new ArrayList<>(local.size() + newLoaders.size());
73             builder.addAll(local);
74             builder.addAll(newLoaders);
75             final ImmutableSet<LeafCodecClassLoader> updated = ImmutableSet.copyOf(builder);
76             if (local.equals(updated) || DEPENDENCIES_UPDATER.compareAndSet(this, local, updated)) {
77                 // No need for an update or the update was successful
78                 return;
79             }
80         }
81     }
82 }