</dependency>
<!-- Binding MD-SAL & Java Binding -->
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-loader</artifactId>
+ <version>11.0.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding-model-api</artifactId>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-model-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-loader</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding-model-api</artifactId>
requires transitive org.opendaylight.mdsal.binding.dom.codec.spi;
requires com.google.common;
requires net.bytebuddy;
+ requires org.opendaylight.mdsal.binding.loader;
requires org.opendaylight.mdsal.binding.model.api;
requires org.opendaylight.mdsal.binding.spec.util;
requires org.opendaylight.yangtools.concepts;
import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
+import com.google.common.base.Strings;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeWriterFactory;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingStreamEventWriter;
import org.opendaylight.mdsal.binding.dom.codec.impl.NodeCodecContext.CodecContextFactory;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader;
import org.opendaylight.mdsal.binding.dom.codec.spi.AbstractBindingNormalizedNodeSerializer;
import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices;
import org.opendaylight.mdsal.binding.dom.codec.spi.BindingSchemaMapping;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader;
import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
}
private static final Logger LOG = LoggerFactory.getLogger(BindingCodecContext.class);
+ private static final File BYTECODE_DIRECTORY;
+
+ static {
+ final String dir = System.getProperty("org.opendaylight.mdsal.binding.dom.codec.loader.bytecodeDumpDirectory");
+ BYTECODE_DIRECTORY = Strings.isNullOrEmpty(dir) ? null : new File(dir);
+ }
private final LoadingCache<Class<?>, DataObjectStreamer<?>> streamers = CacheBuilder.newBuilder().build(
new CacheLoader<Class<?>, DataObjectStreamer<?>>() {
}
});
- private final @NonNull CodecClassLoader loader = CodecClassLoader.create();
+ private final @NonNull BindingClassLoader loader =
+ BindingClassLoader.create(BindingCodecContext.class, BYTECODE_DIRECTORY);
private final @NonNull InstanceIdentifierCodec instanceIdentifierCodec;
private final @NonNull IdentityCodec identityCodec;
private final @NonNull BindingRuntimeContext context;
}
@Override
- public CodecClassLoader getLoader() {
+ public BindingClassLoader getLoader() {
return loader;
}
import static com.google.common.base.Verify.verifyNotNull;
import com.google.common.annotations.Beta;
-import com.google.common.base.Supplier;
+import java.util.function.Supplier;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader.ClassGenerator;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader.ClassGenerator;
/**
* Bridge for initializing generated instance constants during class loading time. This class is public only due to
interface BridgeProvider<T> extends ClassGenerator<T> {
@Override
default Class<T> customizeLoading(final @NonNull Supplier<Class<T>> loader) {
- final BridgeProvider<?> prev = ClassGeneratorBridge.setup(this);
+ final var prev = ClassGeneratorBridge.setup(this);
try {
- final Class<T> result = loader.get();
+ final var result = loader.get();
/*
* This a bit of magic to support NodeContextSupplier constants. These constants need to be resolved
private static final ThreadLocal<BridgeProvider<?>> CURRENT_CUSTOMIZER = new ThreadLocal<>();
private ClassGeneratorBridge() {
-
+ // Hidden on purpose
}
public static @NonNull NodeContextSupplier resolveNodeContextSupplier(final @NonNull String methodName) {
}
static @Nullable BridgeProvider<?> setup(final @NonNull BridgeProvider<?> next) {
- final BridgeProvider<?> prev = CURRENT_CUSTOMIZER.get();
+ final var prev = CURRENT_CUSTOMIZER.get();
CURRENT_CUSTOMIZER.set(verifyNotNull(next));
return prev;
}
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.binding.dom.codec.impl.ClassGeneratorBridge.LocalNameProvider;
import org.opendaylight.mdsal.binding.dom.codec.impl.ClassGeneratorBridge.NodeContextSupplierProvider;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader.ClassGenerator;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader.GeneratorResult;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader.ClassGenerator;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader.GeneratorResult;
import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.slf4j.Logger;
*
* <p>
* We take a different approach here, which takes advantage of the fact we are in control of both code generation (here)
- * and class loading (in {@link CodecClassLoader}). The process is performed in four steps:
+ * and class loading (in {@link BindingClassLoader}). The process is performed in four steps:
* <ul>
* <li>During code generation, the context fields are pointed towards
* {@link ClassGeneratorBridge#resolveNodeContextSupplier(String)} and
this.keyMethod = keyMethod;
}
- static <D extends DataObject, T extends CodecDataObject<T>> Class<T> generate(final CodecClassLoader loader,
+ static <D extends DataObject, T extends CodecDataObject<T>> Class<T> generate(final BindingClassLoader loader,
final Class<D> bindingInterface, final ImmutableMap<Method, ValueNodeCodecContext> simpleProperties,
final Map<Class<?>, PropertyInfo> daoProperties, final Method keyMethod) {
return loader.generateClass(bindingInterface, "codecImpl",
}
static <D extends DataObject, T extends CodecDataObject<T>> Class<T> generateAugmentable(
- final CodecClassLoader loader, final Class<D> bindingInterface,
+ final BindingClassLoader loader, final Class<D> bindingInterface,
final ImmutableMap<Method, ValueNodeCodecContext> simpleProperties,
final Map<Class<?>, PropertyInfo> daoProperties, final Method keyMethod) {
return loader.generateClass(bindingInterface, "codecImpl",
}
@Override
- public final GeneratorResult<T> generateClass(final CodecClassLoader loader, final String fqcn,
+ public final GeneratorResult<T> generateClass(final BindingClassLoader loader, final String fqcn,
final Class<?> bindingInterface) {
LOG.trace("Generating class {}", fqcn);
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingStreamEventWriter;
import org.opendaylight.mdsal.binding.dom.codec.impl.NodeCodecContext.CodecContextFactory;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader.ClassGenerator;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader.GeneratorResult;
import org.opendaylight.mdsal.binding.dom.codec.spi.BindingSchemaMapping;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader.ClassGenerator;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader.GeneratorResult;
import org.opendaylight.mdsal.binding.model.api.GeneratedType;
import org.opendaylight.mdsal.binding.model.api.MethodSignature;
import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
this.startEvent = requireNonNull(startEvent);
}
- static Class<? extends DataObjectStreamer<?>> generateStreamer(final CodecClassLoader loader,
+ static Class<? extends DataObjectStreamer<?>> generateStreamer(final BindingClassLoader loader,
final CodecContextFactory registry, final Class<?> type) {
final var typeAndSchema = registry.getRuntimeContext().getTypeWithSchema(type);
}
@Override
- public GeneratorResult<T> generateClass(final CodecClassLoader loader, final String fqcn,
+ public GeneratorResult<T> generateClass(final BindingClassLoader loader, final String fqcn,
final Class<?> bindingInterface) {
LOG.trace("Definining streamer {}", fqcn);
return result;
}
- private ChildStream createStream(final CodecClassLoader loader, final ImmutableMap<String, Type> props,
+ private ChildStream createStream(final BindingClassLoader loader, final ImmutableMap<String, Type> props,
final DataSchemaNode childSchema, final Method getter) {
if (childSchema instanceof LeafSchemaNode) {
return qnameChildStream(STREAM_LEAF, getter, childSchema);
}
}
- private static Class<?> loadTypeClass(final CodecClassLoader loader, final Type type) {
+ private static Class<?> loadTypeClass(final BindingClassLoader loader, final Type type) {
try {
return loader.loadClass(type.getFullyQualifiedName());
} catch (ClassNotFoundException e) {
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingCodecTreeNode;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader;
import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
*
* @return A codec loader instance
*/
- @NonNull CodecClassLoader getLoader();
+ @NonNull BindingClassLoader getLoader();
@NonNull DataObjectStreamer<?> getDataObjectSerializer(Class<?> type);
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.matcher.ElementMatchers;
import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader.GeneratorResult;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader.GeneratorResult;
import org.opendaylight.mdsal.binding.runtime.api.NotificationRuntimeType;
import org.opendaylight.yangtools.yang.binding.BaseNotification;
import org.opendaylight.yangtools.yang.binding.DataObject;
import net.bytebuddy.jar.asm.Opcodes;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.binding.dom.codec.api.BindingOpaqueObjectCodecTreeNode;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader;
-import org.opendaylight.mdsal.binding.dom.codec.impl.loader.CodecClassLoader.GeneratorResult;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader;
+import org.opendaylight.mdsal.binding.loader.BindingClassLoader.GeneratorResult;
import org.opendaylight.yangtools.yang.binding.OpaqueData;
import org.opendaylight.yangtools.yang.binding.OpaqueObject;
import org.opendaylight.yangtools.yang.data.api.schema.AnydataNode;
implements BindingOpaqueObjectCodecTreeNode<T> {
static final class Anyxml<T extends OpaqueObject<T>> extends OpaqueNodeCodecContext<T> {
Anyxml(final AnyxmlSchemaNode schema, final String getterName, final Class<T> bindingClass,
- final CodecClassLoader loader) {
+ final BindingClassLoader loader) {
super(schema, getterName, bindingClass, loader);
}
static final class Anydata<T extends OpaqueObject<T>> extends OpaqueNodeCodecContext<T> {
Anydata(final AnydataSchemaNode schema, final String getterName, final Class<T> bindingClass,
- final CodecClassLoader loader) {
+ final BindingClassLoader loader) {
super(schema, getterName, bindingClass, loader);
}
private final @NonNull Class<T> bindingClass;
OpaqueNodeCodecContext(final DataSchemaNode schema, final String getterName, final Class<T> bindingClass,
- final CodecClassLoader loader) {
+ final BindingClassLoader loader) {
super(schema, getterName, null);
this.bindingClass = requireNonNull(bindingClass);
proxyConstructor = createImpl(loader, bindingClass);
}
}
- private static MethodHandle createImpl(final CodecClassLoader rootLoader, final Class<?> bindingClass) {
+ private static MethodHandle createImpl(final BindingClassLoader rootLoader, final Class<?> bindingClass) {
final Class<?> proxyClass = rootLoader.generateClass(bindingClass, "codecImpl",
(loader, fqcn, bindingInterface) -> GeneratorResult.of(TEMPLATE
.name(fqcn)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2022 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>dom-parent</artifactId>
+ <version>11.0.0-SNAPSHOT</version>
+ <relativePath>../../dom/dom-parent</relativePath>
+ </parent>
+
+ <artifactId>mdsal-binding-loader</artifactId>
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>net.bytebuddy</groupId>
+ <artifactId>byte-buddy</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2022 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
+ */
+
+/**
+ * A ClassLoader for binding constructs. It allows loading of runtime-generated classes with a combined visibility with
+ * a set of parent class loaders.
+ */
+module org.opendaylight.mdsal.binding.loader {
+ exports org.opendaylight.mdsal.binding.loader;
+
+ requires transitive net.bytebuddy;
+
+ requires com.google.common;
+ requires org.opendaylight.yangtools.yang.binding;
+ requires org.slf4j;
+
+ // Annotations
+ requires static transitive org.eclipse.jdt.annotation;
+}
* 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;
+package org.opendaylight.mdsal.binding.loader;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
-import com.google.common.annotations.Beta;
-import com.google.common.base.Strings;
-import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.io.File;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.HashSet;
-import java.util.Map.Entry;
import java.util.Set;
-import net.bytebuddy.description.type.TypeDescription;
+import java.util.function.Supplier;
import net.bytebuddy.dynamic.DynamicType.Unloaded;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
*
* <p>In single-classloader environments, obviously, the root loader can load all binding classes, and hence no leaf
* loader is created.
- *
- * @author Robert Varga
*/
-@Beta
-public abstract class CodecClassLoader extends ClassLoader {
+public abstract sealed class BindingClassLoader extends ClassLoader
+ permits LeafBindingClassLoader, RootBindingClassLoader {
+ /**
+ * A class generator, generating a class of a particular type.
+ *
+ * @param <T> Type of generated class
+ */
public interface ClassGenerator<T> {
/**
* Generate a class.
* @param bindingInterface Binding interface for which the class is being generated
* @return A result.
*/
- GeneratorResult<T> generateClass(CodecClassLoader loader, String fqcn, Class<?> bindingInterface);
+ GeneratorResult<T> generateClass(BindingClassLoader loader, String fqcn, Class<?> bindingInterface);
/**
* Run the specified loader in a customized environment. The environment customizations must be cleaned up by
}
}
+ /**
+ * Result of class generation.
+ *
+ * @param <T> Type of generated class.
+ */
public static final class GeneratorResult<T> {
private final @NonNull ImmutableSet<Class<?>> dependecies;
private final @NonNull Unloaded<T> result;
public static <T> @NonNull GeneratorResult<T> of(final Unloaded<T> result,
final Collection<Class<?>> dependencies) {
return dependencies.isEmpty() ? of(result) : new GeneratorResult<>(result,
- ImmutableSet.copyOf(dependencies));
+ ImmutableSet.copyOf(dependencies));
}
@NonNull Unloaded<T> getResult() {
}
}
- private static final ClassLoadingStrategy<CodecClassLoader> STRATEGY = (classLoader, types) -> {
+ private static final ClassLoadingStrategy<BindingClassLoader> STRATEGY = (classLoader, types) -> {
verify(types.size() == 1, "Unexpected multiple types", types);
- final Entry<TypeDescription, byte[]> entry = types.entrySet().iterator().next();
+ final var entry = types.entrySet().iterator().next();
return ImmutableMap.of(entry.getKey(), classLoader.loadClass(entry.getKey().getName(), entry.getValue()));
};
verify(ClassLoader.registerAsParallelCapable());
}
- private static final Logger LOG = LoggerFactory.getLogger(CodecClassLoader.class);
- private static final File BYTECODE_DIRECTORY;
+ private static final Logger LOG = LoggerFactory.getLogger(BindingClassLoader.class);
- static {
- final String dir = System.getProperty("org.opendaylight.mdsal.binding.dom.codec.loader.bytecodeDumpDirectory");
- BYTECODE_DIRECTORY = Strings.isNullOrEmpty(dir) ? null : new File(dir);
- }
+ private final @Nullable File dumpDir;
- CodecClassLoader(final ClassLoader parentLoader) {
+ BindingClassLoader(final ClassLoader parentLoader, final @Nullable File dumpDir) {
super(parentLoader);
+ this.dumpDir = dumpDir;
+ }
+
+ BindingClassLoader(final BindingClassLoader parentLoader) {
+ this(parentLoader, parentLoader.dumpDir);
}
/**
- * Instantiate a new CodecClassLoader, which serves as the root of generated code loading.
+ * Instantiate a new BindingClassLoader, which serves as the root of generated code loading.
*
- * @return A new CodecClassLoader.
+ * @param rootClass Class from which to derive the class loader
+ * @param dumpDir Directory in which to dump loaded bytecode
+ * @return A new BindingClassLoader.
+ * @throws NullPointerException if {@code parentLoader} is {@code null}
*/
- public static @NonNull CodecClassLoader create() {
- return AccessController.doPrivileged((PrivilegedAction<CodecClassLoader>)() -> new RootCodecClassLoader());
+ public static @NonNull BindingClassLoader create(final Class<?> rootClass, final @Nullable File dumpDir) {
+ final var parentLoader = rootClass.getClassLoader();
+ return AccessController.doPrivileged(
+ (PrivilegedAction<BindingClassLoader>)() -> new RootBindingClassLoader(parentLoader, dumpDir));
}
/**
* The name of the target class is formed through concatenation of the name of a {@code bindingInterface} and
* specified {@code suffix}.
*
+ * @param <T> Type of generated class
* @param bindingInterface Binding compile-time-generated interface
* @param suffix Suffix to use
* @param generator Code generator to run
* @return A generated class object
* @throws NullPointerException if any argument is null
*/
- public final <T> Class<T> generateClass(final Class<?> bindingInterface,
- final String suffix, final ClassGenerator<T> generator) {
+ public final <T> Class<T> generateClass(final Class<?> bindingInterface, final String suffix,
+ final ClassGenerator<T> generator) {
return findClassLoader(requireNonNull(bindingInterface)).doGenerateClass(bindingInterface, suffix, generator);
}
public final @NonNull Class<?> getGeneratedClass(final Class<?> bindingInterface, final String suffix) {
- final CodecClassLoader loader = findClassLoader(requireNonNull(bindingInterface));
- final String fqcn = generatedClassName(bindingInterface, suffix);
+ final var loader = findClassLoader(requireNonNull(bindingInterface));
+ final var fqcn = generatedClassName(bindingInterface, suffix);
final Class<?> ret;
synchronized (loader.getClassLoadingLock(fqcn)) {
* @param newLoaders Loaders to append
* @throws NullPointerException if {@code loaders} is null
*/
- abstract void appendLoaders(@NonNull Set<LeafCodecClassLoader> newLoaders);
+ abstract void appendLoaders(@NonNull Set<LeafBindingClassLoader> newLoaders);
/**
* Find the loader responsible for holding classes related to a binding class.
* @return a Loader instance
* @throws NullPointerException if {@code bindingClass} is null
*/
- abstract @NonNull CodecClassLoader findClassLoader(@NonNull Class<?> bindingClass);
+ abstract @NonNull BindingClassLoader findClassLoader(@NonNull Class<?> bindingClass);
private <T> Class<T> doGenerateClass(final Class<?> bindingInterface, final String suffix,
final ClassGenerator<T> generator) {
- final String fqcn = generatedClassName(bindingInterface, suffix);
+ final var fqcn = generatedClassName(bindingInterface, suffix);
synchronized (getClassLoadingLock(fqcn)) {
// Attempt to find a loaded class
- final Class<?> existing = findLoadedClass(fqcn);
+ final var existing = findLoadedClass(fqcn);
if (existing != null) {
return (Class<T>) existing;
}
- final GeneratorResult<T> result = generator.generateClass(this, fqcn, bindingInterface);
- final Unloaded<T> unloaded = result.getResult();
+ final var result = generator.generateClass(this, fqcn, bindingInterface);
+ final var unloaded = result.getResult();
verify(fqcn.equals(unloaded.getTypeDescription().getName()), "Unexpected class in %s", unloaded);
verify(unloaded.getAuxiliaryTypes().isEmpty(), "Auxiliary types present in %s", unloaded);
dumpBytecode(unloaded);
final Class<?> loadClass(final String fqcn, final byte[] byteCode) {
synchronized (getClassLoadingLock(fqcn)) {
- final Class<?> existing = findLoadedClass(fqcn);
+ final var existing = findLoadedClass(fqcn);
verify(existing == null, "Attempted to load existing %s", existing);
return defineClass(fqcn, byteCode, 0, byteCode.length);
}
}
private void processDependencies(final Collection<Class<?>> deps) {
- final Set<LeafCodecClassLoader> depLoaders = new HashSet<>();
- for (Class<?> dep : deps) {
- final ClassLoader depLoader = dep.getClassLoader();
- verify(depLoader instanceof CodecClassLoader, "Dependency %s is not a generated class", dep);
- if (this.equals(depLoader)) {
+ final var depLoaders = new HashSet<LeafBindingClassLoader>();
+ for (var dep : deps) {
+ final var depLoader = dep.getClassLoader();
+ verify(depLoader instanceof BindingClassLoader, "Dependency %s is not a generated class", dep);
+ if (equals(depLoader)) {
// Same loader, skip
continue;
}
} catch (ClassNotFoundException e) {
LOG.debug("Cannot find {} in local loader, attempting to compensate", dep, e);
// Root loader is always visible from a leaf, hence the dependency can only be a leaf
- verify(depLoader instanceof LeafCodecClassLoader, "Dependency loader %s is not a leaf", depLoader);
- depLoaders.add((LeafCodecClassLoader) depLoader);
+ verify(depLoader instanceof LeafBindingClassLoader, "Dependency loader %s is not a leaf", depLoader);
+ depLoaders.add((LeafBindingClassLoader) depLoader);
}
}
}
}
- private static void dumpBytecode(final Unloaded<?> unloaded) {
- if (BYTECODE_DIRECTORY != null) {
+ private void dumpBytecode(final Unloaded<?> unloaded) {
+ final var dir = dumpDir;
+ if (dir != null) {
try {
- unloaded.saveIn(BYTECODE_DIRECTORY);
+ unloaded.saveIn(dir);
} catch (IOException | IllegalArgumentException e) {
LOG.info("Failed to save {}", unloaded.getTypeDescription().getName(), e);
}
* 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;
+package org.opendaylight.mdsal.binding.loader;
import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
-import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.eclipse.jdt.annotation.NonNull;
import org.slf4j.LoggerFactory;
// A leaf class loader, binding together a root class loader and some other class loader
-final class LeafCodecClassLoader extends CodecClassLoader {
+final class LeafBindingClassLoader extends BindingClassLoader {
static {
verify(registerAsParallelCapable());
}
- private static final Logger LOG = LoggerFactory.getLogger(LeafCodecClassLoader.class);
+ private static final Logger LOG = LoggerFactory.getLogger(LeafBindingClassLoader.class);
- private final @NonNull RootCodecClassLoader root;
+ private final @NonNull RootBindingClassLoader root;
private final @NonNull ClassLoader target;
@SuppressWarnings("rawtypes")
- private static final AtomicReferenceFieldUpdater<LeafCodecClassLoader, ImmutableSet> DEPENDENCIES_UPDATER =
- AtomicReferenceFieldUpdater.newUpdater(LeafCodecClassLoader.class, ImmutableSet.class, "dependencies");
- private volatile ImmutableSet<LeafCodecClassLoader> dependencies = ImmutableSet.of();
+ private static final AtomicReferenceFieldUpdater<LeafBindingClassLoader, ImmutableSet> DEPENDENCIES_UPDATER =
+ AtomicReferenceFieldUpdater.newUpdater(LeafBindingClassLoader.class, ImmutableSet.class, "dependencies");
+ private volatile ImmutableSet<LeafBindingClassLoader> dependencies = ImmutableSet.of();
- LeafCodecClassLoader(final RootCodecClassLoader root, final ClassLoader target) {
+ LeafBindingClassLoader(final RootBindingClassLoader root, final ClassLoader target) {
super(root);
this.root = requireNonNull(root);
this.target = requireNonNull(target);
return target.loadClass(name);
} catch (ClassNotFoundException e) {
LOG.trace("Class {} not found in target, looking through dependencies", name);
- for (LeafCodecClassLoader loader : dependencies) {
+ for (LeafBindingClassLoader loader : dependencies) {
// Careful: a loading operation may be underway, make sure that process has completed
synchronized (loader.getClassLoadingLock(name)) {
- final Class<?> loaded = loader.findLoadedClass(name);
+ final var loaded = loader.findLoadedClass(name);
if (loaded != null) {
LOG.trace("Class {} found in dependency {}", name, loader);
return loaded;
}
@Override
- CodecClassLoader findClassLoader(final Class<?> bindingClass) {
- final ClassLoader bindingTarget = bindingClass.getClassLoader();
- return target.equals(bindingTarget) ? this : root.findClassLoader(bindingClass);
+ BindingClassLoader findClassLoader(final Class<?> bindingClass) {
+ return target.equals(bindingClass.getClassLoader()) ? this : root.findClassLoader(bindingClass);
}
@Override
- void appendLoaders(final Set<LeafCodecClassLoader> newLoaders) {
+ void appendLoaders(final Set<LeafBindingClassLoader> newLoaders) {
while (true) {
- final ImmutableSet<LeafCodecClassLoader> local = dependencies;
- final List<LeafCodecClassLoader> builder = new ArrayList<>(local.size() + newLoaders.size());
+ final var local = dependencies;
+ final var builder = new ArrayList<LeafBindingClassLoader>(local.size() + newLoaders.size());
builder.addAll(local);
builder.addAll(newLoaders);
- final ImmutableSet<LeafCodecClassLoader> updated = ImmutableSet.copyOf(builder);
+ final var updated = ImmutableSet.copyOf(builder);
if (local.equals(updated) || DEPENDENCIES_UPDATER.compareAndSet(this, local, updated)) {
// No need for an update or the update was successful
return;
* 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;
+package org.opendaylight.mdsal.binding.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.io.File;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import org.eclipse.jdt.annotation.Nullable;
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());
+final class RootBindingClassLoader extends BindingClassLoader {
+ private static final Logger LOG = LoggerFactory.getLogger(RootBindingClassLoader.class);
static {
verify(registerAsParallelCapable());
}
@SuppressWarnings("rawtypes")
- private static final AtomicReferenceFieldUpdater<RootCodecClassLoader, ImmutableMap> LOADERS_UPDATER =
- AtomicReferenceFieldUpdater.newUpdater(RootCodecClassLoader.class, ImmutableMap.class, "loaders");
+ private static final AtomicReferenceFieldUpdater<RootBindingClassLoader, ImmutableMap> LOADERS_UPDATER =
+ AtomicReferenceFieldUpdater.newUpdater(RootBindingClassLoader.class, ImmutableMap.class, "loaders");
- private volatile ImmutableMap<ClassLoader, CodecClassLoader> loaders = ImmutableMap.of();
+ private volatile ImmutableMap<ClassLoader, BindingClassLoader> loaders = ImmutableMap.of();
- RootCodecClassLoader() {
- super(LOADER);
+ RootBindingClassLoader(final ClassLoader parentLoader, final @Nullable File dumpDir) {
+ super(parentLoader, dumpDir);
}
@Override
- CodecClassLoader findClassLoader(final Class<?> bindingClass) {
- final ClassLoader target = bindingClass.getClassLoader();
+ BindingClassLoader findClassLoader(final Class<?> bindingClass) {
+ final var 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);
+ var local = loaders;
+ final var 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;
+ final BindingClassLoader found;
if (!isOurClass(bindingClass)) {
verifyStaticLinkage(target);
found = AccessController.doPrivileged(
- (PrivilegedAction<CodecClassLoader>)() -> new LeafCodecClassLoader(this, target));
+ (PrivilegedAction<BindingClassLoader>)() -> new LeafBindingClassLoader(this, target));
} else {
found = this;
}
// Now make sure we cache this result
while (true) {
- final Builder<ClassLoader, CodecClassLoader> builder = ImmutableMap.builderWithExpectedSize(
- local.size() + 1);
+ final var builder = ImmutableMap.<ClassLoader, BindingClassLoader>builderWithExpectedSize(local.size() + 1);
builder.putAll(local);
builder.put(target, found);
}
local = loaders;
- final CodecClassLoader recheck = local.get(target);
+ final var recheck = local.get(target);
if (recheck != null) {
return recheck;
}
}
@Override
- void appendLoaders(final Set<LeafCodecClassLoader> newLoaders) {
+ void appendLoaders(final Set<LeafBindingClassLoader> 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.
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
/**
- * {@link java.lang.ClassLoader} support for Binding/DOM codec translation code generators. This package provides one
- * core class, {@link CodecClassLoader}, which allows lookup of compile-time-generated Binding classes for the purpose
- * of referencing them within code generators and which serves as the ClassLoader holding runtime-generated codecs.
+ * {@link java.lang.ClassLoader} support for Binding-related runtime-loaded code. This package provides one core class,
+ * {@link BindingClassLoader}, which allows lookup of compile-time-generated Binding classes for the purpose of
+ * referencing them within code generators and which serves as the ClassLoader holding runtime-generated codecs.
*
* <p>
* While the interfaces and classes in this package may be publicly accessible, they are an implementation detail and
* may change incompatibly at any time.
*/
-package org.opendaylight.mdsal.binding.dom.codec.impl.loader;
\ No newline at end of file
+package org.opendaylight.mdsal.binding.loader;
\ No newline at end of file
<module>binding-parent</module>
<!-- FIXME: rename to mdsal-binding-spec-api -->
<module>yang-binding</module>
+ <module>mdsal-binding-loader</module>
<module>mdsal-binding-spec-util</module>
<!-- Binding Runtime Services, dealing with class/schema mapping -->
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-dom-inmemory-datastore</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-loader</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
<artifactId>mdsal-binding-model-api</artifactId>