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;
}
@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);
}
};
}
return;
}
-
final ComponentInstance<OSGiModuleInfoSnapshotImpl> newInstance = contextFactory.newInstance(
OSGiModuleInfoSnapshotImpl.props(nextGeneration(), newSnapshot));
if (currentInstance != null) {
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;
// 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) {
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;
}
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 {
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) {
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