2 * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.binding.loader;
10 import static com.google.common.base.Verify.verify;
12 import com.google.common.collect.ImmutableMap;
14 import java.security.AccessController;
15 import java.security.PrivilegedAction;
17 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.yangtools.yang.binding.DataContainer;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
23 // A root codec classloader, binding only whatever is available StaticClassPool
24 final class RootBindingClassLoader extends BindingClassLoader {
25 private static final Logger LOG = LoggerFactory.getLogger(RootBindingClassLoader.class);
28 verify(registerAsParallelCapable());
31 @SuppressWarnings("rawtypes")
32 private static final AtomicReferenceFieldUpdater<RootBindingClassLoader, ImmutableMap> LOADERS_UPDATER =
33 AtomicReferenceFieldUpdater.newUpdater(RootBindingClassLoader.class, ImmutableMap.class, "loaders");
35 private volatile ImmutableMap<ClassLoader, BindingClassLoader> loaders = ImmutableMap.of();
37 RootBindingClassLoader(final ClassLoader parentLoader, final @Nullable File dumpDir) {
38 super(parentLoader, dumpDir);
42 BindingClassLoader findClassLoader(final Class<?> bindingClass) {
43 final var target = bindingClass.getClassLoader();
45 // No class loader associated ... well, let's use root then
51 final var known = local.get(target);
56 // Alright, we need to determine if the class is accessible through our hierarchy (in which case we use
57 // ourselves) or we need to create a new Leaf.
58 final BindingClassLoader found;
59 if (!isOurClass(bindingClass)) {
60 verifyStaticLinkage(target);
61 found = AccessController.doPrivileged(
62 (PrivilegedAction<BindingClassLoader>)() -> new LeafBindingClassLoader(this, target));
67 // Now make sure we cache this result
69 final var builder = ImmutableMap.<ClassLoader, BindingClassLoader>builderWithExpectedSize(local.size() + 1);
70 builder.putAll(local);
71 builder.put(target, found);
73 if (LOADERS_UPDATER.compareAndSet(this, local, builder.build())) {
78 final var recheck = local.get(target);
79 if (recheck != null) {
86 void appendLoaders(final Set<LeafBindingClassLoader> newLoaders) {
87 // Root loader should never see the requirement for other loaders, as that would violate loop-free nature
88 // of generated code: if a binding class is hosted in root loader, all its references must be visible from
89 // the root loader and hence all the generated code ends up residing in the root loader, too.
90 throw new IllegalStateException("Attempted to extend root loader with " + newLoaders);
93 private boolean isOurClass(final Class<?> bindingClass) {
94 final Class<?> ourClass;
96 ourClass = loadClass(bindingClass.getName(), false);
97 } catch (ClassNotFoundException e) {
98 LOG.debug("Failed to load {}", bindingClass, e);
101 return bindingClass.equals(ourClass);
104 // Sanity check: target has to resolve yang-binding contents to the same class, otherwise we are in a pickle
105 private static void verifyStaticLinkage(final ClassLoader candidate) {
106 final Class<?> targetClazz;
108 targetClazz = candidate.loadClass(DataContainer.class.getName());
109 } catch (ClassNotFoundException e) {
110 throw new IllegalStateException("ClassLoader " + candidate + " cannot load " + DataContainer.class, e);
112 verify(DataContainer.class.equals(targetClazz),
113 "Class mismatch on DataContainer. Ours is from %s, target %s has %s from %s",
114 DataContainer.class.getClassLoader(), candidate, targetClazz, targetClazz.getClassLoader());