Reduce ObjectRegistration use
[mdsal.git] / binding / mdsal-binding-runtime-spi / src / main / java / org / opendaylight / mdsal / binding / runtime / spi / ModuleInfoSnapshotResolver.java
index 1ab8e07a87fc5228695d762da96fdab0d534d81f..ab655c878286b1d785a09d6989594e6db370dcbe 100644 (file)
@@ -13,19 +13,15 @@ import static java.util.Objects.requireNonNull;
 import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 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 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;
@@ -33,18 +29,17 @@ import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.runtime.api.ModuleInfoSnapshot;
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
-import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+import org.opendaylight.yangtools.concepts.AbstractRegistration;
 import org.opendaylight.yangtools.concepts.Mutable;
-import org.opendaylight.yangtools.concepts.ObjectRegistration;
 import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+import org.opendaylight.yangtools.yang.binding.YangFeature;
 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.binding.contract.Naming;
 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.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;
@@ -84,8 +79,12 @@ public final class ModuleInfoSnapshotResolver implements Mutable {
 
         @Override
         public String toString() {
-            return MoreObjects.toStringHelper(this).add("info", info).add("registration", reg)
-                    .add("classLoader", loader).add("refCount", refcount).toString();
+            return MoreObjects.toStringHelper(this)
+                .add("info", info)
+                .add("registration", reg)
+                .add("classLoader", loader)
+                .add("refCount", refcount)
+                .toString();
         }
     }
 
@@ -97,30 +96,37 @@ public final class ModuleInfoSnapshotResolver implements Mutable {
     private final ListMultimap<SourceIdentifier, RegisteredModuleInfo> sourceToInfoReg =
             MultimapBuilder.hashKeys().arrayListValues().build();
     @GuardedBy("this")
+    private final ListMultimap<Class<? extends DataRoot>, ImmutableSet<YangFeature<?, ?>>> moduleToFeatures =
+            MultimapBuilder.hashKeys().arrayListValues().build();
+    @GuardedBy("this")
     private @Nullable ModuleInfoSnapshot currentSnapshot;
 
     public ModuleInfoSnapshotResolver(final String name, final YangParserFactory parserFactory) {
         ctxResolver = YangTextSchemaContextResolver.create(name, parserFactory);
     }
 
-    public 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)));
+    public synchronized <R extends @NonNull DataRoot> Registration registerModuleFeatures(final Class<R> module,
+            final Set<? extends YangFeature<?, R>> supportedFeatures) {
+        final var features = supportedFeatures.stream().map(YangFeature::qname).map(QName::getLocalName).sorted()
+            .collect(ImmutableSet.toImmutableSet());
+        return ctxResolver.registerSupportedFeatures(BindingReflections.getQNameModule(module), features);
+    }
+
+    public synchronized List<Registration> registerModuleInfos(final Iterable<? extends YangModuleInfo> moduleInfos) {
+        final var ret = new ArrayList<Registration>();
+        for (var moduleInfo : moduleInfos) {
+            ret.add(register(requireNonNull(moduleInfo)));
         }
         return ret;
     }
 
     @Holding("this")
-    private ObjectRegistration<YangModuleInfo> register(final @NonNull YangModuleInfo moduleInfo) {
-        final Builder<RegisteredModuleInfo> regBuilder = ImmutableList.builder();
-        for (YangModuleInfo info : flatDependencies(moduleInfo)) {
-            regBuilder.add(registerModuleInfo(info));
-        }
-        final ImmutableList<RegisteredModuleInfo> regInfos = regBuilder.build();
+    private Registration register(final @NonNull YangModuleInfo moduleInfo) {
+        final var regInfos = flatDependencies(moduleInfo).stream()
+            .map(this::registerModuleInfo)
+            .collect(ImmutableList.toImmutableList());
 
-        return new AbstractObjectRegistration<>(moduleInfo) {
+        return new AbstractRegistration() {
             @Override
             protected void removeRegistration() {
                 unregister(regInfos);
@@ -134,8 +140,8 @@ public final class ModuleInfoSnapshotResolver implements Mutable {
     @Holding("this")
     private RegisteredModuleInfo registerModuleInfo(final @NonNull YangModuleInfo info) {
         // First search for an existing explicit registration
-        final SourceIdentifier sourceId = sourceIdentifierFrom(info);
-        for (RegisteredModuleInfo reg : sourceToInfoReg.get(sourceId)) {
+        final var sourceId = sourceIdentifierFrom(info);
+        for (var reg : sourceToInfoReg.get(sourceId)) {
             if (info.equals(reg.info)) {
                 reg.incRef();
                 LOG.debug("Reusing registration {}", reg);
@@ -151,7 +157,7 @@ public final class ModuleInfoSnapshotResolver implements Mutable {
             throw new IllegalStateException("Failed to register info " + info, e);
         }
 
-        final RegisteredModuleInfo regInfo = new RegisteredModuleInfo(info, reg, info.getClass().getClassLoader());
+        final var regInfo = new RegisteredModuleInfo(info, reg, info.getClass().getClassLoader());
         LOG.debug("Created new registration {}", regInfo);
 
         sourceToInfoReg.put(sourceId, regInfo);
@@ -159,8 +165,8 @@ public final class ModuleInfoSnapshotResolver implements Mutable {
     }
 
     public synchronized @NonNull ModuleInfoSnapshot takeSnapshot() {
-        final EffectiveModelContext effectiveModel = ctxResolver.getEffectiveModelContext().orElseThrow();
-        final ModuleInfoSnapshot local = currentSnapshot;
+        final var effectiveModel = ctxResolver.getEffectiveModelContext().orElseThrow();
+        final var local = currentSnapshot;
         if (local != null && local.getEffectiveModelContext().equals(effectiveModel)) {
             return local;
         }
@@ -171,46 +177,44 @@ public final class ModuleInfoSnapshotResolver implements Mutable {
     @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();
+        final var sources = new HashSet<SourceIdentifier>();
+        for (var entry : effectiveModel.getModuleStatements().entrySet()) {
+            final var revision = entry.getKey().getRevision().orElse(null);
+            final var module = entry.getValue();
 
-            sources.add(RevisionSourceIdentifier.create(module.argument().getLocalName(), revision));
+            sources.add(new SourceIdentifier(module.argument(), revision));
             module.streamEffectiveSubstatements(SubmoduleEffectiveStatement.class)
-                .map(submodule -> RevisionSourceIdentifier.create(submodule.argument().getLocalName(), revision))
+                .map(submodule -> new SourceIdentifier(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<RegisteredModuleInfo> regs = sourceToInfoReg.get(source);
+        final var moduleInfos = new HashMap<SourceIdentifier, YangModuleInfo>();
+        final var classLoaders = new HashMap<String, ClassLoader>();
+        for (var source : sources) {
+            final var regs = sourceToInfoReg.get(source);
             checkState(!regs.isEmpty(), "No registration for %s", source);
 
-            final RegisteredModuleInfo reg = regs.get(0);
-            final YangModuleInfo info = reg.info;
+            final var reg = regs.get(0);
+            final var info = reg.info;
             moduleInfos.put(source, info);
-            final Class<?> infoClass = info.getClass();
-            classLoaders.put(BindingReflections.getModelRootPackageName(infoClass.getPackage()),
+            final var infoClass = info.getClass();
+            classLoaders.put(Naming.getModelRootPackageName(infoClass.getPackage().getName()),
                 infoClass.getClassLoader());
         }
 
-        final ModuleInfoSnapshot next = new DefaultModuleInfoSnapshot(effectiveModel, moduleInfos, classLoaders);
+        final var 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<RegisteredModuleInfo> regInfos) {
-        for (RegisteredModuleInfo regInfo : regInfos) {
+    private synchronized void unregister(final List<RegisteredModuleInfo> regInfos) {
+        for (var regInfo : regInfos) {
             if (!regInfo.decRef()) {
                 LOG.debug("Registration {} has references, not removing it", regInfo);
                 continue;
             }
 
-            final SourceIdentifier sourceId = sourceIdentifierFrom(regInfo.info);
+            final var sourceId = sourceIdentifierFrom(regInfo.info);
             if (!sourceToInfoReg.remove(sourceId, regInfo)) {
                 LOG.warn("Failed to find {} registered under {}", regInfo, sourceId);
             }
@@ -220,23 +224,23 @@ public final class ModuleInfoSnapshotResolver implements Mutable {
     }
 
     static @NonNull YangTextSchemaSource toYangTextSource(final YangModuleInfo moduleInfo) {
-        return YangTextSchemaSource.delegateForByteSource(sourceIdentifierFrom(moduleInfo),
-            moduleInfo.getYangTextByteSource());
+        return YangTextSchemaSource.delegateForCharSource(sourceIdentifierFrom(moduleInfo),
+            moduleInfo.getYangTextCharSource());
     }
 
     private static @NonNull YangTextSchemaSource toYangTextSource(final SourceIdentifier identifier,
             final YangModuleInfo moduleInfo) {
-        return YangTextSchemaSource.delegateForByteSource(identifier, moduleInfo.getYangTextByteSource());
+        return YangTextSchemaSource.delegateForCharSource(identifier, moduleInfo.getYangTextCharSource());
     }
 
     private static SourceIdentifier sourceIdentifierFrom(final YangModuleInfo moduleInfo) {
-        final QName name = moduleInfo.getName();
-        return RevisionSourceIdentifier.create(name.getLocalName(), name.getRevision());
+        final var name = moduleInfo.getName();
+        return new SourceIdentifier(name.getLocalName(), name.getRevision().map(Revision::toString).orElse(null));
     }
 
     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<>();
+        final var requiredInfos = new LinkedHashSet<YangModuleInfo>();
         flatDependencies(requiredInfos, moduleInfo);
 
         // ... now reverse the order in an effort to register dependencies first (triggering module last)
@@ -245,7 +249,7 @@ public final class ModuleInfoSnapshotResolver implements Mutable {
 
     static void flatDependencies(final Set<YangModuleInfo> set, final YangModuleInfo moduleInfo) {
         if (set.add(moduleInfo)) {
-            for (YangModuleInfo dep : moduleInfo.getImportedModules()) {
+            for (var dep : moduleInfo.getImportedModules()) {
                 flatDependencies(set, dep);
             }
         }