+++ /dev/null
-/*
- * Copyright (c) 2020 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.osgi.impl;
-
-import org.opendaylight.binding.runtime.api.ClassLoadingStrategy;
-import org.opendaylight.binding.runtime.spi.GeneratedClassLoadingStrategy;
-import org.opendaylight.binding.runtime.spi.ModuleInfoBackedContext;
-import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Deactivate;
-import org.osgi.service.component.annotations.Reference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Component(immediate = true)
-public final class BindingClassLoadingStrategy implements ClassLoadingStrategy {
- private static final Logger LOG = LoggerFactory.getLogger(BindingClassLoadingStrategy.class);
-
- @Reference
- YangParserFactory factory = null;
-
- private ModuleInfoBundleTracker bundleTracker = null;
- private ModuleInfoBackedContext moduleInfoBackedContext = null;
-
- @Activate
- void activate(final BundleContext ctx) {
- LOG.info("Binding-DOM codec starting");
-
- moduleInfoBackedContext = ModuleInfoBackedContext.create("binding-dom-codec", factory,
- // FIXME: This is the fallback strategy, it should not be needed
- GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy());
-
- final OsgiModuleInfoRegistry registry = new OsgiModuleInfoRegistry(moduleInfoBackedContext,
- moduleInfoBackedContext);
-
- LOG.debug("Starting Binding-DOM codec bundle tracker");
- bundleTracker = new ModuleInfoBundleTracker(ctx, registry);
- bundleTracker.open();
-
- LOG.info("Binding-DOM codec started");
- }
-
- @Deactivate
- void deactivate() {
- LOG.info("Binding-DOM codec stopping");
- LOG.debug("Stopping Binding-DOM codec bundle tracker");
- bundleTracker.close();
- moduleInfoBackedContext = null;
- bundleTracker = null;
- LOG.info("Binding-DOM codec stopped");
- }
-
- @Override
- public Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
- return moduleInfoBackedContext.loadClass(fullyQualifiedName);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2017 Pantheon Technologies, 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.osgi.impl;
-
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.io.Resources;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.io.IOException;
-import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.regex.Pattern;
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
-import org.opendaylight.yangtools.yang.binding.YangModelBindingProvider;
-import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.util.tracker.BundleTracker;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Tracks bundles and attempts to retrieve YangModuleInfo, which is then fed into ModuleInfoRegistry.
- */
-final class ModuleInfoBundleTracker extends BundleTracker<Collection<ObjectRegistration<YangModuleInfo>>> {
- private static final Logger LOG = LoggerFactory.getLogger(ModuleInfoBundleTracker.class);
- // FIXME: this should be in a place shared with maven-sal-api-gen-plugin
- private static final String MODULE_INFO_PROVIDER_PATH_PREFIX = "META-INF/services/";
-
- private static final String YANG_MODLE_BINDING_PROVIDER_SERVICE = MODULE_INFO_PROVIDER_PATH_PREFIX
- + YangModelBindingProvider.class.getName();
-
- private static final Pattern BRACE_PATTERN = Pattern.compile("{}", Pattern.LITERAL);
-
- private final OsgiModuleInfoRegistry moduleInfoRegistry;
-
- private volatile boolean deferUpdates = true;
-
- ModuleInfoBundleTracker(final BundleContext context, final OsgiModuleInfoRegistry moduleInfoRegistry) {
- super(context, Bundle.RESOLVED | Bundle.STARTING | Bundle.STOPPING | Bundle.ACTIVE, null);
- this.moduleInfoRegistry = requireNonNull(moduleInfoRegistry);
- }
-
- @Override
- public void open() {
- super.open();
- deferUpdates = false;
- moduleInfoRegistry.updateService();
- }
-
- @Override
- public void close() {
- deferUpdates = true;
- super.close();
- }
-
- @Override
- @SuppressWarnings("checkstyle:illegalCatch")
- public Collection<ObjectRegistration<YangModuleInfo>> addingBundle(final Bundle bundle, final BundleEvent event) {
- final URL resource = bundle.getEntry(YANG_MODLE_BINDING_PROVIDER_SERVICE);
- if (resource == null) {
- LOG.debug("Bundle {} does not have an entry for {}", bundle, YANG_MODLE_BINDING_PROVIDER_SERVICE);
- return ImmutableList.of();
- }
-
- LOG.debug("Got addingBundle({}) with YangModelBindingProvider resource {}", bundle, resource);
- final List<String> lines;
- try {
- lines = Resources.readLines(resource, StandardCharsets.UTF_8);
- } catch (IOException e) {
- LOG.error("Error while reading {} from bundle {}", resource, bundle, e);
- return ImmutableList.of();
- }
-
- if (lines.isEmpty()) {
- LOG.debug("Bundle {} has empty services for {}", bundle, YANG_MODLE_BINDING_PROVIDER_SERVICE);
- return ImmutableList.of();
- }
-
- final List<ObjectRegistration<YangModuleInfo>> registrations = new ArrayList<>(lines.size());
- for (String moduleInfoName : lines) {
- LOG.trace("Retrieve ModuleInfo({}, {})", moduleInfoName, bundle);
- final YangModuleInfo moduleInfo;
- try {
- moduleInfo = retrieveModuleInfo(moduleInfoName, bundle);
- } catch (RuntimeException e) {
- LOG.warn("Failed to acquire {} from bundle {}, ignoring it", moduleInfoName, bundle, e);
- continue;
- }
-
- registrations.add(moduleInfoRegistry.registerInfo(moduleInfo));
- }
-
- if (!deferUpdates) {
- moduleInfoRegistry.updateService();
- }
-
- LOG.trace("Bundle {} resulted in registrations {}", bundle, registrations);
- return registrations;
- }
-
- @Override
- public void modifiedBundle(final Bundle bundle, final BundleEvent event,
- final Collection<ObjectRegistration<YangModuleInfo>> object) {
- // No-op
- }
-
- @Override
- @SuppressWarnings("checkstyle:illegalCatch")
- public void removedBundle(final Bundle bundle, final BundleEvent event,
- final Collection<ObjectRegistration<YangModuleInfo>> regs) {
- if (regs == null) {
- return;
- }
-
- try {
- regs.forEach(reg -> {
- try {
- reg.close();
- } catch (Exception e) {
- LOG.warn("Unable to unregister YangModuleInfo {}", reg.getInstance(), e);
- }
- });
- } finally {
- if (!deferUpdates) {
- moduleInfoRegistry.updateService();
- }
- }
- }
-
- private static YangModuleInfo retrieveModuleInfo(final String moduleInfoClass, final Bundle bundle) {
- final Class<?> clazz = loadClass(moduleInfoClass, bundle);
- if (!YangModelBindingProvider.class.isAssignableFrom(clazz)) {
- String errorMessage = logMessage("Class {} does not implement {} in bundle {}", clazz,
- YangModelBindingProvider.class, bundle);
- throw new IllegalStateException(errorMessage);
- }
-
- final YangModelBindingProvider instance;
- try {
- Object instanceObj = clazz.newInstance();
- instance = YangModelBindingProvider.class.cast(instanceObj);
- } catch (InstantiationException e) {
- String errorMessage = logMessage("Could not instantiate {} in bundle {}, reason {}", moduleInfoClass,
- bundle, e);
- throw new IllegalStateException(errorMessage, e);
- } catch (IllegalAccessException e) {
- String errorMessage = logMessage("Illegal access during instantiation of class {} in bundle {}, reason {}",
- moduleInfoClass, bundle, e);
- throw new IllegalStateException(errorMessage, e);
- }
-
- try {
- return instance.getModuleInfo();
- } catch (NoClassDefFoundError | ExceptionInInitializerError e) {
- throw new IllegalStateException("Error while executing getModuleInfo on " + instance, e);
- }
- }
-
- private static Class<?> loadClass(final String moduleInfoClass, final Bundle bundle) {
- try {
- return bundle.loadClass(moduleInfoClass);
- } catch (ClassNotFoundException e) {
- String errorMessage = logMessage("Could not find class {} in bundle {}, reason {}", moduleInfoClass, bundle,
- e);
- throw new IllegalStateException(errorMessage);
- }
- }
-
- @SuppressFBWarnings("SLF4J_UNKNOWN_ARRAY")
- private static String logMessage(final String slfMessage, final Object... params) {
- LOG.info(slfMessage, params);
- return String.format(BRACE_PATTERN.matcher(slfMessage).replaceAll("%s"), params);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2017 Pantheon Technologies, 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.osgi.impl;
-
-import static java.util.Objects.requireNonNull;
-
-import org.checkerframework.checker.lock.qual.GuardedBy;
-import org.opendaylight.binding.runtime.spi.ModuleInfoBackedContext;
-import org.opendaylight.binding.runtime.spi.ModuleInfoRegistry;
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
-import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
-import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
-import org.osgi.framework.ServiceRegistration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Update SchemaContext service in Service Registry each time new YangModuleInfo is added or removed.
- */
-final class OsgiModuleInfoRegistry implements ModuleInfoRegistry {
- private static final Logger LOG = LoggerFactory.getLogger(OsgiModuleInfoRegistry.class);
-
- private final SchemaContextProvider schemaContextProvider;
- private final ModuleInfoBackedContext moduleInfoRegistry;
-
- @GuardedBy("this")
- private ServiceRegistration<?> registration;
- @GuardedBy("this")
- private long generation;
-
- OsgiModuleInfoRegistry(final ModuleInfoBackedContext moduleInfoRegistry,
- final SchemaContextProvider schemaContextProvider) {
-
- this.moduleInfoRegistry = requireNonNull(moduleInfoRegistry);
- this.schemaContextProvider = requireNonNull(schemaContextProvider);
- }
-
- @Override
- public ObjectRegistration<YangModuleInfo> registerModuleInfo(final YangModuleInfo yangModuleInfo) {
- return new ObjectRegistrationWrapper(registerInfo(yangModuleInfo));
- }
-
- @SuppressWarnings("checkstyle:illegalCatch")
- synchronized void updateService() {
- final SchemaContext context;
- try {
- context = schemaContextProvider.getSchemaContext();
- } catch (final RuntimeException e) {
- // The ModuleInfoBackedContext throws a RuntimeException if it can't create the schema context.
- LOG.error("Error updating the schema context", e);
- return;
- }
- LOG.trace("Assembled context {}", context);
-
- // // FIXME: MDSAL-392: UGH, this should be a snapshot
- // final BindingRuntimeContext next = DefaultBindingRuntimeContext.create(
- // new DefaultBindingRuntimeGenerator().generateTypeMapping(context), moduleInfoRegistry);
-
- // FIXME: publish new the new context, remove the old one
- }
-
- ObjectRegistration<YangModuleInfo> registerInfo(final YangModuleInfo yangModuleInfo) {
- return moduleInfoRegistry.registerModuleInfo(yangModuleInfo);
- }
-
- private class ObjectRegistrationWrapper implements ObjectRegistration<YangModuleInfo> {
- private final ObjectRegistration<YangModuleInfo> inner;
-
- ObjectRegistrationWrapper(final ObjectRegistration<YangModuleInfo> inner) {
- this.inner = requireNonNull(inner);
- }
-
- @Override
- public YangModuleInfo getInstance() {
- return inner.getInstance();
- }
-
- @Override
- @SuppressWarnings("checkstyle:illegalCatch")
- public void close() {
- try {
- inner.close();
- } finally {
- // send modify event when a bundle disappears
- updateService();
- }
- }
-
- @Override
- public String toString() {
- return inner.toString();
- }
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2020 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.binding.runtime.api;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
+
+@Beta
+public interface ModuleInfoSnapshot extends Immutable, ClassLoadingStrategy, EffectiveModelContextProvider,
+ SchemaSourceProvider<YangTextSchemaSource> {
+
+}
<?xml version="1.0" encoding="UTF-8"?>
<!-- vi: set et smarttab sw=4 tabstop=4: -->
<!--
- Copyright (c) 2017 Pantheon Technologies, s.r.o. and others. All rights reserved.
+ Copyright (c) 2020 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,
<relativePath>../../dom/dom-parent</relativePath>
</parent>
- <artifactId>mdsal-binding-dom-codec-osgi</artifactId>
+ <artifactId>mdsal-binding-runtime-osgi</artifactId>
<packaging>bundle</packaging>
<dependencies>
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-binding-dom-codec</artifactId>
- </dependency>
-
- <!-- FIXME: MDSAL-392: this is ugly, we should be looking this up,
- but then we may want to end up doing something
- completely different in thes artifacts -->
- <dependency>
- <groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-binding-generator-impl</artifactId>
+ <artifactId>mdsal-binding-runtime-spi</artifactId>
</dependency>
-
<dependency>
<groupId>org.opendaylight.mdsal</groupId>
- <artifactId>mdsal-binding-runtime-spi</artifactId>
+ <artifactId>mdsal-dom-schema-osgi</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>mockito-configuration</artifactId>
</dependency>
<dependency>
- <groupId>org.opendaylight.yangtools</groupId>
- <artifactId>yang-test-util</artifactId>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-test-model</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-generator-impl</artifactId>
+ <scope>test</scope>
</dependency>
</dependencies>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
<configuration>
+ <Automatic-Module-Name>org.opendaylight.mdsal.binding.runtime.osgi</Automatic-Module-Name>
<instructions>
- <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ <!-- Karaf cannot handle Factory Component requirements, see https://issues.apache.org/jira/browse/KARAF-6625 -->
+ <_dsannotations-options>norequirements</_dsannotations-options>
</instructions>
</configuration>
</plugin>
--- /dev/null
+/*
+ * Copyright (c) 2020 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.runtime.osgi.impl;
+
+import org.opendaylight.binding.runtime.api.AbstractBindingRuntimeContext;
+import org.opendaylight.binding.runtime.api.BindingRuntimeContext;
+import org.opendaylight.binding.runtime.api.BindingRuntimeGenerator;
+import org.opendaylight.binding.runtime.api.BindingRuntimeTypes;
+import org.opendaylight.binding.runtime.api.ClassLoadingStrategy;
+import org.opendaylight.binding.runtime.api.DefaultBindingRuntimeContext;
+import org.opendaylight.mdsal.dom.schema.osgi.OSGiModuleInfoSnapshot;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Factory Component which implements {@link BindingRuntimeContext}.
+ */
+@Component(service = BindingRuntimeContext.class, immediate = true)
+public final class BindingRuntimeContextImpl extends AbstractBindingRuntimeContext {
+ private static final Logger LOG = LoggerFactory.getLogger(BindingRuntimeContextImpl.class);
+
+ @Reference
+ OSGiModuleInfoSnapshot effectiveModel = null;
+ @Reference
+ BindingRuntimeGenerator generator = null;
+
+ private BindingRuntimeContext delegate = null;
+ private long generation;
+
+ @Override
+ public ClassLoadingStrategy getStrategy() {
+ return delegate.getStrategy();
+ }
+
+ @Override
+ public BindingRuntimeTypes getTypes() {
+ return delegate.getTypes();
+ }
+
+ @Activate
+ void activate() {
+ generation = effectiveModel.getGeneration();
+ delegate = DefaultBindingRuntimeContext.create(
+ generator.generateTypeMapping(effectiveModel.getEffectiveModelContext()), effectiveModel);
+
+ LOG.debug("BindingRuntimeContext generation {} activated", generation);
+ }
+
+ @Deactivate
+ void deactivate() {
+ delegate = null;
+ LOG.debug("BindingRuntimeContext generation {} deactivated", generation);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 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.binding.runtime.spi;
+
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.MultimapBuilder;
+import com.google.common.util.concurrent.ListenableFuture;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import org.checkerframework.checker.lock.qual.GuardedBy;
+import org.checkerframework.checker.lock.qual.Holding;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.binding.runtime.api.ModuleInfoSnapshot;
+import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.Mutable;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
+import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaSourceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract base class for things that create an EffectiveModuleContext or similar things from a (dynamic) set of
+ * YangModuleInfo objects.
+ *
+ * <p>
+ * Note this class has some locking quirks and may end up being further refactored.
+ */
+abstract class AbstractModuleInfoTracker implements Mutable {
+ abstract static class AbstractRegisteredModuleInfo {
+ final YangTextSchemaSourceRegistration reg;
+ final YangModuleInfo info;
+ final ClassLoader loader;
+
+ AbstractRegisteredModuleInfo(final YangModuleInfo info, final YangTextSchemaSourceRegistration reg,
+ final ClassLoader loader) {
+ this.info = requireNonNull(info);
+ this.reg = requireNonNull(reg);
+ this.loader = requireNonNull(loader);
+ }
+
+ @Override
+ public final String toString() {
+ return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
+ }
+
+ ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+ return helper.add("info", info).add("registration", reg).add("classLoader", loader);
+ }
+ }
+
+ private static final class ExplicitRegisteredModuleInfo extends AbstractRegisteredModuleInfo {
+ private int refcount = 1;
+
+ ExplicitRegisteredModuleInfo(final YangModuleInfo info, final YangTextSchemaSourceRegistration reg,
+ final ClassLoader loader) {
+ super(info, reg, loader);
+ }
+
+ void incRef() {
+ ++refcount;
+ }
+
+ boolean decRef() {
+ return --refcount == 0;
+ }
+
+ @Override
+ ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+ return super.addToStringAttributes(helper).add("refCount", refcount);
+ }
+ }
+
+ private static final class ImplicitRegisteredModuleInfo extends AbstractRegisteredModuleInfo {
+ ImplicitRegisteredModuleInfo(final YangModuleInfo info, final YangTextSchemaSourceRegistration reg,
+ final ClassLoader loader) {
+ super(info, reg, loader);
+ }
+ }
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractModuleInfoTracker.class);
+
+ private final YangTextSchemaContextResolver ctxResolver;
+
+ @GuardedBy("this")
+ private final ListMultimap<String, AbstractRegisteredModuleInfo> packageToInfoReg =
+ MultimapBuilder.hashKeys().arrayListValues().build();
+ @GuardedBy("this")
+ private final ListMultimap<SourceIdentifier, AbstractRegisteredModuleInfo> sourceToInfoReg =
+ MultimapBuilder.hashKeys().arrayListValues().build();
+ @GuardedBy("this")
+ private @Nullable ModuleInfoSnapshot currentSnapshot;
+
+ AbstractModuleInfoTracker(final YangTextSchemaContextResolver resolver) {
+ this.ctxResolver = requireNonNull(resolver);
+ }
+
+ public final synchronized List<ObjectRegistration<YangModuleInfo>> registerModuleInfos(
+ final Iterable<? extends YangModuleInfo> moduleInfos) {
+ final List<ObjectRegistration<YangModuleInfo>> ret = new ArrayList<>();
+ for (YangModuleInfo yangModuleInfo : moduleInfos) {
+ ret.add(register(requireNonNull(yangModuleInfo)));
+ }
+ return ret;
+ }
+
+ @Holding("this")
+ private ObjectRegistration<YangModuleInfo> register(final @NonNull YangModuleInfo moduleInfo) {
+ final Builder<ExplicitRegisteredModuleInfo> regBuilder = ImmutableList.builder();
+ for (YangModuleInfo info : flatDependencies(moduleInfo)) {
+ regBuilder.add(registerExplicitModuleInfo(info));
+ }
+ final ImmutableList<ExplicitRegisteredModuleInfo> regInfos = regBuilder.build();
+
+ return new AbstractObjectRegistration<>(moduleInfo) {
+ @Override
+ protected void removeRegistration() {
+ unregister(regInfos);
+ }
+ };
+ }
+
+ @Holding("this")
+ final void registerImplicitBindingClass(final Class<?> bindingClass) {
+ registerImplicitModuleInfo(BindingRuntimeHelpers.extractYangModuleInfo(bindingClass));
+ }
+
+ @Holding("this")
+ final @Nullable ClassLoader findClassLoader(final String fullyQualifiedName) {
+ // This performs an explicit check for binding classes
+ final String modulePackageName = BindingReflections.getModelRootPackageName(fullyQualifiedName);
+
+ // Try to find a loaded class loader
+ // FIXME: two-step process, try explicit registrations first
+ for (AbstractRegisteredModuleInfo reg : packageToInfoReg.get(modulePackageName)) {
+ return reg.loader;
+ }
+ return null;
+ }
+
+ /*
+ * Perform implicit registration of a YangModuleInfo and any of its dependencies. If there is a registration for
+ * a particular source, we do not create a duplicate registration.
+ */
+ @Holding("this")
+ private void registerImplicitModuleInfo(final @NonNull YangModuleInfo moduleInfo) {
+ for (YangModuleInfo info : flatDependencies(moduleInfo)) {
+ final Class<?> infoClass = info.getClass();
+ final SourceIdentifier sourceId = sourceIdentifierFrom(info);
+ if (sourceToInfoReg.containsKey(sourceId)) {
+ LOG.debug("Skipping implicit registration of {} as source {} is already registered", info, sourceId);
+ continue;
+ }
+
+ final YangTextSchemaSourceRegistration reg;
+ try {
+ reg = ctxResolver.registerSource(toYangTextSource(sourceId, info));
+ } catch (YangSyntaxErrorException | SchemaSourceException | IOException e) {
+ LOG.warn("Failed to register info {} source {}, ignoring it", info, sourceId, e);
+ continue;
+ }
+
+ final ImplicitRegisteredModuleInfo regInfo = new ImplicitRegisteredModuleInfo(info, reg,
+ infoClass.getClassLoader());
+ sourceToInfoReg.put(sourceId, regInfo);
+ packageToInfoReg.put(BindingReflections.getModelRootPackageName(infoClass.getPackage()), regInfo);
+ }
+ }
+
+ /*
+ * Perform explicit registration of a YangModuleInfo. This always results in a new explicit registration. In case
+ * there is a pre-existing implicit registration, it is removed just after the explicit registration is made.
+ */
+ @Holding("this")
+ private ExplicitRegisteredModuleInfo registerExplicitModuleInfo(final @NonNull YangModuleInfo info) {
+ // First search for an existing explicit registration
+ final SourceIdentifier sourceId = sourceIdentifierFrom(info);
+ for (AbstractRegisteredModuleInfo reg : sourceToInfoReg.get(sourceId)) {
+ if (reg instanceof ExplicitRegisteredModuleInfo && info.equals(reg.info)) {
+ final ExplicitRegisteredModuleInfo explicit = (ExplicitRegisteredModuleInfo) reg;
+ explicit.incRef();
+ LOG.debug("Reusing explicit registration {}", explicit);
+ return explicit;
+ }
+ }
+
+ // Create an explicit registration
+ final YangTextSchemaSourceRegistration reg;
+ try {
+ reg = ctxResolver.registerSource(toYangTextSource(sourceId, info));
+ } catch (YangSyntaxErrorException | SchemaSourceException | IOException e) {
+ throw new IllegalStateException("Failed to register info " + info, e);
+ }
+
+ final Class<?> infoClass = info.getClass();
+ final String packageName = BindingReflections.getModelRootPackageName(infoClass.getPackage());
+ final ExplicitRegisteredModuleInfo regInfo = new ExplicitRegisteredModuleInfo(info, reg,
+ infoClass.getClassLoader());
+ LOG.debug("Created new explicit registration {}", regInfo);
+
+ sourceToInfoReg.put(sourceId, regInfo);
+ removeImplicit(sourceToInfoReg.get(sourceId));
+ packageToInfoReg.put(packageName, regInfo);
+ removeImplicit(packageToInfoReg.get(packageName));
+
+ return regInfo;
+ }
+
+ // Reconsider utility of this
+ final Optional<? extends EffectiveModelContext> getResolverEffectiveModel() {
+ return ctxResolver.getEffectiveModelContext();
+ }
+
+ @Deprecated
+ final ListenableFuture<? extends YangTextSchemaSource> getResolverSource(final SourceIdentifier sourceIdentifier) {
+ return ctxResolver.getSource(sourceIdentifier);
+ }
+
+ @Holding("this")
+ final @NonNull ModuleInfoSnapshot updateSnapshot() {
+ final EffectiveModelContext effectiveModel = ctxResolver.getEffectiveModelContext().orElseThrow();
+ final ModuleInfoSnapshot local = currentSnapshot;
+ if (local != null && local.getEffectiveModelContext().equals(effectiveModel)) {
+ return local;
+ }
+
+ return updateSnapshot(effectiveModel);
+ }
+
+ @Holding("this")
+ private @NonNull ModuleInfoSnapshot updateSnapshot(final EffectiveModelContext effectiveModel) {
+ // Alright, now let's find out which sources got captured
+ final Set<SourceIdentifier> sources = new HashSet<>();
+ for (Entry<QNameModule, ModuleEffectiveStatement> entry : effectiveModel.getModuleStatements().entrySet()) {
+ final Optional<Revision> revision = entry.getKey().getRevision();
+ final ModuleEffectiveStatement module = entry.getValue();
+
+ sources.add(RevisionSourceIdentifier.create(module.argument(), revision));
+ module.streamEffectiveSubstatements(SubmoduleEffectiveStatement.class)
+ .map(submodule -> RevisionSourceIdentifier.create(submodule.argument(), revision))
+ .forEach(sources::add);
+ }
+
+ final Map<SourceIdentifier, YangModuleInfo> moduleInfos = new HashMap<>();
+ final Map<String, ClassLoader> classLoaders = new HashMap<>();
+ for (SourceIdentifier source : sources) {
+ final List<AbstractRegisteredModuleInfo> regs = sourceToInfoReg.get(source);
+ checkState(!regs.isEmpty(), "No registration for %s", source);
+
+ AbstractRegisteredModuleInfo reg = regs.stream()
+ .filter(ExplicitRegisteredModuleInfo.class::isInstance).findFirst()
+ .orElse(null);
+ if (reg == null) {
+ reg = regs.get(0);
+ }
+
+ final YangModuleInfo info = reg.info;
+ moduleInfos.put(source, info);
+ final Class<?> infoClass = info.getClass();
+ classLoaders.put(BindingReflections.getModelRootPackageName(infoClass.getPackage()),
+ infoClass.getClassLoader());
+ }
+
+ final ModuleInfoSnapshot next = new DefaultModuleInfoSnapshot(effectiveModel, moduleInfos, classLoaders);
+ currentSnapshot = next;
+ return next;
+ }
+
+ @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+ justification = "https://github.com/spotbugs/spotbugs/issues/811")
+ private synchronized void unregister(final ImmutableList<ExplicitRegisteredModuleInfo> regInfos) {
+ for (ExplicitRegisteredModuleInfo regInfo : regInfos) {
+ if (!regInfo.decRef()) {
+ LOG.debug("Registration {} has references, not removing it", regInfo);
+ continue;
+ }
+
+ final SourceIdentifier sourceId = sourceIdentifierFrom(regInfo.info);
+ if (!sourceToInfoReg.remove(sourceId, regInfo)) {
+ LOG.warn("Failed to find {} registered under {}", regInfo, sourceId);
+ }
+
+ final String packageName = BindingReflections.getModelRootPackageName(regInfo.info.getClass().getPackage());
+ if (!packageToInfoReg.remove(packageName, regInfo)) {
+ LOG.warn("Failed to find {} registered under {}", regInfo, packageName);
+ }
+
+ regInfo.reg.close();
+ }
+ }
+
+ @Holding("this")
+ private static void removeImplicit(final List<AbstractRegisteredModuleInfo> regs) {
+ /*
+ * Search for implicit registration for a sourceId/packageName.
+ *
+ * Since we are called while an explicit registration is being created (and has already been inserted, we know
+ * there is at least one entry in the maps. We also know registrations retain the order in which they were
+ * created and that implicit registrations are not created if there already is a registration.
+ *
+ * This means that if an implicit registration exists, it will be the first entry in the list.
+ */
+ final AbstractRegisteredModuleInfo reg = regs.get(0);
+ if (reg instanceof ImplicitRegisteredModuleInfo) {
+ LOG.debug("Removing implicit registration {}", reg);
+ regs.remove(0);
+ reg.reg.close();
+ }
+ }
+
+ private static @NonNull YangTextSchemaSource toYangTextSource(final SourceIdentifier identifier,
+ final YangModuleInfo moduleInfo) {
+ return YangTextSchemaSource.delegateForByteSource(identifier, moduleInfo.getYangTextByteSource());
+ }
+
+ private static SourceIdentifier sourceIdentifierFrom(final YangModuleInfo moduleInfo) {
+ final QName name = moduleInfo.getName();
+ return RevisionSourceIdentifier.create(name.getLocalName(), name.getRevision());
+ }
+
+ private static @NonNull List<@NonNull YangModuleInfo> flatDependencies(final YangModuleInfo moduleInfo) {
+ // Flatten the modules being registered, with the triggering module being first...
+ final Set<YangModuleInfo> requiredInfos = new LinkedHashSet<>();
+ flatDependencies(requiredInfos, moduleInfo);
+
+ // ... now reverse the order in an effort to register dependencies first (triggering module last)
+ return ImmutableList.copyOf(requiredInfos).reverse();
+ }
+
+ private static void flatDependencies(final Set<YangModuleInfo> set, final YangModuleInfo moduleInfo) {
+ if (set.add(moduleInfo)) {
+ for (YangModuleInfo dep : moduleInfo.getImportedModules()) {
+ flatDependencies(set, dep);
+ }
+ }
+ }
+}
}
@SuppressWarnings("checkstyle:IllegalCatch")
- static YangModuleInfo extractYangModuleInfo(final Class<?> clazz) {
+ static @NonNull YangModuleInfo extractYangModuleInfo(final Class<?> clazz) {
try {
return BindingReflections.getModuleInfo(clazz);
} catch (Exception e) {
private static ModuleInfoBackedContext prepareContext(final Iterable<? extends YangModuleInfo> moduleInfos) {
final ModuleInfoBackedContext ctx = ModuleInfoBackedContext.create();
- ctx.addModuleInfos(moduleInfos);
+ ctx.registerModuleInfos(moduleInfos);
return ctx;
}
}
--- /dev/null
+/*
+ * Copyright (c) 2020 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.binding.runtime.spi;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Map;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.binding.runtime.api.ModuleInfoSnapshot;
+import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.repo.api.MissingSchemaSourceException;
+import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+
+final class DefaultModuleInfoSnapshot extends GeneratedClassLoadingStrategy implements ModuleInfoSnapshot {
+ private final ImmutableMap<SourceIdentifier, YangModuleInfo> moduleInfos;
+ private final ImmutableMap<String, ClassLoader> classLoaders;
+ private final @NonNull EffectiveModelContext effectiveModel;
+
+ DefaultModuleInfoSnapshot(final EffectiveModelContext effectiveModel,
+ final Map<SourceIdentifier, YangModuleInfo> moduleInfos, final Map<String, ClassLoader> classLoaders) {
+ this.effectiveModel = requireNonNull(effectiveModel);
+ this.moduleInfos = ImmutableMap.copyOf(moduleInfos);
+ this.classLoaders = ImmutableMap.copyOf(classLoaders);
+ }
+
+ @Override
+ public EffectiveModelContext getEffectiveModelContext() {
+ return effectiveModel;
+ }
+
+ @Override
+ public ListenableFuture<? extends YangTextSchemaSource> getSource(final SourceIdentifier sourceIdentifier) {
+ final YangModuleInfo info = moduleInfos.get(sourceIdentifier);
+ if (info == null) {
+ return Futures.immediateFailedFuture(
+ new MissingSchemaSourceException("No source registered", sourceIdentifier));
+ }
+ return Futures.immediateFuture(YangTextSchemaSource.delegateForByteSource(sourceIdentifier,
+ info.getYangTextByteSource()));
+ }
+
+ @Override
+ public Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
+ final String packageName = BindingReflections.getModelRootPackageName(fullyQualifiedName);
+ final ClassLoader loader = classLoaders.get(packageName);
+ if (loader == null) {
+ throw new ClassNotFoundException("Package " + packageName + " not found");
+ }
+ return loader.loadClass(fullyQualifiedName);
+ }
+}
import static java.util.Objects.requireNonNull;
import com.google.common.annotations.Beta;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.MultimapBuilder;
import com.google.common.util.concurrent.ListenableFuture;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
import java.util.Optional;
import java.util.Set;
-import org.checkerframework.checker.lock.qual.GuardedBy;
import org.checkerframework.checker.lock.qual.Holding;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.binding.runtime.api.BindingRuntimeContext;
import org.opendaylight.binding.runtime.api.BindingRuntimeGenerator;
import org.opendaylight.binding.runtime.api.ClassLoadingStrategy;
import org.opendaylight.binding.runtime.api.DefaultBindingRuntimeContext;
-import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
import org.opendaylight.yangtools.util.ClassLoaderUtils;
import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
-import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider;
import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory;
-import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
-import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
-import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider;
import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
-import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaSourceRegistration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
@Beta
-public class ModuleInfoBackedContext extends GeneratedClassLoadingStrategy
- implements ModuleInfoRegistry, EffectiveModelContextProvider, SchemaSourceProvider<YangTextSchemaSource> {
+public class ModuleInfoBackedContext extends AbstractModuleInfoTracker implements ClassLoadingStrategy,
+ EffectiveModelContextProvider, SchemaSourceProvider<YangTextSchemaSource> {
private static final class WithFallback extends ModuleInfoBackedContext {
private final @NonNull ClassLoadingStrategy fallback;
Class<?> loadUnknownClass(final String fullyQualifiedName) throws ClassNotFoundException {
// We have not found a matching registration, consult the backing strategy
final Class<?> cls = fallback.loadClass(fullyQualifiedName);
- registerImplicitModuleInfo(BindingRuntimeHelpers.extractYangModuleInfo(cls));
+ registerImplicitBindingClass(cls);
return cls;
}
}
- private abstract static class AbstractRegisteredModuleInfo {
- final YangTextSchemaSourceRegistration reg;
- final YangModuleInfo info;
- final ClassLoader loader;
-
- AbstractRegisteredModuleInfo(final YangModuleInfo info, final YangTextSchemaSourceRegistration reg,
- final ClassLoader loader) {
- this.info = requireNonNull(info);
- this.reg = requireNonNull(reg);
- this.loader = requireNonNull(loader);
- }
-
- @Override
- public final String toString() {
- return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
- }
-
- ToStringHelper addToStringAttributes(final ToStringHelper helper) {
- return helper.add("info", info).add("registration", reg).add("classLoader", loader);
- }
- }
-
- private static final class ExplicitRegisteredModuleInfo extends AbstractRegisteredModuleInfo {
- private int refcount = 1;
-
- ExplicitRegisteredModuleInfo(final YangModuleInfo info, final YangTextSchemaSourceRegistration reg,
- final ClassLoader loader) {
- super(info, reg, loader);
- }
-
- void incRef() {
- ++refcount;
- }
-
- boolean decRef() {
- return --refcount == 0;
- }
-
- @Override
- ToStringHelper addToStringAttributes(final ToStringHelper helper) {
- return super.addToStringAttributes(helper).add("refCount", refcount);
- }
- }
-
- private static final class ImplicitRegisteredModuleInfo extends AbstractRegisteredModuleInfo {
- ImplicitRegisteredModuleInfo(final YangModuleInfo info, final YangTextSchemaSourceRegistration reg,
- final ClassLoader loader) {
- super(info, reg, loader);
- }
- }
-
- private static final Logger LOG = LoggerFactory.getLogger(ModuleInfoBackedContext.class);
-
private static final LoadingCache<ClassLoadingStrategy,
LoadingCache<ImmutableSet<YangModuleInfo>, ModuleInfoBackedContext>> CONTEXT_CACHES = CacheBuilder.newBuilder()
.weakKeys().build(new CacheLoader<ClassLoadingStrategy,
@Override
public ModuleInfoBackedContext load(final Set<YangModuleInfo> key) {
final ModuleInfoBackedContext context = ModuleInfoBackedContext.create(strategy);
- context.addModuleInfos(key);
+ context.registerModuleInfos(key);
return context;
}
});
}
});
- private final YangTextSchemaContextResolver ctxResolver;
-
- @GuardedBy("this")
- private final ListMultimap<String, AbstractRegisteredModuleInfo> packageToInfoReg =
- MultimapBuilder.hashKeys().arrayListValues().build();
- @GuardedBy("this")
- private final ListMultimap<SourceIdentifier, AbstractRegisteredModuleInfo> sourceToInfoReg =
- MultimapBuilder.hashKeys().arrayListValues().build();
-
ModuleInfoBackedContext(final YangTextSchemaContextResolver resolver) {
- this.ctxResolver = requireNonNull(resolver);
+ super(resolver);
}
@Beta
}
@Override
- @SuppressWarnings("checkstyle:illegalCatch")
- public final Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
- // This performs an explicit check for binding classes
- final String modulePackageName = BindingReflections.getModelRootPackageName(fullyQualifiedName);
-
- synchronized (this) {
- // Try to find a loaded class loader
- // FIXME: two-step process, try explicit registrations first
- for (AbstractRegisteredModuleInfo reg : packageToInfoReg.get(modulePackageName)) {
- return ClassLoaderUtils.loadClass(reg.loader, fullyQualifiedName);
- }
-
- return loadUnknownClass(fullyQualifiedName);
- }
- }
-
- @Holding("this")
- Class<?> loadUnknownClass(final String fullyQualifiedName) throws ClassNotFoundException {
- throw new ClassNotFoundException(fullyQualifiedName);
- }
-
- @Override
- public final synchronized ObjectRegistration<YangModuleInfo> registerModuleInfo(
- final YangModuleInfo yangModuleInfo) {
- return register(requireNonNull(yangModuleInfo));
+ public final synchronized Class<?> loadClass(final String fullyQualifiedName) throws ClassNotFoundException {
+ final ClassLoader loader = findClassLoader(fullyQualifiedName);
+ return loader != null ? ClassLoaderUtils.loadClass(loader, fullyQualifiedName)
+ : loadUnknownClass(fullyQualifiedName);
}
@Override
public final ListenableFuture<? extends YangTextSchemaSource> getSource(final SourceIdentifier sourceIdentifier) {
- return ctxResolver.getSource(sourceIdentifier);
- }
-
- final synchronized void addModuleInfos(final Iterable<? extends YangModuleInfo> moduleInfos) {
- for (YangModuleInfo yangModuleInfo : moduleInfos) {
- register(requireNonNull(yangModuleInfo));
- }
+ return getResolverSource(sourceIdentifier);
}
@Beta
// Unite with current SchemaService
public final Optional<? extends EffectiveModelContext> tryToCreateModelContext() {
- return ctxResolver.getEffectiveModelContext();
+ return getResolverEffectiveModel();
}
@Holding("this")
- private ObjectRegistration<YangModuleInfo> register(final @NonNull YangModuleInfo moduleInfo) {
- final Builder<ExplicitRegisteredModuleInfo> regBuilder = ImmutableList.builder();
- for (YangModuleInfo info : flatDependencies(moduleInfo)) {
- regBuilder.add(registerExplicitModuleInfo(info));
- }
- final ImmutableList<ExplicitRegisteredModuleInfo> regInfos = regBuilder.build();
-
- return new AbstractObjectRegistration<>(moduleInfo) {
- @Override
- protected void removeRegistration() {
- unregister(regInfos);
- }
- };
- }
-
- /*
- * Perform implicit registration of a YangModuleInfo and any of its dependencies. If there is a registration for
- * a particular source, we do not create a duplicate registration.
- */
- @Holding("this")
- final void registerImplicitModuleInfo(final @NonNull YangModuleInfo moduleInfo) {
- for (YangModuleInfo info : flatDependencies(moduleInfo)) {
- final Class<?> infoClass = info.getClass();
- final SourceIdentifier sourceId = sourceIdentifierFrom(info);
- if (sourceToInfoReg.containsKey(sourceId)) {
- LOG.debug("Skipping implicit registration of {} as source {} is already registered", info, sourceId);
- continue;
- }
-
- final YangTextSchemaSourceRegistration reg;
- try {
- reg = ctxResolver.registerSource(toYangTextSource(sourceId, info));
- } catch (YangSyntaxErrorException | SchemaSourceException | IOException e) {
- LOG.warn("Failed to register info {} source {}, ignoring it", info, sourceId, e);
- continue;
- }
-
- final ImplicitRegisteredModuleInfo regInfo = new ImplicitRegisteredModuleInfo(info, reg,
- infoClass.getClassLoader());
- sourceToInfoReg.put(sourceId, regInfo);
- packageToInfoReg.put(BindingReflections.getModelRootPackageName(infoClass.getPackage()), regInfo);
- }
- }
-
- /*
- * Perform explicit registration of a YangModuleInfo. This always results in a new explicit registration. In case
- * there is a pre-existing implicit registration, it is removed just after the explicit registration is made.
- */
- @Holding("this")
- private ExplicitRegisteredModuleInfo registerExplicitModuleInfo(final @NonNull YangModuleInfo info) {
- // First search for an existing explicit registration
- final SourceIdentifier sourceId = sourceIdentifierFrom(info);
- for (AbstractRegisteredModuleInfo reg : sourceToInfoReg.get(sourceId)) {
- if (reg instanceof ExplicitRegisteredModuleInfo && info.equals(reg.info)) {
- final ExplicitRegisteredModuleInfo explicit = (ExplicitRegisteredModuleInfo) reg;
- explicit.incRef();
- LOG.debug("Reusing explicit registration {}", explicit);
- return explicit;
- }
- }
-
- // Create an explicit registration
- final YangTextSchemaSourceRegistration reg;
- try {
- reg = ctxResolver.registerSource(toYangTextSource(sourceId, info));
- } catch (YangSyntaxErrorException | SchemaSourceException | IOException e) {
- throw new IllegalStateException("Failed to register info " + info, e);
- }
-
- final Class<?> infoClass = info.getClass();
- final String packageName = BindingReflections.getModelRootPackageName(infoClass.getPackage());
- final ExplicitRegisteredModuleInfo regInfo = new ExplicitRegisteredModuleInfo(info, reg,
- infoClass.getClassLoader());
- LOG.debug("Created new explicit registration {}", regInfo);
-
- sourceToInfoReg.put(sourceId, regInfo);
- removeImplicit(sourceToInfoReg.get(sourceId));
- packageToInfoReg.put(packageName, regInfo);
- removeImplicit(packageToInfoReg.get(packageName));
-
- return regInfo;
- }
-
- final synchronized void unregister(final ImmutableList<ExplicitRegisteredModuleInfo> regInfos) {
- for (ExplicitRegisteredModuleInfo regInfo : regInfos) {
- if (!regInfo.decRef()) {
- LOG.debug("Registration {} has references, not removing it", regInfo);
- continue;
- }
-
- final SourceIdentifier sourceId = sourceIdentifierFrom(regInfo.info);
- if (!sourceToInfoReg.remove(sourceId, regInfo)) {
- LOG.warn("Failed to find {} registered under {}", regInfo, sourceId);
- }
-
- final String packageName = BindingReflections.getModelRootPackageName(regInfo.info.getClass().getPackage());
- if (!packageToInfoReg.remove(packageName, regInfo)) {
- LOG.warn("Failed to find {} registered under {}", regInfo, packageName);
- }
-
- regInfo.reg.close();
- }
- }
-
- @Holding("this")
- private static void removeImplicit(final List<AbstractRegisteredModuleInfo> regs) {
- /*
- * Search for implicit registration for a sourceId/packageName.
- *
- * Since we are called while an explicit registration is being created (and has already been inserted, we know
- * there is at least one entry in the maps. We also know registrations retain the order in which they were
- * created and that implicit registrations are not created if there already is a registration.
- *
- * This means that if an implicit registration exists, it will be the first entry in the list.
- */
- final AbstractRegisteredModuleInfo reg = regs.get(0);
- if (reg instanceof ImplicitRegisteredModuleInfo) {
- LOG.debug("Removing implicit registration {}", reg);
- regs.remove(0);
- reg.reg.close();
- }
- }
-
- private static @NonNull YangTextSchemaSource toYangTextSource(final SourceIdentifier identifier,
- final YangModuleInfo moduleInfo) {
- return YangTextSchemaSource.delegateForByteSource(identifier, moduleInfo.getYangTextByteSource());
- }
-
- private static SourceIdentifier sourceIdentifierFrom(final YangModuleInfo moduleInfo) {
- final QName name = moduleInfo.getName();
- return RevisionSourceIdentifier.create(name.getLocalName(), name.getRevision());
- }
-
- private static List<YangModuleInfo> flatDependencies(final YangModuleInfo moduleInfo) {
- // Flatten the modules being registered, with the triggering module being first...
- final Set<YangModuleInfo> requiredInfos = new LinkedHashSet<>();
- flatDependencies(requiredInfos, moduleInfo);
-
- // ... now reverse the order in an effort to register dependencies first (triggering module last)
- final List<YangModuleInfo> intendedOrder = new ArrayList<>(requiredInfos);
- Collections.reverse(intendedOrder);
-
- return intendedOrder;
- }
-
- private static void flatDependencies(final Set<YangModuleInfo> set, final YangModuleInfo moduleInfo) {
- if (set.add(moduleInfo)) {
- for (YangModuleInfo dep : moduleInfo.getImportedModules()) {
- flatDependencies(set, dep);
- }
- }
+ Class<?> loadUnknownClass(final String fullyQualifiedName) throws ClassNotFoundException {
+ throw new ClassNotFoundException(fullyQualifiedName);
}
}
+++ /dev/null
-/*
- * Copyright (c) 2013 Cisco Systems, Inc. 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.binding.runtime.spi;
-
-import com.google.common.annotations.Beta;
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
-import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
-
-@Beta
-public interface ModuleInfoRegistry {
-
- ObjectRegistration<YangModuleInfo> registerModuleInfo(YangModuleInfo yangModuleInfo);
-}
--- /dev/null
+/*
+ * Copyright (c) 2020 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.binding.runtime.spi;
+
+import com.google.common.annotations.Beta;
+import java.util.NoSuchElementException;
+import org.opendaylight.binding.runtime.api.ModuleInfoSnapshot;
+import org.opendaylight.yangtools.concepts.CheckedBuilder;
+import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory;
+import org.opendaylight.yangtools.yang.parser.repo.YangTextSchemaContextResolver;
+
+@Beta
+public final class ModuleInfoSnapshotBuilder extends AbstractModuleInfoTracker
+ implements CheckedBuilder<ModuleInfoSnapshot, NoSuchElementException> {
+
+ public ModuleInfoSnapshotBuilder(final String name, final YangParserFactory parserFactory) {
+ super(YangTextSchemaContextResolver.create(name, parserFactory));
+ }
+
+ @Override
+ public synchronized ModuleInfoSnapshot build() {
+ return updateSnapshot();
+ }
+}