From 0def314d2f0495f11a75d49e7ba33cf86e8e9c88 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Thu, 30 Jul 2020 23:59:36 +0200 Subject: [PATCH] Add binding adapter components for data services Rather than operating on service registry directly, create binding adapters as dedicated components. This allows proper provides/requires validation for downstream component users. JIRA: MDSAL-587 Change-Id: I5c9c8140660ac5c7d7a82c25bcbf4e26fc8716be Signed-off-by: Robert Varga --- .../adapter/osgi/AbstractAdaptingTracker.java | 92 ------------------- .../osgi/AdaptingComponentTracker.java | 55 ----------- .../dom/adapter/osgi/AdaptingTracker.java | 79 ++++++++++++---- .../mdsal/binding/dom/adapter/osgi/Dict.java | 23 +---- .../adapter/osgi/DynamicBindingAdapter.java | 32 ++++--- .../dom/adapter/osgi/OSGiDataBroker.java | 78 ++++++++++++++++ .../dom/adapter/osgi/OSGiDataTreeService.java | 54 +++++++++++ 7 files changed, 218 insertions(+), 195 deletions(-) delete mode 100644 binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AbstractAdaptingTracker.java delete mode 100644 binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AdaptingComponentTracker.java create mode 100644 binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/OSGiDataBroker.java create mode 100644 binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/OSGiDataTreeService.java diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AbstractAdaptingTracker.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AbstractAdaptingTracker.java deleted file mode 100644 index bfd368d628..0000000000 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AbstractAdaptingTracker.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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 DOMService type - * @param BindingService type - * @author Robert Varga - */ -abstract class AbstractAdaptingTracker - extends ServiceTracker { - private static final Logger LOG = LoggerFactory.getLogger(AbstractAdaptingTracker.class); - - private final Function bindingFactory; - final @NonNull Class bindingClass; - - AbstractAdaptingTracker(final BundleContext ctx, final Class domClass, final Class bindingClass, - final Function 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 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 reference, @NonNull D dom, @NonNull B binding); - - @Override - public final void modifiedService(final ServiceReference reference, final T service) { - if (service != null && reference != null) { - updatedService(reference, service); - } - } - - abstract void updatedService(@NonNull ServiceReference reference, @NonNull T service); - - @Override - public final void removedService(final ServiceReference reference, final T service) { - if (service != null) { - context.ungetService(reference); - removedService(service); - LOG.debug("Unregistered service {}", service); - } - } - - abstract void removedService(@NonNull T service); - -} diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AdaptingComponentTracker.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AdaptingComponentTracker.java deleted file mode 100644 index 86a8c09dc2..0000000000 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AdaptingComponentTracker.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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 - extends AbstractAdaptingTracker> { - static final class ComponentHolder { - 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 domClass, final Class bindingClass, - final Function bindingFactory, final ComponentFactory componentFactory) { - super(ctx, domClass, bindingClass, bindingFactory); - this.componentFactory = requireNonNull(componentFactory); - } - - @Override - ComponentHolder addingService(final ServiceReference reference, final D dom, final B binding) { - return new ComponentHolder<>(binding, componentFactory.newInstance(Dict.fromReference(reference, binding))); - } - - @Override - void removedService(final ComponentHolder service) { - service.component.dispose(); - } - - @Override - void updatedService(final ServiceReference reference, final ComponentHolder service) { - service.component.dispose(); - service.component = componentFactory.newInstance(Dict.fromReference(reference, service.binding)); - } -} diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AdaptingTracker.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AdaptingTracker.java index 5047134f68..2413ca9e83 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AdaptingTracker.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AdaptingTracker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 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, @@ -7,12 +7,17 @@ */ 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.framework.ServiceRegistration; +import org.osgi.service.component.ComponentFactory; +import org.osgi.service.component.ComponentInstance; +import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,31 +29,73 @@ import org.slf4j.LoggerFactory; * @author Robert Varga */ final class AdaptingTracker - extends AbstractAdaptingTracker> { + extends ServiceTracker> { + static final class ComponentHolder { + final B binding; + ComponentInstance component; + + ComponentHolder(final B binding, final ComponentInstance component) { + this.binding = requireNonNull(binding); + this.component = requireNonNull(component); + } + } + private static final Logger LOG = LoggerFactory.getLogger(AdaptingTracker.class); + private final Function bindingFactory; + private final @NonNull Class bindingClass; + private final ComponentFactory componentFactory; + AdaptingTracker(final BundleContext ctx, final Class domClass, final Class bindingClass, - final Function bindingFactory) { - super(ctx, domClass, bindingClass, bindingFactory); + final Function bindingFactory, final ComponentFactory componentFactory) { + super(ctx, domClass, null); + this.bindingClass = requireNonNull(bindingClass); + this.bindingFactory = requireNonNull(bindingFactory); + this.componentFactory = requireNonNull(componentFactory); } @Override - ServiceRegistration addingService(final ServiceReference reference, final D dom, final B binding) { - final Dict props = Dict.fromReference(reference); - final ServiceRegistration reg = context.registerService(bindingClass, binding, props); - LOG.debug("Registered {} adapter {} of {} with {} as {}", bindingClass.getName(), binding, dom, props, reg); - return reg; + public void open(final boolean trackAllServices) { + LOG.debug("Starting tracker for {}", bindingClass.getName()); + super.open(trackAllServices); + LOG.debug("Tracker for {} started", bindingClass.getName()); + } + + @Override + public ComponentHolder addingService(final ServiceReference 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); + return new ComponentHolder<>(binding, componentFactory.newInstance(Dict.fromReference(reference, binding))); } @Override - void removedService(final ServiceRegistration service) { - service.unregister(); + public void modifiedService(final ServiceReference reference, final ComponentHolder service) { + if (service != null && reference != null) { + service.component.dispose(); + service.component = componentFactory.newInstance(Dict.fromReference(reference, service.binding)); + } } @Override - void updatedService(final ServiceReference reference, final ServiceRegistration service) { - final Dict newProps = Dict.fromReference(reference); - LOG.debug("Updating service {} with properties {}", service, newProps); - service.setProperties(newProps); + public void removedService(final ServiceReference reference, final ComponentHolder service) { + if (service != null) { + context.ungetService(reference); + service.component.dispose(); + LOG.debug("Unregistered service {}", service); + } } } diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/Dict.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/Dict.java index d30f5ffc24..09a1ef7c93 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/Dict.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/Dict.java @@ -23,7 +23,6 @@ import org.slf4j.LoggerFactory; @NonNullByDefault final class Dict extends Dictionary { private static final Logger LOG = LoggerFactory.getLogger(Dict.class); - private static final Dict EMPTY = new Dict(ImmutableMap.of()); private final Map map; @@ -31,24 +30,9 @@ final class Dict extends Dictionary { this.map = ImmutableMap.copyOf(map); } - static Dict fromReference(final ServiceReference ref) { - final String[] keys = ref.getPropertyKeys(); - if (keys.length == 0) { - return EMPTY; - } - - return new Dict(populateProperties(ref, keys, 0)); - } - static Dict fromReference(final ServiceReference ref, final BindingService service) { - final Map props = populateProperties(ref, ref.getPropertyKeys(), 1); - props.put(AbstractAdaptedService.DELEGATE, service); - return new Dict(props); - } - - private static Map populateProperties(final ServiceReference ref, final String[] keys, - final int extra) { - final Map props = Maps.newHashMapWithExpectedSize(keys.length + extra); + final String[] keys = ref.getPropertyKeys(); + final Map props = Maps.newHashMapWithExpectedSize(keys.length + 1); for (String key : keys) { // Ignore properties with our prefix: we are not exporting those if (!key.startsWith(ServiceProperties.PREFIX)) { @@ -73,7 +57,8 @@ final class Dict extends Dictionary { } } - return props; + props.put(AbstractAdaptedService.DELEGATE, service); + return new Dict(props); } @Override diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/DynamicBindingAdapter.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/DynamicBindingAdapter.java index dace2cd5c5..5cc9bdb36f 100644 --- a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/DynamicBindingAdapter.java +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/DynamicBindingAdapter.java @@ -50,7 +50,7 @@ import org.slf4j.LoggerFactory; public final class DynamicBindingAdapter { private static final Logger LOG = LoggerFactory.getLogger(DynamicBindingAdapter.class); - private List> trackers = ImmutableList.of(); + private List> trackers = ImmutableList.of(); @Reference AdapterFactory factory = null; @@ -58,6 +58,10 @@ public final class DynamicBindingAdapter { ComponentFactory actionServiceFactory = null; @Reference(target = "(component.factory=" + OSGiActionProviderService.FACTORY_NAME + ")") ComponentFactory actionProviderServiceFactory = null; + @Reference(target = "(component.factory=" + OSGiDataBroker.FACTORY_NAME + ")") + ComponentFactory dataBrokerFactory = null; + @Reference(target = "(component.factory=" + OSGiDataTreeService.FACTORY_NAME + ")") + ComponentFactory dataTreeServiceFactory = null; @Reference(target = "(component.factory=" + OSGiMountPointService.FACTORY_NAME + ")") ComponentFactory mountPointServiceFactory = null; @Reference(target = "(component.factory=" + OSGiNotificationService.FACTORY_NAME + ")") @@ -72,22 +76,24 @@ public final class DynamicBindingAdapter { @Activate void activate(final BundleContext ctx) { trackers = ImmutableList.of( - new AdaptingTracker<>(ctx, DOMDataBroker.class, DataBroker.class, factory::createDataBroker), - new AdaptingTracker<>(ctx, DOMDataTreeService.class, DataTreeService.class, factory::createDataTreeService), - new AdaptingComponentTracker<>(ctx, DOMMountPointService.class, MountPointService.class, + new AdaptingTracker<>(ctx, DOMDataBroker.class, DataBroker.class, factory::createDataBroker, + dataBrokerFactory), + new AdaptingTracker<>(ctx, DOMDataTreeService.class, DataTreeService.class, factory::createDataTreeService, + dataTreeServiceFactory), + new AdaptingTracker<>(ctx, DOMMountPointService.class, MountPointService.class, factory::createMountPointService, mountPointServiceFactory), - new AdaptingComponentTracker<>(ctx, DOMNotificationService.class, NotificationService.class, + new AdaptingTracker<>(ctx, DOMNotificationService.class, NotificationService.class, factory::createNotificationService, notificationServiceFactory), - new AdaptingComponentTracker<>(ctx, DOMNotificationPublishService.class, NotificationPublishService.class, + new AdaptingTracker<>(ctx, DOMNotificationPublishService.class, NotificationPublishService.class, factory::createNotificationPublishService, notificationPublishServiceFactory), - new AdaptingComponentTracker<>(ctx, DOMRpcService.class, RpcConsumerRegistry.class, + new AdaptingTracker<>(ctx, DOMRpcService.class, RpcConsumerRegistry.class, factory::createRpcConsumerRegistry, rpcConsumerRegistryFactory), - new AdaptingComponentTracker<>(ctx, DOMRpcProviderService.class, RpcProviderService.class, + new AdaptingTracker<>(ctx, DOMRpcProviderService.class, RpcProviderService.class, factory::createRpcProviderService, rpcProviderServiceFactory), - new AdaptingComponentTracker<>(ctx, DOMActionService.class, ActionService.class, - factory::createActionService, actionServiceFactory), - new AdaptingComponentTracker<>(ctx, DOMActionProviderService.class, ActionProviderService.class, - factory::createActionProviderService, actionProviderServiceFactory)); + new AdaptingTracker<>(ctx, DOMActionService.class, ActionService.class, factory::createActionService, + actionServiceFactory), + new AdaptingTracker<>(ctx, DOMActionProviderService.class, ActionProviderService.class, + factory::createActionProviderService, actionProviderServiceFactory)); LOG.debug("Starting {} DOMService trackers", trackers.size()); trackers.forEach(ServiceTracker::open); @@ -98,7 +104,7 @@ public final class DynamicBindingAdapter { void deactivate() { LOG.debug("Stopping {} DOMService trackers", trackers.size()); if (!trackers.isEmpty()) { - trackers.forEach(AbstractAdaptingTracker::close); + trackers.forEach(AdaptingTracker::close); LOG.info("{} DOMService trackers stopped", trackers.size()); } trackers = ImmutableList.of(); diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/OSGiDataBroker.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/OSGiDataBroker.java new file mode 100644 index 0000000000..3f9ebce162 --- /dev/null +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/OSGiDataBroker.java @@ -0,0 +1,78 @@ +/* + * 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.eclipse.jdt.annotation.NonNull; +import org.opendaylight.mdsal.binding.api.DataBroker; +import org.opendaylight.mdsal.binding.api.DataTreeChangeListener; +import org.opendaylight.mdsal.binding.api.DataTreeIdentifier; +import org.opendaylight.mdsal.binding.api.ReadTransaction; +import org.opendaylight.mdsal.binding.api.ReadWriteTransaction; +import org.opendaylight.mdsal.binding.api.TransactionChain; +import org.opendaylight.mdsal.binding.api.TransactionChainListener; +import org.opendaylight.mdsal.binding.api.WriteTransaction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; + +@Beta +@Component(factory = OSGiDataBroker.FACTORY_NAME) +public final class OSGiDataBroker extends AbstractAdaptedService implements DataBroker { + // OSGi DS Component Factory name + static final String FACTORY_NAME = "org.opendaylight.mdsal.binding.dom.adapter.osgi.OSGiDataBroker"; + + public OSGiDataBroker() { + super(DataBroker.class); + } + + @Override + public ReadTransaction newReadOnlyTransaction() { + return delegate().newReadOnlyTransaction(); + } + + @Override + public ReadWriteTransaction newReadWriteTransaction() { + return delegate().newReadWriteTransaction(); + } + + @Override + public WriteTransaction newWriteOnlyTransaction() { + return delegate().newWriteOnlyTransaction(); + } + + @Override + public > + ListenerRegistration registerDataTreeChangeListener(final DataTreeIdentifier treeId, + final L listener) { + return delegate().registerDataTreeChangeListener(treeId, listener); + } + + @Override + public TransactionChain createTransactionChain(@NonNull final TransactionChainListener listener) { + return delegate().createTransactionChain(listener); + } + + @Override + public TransactionChain createMergingTransactionChain(final TransactionChainListener listener) { + return delegate().createMergingTransactionChain(listener); + } + + @Activate + void activate(final Map properties) { + start(properties); + } + + @Deactivate + void deactivate() { + stop(); + } +} diff --git a/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/OSGiDataTreeService.java b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/OSGiDataTreeService.java new file mode 100644 index 0000000000..9210fd4af4 --- /dev/null +++ b/binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/OSGiDataTreeService.java @@ -0,0 +1,54 @@ +/* + * 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.Collection; +import java.util.Map; +import org.opendaylight.mdsal.binding.api.DataTreeIdentifier; +import org.opendaylight.mdsal.binding.api.DataTreeListener; +import org.opendaylight.mdsal.binding.api.DataTreeLoopException; +import org.opendaylight.mdsal.binding.api.DataTreeProducer; +import org.opendaylight.mdsal.binding.api.DataTreeService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; + +@Beta +@Component(factory = OSGiDataTreeService.FACTORY_NAME) +public final class OSGiDataTreeService extends AbstractAdaptedService implements DataTreeService { + // OSGi DS Component Factory name + static final String FACTORY_NAME = "org.opendaylight.mdsal.binding.dom.adapter.osgi.OSGiDataTreeService"; + + public OSGiDataTreeService() { + super(DataTreeService.class); + } + + @Override + public DataTreeProducer createProducer(final Collection> subtrees) { + return delegate().createProducer(subtrees); + } + + @Override + public ListenerRegistration registerListener(final T listener, + final Collection> subtrees, final boolean allowRxMerges, + final Collection producers) throws DataTreeLoopException { + return delegate().registerListener(listener, subtrees, allowRxMerges, producers); + } + + @Activate + void activate(final Map properties) { + start(properties); + } + + @Deactivate + void deactivate() { + stop(); + } +} -- 2.36.6