Load YangFeatureProviders in mdsal-dom-schema-osgi 89/102089/16
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 16 Aug 2022 11:04:35 +0000 (13:04 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 20 Apr 2023 14:39:51 +0000 (16:39 +0200)
YangModuleProvider provides a view into explicitly defined per-module
feature set. These are defined by applications implementing YANG
modules which provide if-feature'd contents and the application does
not support the full feature set.

This patch add the basic smarts to perform loading of providers, and
propagates them to ModuleInfoSnapshotResolver.

JIRA: MDSAL-790
Change-Id: Ib08915be7b5aba785a8a09ec28dd6e008b61db67
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/KarafYangModuleInfoRegistry.java
dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/RegularYangModuleInfoRegistry.java
dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/YangModuleInfoRegistry.java
dom/mdsal-dom-schema-osgi/src/main/java/org/opendaylight/mdsal/dom/schema/osgi/impl/YangModuleInfoScanner.java

index 7c3fb8478dcf4cdd1633d466e2f59aa7a5b0cbb0..1461a23a597cee64eb77b3fda00a25f832f32fd5 100644 (file)
@@ -15,6 +15,7 @@ import org.apache.karaf.features.DeploymentListener;
 import org.apache.karaf.features.FeaturesService;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.YangFeatureProvider;
 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -70,13 +71,13 @@ final class KarafYangModuleInfoRegistry extends YangModuleInfoRegistry implement
         scannerEnabled = true;
         if (updatesEnabled) {
             delegate.enableScannerAndUpdate();
-
         }
     }
 
     @Override
-    Registration registerInfos(final List<YangModuleInfo> infos) {
-        return delegate.registerInfos(infos);
+    Registration registerBundle(final List<YangModuleInfo> moduleInfos,
+            final List<YangFeatureProvider<?>> featureProviders) {
+        return delegate.registerBundle(moduleInfos, featureProviders);
     }
 
     @Override
index 006d14b7cae8d2530a101e37d69c4d9b9cc13073..8c0b167db6967ea29a3ba6dfdff9c7925fb2d874 100644 (file)
@@ -9,15 +9,19 @@ package org.opendaylight.mdsal.dom.schema.osgi.impl;
 
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.collect.ImmutableList;
 import java.util.List;
 import java.util.NoSuchElementException;
 import org.checkerframework.checker.lock.qual.GuardedBy;
 import org.checkerframework.checker.lock.qual.Holding;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.runtime.api.ModuleInfoSnapshot;
 import org.opendaylight.mdsal.binding.runtime.spi.ModuleInfoSnapshotResolver;
 import org.opendaylight.yangtools.concepts.AbstractRegistration;
 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.YangFeatureProvider;
 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 import org.opendaylight.yangtools.yang.parser.api.YangParserFactory;
 import org.osgi.service.component.ComponentFactory;
@@ -80,12 +84,22 @@ final class RegularYangModuleInfoRegistry extends YangModuleInfoRegistry {
     }
 
     @Override
-    Registration registerInfos(final List<YangModuleInfo> infos) {
-        final var regs = resolver.registerModuleInfos(infos);
+    Registration registerBundle(final List<YangModuleInfo> moduleInfos,
+            final List<YangFeatureProvider<?>> featureProviders) {
+        final var infoRegs = resolver.registerModuleInfos(moduleInfos);
+        final var featureRegs = featureProviders.stream()
+            .map(provider -> {
+                @SuppressWarnings("unchecked")
+                final var raw = (YangFeatureProvider<@NonNull DataRoot>) provider;
+                return resolver.registerModuleFeatures(raw.boundModule(), raw.supportedFeatures());
+            })
+            .collect(ImmutableList.toImmutableList());
+
         return new AbstractRegistration() {
             @Override
             protected void removeRegistration() {
-                regs.forEach(ObjectRegistration::close);
+                featureRegs.forEach(Registration::close);
+                infoRegs.forEach(ObjectRegistration::close);
             }
         };
     }
@@ -104,7 +118,6 @@ final class RegularYangModuleInfoRegistry extends YangModuleInfoRegistry {
             return;
         }
 
-
         final ComponentInstance<OSGiModuleInfoSnapshotImpl> newInstance = contextFactory.newInstance(
             OSGiModuleInfoSnapshotImpl.props(nextGeneration(), newSnapshot));
         if (currentInstance != null) {
index 54bb5e796fe6d563ec55f589760117969a44efdd..28313f0b0cce351e3d8fe65a32b6d4bba58e9b99 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.mdsal.dom.schema.osgi.impl;
 import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.YangFeatureProvider;
 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 import org.opendaylight.yangtools.yang.parser.api.YangParserFactory;
 import org.osgi.framework.BundleContext;
@@ -33,5 +34,6 @@ abstract class YangModuleInfoRegistry {
 
     abstract void close();
 
-    abstract @NonNull Registration registerInfos(List<YangModuleInfo> infos);
+    abstract @NonNull Registration registerBundle(List<YangModuleInfo> moduleInfos,
+        List<YangFeatureProvider<?>> featureProviders);
 }
index 67e18bc3b249e1ed59f5d517b7f3812afe4823e7..a677219e38f75bb4fb89d8a7181438db2ceaaf88 100644 (file)
@@ -17,10 +17,12 @@ import java.lang.reflect.InvocationTargetException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
+import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.YangFeatureProvider;
 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;
@@ -39,9 +41,6 @@ final class YangModuleInfoScanner extends BundleTracker<Registration> {
     // 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 final YangModuleInfoRegistry moduleInfoRegistry;
 
     YangModuleInfoScanner(final BundleContext context, final YangModuleInfoRegistry moduleInfoRegistry) {
@@ -57,41 +56,22 @@ final class YangModuleInfoScanner extends BundleTracker<Registration> {
             return NOOP_REGISTRATION;
         }
 
-        final var 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 null;
-        }
+        // Load YangModuleInfos
+        final var moduleInfos = loadBundleServices(bundle, YangModelBindingProvider.class).stream()
+            .map(YangModelBindingProvider::getModuleInfo)
+            .collect(Collectors.toUnmodifiableList());
 
-        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 null;
-        }
+        // Load YangFeatureProviders
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        final List<YangFeatureProvider<?>> featureProviders =
+            (List) loadBundleServices(bundle, YangFeatureProvider.class);
 
-        if (lines.isEmpty()) {
-            LOG.debug("Bundle {} has empty services for {}", bundle, YANG_MODLE_BINDING_PROVIDER_SERVICE);
+        if (moduleInfos.isEmpty() && featureProviders.isEmpty()) {
+            LOG.debug("Bundle {} does not have any interesting service", bundle);
             return null;
         }
 
-        final var infos = new ArrayList<YangModuleInfo>(lines.size());
-        for (var moduleInfoName : lines) {
-            LOG.trace("Retrieve ModuleInfo({}, {})", moduleInfoName, bundle);
-            final YangModuleInfo moduleInfo;
-            try {
-                moduleInfo = retrieveModuleInfo(moduleInfoName, bundle);
-            } catch (ScanningException e) {
-                LOG.warn("Failed to acquire {} from bundle {}, ignoring it", moduleInfoName, bundle, e);
-                continue;
-            }
-
-            infos.add(moduleInfo);
-        }
-
-        final var reg = moduleInfoRegistry.registerInfos(infos);
+        final var reg = moduleInfoRegistry.registerBundle(moduleInfos, featureProviders);
         moduleInfoRegistry.scannerUpdate();
         return reg;
     }
@@ -113,7 +93,46 @@ final class YangModuleInfoScanner extends BundleTracker<Registration> {
         moduleInfoRegistry.scannerUpdate();
     }
 
-    private static YangModuleInfo retrieveModuleInfo(final String className, final Bundle bundle)
+    private static <T> List<T> loadBundleServices(final Bundle bundle, final Class<T> serviceClass) {
+        final var serviceName = serviceClass.getName();
+        final var serviceEntry = MODULE_INFO_PROVIDER_PATH_PREFIX + serviceName;
+        final var resource = bundle.getEntry(serviceEntry);
+        if (resource == null) {
+            LOG.debug("Bundle {} does not have an entry for {}", bundle, serviceEntry);
+            return List.of();
+        }
+
+        LOG.debug("Got addingBundle({}) with {} resource {}", bundle, serviceName, 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 List.of();
+        }
+
+        if (lines.isEmpty()) {
+            LOG.debug("Bundle {} has empty services for {}", bundle, serviceEntry);
+            return List.of();
+        }
+
+        final var services = new ArrayList<T>(lines.size());
+        for (var implName : lines) {
+            LOG.trace("Retrieve ModuleInfo({}, {})", implName, bundle);
+            final T service;
+            try {
+                service = loadImpl(serviceClass, bundle, implName);
+            } catch (ScanningException e) {
+                LOG.warn("Failed to acquire {} from bundle {}, ignoring it", implName, bundle, e);
+                continue;
+            }
+
+            services.add(service);
+        }
+        return services;
+    }
+
+    private static <T> @NonNull T loadImpl(final Class<T> type, final Bundle bundle, final String className)
             throws ScanningException {
         final Class<?> loadedClass;
         try {
@@ -122,14 +141,14 @@ final class YangModuleInfoScanner extends BundleTracker<Registration> {
             throw new ScanningException(e, "Failed to load class %s", className);
         }
 
-        final Class<? extends YangModelBindingProvider> providerClass;
+        final Class<? extends T> providerClass;
         try {
-            providerClass = loadedClass.asSubclass(YangModelBindingProvider.class);
+            providerClass = loadedClass.asSubclass(type);
         } catch (ClassCastException e) {
             throw new ScanningException(e, "Failed to validate %s", loadedClass);
         }
 
-        final Constructor<? extends YangModelBindingProvider> ctor;
+        final Constructor<? extends T> ctor;
         try {
             ctor = providerClass.getDeclaredConstructor();
         } catch (NoSuchMethodException e) {
@@ -138,15 +157,12 @@ final class YangModuleInfoScanner extends BundleTracker<Registration> {
             throw new ScanningException(e, "Failed to reflect on %s", providerClass);
         }
 
-        YangModelBindingProvider instance;
         try {
-            instance = ctor.newInstance();
+            return ctor.newInstance();
         } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
                 | InvocationTargetException e) {
             throw new ScanningException(e, "Failed to instantiate %s", providerClass);
         }
-
-        return instance.getModuleInfo();
     }
 
     @NonNullByDefault