+++ /dev/null
-/*
- * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.binding.dom.codec.impl.loader;
-
-import static com.google.common.base.Verify.verify;
-import static com.google.common.base.Verify.verifyNotNull;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMap.Builder;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-// A root codec classloader, binding only whatever is available StaticClassPool
-final class RootCodecClassLoader extends CodecClassLoader {
- private static final Logger LOG = LoggerFactory.getLogger(RootCodecClassLoader.class);
- private static final ClassLoader LOADER = verifyNotNull(RootCodecClassLoader.class.getClassLoader());
-
- static {
- verify(registerAsParallelCapable());
- }
-
- @SuppressWarnings("rawtypes")
- private static final AtomicReferenceFieldUpdater<RootCodecClassLoader, ImmutableMap> LOADERS_UPDATER =
- AtomicReferenceFieldUpdater.newUpdater(RootCodecClassLoader.class, ImmutableMap.class, "loaders");
-
- private volatile ImmutableMap<ClassLoader, CodecClassLoader> loaders = ImmutableMap.of();
-
- RootCodecClassLoader() {
- super(LOADER);
- }
-
- @Override
- CodecClassLoader findClassLoader(final Class<?> bindingClass) {
- final ClassLoader target = bindingClass.getClassLoader();
- if (target == null) {
- // No class loader associated ... well, let's use root then
- return this;
- }
-
- // Cache for update
- ImmutableMap<ClassLoader, CodecClassLoader> local = loaders;
- final CodecClassLoader known = local.get(target);
- if (known != null) {
- return known;
- }
-
- // Alright, we need to determine if the class is accessible through our hierarchy (in which case we use
- // ourselves) or we need to create a new Leaf.
- final CodecClassLoader found;
- if (!isOurClass(bindingClass)) {
- verifyStaticLinkage(target);
- found = AccessController.doPrivileged(
- (PrivilegedAction<CodecClassLoader>)() -> new LeafCodecClassLoader(this, target));
- } else {
- found = this;
- }
-
- // Now make sure we cache this result
- while (true) {
- final Builder<ClassLoader, CodecClassLoader> builder = ImmutableMap.builderWithExpectedSize(
- local.size() + 1);
- builder.putAll(local);
- builder.put(target, found);
-
- if (LOADERS_UPDATER.compareAndSet(this, local, builder.build())) {
- return found;
- }
-
- local = loaders;
- final CodecClassLoader recheck = local.get(target);
- if (recheck != null) {
- return recheck;
- }
- }
- }
-
- @Override
- void appendLoaders(final Set<LeafCodecClassLoader> newLoaders) {
- // Root loader should never see the requirement for other loaders, as that would violate loop-free nature
- // of generated code: if a binding class is hosted in root loader, all its references must be visible from
- // the root loader and hence all the generated code ends up residing in the root loader, too.
- throw new IllegalStateException("Attempted to extend root loader with " + newLoaders);
- }
-
- private boolean isOurClass(final Class<?> bindingClass) {
- final Class<?> ourClass;
- try {
- ourClass = loadClass(bindingClass.getName(), false);
- } catch (ClassNotFoundException e) {
- LOG.debug("Failed to load {}", bindingClass, e);
- return false;
- }
- return bindingClass.equals(ourClass);
- }
-
- // Sanity check: target has to resolve yang-binding contents to the same class, otherwise we are in a pickle
- private static void verifyStaticLinkage(final ClassLoader candidate) {
- final Class<?> targetClazz;
- try {
- targetClazz = candidate.loadClass(DataContainer.class.getName());
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException("ClassLoader " + candidate + " cannot load " + DataContainer.class, e);
- }
- verify(DataContainer.class.equals(targetClazz),
- "Class mismatch on DataContainer. Ours is from %s, target %s has %s from %s",
- DataContainer.class.getClassLoader(), candidate, targetClazz, targetClazz.getClassLoader());
- }
-}