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.dom.codec.loader;
10 import static com.google.common.base.Verify.verify;
11 import static com.google.common.base.Verify.verifyNotNull;
13 import com.google.common.collect.ImmutableMap;
14 import com.google.common.collect.ImmutableMap.Builder;
15 import java.security.AccessController;
16 import java.security.PrivilegedAction;
18 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
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 RootCodecClassLoader extends CodecClassLoader {
25 private static final Logger LOG = LoggerFactory.getLogger(RootCodecClassLoader.class);
26 private static final ClassLoader LOADER = verifyNotNull(RootCodecClassLoader.class.getClassLoader());
29 verify(registerAsParallelCapable());
32 @SuppressWarnings("rawtypes")
33 private static final AtomicReferenceFieldUpdater<RootCodecClassLoader, ImmutableMap> LOADERS_UPDATER =
34 AtomicReferenceFieldUpdater.newUpdater(RootCodecClassLoader.class, ImmutableMap.class, "loaders");
36 private volatile ImmutableMap<ClassLoader, CodecClassLoader> loaders = ImmutableMap.of();
38 RootCodecClassLoader() {
43 CodecClassLoader findClassLoader(final Class<?> bindingClass) {
44 final ClassLoader target = bindingClass.getClassLoader();
46 // No class loader associated ... well, let's use root then
51 ImmutableMap<ClassLoader, CodecClassLoader> local = loaders;
52 final CodecClassLoader known = local.get(target);
57 // Alright, we need to determine if the class is accessible through our hierarchy (in which case we use
58 // ourselves) or we need to create a new Leaf.
59 final CodecClassLoader found;
60 if (!isOurClass(bindingClass)) {
61 verifyStaticLinkage(target);
62 found = AccessController.doPrivileged(
63 (PrivilegedAction<CodecClassLoader>)() -> new LeafCodecClassLoader(this, target));
68 // Now make sure we cache this result
70 final Builder<ClassLoader, CodecClassLoader> builder = ImmutableMap.builderWithExpectedSize(
72 builder.putAll(local);
73 builder.put(target, found);
75 if (LOADERS_UPDATER.compareAndSet(this, local, builder.build())) {
80 final CodecClassLoader recheck = local.get(target);
81 if (recheck != null) {
88 void appendLoaders(final Set<LeafCodecClassLoader> newLoaders) {
89 // Root loader should never see the requirement for other loaders, as that would violate loop-free nature
90 // of generated code: if a binding class is hosted in root loader, all its references must be visible from
91 // the root loader and hence all the generated code ends up residing in the root loader, too.
92 throw new IllegalStateException("Attempted to extend root loader with " + newLoaders);
95 private boolean isOurClass(final Class<?> bindingClass) {
96 final Class<?> ourClass;
98 ourClass = loadClass(bindingClass.getName(), false);
99 } catch (ClassNotFoundException e) {
100 LOG.debug("Failed to load {}", bindingClass, e);
103 return bindingClass.equals(ourClass);
106 // Sanity check: target has to resolve yang-binding contents to the same class, otherwise we are in a pickle
107 private static void verifyStaticLinkage(final ClassLoader candidate) {
108 final Class<?> targetClazz;
110 targetClazz = candidate.loadClass(DataContainer.class.getName());
111 } catch (ClassNotFoundException e) {
112 throw new IllegalStateException("ClassLoader " + candidate + " cannot load " + DataContainer.class, e);
114 verify(DataContainer.class.equals(targetClazz),
115 "Class mismatch on DataContainer. Ours is from %s, target %s has %s from %s",
116 DataContainer.class.getClassLoader(), candidate, targetClazz, targetClazz.getClassLoader());