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;
12 import com.google.common.collect.ImmutableMap;
13 import com.google.common.collect.ImmutableMap.Builder;
14 import java.security.AccessController;
15 import java.security.PrivilegedAction;
17 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
21 // A root codec classloader, binding only whatever is available StaticClassPool
22 final class RootCodecClassLoader extends CodecClassLoader {
23 private static final Logger LOG = LoggerFactory.getLogger(RootCodecClassLoader.class);
26 verify(registerAsParallelCapable());
29 @SuppressWarnings("rawtypes")
30 private static final AtomicReferenceFieldUpdater<RootCodecClassLoader, ImmutableMap> LOADERS_UPDATER =
31 AtomicReferenceFieldUpdater.newUpdater(RootCodecClassLoader.class, ImmutableMap.class, "loaders");
33 private volatile ImmutableMap<ClassLoader, CodecClassLoader> loaders = ImmutableMap.of();
35 RootCodecClassLoader() {
40 CodecClassLoader findClassLoader(final Class<?> bindingClass) {
41 final ClassLoader target = bindingClass.getClassLoader();
43 // No class loader associated ... well, let's use root then
48 ImmutableMap<ClassLoader, CodecClassLoader> local = loaders;
49 final CodecClassLoader known = local.get(target);
54 // Alright, we need to determine if the class is accessible through our hierarchy (in which case we use
55 // ourselves) or we need to create a new Leaf.
56 final CodecClassLoader found;
57 if (!isOurClass(bindingClass)) {
58 StaticClassPool.verifyStaticLinkage(target);
59 found = AccessController.doPrivileged(
60 (PrivilegedAction<CodecClassLoader>)() -> new LeafCodecClassLoader(this, target));
65 // Now make sure we cache this result
67 final Builder<ClassLoader, CodecClassLoader> builder = ImmutableMap.builderWithExpectedSize(
69 builder.putAll(local);
70 builder.put(target, found);
72 if (LOADERS_UPDATER.compareAndSet(this, local, builder.build())) {
77 final CodecClassLoader recheck = local.get(target);
78 if (recheck != null) {
85 void appendLoaders(final Set<LeafCodecClassLoader> newLoaders) {
86 // Root loader should never see the requirement for other loaders, as that would violate loop-free nature
87 // of generated code: if a binding class is hosted in root loader, all its references must be visible from
88 // the root loader and hence all the generated code ends up residing in the root loader, too.
89 throw new IllegalStateException("Attempted to extend root loader with " + newLoaders);
92 private boolean isOurClass(final Class<?> bindingClass) {
93 final Class<?> ourClass;
95 ourClass = loadClass(bindingClass.getName(), false);
96 } catch (ClassNotFoundException e) {
97 LOG.debug("Failed to load {}", bindingClass, e);
100 return bindingClass.equals(ourClass);