<build>
<plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <Automatic-Module-Name>org.opendaylight.mdsal.binding.dom.adapter</Automatic-Module-Name>
+ <instructions>
+ <!-- Karaf cannot handle Factory Component requirements, see https://issues.apache.org/jira/browse/KARAF-6625 -->
+ <_dsannotations-options>norequirements</_dsannotations-options>
+ </instructions>
+ </configuration>
+ </plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
--- /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.adapter.osgi;
+
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+
+import java.util.Map;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.api.BindingService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class AbstractAdaptedService<B extends BindingService> {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractAdaptedService.class);
+ static final @NonNull String DELEGATE =
+ "org.opendaylight.mdsal.binding.dom.adapter.osgi.AbstractAdaptedService.DELEGATE";
+
+ private final Class<B> bindingService;
+
+ private @Nullable B delegate;
+
+ AbstractAdaptedService(final Class<B> bindingService) {
+ this.bindingService = requireNonNull(bindingService);
+ }
+
+ final void start(final Map<String, ?> properties) {
+ delegate = bindingService.cast(verifyNotNull(properties.get(DELEGATE)));
+ LOG.info("Binding/DOM adapter for {} activated", bindingService.getSimpleName());
+ }
+
+ final void stop() {
+ delegate = null;
+ LOG.info("Binding/DOM adapter for {} deactivated", bindingService.getSimpleName());
+ }
+
+ final @NonNull B delegate() {
+ return verifyNotNull(delegate);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2018 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.adapter.osgi;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.function.Function;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.api.BindingService;
+import org.opendaylight.mdsal.dom.api.DOMService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A ServiceTracker which adapts a DOMService to a BindingService.
+ *
+ * @param <D> DOMService type
+ * @param <B> BindingService type
+ * @author Robert Varga
+ */
+abstract class AbstractAdaptingTracker<D extends DOMService, B extends BindingService, T>
+ extends ServiceTracker<D, T> {
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractAdaptingTracker.class);
+
+ private final Function<D, B> bindingFactory;
+ final @NonNull Class<B> bindingClass;
+
+ AbstractAdaptingTracker(final BundleContext ctx, final Class<D> domClass, final Class<B> bindingClass,
+ final Function<D, B> bindingFactory) {
+ super(ctx, domClass, null);
+ this.bindingClass = requireNonNull(bindingClass);
+ this.bindingFactory = requireNonNull(bindingFactory);
+ }
+
+ @Override
+ public final void open(final boolean trackAllServices) {
+ LOG.debug("Starting tracker for {}", bindingClass.getName());
+ super.open(trackAllServices);
+ LOG.debug("Tracker for {} started", bindingClass.getName());
+ }
+
+ @Override
+ public final T addingService(final ServiceReference<D> reference) {
+ if (reference == null) {
+ LOG.debug("Null reference for {}, ignoring it", bindingClass.getName());
+ return null;
+ }
+ if (reference.getProperty(ServiceProperties.IGNORE_PROP) != null) {
+ LOG.debug("Ignoring reference {} due to {}", reference, ServiceProperties.IGNORE_PROP);
+ return null;
+ }
+
+ final D dom = context.getService(reference);
+ if (dom == null) {
+ LOG.debug("Could not get {} service from {}, ignoring it", bindingClass.getName(), reference);
+ return null;
+ }
+
+ return addingService(reference, dom, bindingFactory.apply(dom));
+ }
+
+ abstract @NonNull T addingService(@NonNull ServiceReference<D> reference, @NonNull D dom, @NonNull B binding);
+
+ @Override
+ public final void modifiedService(final ServiceReference<D> reference, final T service) {
+ if (service != null && reference != null) {
+ updatedService(reference, service);
+ }
+ }
+
+ abstract void updatedService(@NonNull ServiceReference<D> reference, @NonNull T service);
+
+ @Override
+ public final void removedService(final ServiceReference<D> reference, final T service) {
+ if (service != null) {
+ context.ungetService(reference);
+ removedService(service);
+ LOG.debug("Unregistered service {}", service);
+ }
+ }
+
+ abstract void removedService(@NonNull T service);
+
+}
--- /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.adapter.osgi;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.function.Function;
+import org.opendaylight.mdsal.binding.api.BindingService;
+import org.opendaylight.mdsal.dom.api.DOMService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentFactory;
+import org.osgi.service.component.ComponentInstance;
+
+final class AdaptingComponentTracker<D extends DOMService, B extends BindingService>
+ extends AbstractAdaptingTracker<D, B, AdaptingComponentTracker.ComponentHolder<B>> {
+ static final class ComponentHolder<B extends BindingService> {
+ final B binding;
+ ComponentInstance component;
+
+ ComponentHolder(final B binding, final ComponentInstance component) {
+ this.binding = requireNonNull(binding);
+ this.component = requireNonNull(component);
+ }
+ }
+
+ private final ComponentFactory componentFactory;
+
+ AdaptingComponentTracker(final BundleContext ctx, final Class<D> domClass, final Class<B> bindingClass,
+ final Function<D, B> bindingFactory, final ComponentFactory componentFactory) {
+ super(ctx, domClass, bindingClass, bindingFactory);
+ this.componentFactory = requireNonNull(componentFactory);
+ }
+
+ @Override
+ ComponentHolder<B> addingService(final ServiceReference<D> reference, final D dom, final B binding) {
+ return new ComponentHolder<>(binding, componentFactory.newInstance(Dict.fromReference(reference, binding)));
+ }
+
+ @Override
+ void removedService(final ComponentHolder<B> service) {
+ service.component.dispose();
+ }
+
+ @Override
+ void updatedService(final ServiceReference<D> reference, final ComponentHolder<B> service) {
+ service.component.dispose();
+ service.component = componentFactory.newInstance(Dict.fromReference(reference, service.binding));
+ }
+}
*/
package org.opendaylight.mdsal.binding.dom.adapter.osgi;
-import static java.util.Objects.requireNonNull;
-
import java.util.function.Function;
import org.opendaylight.mdsal.binding.api.BindingService;
import org.opendaylight.mdsal.dom.api.DOMService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
-import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* @author Robert Varga
*/
final class AdaptingTracker<D extends DOMService, B extends BindingService>
- extends ServiceTracker<D, ServiceRegistration<B>> {
+ extends AbstractAdaptingTracker<D, B, ServiceRegistration<B>> {
private static final Logger LOG = LoggerFactory.getLogger(AdaptingTracker.class);
- private final Function<D, B> bindingFactory;
- private final Class<B> bindingClass;
-
AdaptingTracker(final BundleContext ctx, final Class<D> domClass, final Class<B> bindingClass,
- final Function<D, B> bindingFactory) {
- super(ctx, domClass, null);
- this.bindingClass = requireNonNull(bindingClass);
- this.bindingFactory = requireNonNull(bindingFactory);
- }
-
- @Override
- public void open(final boolean trackAllServices) {
- LOG.debug("Starting tracker for {}", bindingClass.getName());
- super.open(trackAllServices);
- LOG.debug("Tracker for {} started", bindingClass.getName());
+ final Function<D, B> bindingFactory) {
+ super(ctx, domClass, bindingClass, bindingFactory);
}
@Override
- public ServiceRegistration<B> addingService(final ServiceReference<D> reference) {
- if (reference == null) {
- LOG.debug("Null reference for {}, ignoring it", bindingClass.getName());
- return null;
- }
- if (reference.getProperty(ServiceProperties.IGNORE_PROP) != null) {
- LOG.debug("Ignoring reference {} due to {}", reference, ServiceProperties.IGNORE_PROP);
- return null;
- }
-
- final D dom = context.getService(reference);
- if (dom == null) {
- LOG.debug("Could not get {} service from {}, ignoring it", bindingClass.getName(), reference);
- return null;
- }
- final B binding = bindingFactory.apply(dom);
+ ServiceRegistration<B> addingService(final ServiceReference<D> reference, final D dom, final B binding) {
final Dict props = Dict.fromReference(reference);
final ServiceRegistration<B> reg = context.registerService(bindingClass, binding, props);
LOG.debug("Registered {} adapter {} of {} with {} as {}", bindingClass.getName(), binding, dom, props, reg);
}
@Override
- public void modifiedService(final ServiceReference<D> reference, final ServiceRegistration<B> service) {
- if (service != null && reference != null) {
- final Dict newProps = Dict.fromReference(reference);
- LOG.debug("Updating service {} with properties {}", service, newProps);
- service.setProperties(newProps);
- }
+ void removedService(final ServiceRegistration<B> service) {
+ service.unregister();
}
@Override
- public void removedService(final ServiceReference<D> reference, final ServiceRegistration<B> service) {
- if (service != null) {
- context.ungetService(reference);
- service.unregister();
- LOG.debug("Unregistered service {}", service);
- }
+ void updatedService(final ServiceReference<D> reference, final ServiceRegistration<B> service) {
+ final Dict newProps = Dict.fromReference(reference);
+ LOG.debug("Updating service {} with properties {}", service, newProps);
+ service.setProperties(newProps);
}
}
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.api.BindingService;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
return EMPTY;
}
- final Map<String, Object> props = Maps.newHashMapWithExpectedSize(keys.length);
+ return new Dict(populateProperties(ref, keys, 0));
+ }
+
+ static Dict fromReference(final ServiceReference<?> ref, final BindingService service) {
+ final Map<String, Object> props = populateProperties(ref, ref.getPropertyKeys(), 1);
+ props.put(AbstractAdaptedService.DELEGATE, service);
+ return new Dict(props);
+ }
+
+ private static Map<String, Object> populateProperties(final ServiceReference<?> ref, final String[] keys,
+ final int extra) {
+ final Map<String, Object> props = Maps.newHashMapWithExpectedSize(keys.length + extra);
for (String key : keys) {
// Ignore properties with our prefix: we are not exporting those
if (!key.startsWith(ServiceProperties.PREFIX)) {
}
}
- return new Dict(props);
+ return props;
}
@Override
import org.opendaylight.mdsal.dom.api.DOMRpcService;
import org.opendaylight.mdsal.dom.api.DOMService;
import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentFactory;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
public final class DynamicBindingAdapter {
private static final Logger LOG = LoggerFactory.getLogger(DynamicBindingAdapter.class);
- private List<AdaptingTracker<?, ?>> trackers = ImmutableList.of();
+ private List<AbstractAdaptingTracker<?, ?, ?>> trackers = ImmutableList.of();
@Reference
AdapterFactory factory = null;
+ @Reference(target = "(component.factory=" + OSGiRpcConsumerRegistry.FACTORY_NAME + ")")
+ ComponentFactory rpcConsumerRegistryFactory = null;
+ @Reference(target = "(component.factory=" + OSGiRpcProviderService.FACTORY_NAME + ")")
+ ComponentFactory rpcProviderServiceFactory = null;
@Activate
void activate(final BundleContext ctx) {
factory::createNotificationService),
new AdaptingTracker<>(ctx, DOMNotificationPublishService.class, NotificationPublishService.class,
factory::createNotificationPublishService),
- new AdaptingTracker<>(ctx, DOMRpcService.class, RpcConsumerRegistry.class,
- factory::createRpcConsumerRegistry),
- new AdaptingTracker<>(ctx, DOMRpcProviderService.class, RpcProviderService.class,
- factory::createRpcProviderService),
+ new AdaptingComponentTracker<>(ctx, DOMRpcService.class, RpcConsumerRegistry.class,
+ factory::createRpcConsumerRegistry, rpcConsumerRegistryFactory),
+ new AdaptingComponentTracker<>(ctx, DOMRpcProviderService.class, RpcProviderService.class,
+ factory::createRpcProviderService, rpcProviderServiceFactory),
new AdaptingTracker<>(ctx, DOMActionService.class, ActionService.class, factory::createActionService),
new AdaptingTracker<>(ctx, DOMActionProviderService.class, ActionProviderService.class,
factory::createActionProviderService));
void deactivate() {
LOG.debug("Stopping {} DOMService trackers", trackers.size());
if (!trackers.isEmpty()) {
- trackers.forEach(AdaptingTracker::close);
+ trackers.forEach(AbstractAdaptingTracker::close);
LOG.info("{} DOMService trackers stopped", trackers.size());
}
trackers = ImmutableList.of();
--- /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.adapter.osgi;
+
+import com.google.common.annotations.Beta;
+import java.util.Map;
+import org.opendaylight.mdsal.binding.api.RpcConsumerRegistry;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+
+@Beta
+@Component(factory = OSGiRpcConsumerRegistry.FACTORY_NAME)
+public final class OSGiRpcConsumerRegistry extends AbstractAdaptedService<RpcConsumerRegistry>
+ implements RpcConsumerRegistry {
+ // OSGi DS Component Factory name
+ static final String FACTORY_NAME = "org.opendaylight.mdsal.binding.dom.adapter.osgi.OSGiRpcConsumerRegistry";
+
+ public OSGiRpcConsumerRegistry() {
+ super(RpcConsumerRegistry.class);
+ }
+
+ @Override
+ public <T extends RpcService> T getRpcService(final Class<T> serviceInterface) {
+ return delegate().getRpcService(serviceInterface);
+ }
+
+ @Activate
+ void activate(final Map<String, ?> properties) {
+ start(properties);
+ }
+
+ @Deactivate
+ void deactivate() {
+ stop();
+ }
+}
--- /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.adapter.osgi;
+
+import com.google.common.annotations.Beta;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.mdsal.binding.api.RpcProviderService;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+
+@Beta
+@Component(factory = OSGiRpcProviderService.FACTORY_NAME)
+public final class OSGiRpcProviderService extends AbstractAdaptedService<RpcProviderService>
+ implements RpcProviderService {
+ // OSGi DS Component Factory name
+ static final String FACTORY_NAME = "org.opendaylight.mdsal.binding.dom.adapter.osgi.OSGiRpcProviderService";
+
+ public OSGiRpcProviderService() {
+ super(RpcProviderService.class);
+ }
+
+ @Override
+ public <S extends RpcService, T extends S> ObjectRegistration<T> registerRpcImplementation(final Class<S> type,
+ final T implementation) {
+ return delegate().registerRpcImplementation(type, implementation);
+ }
+
+ @Override
+ public <S extends RpcService, T extends S> ObjectRegistration<T> registerRpcImplementation(final Class<S> type,
+ final T implementation, final Set<InstanceIdentifier<?>> paths) {
+ return delegate().registerRpcImplementation(type, implementation, paths);
+ }
+
+ @Activate
+ void activate(final Map<String, ?> properties) {
+ start(properties);
+ }
+
+ @Deactivate
+ void deactivate() {
+ stop();
+ }
+}