Merge DOMExtensibleService into DOMService 62/109062/8
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 24 Nov 2023 19:56:45 +0000 (20:56 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 7 Dec 2023 12:17:16 +0000 (13:17 +0100)
yangtools.concepts.ExtensibleObject provides a generalized view on what
we are trying to achieve here.

This patch adopts it into DOMService, forcing all DOMServices to define
their type-safe Extension point.

This has a side-effect that multiple DOMServices cannot be implemented
by the same object, forcing DOMNotificationRouter to split out its
component services.

JIRA: MDSAL-841
Change-Id: I355fbe82cf913af7682432611b5f25773832a9ab
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
61 files changed:
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionProviderServiceAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/ActionServiceAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AdapterLoader.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMAdapterBuilder.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMAdapterLoader.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMDataBrokerAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMNotificationPublishServiceAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMNotificationServiceAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMRpcServiceAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/BindingMountPointAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/InstanceNotificationPublishServiceAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/InstanceNotificationServiceAdapter.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/osgi/AdaptingTracker.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMAdapterLoaderTest.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/BindingDOMTransactionChainAdapterTest.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/AbstractDataBrokerTestCustomizer.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/util/BindingTestContext.java
binding/mdsal-binding-dom-adapter/src/test/java/org/opendaylight/mdsal/binding/dom/adapter/test/util/MockSchemaService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMActionProviderService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMActionProviderServiceExtension.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMActionService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMActionServiceExtension.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataBroker.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataBrokerExtension.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeChangeService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMExtensibleService.java [deleted file]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMInstanceNotificationPublishService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMInstanceNotificationService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMMountPoint.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMMountPointService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMNotificationPublishService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMNotificationService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMRpcProviderService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMRpcService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMSchemaService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMSchemaServiceExtension.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMService.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMServiceExtension.java [deleted file]
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMDataBroker.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMMountPointServiceImpl.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMNotificationRouter.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouter.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/RouterDOMNotificationService.java [new file with mode: 0644]
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/RouterDOMPublishNotificationService.java [new file with mode: 0644]
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/DOMDataTreeListenerTest.java
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/DOMNotificationRouterTest.java
dom/mdsal-dom-broker/src/test/java/org/opendaylight/mdsal/dom/broker/DOMRpcRouterTest.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/AbstractDOMSchemaService.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/FixedDOMSchemaService.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMActionProviderService.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMActionService.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMDataBroker.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMExtensibleService.java [deleted file]
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMService.java [new file with mode: 0644]
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/SimpleDOMMountPoint.java
dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMDataBrokerTest.java
dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMRpcImplementationTest.java
dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/SimpleDOMMountPointTest.java
replicate/mdsal-replicate-netty/src/main/java/org/opendaylight/mdsal/replicate/netty/NettyReplicationSource.java
trace/mdsal-trace-impl/src/main/java/org/opendaylight/mdsal/trace/impl/CloseTrackedTrait.java
trace/mdsal-trace-impl/src/main/java/org/opendaylight/mdsal/trace/impl/TracingBroker.java

index dd26b429532dea3adbff1543aa72d06e58302926..dc3492a65533bf213c7d2473f063e57214b1ec64 100644 (file)
@@ -55,13 +55,13 @@ public final class ActionProviderServiceAdapter extends AbstractBindingAdapter<D
         }
 
         @Override
-        protected ActionProviderService createInstance(final ClassToInstanceMap<DOMService> delegates) {
+        protected ActionProviderService createInstance(final ClassToInstanceMap<DOMService<?, ?>> delegates) {
             return new ActionProviderServiceAdapter(adapterContext(),
                 delegates.getInstance(DOMActionProviderService.class));
         }
 
         @Override
-        public Set<? extends Class<? extends DOMService>> getRequiredDelegates() {
+        public Set<? extends Class<? extends DOMService<?, ?>>> getRequiredDelegates() {
             return ImmutableSet.of(DOMActionProviderService.class);
         }
     }
index 08f6ff6bd830ecd3e43376c86afd1cef285c0ae9..56842cb35d741d0476fb59642a12ee83252681c0 100644 (file)
@@ -35,12 +35,12 @@ final class ActionServiceAdapter
         }
 
         @Override
-        public Set<? extends Class<? extends DOMService>> getRequiredDelegates() {
+        public Set<? extends Class<? extends DOMService<?, ?>>> getRequiredDelegates() {
             return ImmutableSet.of(DOMActionService.class);
         }
 
         @Override
-        protected ActionService createInstance(final ClassToInstanceMap<DOMService> delegates) {
+        protected ActionService createInstance(final ClassToInstanceMap<DOMService<?, ?>> delegates) {
             return new ActionServiceAdapter(adapterContext(), delegates.getInstance(DOMActionService.class));
         }
     }
index 6265f9a52cfc34bccda1e622ebf35873f44c7b9a..a1f1ec38dd7dd6bfe6cf49789f778ed817a212e4 100644 (file)
@@ -16,10 +16,9 @@ public abstract class AdapterLoader<T, D> extends CacheLoader<Class<? extends T>
 
     @Override
     public Optional<T> load(final Class<? extends T> key) {
-
-        final AdapterBuilder<? extends T, D> builder = createBuilder(key);
-        for (final Class<? extends D> reqDeleg : builder.getRequiredDelegates()) {
-            final D deleg = getDelegate(reqDeleg);
+        final var builder = createBuilder(key);
+        for (var reqDeleg : builder.getRequiredDelegates()) {
+            final var deleg = getDelegate(reqDeleg);
             if (deleg != null) {
                 builder.addDelegate(reqDeleg, deleg);
             } else {
index be5503b8af876760d664135762d0eefe3a791a5c..a343f8b6b505defb3708fcb0678289ec23516fdd 100644 (file)
@@ -13,7 +13,7 @@ import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.api.BindingService;
 import org.opendaylight.mdsal.dom.api.DOMService;
 
-abstract class BindingDOMAdapterBuilder<T extends BindingService> extends AdapterBuilder<T, DOMService> {
+abstract class BindingDOMAdapterBuilder<T extends BindingService> extends AdapterBuilder<T, DOMService<?, ?>> {
 
     @FunctionalInterface
     interface Factory<T extends BindingService> {
index f17f30df6686e3ee658de8adee00f90ba1edd9c4..b0fa8f932a1a74b07a76d5d71bdf2fb7cfe5f60a 100644 (file)
@@ -11,7 +11,6 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.ImmutableMap;
-import java.util.Map;
 import org.opendaylight.mdsal.binding.api.ActionProviderService;
 import org.opendaylight.mdsal.binding.api.ActionService;
 import org.opendaylight.mdsal.binding.api.BindingService;
@@ -21,12 +20,11 @@ import org.opendaylight.mdsal.binding.api.InstanceNotificationService;
 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
 import org.opendaylight.mdsal.binding.api.NotificationService;
 import org.opendaylight.mdsal.binding.api.RpcService;
-import org.opendaylight.mdsal.binding.dom.adapter.BindingDOMAdapterBuilder.Factory;
 import org.opendaylight.mdsal.dom.api.DOMService;
 
-public abstract class BindingDOMAdapterLoader extends AdapterLoader<BindingService, DOMService> {
-    private static final Map<Class<?>,BindingDOMAdapterBuilder.Factory<?>> FACTORIES =
-            ImmutableMap.<Class<?>, BindingDOMAdapterBuilder.Factory<?>>builder()
+public abstract class BindingDOMAdapterLoader extends AdapterLoader<BindingService, DOMService<?, ?>> {
+    private static final ImmutableMap<Class<?>, BindingDOMAdapterBuilder.Factory<?>> FACTORIES =
+        ImmutableMap.<Class<?>, BindingDOMAdapterBuilder.Factory<?>>builder()
             .put(NotificationService.class, BindingDOMNotificationServiceAdapter.BUILDER_FACTORY)
             .put(NotificationPublishService.class, BindingDOMNotificationPublishServiceAdapter.BUILDER_FACTORY)
             .put(DataBroker.class, BindingDOMDataBrokerAdapter.BUILDER_FACTORY)
@@ -34,20 +32,19 @@ public abstract class BindingDOMAdapterLoader extends AdapterLoader<BindingServi
             .put(ActionService.class, ActionServiceAdapter.BUILDER_FACTORY)
             .put(ActionProviderService.class, ActionProviderServiceAdapter.BUILDER_FACTORY)
             .put(InstanceNotificationService.class, InstanceNotificationServiceAdapter.BUILDER_FACTORY)
-            .put(InstanceNotificationPublishService.class,
-                InstanceNotificationPublishServiceAdapter.BUILDER_FACTORY)
+            .put(InstanceNotificationPublishService.class, InstanceNotificationPublishServiceAdapter.BUILDER_FACTORY)
             .build();
 
     private final AdapterContext codec;
 
-    public BindingDOMAdapterLoader(final AdapterContext codec) {
+    protected BindingDOMAdapterLoader(final AdapterContext codec) {
         this.codec = requireNonNull(codec);
     }
 
     @Override
-    protected final AdapterBuilder<? extends BindingService, DOMService> createBuilder(
-                final Class<? extends BindingService> key) {
-        final Factory<?> factory = FACTORIES.get(key);
+    protected final AdapterBuilder<? extends BindingService, DOMService<?, ?>> createBuilder(
+            final Class<? extends BindingService> key) {
+        final var factory = FACTORIES.get(key);
         checkArgument(factory != null, "Unsupported service type %s", key);
         return factory.newBuilder(codec);
     }
index 349115e3638136a9d16d6e6911102e8ac5f08e99..0a9cc5ea81e015080a6a6951eee701ada11fed70 100644 (file)
@@ -44,8 +44,7 @@ public class BindingDOMDataBrokerAdapter extends AbstractBindingAdapter<@NonNull
 
     public BindingDOMDataBrokerAdapter(final AdapterContext adapterContext, final DOMDataBroker domDataBroker) {
         super(adapterContext, domDataBroker);
-        final DOMDataTreeChangeService domTreeChange = domDataBroker.getExtensions()
-                .getInstance(DOMDataTreeChangeService.class);
+        final var domTreeChange = domDataBroker.extension(DOMDataTreeChangeService.class);
         treeChangeService = domTreeChange == null ? null
                 : new BindingDOMDataTreeChangeServiceAdapter(adapterContext, domTreeChange);
     }
@@ -82,12 +81,12 @@ public class BindingDOMDataBrokerAdapter extends AbstractBindingAdapter<@NonNull
         }
 
         @Override
-        public Set<? extends Class<? extends DOMService>> getRequiredDelegates() {
+        public Set<? extends Class<? extends DOMService<?, ?>>> getRequiredDelegates() {
             return ImmutableSet.of(DOMDataBroker.class);
         }
 
         @Override
-        protected DataBroker createInstance(final ClassToInstanceMap<DOMService> delegates) {
+        protected DataBroker createInstance(final ClassToInstanceMap<DOMService<?, ?>> delegates) {
             return new BindingDOMDataBrokerAdapter(adapterContext(), delegates.getInstance(DOMDataBroker.class));
         }
     }
index 7472fb87aaddb98741d9b6ce24d3b62698e81134..f752b7de8f225ad83936c80bef16ba5b364ad0ea 100644 (file)
@@ -63,12 +63,12 @@ public final class BindingDOMNotificationPublishServiceAdapter
         }
 
         @Override
-        public Set<Class<? extends DOMService>> getRequiredDelegates() {
+        public Set<Class<? extends DOMService<?, ?>>> getRequiredDelegates() {
             return ImmutableSet.of(DOMNotificationPublishService.class);
         }
 
         @Override
-        protected NotificationPublishService createInstance(final ClassToInstanceMap<DOMService> delegates) {
+        protected NotificationPublishService createInstance(final ClassToInstanceMap<DOMService<?, ?>> delegates) {
             return new BindingDOMNotificationPublishServiceAdapter(adapterContext(),
                 delegates.getInstance(DOMNotificationPublishService.class));
         }
index 6b4dd076428533bb69c213cdc71f31f0d31b1c4c..10c5040a0a7bfdff79c1b65f8673073823e2b830 100644 (file)
@@ -64,13 +64,13 @@ public class BindingDOMNotificationServiceAdapter implements NotificationService
         }
 
         @Override
-        protected NotificationService createInstance(final ClassToInstanceMap<DOMService> delegates) {
+        protected NotificationService createInstance(final ClassToInstanceMap<DOMService<?, ?>> delegates) {
             return new BindingDOMNotificationServiceAdapter(adapterContext(),
                 delegates.getInstance(DOMNotificationService.class));
         }
 
         @Override
-        public Set<? extends Class<? extends DOMService>> getRequiredDelegates() {
+        public Set<? extends Class<? extends DOMService<?, ?>>> getRequiredDelegates() {
             return ImmutableSet.of(DOMNotificationService.class);
         }
     }
index a135dabd9ec7adc0d7b3f1feee32c1631201a8bb..ed2d4fba992049bec454b938917d862f6a46c7ed 100644 (file)
@@ -52,12 +52,12 @@ public final class BindingDOMRpcServiceAdapter
         }
 
         @Override
-        public Set<? extends Class<? extends DOMService>> getRequiredDelegates() {
+        public Set<? extends Class<? extends DOMService<?, ?>>> getRequiredDelegates() {
             return ImmutableSet.of(DOMRpcService.class);
         }
 
         @Override
-        protected RpcService createInstance(final ClassToInstanceMap<DOMService> delegates) {
+        protected RpcService createInstance(final ClassToInstanceMap<DOMService<?, ?>> delegates) {
             return new BindingDOMRpcServiceAdapter(adapterContext(), delegates.getInstance(DOMRpcService.class));
         }
     }
index 3f978cd6ea263ce179c2ea9dd6096a9cbb36b5f2..a2683f362f701a7cfd7310f122b4377adaf9ad0f 100644 (file)
@@ -24,8 +24,9 @@ final class BindingMountPointAdapter implements MountPoint {
         identifier = codec.currentSerializer().fromYangInstanceIdentifier(domMountPoint.getIdentifier());
         services = CacheBuilder.newBuilder().build(new BindingDOMAdapterLoader(codec) {
             @Override
-            protected DOMService getDelegate(final Class<? extends DOMService> reqDeleg) {
-                return domMountPoint.getService(reqDeleg).orElse(null);
+            @SuppressWarnings({ "rawtypes", "unchecked" })
+            protected DOMService<?, ?> getDelegate(final Class<? extends DOMService<?, ?>> reqDeleg) {
+                return reqDeleg.cast(domMountPoint.getService((Class) reqDeleg).orElse(null));
             }
         });
     }
index d1f11c9b4ac9d64d56ad93e00353416d0017e870..6b201281ff9fe3f9dceecb6d761030072510d085 100644 (file)
@@ -31,12 +31,13 @@ final class InstanceNotificationPublishServiceAdapter
         }
 
         @Override
-        public Set<Class<? extends DOMService>> getRequiredDelegates() {
+        public Set<Class<? extends DOMService<?, ?>>> getRequiredDelegates() {
             return ImmutableSet.of(DOMInstanceNotificationPublishService.class);
         }
 
         @Override
-        protected InstanceNotificationPublishService createInstance(final ClassToInstanceMap<DOMService> delegates) {
+        protected InstanceNotificationPublishService createInstance(
+                final ClassToInstanceMap<DOMService<?, ?>> delegates) {
             return new InstanceNotificationPublishServiceAdapter(adapterContext(),
                 delegates.getInstance(DOMInstanceNotificationPublishService.class));
         }
index 5bc0446c28acf894adceecff02f07fd35a69664c..09a32f421f45ea7cc42ec361d36ee05c2b6bd906 100644 (file)
@@ -38,13 +38,13 @@ final class InstanceNotificationServiceAdapter implements InstanceNotificationSe
         }
 
         @Override
-        protected InstanceNotificationService createInstance(final ClassToInstanceMap<DOMService> delegates) {
+        protected InstanceNotificationService createInstance(final ClassToInstanceMap<DOMService<?, ?>> delegates) {
             return new InstanceNotificationServiceAdapter(adapterContext(),
                 delegates.getInstance(DOMInstanceNotificationService.class));
         }
 
         @Override
-        public Set<? extends Class<? extends DOMService>> getRequiredDelegates() {
+        public Set<? extends Class<? extends DOMService<?, ?>>> getRequiredDelegates() {
             return ImmutableSet.of(DOMInstanceNotificationService.class);
         }
     }
index 664ee6628c1e4d55603ff781cf5cb5c537b2bcc3..51287982e819c8a8b968f9541c4c462855c44da8 100644 (file)
@@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory;
  * @param <B> BindingService type
  * @author Robert Varga
  */
-final class AdaptingTracker<D extends DOMService, B extends BindingService>
+final class AdaptingTracker<D extends DOMService<?, ?>, B extends BindingService>
         extends ServiceTracker<D, AdaptingTracker.ComponentHolder<B>> {
     static final class ComponentHolder<B extends BindingService> {
         final B binding;
index 2e2d2a192ae8661a57d3b638ca906a5a83d0d2a8..95f82cf25b4b689295c5c1d82a4121a056f53baf 100644 (file)
@@ -12,10 +12,8 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThrows;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
-import com.google.common.collect.ImmutableClassToInstanceMap;
 import java.util.Optional;
 import org.junit.Before;
 import org.junit.Test;
@@ -43,10 +41,9 @@ public class BindingDOMAdapterLoaderTest {
 
     @Before
     public void setUp() {
-        doReturn(ImmutableClassToInstanceMap.of()).when(domService).getExtensions();
         bindingDOMAdapterLoader = new BindingDOMAdapterLoader(mockContext) {
             @Override
-            protected DOMService getDelegate(final Class<? extends DOMService> reqDeleg) {
+            protected DOMService<?, ?> getDelegate(final Class<? extends DOMService<?, ?>> reqDeleg) {
                 return domService;
             }
         };
index c75801e4378e126d035f062f7a47eb946ce1b0ca..c80847b9865818fd5d100b0f8807692cd4e5332f 100644 (file)
@@ -42,7 +42,7 @@ import org.opendaylight.mdsal.dom.spi.PingPongMergingDOMDataBroker;
 
 @RunWith(Parameterized.class)
 public class BindingDOMTransactionChainAdapterTest {
-    enum TransactionChainType implements BiFunction<DataBroker, TransactionChainListener, TransactionChain> {
+    public enum TransactionChainType implements BiFunction<DataBroker, TransactionChainListener, TransactionChain> {
         NORMAL {
             @Override
             public TransactionChain apply(final DataBroker broker, final TransactionChainListener listener) {
@@ -109,7 +109,6 @@ public class BindingDOMTransactionChainAdapterTest {
 
     @Before
     public void setUp() {
-        doCallRealMethod().when(domService).getExtensions();
         doReturn(transactionChain).when(domService).createTransactionChain(any());
         if (type == TransactionChainType.MERGING) {
             doCallRealMethod().when(domService).createMergingTransactionChain(any());
@@ -119,7 +118,7 @@ public class BindingDOMTransactionChainAdapterTest {
         BindingDOMAdapterLoader bindingDOMAdapterLoader = new BindingDOMAdapterLoader(
                 new ConstantAdapterContext(mockCodecRegistry)) {
             @Override
-            protected DOMService getDelegate(final Class<? extends DOMService> reqDeleg) {
+            protected DOMService<?, ?> getDelegate(final Class<? extends DOMService<?, ?>> reqDeleg) {
                 return domService;
             }
         };
index 41b35b8d01ac436ad67b2f5e564e4ccfc686bbad..4d69c99603ff1701551b95aa5dd172789f50e0a2 100644 (file)
@@ -58,11 +58,12 @@ public abstract class AbstractDataBrokerTestCustomizer {
     }
 
     public NotificationService createNotificationService() {
-        return new BindingDOMNotificationServiceAdapter(schemaService, domNotificationRouter);
+        return new BindingDOMNotificationServiceAdapter(schemaService, domNotificationRouter.notificationService());
     }
 
     public NotificationPublishService createNotificationPublishService() {
-        return new BindingDOMNotificationPublishServiceAdapter(schemaService, domNotificationRouter);
+        return new BindingDOMNotificationPublishServiceAdapter(schemaService,
+            domNotificationRouter.notificationPublishService());
     }
 
     public abstract ListeningExecutorService getCommitCoordinatorExecutor();
index 24f5bf6687b65cb2781611f82e94466e2c123455..5a80df68ce56a8aea8c7a7e49bfc310e7435e4e8 100644 (file)
@@ -173,9 +173,9 @@ public class BindingTestContext implements AutoCloseable {
 
     public void startBindingNotificationBroker() {
         checkState(executor != null);
-        final DOMNotificationRouter router = new DOMNotificationRouter(16);
-        domPublishService = router;
-        domListenService = router;
+        final var router = new DOMNotificationRouter(16);
+        domPublishService = router.notificationPublishService();
+        domListenService = router.notificationService();
         publishService = new BindingDOMNotificationPublishServiceAdapter(mockSchemaService, domPublishService);
         listenService = new BindingDOMNotificationServiceAdapter(mockSchemaService, domListenService);
 
index 33a054a8cc93cc815329c8b6ced15cce9e5abe29..2d8a1de7201b300ee9346bde6941d9b105c0d026 100644 (file)
@@ -12,8 +12,6 @@ import static com.google.common.base.Verify.verifyNotNull;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.ImmutableClassToInstanceMap;
 import java.util.ServiceLoader;
 import org.opendaylight.mdsal.binding.dom.adapter.AdapterContext;
 import org.opendaylight.mdsal.binding.dom.adapter.CurrentAdapterSerializer;
@@ -21,7 +19,6 @@ import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecFactory;
 import org.opendaylight.mdsal.binding.dom.codec.spi.BindingDOMCodecServices;
 import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
-import org.opendaylight.mdsal.dom.api.DOMSchemaServiceExtension;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.util.ListenerRegistry;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
@@ -62,11 +59,6 @@ public final class MockSchemaService implements DOMSchemaService, EffectiveModel
         return schemaContext;
     }
 
-    @Override
-    public ClassToInstanceMap<DOMSchemaServiceExtension> getExtensions() {
-        return ImmutableClassToInstanceMap.of();
-    }
-
     public synchronized void changeSchema(final BindingRuntimeContext newContext) {
         serializer = new CurrentAdapterSerializer(CODEC_CACHE.getUnchecked(newContext));
         schemaContext = newContext.getEffectiveModelContext();
index ff6c08e8b5a956b98f758bfcac0e44050b883764..45a4f178bec64da2430e2e2334ea43afd57369bc 100644 (file)
@@ -20,7 +20,7 @@ import org.opendaylight.yangtools.concepts.ObjectRegistration;
 @Beta
 @NonNullByDefault
 public interface DOMActionProviderService
-        extends DOMExtensibleService<DOMActionProviderService, DOMActionProviderServiceExtension> {
+        extends DOMService<DOMActionProviderService, DOMActionProviderServiceExtension> {
     /**
      * Register an {@link DOMActionImplementation} object with this service, servicing specified action instances.
      *
index 443b7b0c7c3954df2a9013ab1ae062d8924f01b1..411b9f5651de20a605e6199961c848fb0b6d9644 100644 (file)
@@ -12,12 +12,10 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
 
 /**
  * Marker interface for extensions of {@link DOMActionProviderService}.
- *
- * @author Robert Varga
  */
 @Beta
 @NonNullByDefault
 public interface DOMActionProviderServiceExtension
-    extends DOMServiceExtension<DOMActionProviderService, DOMActionProviderServiceExtension> {
+    extends DOMService.Extension<DOMActionProviderService, DOMActionProviderServiceExtension> {
 
 }
index 8627d914a6624db2ae7d667bc3983ae79198bfdc..f1a26809d3114c773f03f3cc015440f327e1be09 100644 (file)
@@ -17,12 +17,10 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absol
 /**
  * A {@link DOMService} which allows clients to invoke Actions. The conceptual model of this service is that
  * of a dynamic router, where the set of available Action services can change dynamically.
- *
- * @author Robert Varga
  */
 @Beta
 @NonNullByDefault
-public interface DOMActionService extends DOMExtensibleService<DOMActionService, DOMActionServiceExtension> {
+public interface DOMActionService extends DOMService<DOMActionService, DOMActionServiceExtension> {
     /**
      * Initiate invocation of an Action. This method is guaranteed to not block on any external resources.
      *
index 466e252228d330f35c9aba7142ad6470a9cfb93c..19322acb5b7919d0f12fa3ee7be461f3b8d5faed 100644 (file)
@@ -12,12 +12,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
 
 /**
  * Marker interface for extensions of {@link DOMActionService}.
- *
- * @author Robert Varga
  */
 @Beta
 @NonNullByDefault
-public interface DOMActionServiceExtension
-    extends DOMServiceExtension<DOMActionService, DOMActionServiceExtension> {
+public interface DOMActionServiceExtension extends DOMService.Extension<DOMActionService, DOMActionServiceExtension> {
 
 }
index 7e05dd66748d00ac83e2a067129d7f6573605b57..1f7666bae9e766095e6a8b0d767c665333ac6030 100644 (file)
@@ -41,8 +41,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
  * <b>Implementation Note:</b> This interface is not intended to be implemented by users of MD-SAL,
  * but only to be consumed by them.
  */
-public interface DOMDataBroker extends DOMTransactionFactory,
-        DOMExtensibleService<DOMDataBroker, DOMDataBrokerExtension> {
+public interface DOMDataBroker extends DOMService<DOMDataBroker, DOMDataBrokerExtension>, DOMTransactionFactory {
     /**
      * Create a new transaction chain. The chain will be initialized to read from its backing datastore, with
      * no outstanding transaction. Listener will be registered to handle chain-level events.
index 3d6eb16917a5e1d211575e712e671d2b2cf1459c..691597e0ec237a0c0a9451f2aba6b941cdeec9c3 100644 (file)
@@ -8,9 +8,8 @@
 package org.opendaylight.mdsal.dom.api;
 
 /**
- * Type capture of a {@link DOMServiceExtension} applicable to {@link DOMDataBroker}
- * implementations.
+ * Type capture of a {@link DOMService.Extension} applicable to {@link DOMDataBroker} implementations.
  */
-public interface DOMDataBrokerExtension extends DOMServiceExtension<DOMDataBroker, DOMDataBrokerExtension> {
-
+public interface DOMDataBrokerExtension extends DOMService.Extension<DOMDataBroker, DOMDataBrokerExtension> {
+    // Marker interface
 }
index c7a13836b8f0ebe015606f57a1e2183a16d9f7ac..c805f273d758ec2b0dfffa415f1a83e28d74239a 100644 (file)
@@ -11,35 +11,33 @@ import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 
 /**
- * A {@link DOMServiceExtension} which allows users to register for changes to a
- * subtree.
+ * A {@link DOMDataBrokerExtension} which allows users to register for changes to a subtree.
  */
 public interface DOMDataTreeChangeService extends DOMDataBrokerExtension {
     /**
-     * Registers a {@link DOMDataTreeChangeListener} to receive notifications when data changes
-     * under a given path in the conceptual data tree.
+     * Registers a {@link DOMDataTreeChangeListener} to receive notifications when data changes under a given path in
+     * the conceptual data tree.
      *
      * <p>
-     * You are able to register for notifications for any node or subtree which can be represented
-     * using {@link DOMDataTreeIdentifier}.
+     * You are able to register for notifications for any node or subtree which can be represented using
+     * {@link DOMDataTreeIdentifier}.
      *
      * <p>
-     * You are able to register for data change notifications for a subtree or leaf even if it does
-     * not exist. You will receive notification once that node is created.
+     * You are able to register for data change notifications for a subtree or leaf even if it does not exist. You will
+     * receive notification once that node is created.
      *
      * <p>
-     * If there is any pre-existing data in the data tree for the path for which you are
-     * registering, you will receive an initial data change event, which will contain all
-     * pre-existing data, marked as created.
+     * If there is any pre-existing data in the data tree for the path for which you are registering, you will receive
+     * an initial data change event, which will contain all pre-existing data, marked as created.
      *
      * <p>
-     * This method returns a {@link ListenerRegistration} object. To "unregister" your listener for
-     * changes call the {@link ListenerRegistration#close()} method on the returned object.
+     * This method returns a {@link ListenerRegistration} object. To "unregister" your listener for changes call
+     * the {@link ListenerRegistration#close()} method on the returned object.
      *
      * <p>
-     * You MUST explicitly unregister your listener when you no longer want to receive
-     * notifications. This is especially true in OSGi environments, where failure to do so during
-     * bundle shutdown can lead to stale listeners being still registered.
+     * You MUST explicitly unregister your listener when you no longer want to receive notifications. This is especially
+     * true in OSGi environments, where failure to do so during bundle shutdown can lead to stale listeners being still
+     * registered.
      *
      * @param treeId Data tree identifier of the subtree which should be watched for changes.
      * @param listener Listener instance which is being registered
@@ -48,6 +46,7 @@ public interface DOMDataTreeChangeService extends DOMDataBrokerExtension {
      *         {@link ListenerRegistration#close()} to stop delivery of change events.
      * @throws NullPointerException if any of the arguments is null
      */
+    // FIXME: just Registration
     <L extends DOMDataTreeChangeListener> @NonNull ListenerRegistration<L> registerDataTreeChangeListener(
             @NonNull DOMDataTreeIdentifier treeId, @NonNull L listener);
 }
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMExtensibleService.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMExtensibleService.java
deleted file mode 100644 (file)
index 807ad33..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.dom.api;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.ImmutableClassToInstanceMap;
-import org.eclipse.jdt.annotation.NonNull;
-
-/**
- * Marker interface for services which can support {@link DOMServiceExtension}. Aside for marking
- * these, they also provide runtime query to detect whether a particular trait is in fact available.
- *
- * @param <T> Base {@link DOMService}
- * @param <E> Extension type
- */
-@Beta
-public interface DOMExtensibleService<T extends DOMExtensibleService<T, E>,
-    E extends DOMServiceExtension<T, E>> extends DOMService {
-    /**
-     * Return a map of currently-supported extensions, along with accessor services which provide access to the specific
-     * functionality bound to this service. Default implementation reports no extensions.
-     *
-     * @return A map of supported functionality.
-     */
-    default @NonNull ClassToInstanceMap<E> getExtensions() {
-        return ImmutableClassToInstanceMap.of();
-    }
-}
index c655c3dc759ac270fa73b9fded87b59af290662f..fc9270d4b298ce48f8922164bf6a7a6d51dd5d90 100644 (file)
@@ -24,7 +24,15 @@ import org.opendaylight.yangtools.util.concurrent.FluentFutures;
  * </ul>
  */
 @Beta
-public interface DOMInstanceNotificationPublishService extends DOMService {
+public interface DOMInstanceNotificationPublishService extends
+        DOMService<DOMInstanceNotificationPublishService, DOMInstanceNotificationPublishService.Extension> {
+    /**
+     * Marker interface for an extension to {@link DOMInstanceNotificationPublishService}.
+     */
+    interface Extension extends DOMService.Extension<DOMInstanceNotificationPublishService, Extension> {
+        // Marker interface
+    }
+
     /**
      * Well-known value indicating that the implementation is currently not
      * able to accept a notification.
index 29e12806977d68d20f970a6a44604d59f519f0ea..61dcfec221ab1176536fde9d94f69d9e05e76fdb 100644 (file)
@@ -19,7 +19,15 @@ import org.opendaylight.yangtools.yang.common.QName;
  */
 @Beta
 @NonNullByDefault
-public interface DOMInstanceNotificationService extends DOMService {
+public interface DOMInstanceNotificationService
+        extends DOMService<DOMInstanceNotificationService, DOMInstanceNotificationService.Extension> {
+    /**
+     * Marker interface for an extension to {@link DOMInstanceNotificationService}.
+     */
+    interface Extension extends DOMService.Extension<DOMInstanceNotificationService, Extension> {
+        // Marker interface
+    }
+
     /**
      * Register a {@link DOMInstanceNotificationListener} for a particular {@code path} and notification {@code type}.
      *
index df743e28358ded20a7f5ec3075653e816660c2ab..8feb783a2db7ed75ce691c06c95365ce2a90ad06 100644 (file)
@@ -13,5 +13,5 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
 public interface DOMMountPoint extends Identifiable<YangInstanceIdentifier> {
 
-    <T extends DOMService> Optional<T> getService(Class<T> cls);
+    <T extends DOMService<T, E>, E extends DOMService.Extension<T, E>> Optional<T> getService(Class<T> cls);
 }
index fdbcff2d56c2c66a366c5dd5577fa983709568d8..22d323c7bfee32b935e459c823134a14ef296d99 100644 (file)
@@ -5,7 +5,6 @@
  * 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.dom.api;
 
 import java.util.Optional;
@@ -13,18 +12,27 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
-public interface DOMMountPointService extends DOMService {
+public interface DOMMountPointService extends DOMService<DOMMountPointService, DOMMountPointService.Extension> {
+    /**
+     * Marker interface for an extension to {@link DOMMountPointService}.
+     */
+    interface Extension extends DOMService.Extension<DOMMountPointService, Extension> {
+        // Marker interface
+    }
 
     Optional<DOMMountPoint> getMountPoint(YangInstanceIdentifier path);
 
     DOMMountPointBuilder createMountPoint(YangInstanceIdentifier path);
 
+    // FIXME: just Registration
     ListenerRegistration<DOMMountPointListener> registerProvisionListener(DOMMountPointListener listener);
 
     interface DOMMountPointBuilder {
 
-        <T extends DOMService> DOMMountPointBuilder addService(Class<T> type,T impl);
+        <T extends DOMService<T, E>, E extends DOMService.Extension<T, E>> DOMMountPointBuilder addService(
+            Class<T> type, T impl);
 
+        // FIXME: just Registration
         ObjectRegistration<DOMMountPoint> register();
     }
 }
index 02615efa7a4fff76041f8e6d2a7cb73a20138593..a927405a877e57c7de0c16b512984e6d0f7d3073 100644 (file)
@@ -22,7 +22,15 @@ import org.opendaylight.yangtools.util.concurrent.FluentFutures;
  *       should never wait, or put an upper bound on how long it is going to wait</li>
  * </ul>
  */
-public interface DOMNotificationPublishService extends DOMService {
+public interface DOMNotificationPublishService
+        extends DOMService<DOMNotificationPublishService, DOMNotificationPublishService.Extension> {
+    /**
+     * Marker interface for an extension to {@link DOMNotificationPublishService}.
+     */
+    interface Extension extends DOMService.Extension<DOMNotificationPublishService, Extension> {
+        // Marker interface
+    }
+
     /**
      * Well-known value indicating that the implementation is currently not able to accept a notification.
      */
index 283215a7e52adb6f6c161a86e06027f8f8329ed7..bcc4d71be1f2406082854004d9444c83aa8d91e1 100644 (file)
@@ -7,8 +7,8 @@
  */
 package org.opendaylight.mdsal.dom.api;
 
-import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
@@ -18,7 +18,14 @@ import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absol
 /**
  * A {@link DOMService} which allows its users to subscribe to receive top-level (YANG 1.0) {@link DOMNotification}s.
  */
-public interface DOMNotificationService extends DOMService {
+public interface DOMNotificationService extends DOMService<DOMNotificationService, DOMNotificationService.Extension> {
+    /**
+     * Marker interface for an extension to {@link DOMNotificationService}.
+     */
+    interface Extension extends DOMService.Extension<DOMNotificationService, Extension> {
+        // Marker interface
+    }
+
     /**
      * Register a {@link DOMNotificationListener} to receive a set of notifications. As with other
      * {@link ListenerRegistration}-based interfaces, registering an instance multiple times results in
@@ -33,6 +40,7 @@ public interface DOMNotificationService extends DOMService {
      *         null or a schema node identifier which does not represent a valid {@link DOMNotification} type.
      * @throws NullPointerException if either of the arguments is null
      */
+    // FIXME: just Registration and default implementation forwarding to Map-based thing
     <T extends DOMNotificationListener> @NonNull ListenerRegistration<T>
             registerNotificationListener(@NonNull T listener, @NonNull Collection<Absolute> types);
 
@@ -50,9 +58,10 @@ public interface DOMNotificationService extends DOMService {
      *         null or a schema node identifier which does not represent a valid {@link DOMNotification} type.
      * @throws NullPointerException if listener is null
      */
+    // FIXME: just Registration
     default <T extends DOMNotificationListener> @NonNull ListenerRegistration<T>
             registerNotificationListener(@NonNull final T listener, final Absolute... types) {
-        return registerNotificationListener(listener, Arrays.asList(types));
+        return registerNotificationListener(listener, List.of(types));
     }
 
     /**
index d35bb6f532f91d2236189d4deb32f74dbfc5231d..90a470f492cb455c0ef311241c3df3a305ba51c5 100644 (file)
@@ -16,7 +16,14 @@ import org.opendaylight.yangtools.concepts.Registration;
  * A {@link DOMService} which allows registration of RPC implementations with a conceptual router. The client
  * counterpart of this service is {@link DOMRpcService}.
  */
-public interface DOMRpcProviderService extends DOMService {
+public interface DOMRpcProviderService extends DOMService<DOMRpcProviderService, DOMRpcProviderService.Extension> {
+    /**
+     * Marker interface for an extension to {@link DOMRpcProviderService}.
+     */
+    interface Extension extends DOMService.Extension<DOMRpcProviderService, Extension> {
+        // Marker interface
+    }
+
     /**
      * Register an {@link DOMRpcImplementation} object with this service.
      *
@@ -27,6 +34,8 @@ public interface DOMRpcProviderService extends DOMService {
      * @throws NullPointerException if implementation or types is null
      * @throws IllegalArgumentException if types is empty or contains a null element.
      */
+    // FIXME: just Registration and forward to set
+    // FIXME: single-instance specialization
     @NonNull <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T>
         registerRpcImplementation(@NonNull T implementation, @NonNull DOMRpcIdentifier... rpcs);
 
@@ -39,6 +48,7 @@ public interface DOMRpcProviderService extends DOMService {
      * @throws NullPointerException if implementation or types is null
      * @throws IllegalArgumentException if types is empty or contains a null element.
      */
+    // FIXME: just Registration and forward to set
     @NonNull <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T>
         registerRpcImplementation(@NonNull T implementation, @NonNull Set<DOMRpcIdentifier> rpcs);
 
index b16ba74c895c8ba38d02cc1bb15d5af1d5647465..838b972f3e615922456fce76e84ca57b4851bd01 100644 (file)
@@ -19,7 +19,14 @@ import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
  * to track the process of RPCs becoming available.
  */
 // FIXME: once we have a DOMOperationService implementation, deprecate this interface
-public interface DOMRpcService extends DOMService {
+public interface DOMRpcService extends DOMService<DOMRpcService, DOMRpcService.Extension> {
+    /**
+     * Marker interface for an extension to {@link DOMRpcService}.
+     */
+    interface Extension extends DOMService.Extension<DOMRpcService, Extension> {
+        // Marker interface
+    }
+
     /**
      * Initiate invocation of an RPC. This method is guaranteed to not block on any external
      * resources.
index ead53a85766eb0c9c66ddd55c046c637ce4c53b6..94ca7bb12f0a1c99aaefd3a2c8cb694c1358d513 100644 (file)
@@ -12,7 +12,7 @@ import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextListener;
 
-public interface DOMSchemaService extends DOMExtensibleService<DOMSchemaService, DOMSchemaServiceExtension> {
+public interface DOMSchemaService extends DOMService<DOMSchemaService, DOMSchemaServiceExtension> {
     /**
      * Returns global schema context.
      *
index 609d8b6af89af8565715417ac10ad7131f0902a2..cde8e4bbacbf594034c493ba36505d0977231721 100644 (file)
@@ -8,9 +8,8 @@
 package org.opendaylight.mdsal.dom.api;
 
 /**
- * Type capture of a {@link DOMServiceExtension} applicable to {@link DOMSchemaService}
- * implementations.
+ * Type capture of a {@link DOMService.Extension} applicable to {@link DOMSchemaService} implementations.
  */
-public interface DOMSchemaServiceExtension extends DOMServiceExtension<DOMSchemaService, DOMSchemaServiceExtension> {
-
+public interface DOMSchemaServiceExtension extends DOMService.Extension<DOMSchemaService, DOMSchemaServiceExtension> {
+    // Marker interface
 }
index 94114bea14323f910fcbcdad8b2273c87798b571..6591e0d9861186018a05279141a6124235e46943 100644 (file)
@@ -7,10 +7,26 @@
  */
 package org.opendaylight.mdsal.dom.api;
 
+import org.opendaylight.yangtools.concepts.ExtensibleObject;
+import org.opendaylight.yangtools.concepts.ObjectExtension;
+
 /**
- * Marker interface for services which can be obtained from a {@link DOMMountPoint}
- * instance. No further semantics are implied.
+ * Marker interface for services which can be obtained from a {@link DOMMountPoint} instance. The only further semantics
+ * implied are that each service can also host related {@link Extension}s supported via the {@link ExtensibleObject}
+ * contract.
+ *
+ * @param <T> Concrete service type
+ * @param <E> Extension type
  */
-public interface DOMService {
-
+public interface DOMService<T extends DOMService<T, E>, E extends DOMService.Extension<T, E>>
+        extends ExtensibleObject<T, E> {
+    /**
+     * Extension to a concrete {@link DOMService}.
+     *
+     * @param <T> Concrete service type
+     * @param <E> Extension type
+     */
+    interface Extension<T extends DOMService<T, E>, E extends Extension<T, E>> extends ObjectExtension<T, E> {
+        // Only a marker interface
+    }
 }
diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMServiceExtension.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMServiceExtension.java
deleted file mode 100644 (file)
index 63687aa..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2017 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.dom.api;
-
-import com.google.common.annotations.Beta;
-
-/**
- * Marker interface for services which expose additional functionality on top
- * of some base {@link DOMService}.
- */
-@Beta
-public interface DOMServiceExtension<T extends DOMExtensibleService<T, E>, E extends DOMServiceExtension<T, E>> {
-
-}
index 2aba605a5a01e5ecec47d75c699db87070825eae..412fad0906dc88da4e90fb07b6c5da3d0ba775ee 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.mdsal.dom.broker;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ClassToInstanceMap;
 import com.google.common.collect.ImmutableClassToInstanceMap;
+import java.util.Collection;
 import java.util.EnumMap;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -93,8 +94,8 @@ public abstract class AbstractDOMDataBroker extends AbstractDOMForwardedTransact
     }
 
     @Override
-    public ClassToInstanceMap<DOMDataBrokerExtension> getExtensions() {
-        return extensions;
+    public final Collection<DOMDataBrokerExtension> supportedExtensions() {
+        return extensions.values();
     }
 
     @Override
index 843edcec4a03e6851d4379a2914b431d598b4599..54f5837c5cdbe54bb51ed5a467244714c3a758da 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.mdsal.dom.broker;
 
-import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.MutableClassToInstanceMap;
@@ -111,11 +110,13 @@ public final class DOMMountPointServiceImpl implements DOMMountPointService {
     }
 
     private static void checkNotExists(final YangInstanceIdentifier id, final DOMMountPoint mountPoint) {
-        checkState(mountPoint == null, "Mount point %s already exists as %s", id, mountPoint);
+        if (mountPoint != null) {
+            throw new IllegalStateException("Mount point " + id + " already exists as " + mountPoint);
+        }
     }
 
     private final class DOMMountPointBuilderImpl implements DOMMountPointBuilder {
-        private final MutableClassToInstanceMap<DOMService> services = MutableClassToInstanceMap.create();
+        private final MutableClassToInstanceMap<DOMService<?, ?>> services = MutableClassToInstanceMap.create();
         private final YangInstanceIdentifier path;
 
         private SimpleDOMMountPoint mountPoint;
@@ -125,14 +126,17 @@ public final class DOMMountPointServiceImpl implements DOMMountPointService {
         }
 
         @Override
-        public <T extends DOMService> DOMMountPointBuilder addService(final Class<T> type, final T impl) {
-            services.putInstance(requireNonNull(type), requireNonNull(impl));
+        public <T extends DOMService<T, E>, E extends DOMService.Extension<T, E>> DOMMountPointBuilder addService(
+                final Class<T> type, final T impl) {
+            services.putInstance(type, requireNonNull(impl));
             return this;
         }
 
         @Override
         public ObjectRegistration<DOMMountPoint> register() {
-            checkState(mountPoint == null, "Mount point is already built.");
+            if (mountPoint != null) {
+                throw new IllegalStateException("Mount point is already built");
+            }
             mountPoint = SimpleDOMMountPoint.create(path, services);
             return registerMountPoint(mountPoint);
         }
index 0f0633c7be04d86e2360fe21a01def563f285534..32f218c62462444a33f417121fe3c170478c06de 100644 (file)
@@ -60,14 +60,12 @@ import org.slf4j.LoggerFactory;
  * Internal implementation one by using a {@link QueuedNotificationManager}.
  *</p>
  */
-@Component(immediate = true, configurationPid = "org.opendaylight.mdsal.dom.notification", service = {
-    DOMNotificationService.class, DOMNotificationPublishService.class,
-    DOMNotificationSubscriptionListenerRegistry.class
+@Component(configurationPid = "org.opendaylight.mdsal.dom.notification", service = {
+    DOMNotificationRouter.class, DOMNotificationSubscriptionListenerRegistry.class
 })
 @Designate(ocd = DOMNotificationRouter.Config.class)
 // Non-final for testing
-public class DOMNotificationRouter implements AutoCloseable, DOMNotificationPublishService,
-        DOMNotificationService, DOMNotificationSubscriptionListenerRegistry {
+public class DOMNotificationRouter implements DOMNotificationSubscriptionListenerRegistry, AutoCloseable {
     @ObjectClassDefinition()
     public @interface Config {
         @AttributeDefinition(name = "notification-queue-depth")
@@ -103,6 +101,94 @@ public class DOMNotificationRouter implements AutoCloseable, DOMNotificationPubl
         }
     }
 
+    private final class PublishFacade implements DOMNotificationPublishService {
+        @Override
+        public ListenableFuture<? extends Object> putNotification(final DOMNotification notification)
+                throws InterruptedException {
+            return putNotificationImpl(notification);
+        }
+
+        @Override
+        public ListenableFuture<? extends Object> offerNotification(final DOMNotification notification) {
+            final var subscribers = listeners.get(notification.getType());
+            return subscribers.isEmpty() ? NO_LISTENERS : publish(notification, subscribers);
+        }
+
+        @Override
+        public ListenableFuture<? extends Object> offerNotification(final DOMNotification notification,
+                final long timeout, final TimeUnit unit) throws InterruptedException {
+            final var subscribers = listeners.get(notification.getType());
+            if (subscribers.isEmpty()) {
+                return NO_LISTENERS;
+            }
+            // Attempt to perform a non-blocking publish first
+            final var noBlock = publish(notification, subscribers);
+            if (!DOMNotificationPublishService.REJECTED.equals(noBlock)) {
+                return noBlock;
+            }
+
+            try {
+                final var publishThread = Thread.currentThread();
+                final var timerTask = observer.schedule(publishThread::interrupt, timeout, unit);
+                final var withBlock = putNotificationImpl(notification);
+                timerTask.cancel(true);
+                if (observer.getQueue().size() > 50) {
+                    observer.purge();
+                }
+                return withBlock;
+            } catch (InterruptedException e) {
+                return DOMNotificationPublishService.REJECTED;
+            }
+        }
+    }
+
+    private final class SubscribeFacade implements DOMNotificationService {
+        @Override
+        public <T extends DOMNotificationListener> ListenerRegistration<T> registerNotificationListener(
+                final T listener, final Collection<Absolute> types) {
+            synchronized (DOMNotificationRouter.this) {
+                final var reg = new SingleReg<>(listener);
+
+                if (!types.isEmpty()) {
+                    final var b = ImmutableMultimap.<Absolute, Reg<?>>builder();
+                    b.putAll(listeners);
+
+                    for (var t : types) {
+                        b.put(t, reg);
+                    }
+
+                    replaceListeners(b.build());
+                }
+
+                return reg;
+            }
+        }
+
+        @Override
+        public synchronized Registration registerNotificationListeners(
+                final Map<Absolute, DOMNotificationListener> typeToListener) {
+            synchronized (DOMNotificationRouter.this) {
+                final var b = ImmutableMultimap.<Absolute, Reg<?>>builder();
+                b.putAll(listeners);
+
+                final var tmp = new HashMap<DOMNotificationListener, ComponentReg>();
+                for (var e : typeToListener.entrySet()) {
+                    b.put(e.getKey(), tmp.computeIfAbsent(e.getValue(), ComponentReg::new));
+                }
+                replaceListeners(b.build());
+
+                final var regs = List.copyOf(tmp.values());
+                return new AbstractRegistration() {
+                    @Override
+                    protected void removeRegistration() {
+                        regs.forEach(ComponentReg::close);
+                        removeRegistrations(regs);
+                    }
+                };
+            }
+        }
+    }
+
     private static final Logger LOG = LoggerFactory.getLogger(DOMNotificationRouter.class);
     private static final @NonNull ListenableFuture<?> NO_LISTENERS = Futures.immediateFuture(Empty.value());
 
@@ -110,6 +196,8 @@ public class DOMNotificationRouter implements AutoCloseable, DOMNotificationPubl
             ListenerRegistry.create();
     private final EqualityQueuedNotificationManager<AbstractListenerRegistration<? extends DOMNotificationListener>,
                 DOMNotificationRouterEvent> queueNotificationManager;
+    private final @NonNull DOMNotificationPublishService notificationPublishService = new PublishFacade();
+    private final @NonNull DOMNotificationService notificationService = new SubscribeFacade();
     private final ScheduledThreadPoolExecutor observer;
     private final ExecutorService executor;
 
@@ -135,45 +223,12 @@ public class DOMNotificationRouter implements AutoCloseable, DOMNotificationPubl
         this(config.queueDepth());
     }
 
-    @Override
-    public synchronized <T extends DOMNotificationListener> ListenerRegistration<T> registerNotificationListener(
-            final T listener, final Collection<Absolute> types) {
-        final var reg = new SingleReg<>(listener);
-
-        if (!types.isEmpty()) {
-            final var b = ImmutableMultimap.<Absolute, Reg<?>>builder();
-            b.putAll(listeners);
-
-            for (var t : types) {
-                b.put(t, reg);
-            }
-
-            replaceListeners(b.build());
-        }
-
-        return reg;
+    public @NonNull DOMNotificationService notificationService() {
+        return notificationService;
     }
 
-    @Override
-    public synchronized Registration registerNotificationListeners(
-            final Map<Absolute, DOMNotificationListener> typeToListener) {
-        final var b = ImmutableMultimap.<Absolute, Reg<?>>builder();
-        b.putAll(listeners);
-
-        final var tmp = new HashMap<DOMNotificationListener, ComponentReg>();
-        for (var e : typeToListener.entrySet()) {
-            b.put(e.getKey(), tmp.computeIfAbsent(e.getValue(), ComponentReg::new));
-        }
-        replaceListeners(b.build());
-
-        final var regs = List.copyOf(tmp.values());
-        return new AbstractRegistration() {
-            @Override
-            protected void removeRegistration() {
-                regs.forEach(ComponentReg::close);
-                removeRegistrations(regs);
-            }
-        };
+    public @NonNull DOMNotificationPublishService notificationPublishService() {
+        return notificationPublishService;
     }
 
     private synchronized void removeRegistration(final SingleReg<?> reg) {
@@ -216,6 +271,13 @@ public class DOMNotificationRouter implements AutoCloseable, DOMNotificationPubl
         return subscriptionListeners.register(listener);
     }
 
+    @VisibleForTesting
+    @NonNull ListenableFuture<? extends Object> putNotificationImpl(final DOMNotification notification)
+            throws InterruptedException {
+        final var subscribers = listeners.get(notification.getType());
+        return subscribers.isEmpty() ? NO_LISTENERS : publish(notification, subscribers);
+    }
+
     @VisibleForTesting
     @NonNull ListenableFuture<?> publish(final DOMNotification notification, final Collection<Reg<?>> subscribers) {
         final var futures = new ArrayList<ListenableFuture<?>>(subscribers.size());
@@ -228,46 +290,6 @@ public class DOMNotificationRouter implements AutoCloseable, DOMNotificationPubl
             MoreExecutors.directExecutor());
     }
 
-    @Override
-    public ListenableFuture<? extends Object> putNotification(final DOMNotification notification)
-            throws InterruptedException {
-        final var subscribers = listeners.get(notification.getType());
-        return subscribers.isEmpty() ? NO_LISTENERS : publish(notification, subscribers);
-    }
-
-    @Override
-    public ListenableFuture<? extends Object> offerNotification(final DOMNotification notification) {
-        final var subscribers = listeners.get(notification.getType());
-        return subscribers.isEmpty() ? NO_LISTENERS : publish(notification, subscribers);
-    }
-
-    @Override
-    public ListenableFuture<? extends Object> offerNotification(final DOMNotification notification, final long timeout,
-            final TimeUnit unit) throws InterruptedException {
-        final var subscribers = listeners.get(notification.getType());
-        if (subscribers.isEmpty()) {
-            return NO_LISTENERS;
-        }
-        // Attempt to perform a non-blocking publish first
-        final var noBlock = publish(notification, subscribers);
-        if (!DOMNotificationPublishService.REJECTED.equals(noBlock)) {
-            return noBlock;
-        }
-
-        try {
-            final var publishThread = Thread.currentThread();
-            final var timerTask = observer.schedule(publishThread::interrupt, timeout, unit);
-            final var withBlock = putNotification(notification);
-            timerTask.cancel(true);
-            if (observer.getQueue().size() > 50) {
-                observer.purge();
-            }
-            return withBlock;
-        } catch (InterruptedException e) {
-            return DOMNotificationPublishService.REJECTED;
-        }
-    }
-
     @PreDestroy
     @Deactivate
     @Override
index 4997cde5d7d79689f43df297c085cf970b2e6d73..578f84cfded611ee2af64e2dec6939c735e568e5 100644 (file)
@@ -12,9 +12,7 @@ import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ClassToInstanceMap;
 import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableClassToInstanceMap;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableTable;
@@ -399,31 +397,10 @@ public final class DOMRpcRouter extends AbstractRegistration implements Effectiv
     }
 
     @NonNullByDefault
-    private final class ActionAvailabilityFacade implements DOMActionAvailabilityExtension {
+    private final class ActionServiceFacade implements DOMActionService, DOMActionAvailabilityExtension {
         @Override
-        public <T extends AvailabilityListener> ListenerRegistration<T> registerAvailabilityListener(final T listener) {
-            synchronized (DOMRpcRouter.this) {
-                final ActionRegistration<T> ret = new ActionRegistration<>(DOMRpcRouter.this, listener,
-                    actionRoutingTable.getOperations(listener));
-                actionListeners = ImmutableList.<ActionRegistration<?>>builder()
-                    .addAll(actionListeners)
-                    .add(ret)
-                    .build();
-
-                listenerNotifier.execute(ret::initialTable);
-                return ret;
-            }
-        }
-    }
-
-    @NonNullByDefault
-    private final class ActionServiceFacade implements DOMActionService {
-        private final ClassToInstanceMap<DOMActionServiceExtension> extensions = ImmutableClassToInstanceMap.of(
-            DOMActionAvailabilityExtension.class, new ActionAvailabilityFacade());
-
-        @Override
-        public ClassToInstanceMap<DOMActionServiceExtension> getExtensions() {
-            return extensions;
+        public Collection<DOMActionServiceExtension> supportedExtensions() {
+            return List.of(this);
         }
 
         @Override
@@ -437,6 +414,21 @@ public final class DOMRpcRouter extends AbstractRegistration implements Effectiv
                 : Futures.immediateFailedFuture(
                     new DOMActionNotAvailableException("No implementation of Action %s available", type));
         }
+
+        @Override
+        public <T extends AvailabilityListener> ListenerRegistration<T> registerAvailabilityListener(final T listener) {
+            synchronized (DOMRpcRouter.this) {
+                final ActionRegistration<T> ret = new ActionRegistration<>(DOMRpcRouter.this, listener,
+                    actionRoutingTable.getOperations(listener));
+                actionListeners = ImmutableList.<ActionRegistration<?>>builder()
+                    .addAll(actionListeners)
+                    .add(ret)
+                    .build();
+
+                listenerNotifier.execute(ret::initialTable);
+                return ret;
+            }
+        }
     }
 
     @NonNullByDefault
diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/RouterDOMNotificationService.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/RouterDOMNotificationService.java
new file mode 100644 (file)
index 0000000..9869867
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2023 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.dom.broker;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.dom.api.DOMNotificationService;
+import org.opendaylight.mdsal.dom.spi.ForwardingDOMNotificationService;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+@Singleton
+@Component(service = DOMNotificationService.class)
+public final class RouterDOMNotificationService extends ForwardingDOMNotificationService {
+    private final @NonNull DOMNotificationService delegate;
+
+    @Inject
+    @Activate
+    public RouterDOMNotificationService(@Reference final DOMNotificationRouter router) {
+        delegate = router.notificationService();
+    }
+
+    @Override
+    protected DOMNotificationService delegate() {
+        return delegate;
+    }
+}
diff --git a/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/RouterDOMPublishNotificationService.java b/dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/RouterDOMPublishNotificationService.java
new file mode 100644 (file)
index 0000000..9aa0fdf
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2023 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.dom.broker;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.dom.api.DOMNotificationPublishService;
+import org.opendaylight.mdsal.dom.spi.ForwardingDOMNotificationPublishService;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+@Singleton
+@Component(service = DOMNotificationPublishService.class)
+public final class RouterDOMPublishNotificationService extends ForwardingDOMNotificationPublishService {
+    private final @NonNull DOMNotificationPublishService delegate;
+
+    @Inject
+    @Activate
+    public RouterDOMPublishNotificationService(@Reference final DOMNotificationRouter router) {
+        delegate = router.notificationPublishService();
+    }
+
+    @Override
+    protected DOMNotificationPublishService delegate() {
+        return delegate;
+    }
+}
index 6524e46da82b34b5df0bf0512e56bfd0a9014d53..7d506fe08d035ab8eb76ff8e9a711cf601c840b9 100644 (file)
@@ -384,7 +384,7 @@ public class DOMDataTreeListenerTest extends AbstractDatastoreTest {
     }
 
     private DOMDataTreeChangeService getDOMDataTreeChangeService() {
-        return domBroker.getExtensions().getInstance(DOMDataTreeChangeService.class);
+        return domBroker.extension(DOMDataTreeChangeService.class);
     }
 
     static class CommitExecutorService extends ForwardingExecutorService {
index 0069f192e2b0a0023f800b4045943f73b31a3517..133b1a154207506fa3b969904525084324dc6370 100644 (file)
@@ -32,7 +32,6 @@ import org.opendaylight.mdsal.dom.api.DOMNotification;
 import org.opendaylight.mdsal.dom.api.DOMNotificationListener;
 import org.opendaylight.mdsal.dom.api.DOMNotificationPublishService;
 import org.opendaylight.mdsal.dom.spi.DOMNotificationSubscriptionListener;
-import org.opendaylight.yangtools.util.ListenerRegistry;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 
@@ -42,11 +41,11 @@ public class DOMNotificationRouterTest {
         try (var domNotificationRouter = new DOMNotificationRouter(1024)) {
             final var domNotificationListener = mock(DOMNotificationListener.class);
 
-            domNotificationRouter.registerNotificationListener(domNotificationListener,
+            domNotificationRouter.notificationService().registerNotificationListener(domNotificationListener,
                 List.of(Absolute.of(QName.create("urn:opendaylight:test-listener", "notif1"))));
             assertEquals(1, domNotificationRouter.listeners().size());
 
-            domNotificationRouter.registerNotificationListener(domNotificationListener,
+            domNotificationRouter.notificationService().registerNotificationListener(domNotificationListener,
                 List.of(Absolute.of(QName.create("urn:opendaylight:test-listener", "notif2")),
                     Absolute.of(QName.create("urn:opendaylight:test-listener", "notif3"))));
             assertEquals(3, domNotificationRouter.listeners().size());
@@ -59,7 +58,7 @@ public class DOMNotificationRouterTest {
             final var domNotificationListener1 = mock(DOMNotificationListener.class);
             final var domNotificationListener2 = mock(DOMNotificationListener.class);
 
-            domNotificationRouter.registerNotificationListeners(
+            domNotificationRouter.notificationService().registerNotificationListeners(
                 Map.of(Absolute.of(QName.create("urn:opendaylight:test-listener", "notif1")), domNotificationListener1,
                     Absolute.of(QName.create("urn:opendaylight:test-listener", "notif2")), domNotificationListener2));
             assertEquals(2, domNotificationRouter.listeners().size());
@@ -69,28 +68,28 @@ public class DOMNotificationRouterTest {
     @SuppressWarnings("checkstyle:IllegalCatch")
     @Test
     public void complexTest() throws Exception {
-        final DOMNotificationSubscriptionListener domNotificationSubscriptionListener =
-                mock(DOMNotificationSubscriptionListener.class);
+        final var domNotificationSubscriptionListener = mock(DOMNotificationSubscriptionListener.class);
         doNothing().when(domNotificationSubscriptionListener).onSubscriptionChanged(any());
 
-        final CountDownLatch latch = new CountDownLatch(1);
-        final DOMNotificationListener domNotificationListener = new TestListener(latch);
-        final DOMNotificationRouter domNotificationRouter = new DOMNotificationRouter(1024);
+        final var latch = new CountDownLatch(1);
+        final var domNotificationListener = new TestListener(latch);
+        final var domNotificationRouter = new DOMNotificationRouter(1024);
+        final var notifService = domNotificationRouter.notificationService();
+        final var notifPubService = domNotificationRouter.notificationPublishService();
 
         var listeners = domNotificationRouter.listeners();
 
         assertTrue(listeners.isEmpty());
-        assertNotNull(domNotificationRouter.registerNotificationListener(domNotificationListener,
-            Absolute.of(TestModel.TEST_QNAME)));
-        assertNotNull(domNotificationRouter.registerNotificationListener(domNotificationListener,
-            Absolute.of(TestModel.TEST2_QNAME)));
+        assertNotNull(notifService.registerNotificationListener(domNotificationListener,
+            List.of(Absolute.of(TestModel.TEST_QNAME))));
+        assertNotNull(notifService.registerNotificationListener(domNotificationListener,
+            List.of(Absolute.of(TestModel.TEST2_QNAME))));
 
         listeners = domNotificationRouter.listeners();
 
         assertFalse(listeners.isEmpty());
 
-        ListenerRegistry<DOMNotificationSubscriptionListener> subscriptionListeners =
-                domNotificationRouter.subscriptionListeners();
+        var subscriptionListeners = domNotificationRouter.subscriptionListeners();
 
         assertEquals(0, subscriptionListeners.streamListeners().count());
         assertNotNull(domNotificationRouter.registerSubscriptionListener(domNotificationSubscriptionListener));
@@ -99,56 +98,57 @@ public class DOMNotificationRouterTest {
         assertSame(domNotificationSubscriptionListener,
             subscriptionListeners.streamListeners().findAny().orElseThrow());
 
-        final DOMNotification domNotification = mock(DOMNotification.class);
+        final var domNotification = mock(DOMNotification.class);
         doReturn("test").when(domNotification).toString();
         doReturn(Absolute.of(TestModel.TEST_QNAME)).when(domNotification).getType();
         doReturn(TEST_CHILD).when(domNotification).getBody();
 
-        assertNotNull(domNotificationRouter.offerNotification(domNotification));
+        assertNotNull(notifPubService.offerNotification(domNotification));
 
-        try {
-            assertNotNull(domNotificationRouter.offerNotification(domNotification, 1, TimeUnit.SECONDS));
-            assertNotNull(domNotificationRouter.offerNotification(domNotification, 1, TimeUnit.SECONDS));
-        } catch (Exception e) {
-            // FIXME: what is the point here?!
-            assertTrue(e instanceof UnsupportedOperationException);
-        }
-
-        assertNotNull(domNotificationRouter.putNotification(domNotification));
+        assertNotNull(notifPubService.offerNotification(domNotification, 1, TimeUnit.SECONDS));
+        assertNotNull(notifPubService.offerNotification(domNotification, 1, TimeUnit.SECONDS));
+        assertNotNull(notifPubService.putNotification(domNotification));
     }
 
     @Test
     public void offerNotification() throws Exception {
         try (var domNotificationRouter = new DOMNotificationRouter(1024)) {
-            final DOMNotification domNotification = mock(DOMNotification.class);
+            final var domNotification = mock(DOMNotification.class);
             doReturn(Absolute.of(TestModel.TEST_QNAME)).when(domNotification).getType();
             doReturn(TEST_CHILD).when(domNotification).getBody();
-            assertNotNull(domNotificationRouter.putNotification(domNotification));
-            assertNotNull(domNotificationRouter.offerNotification(domNotification));
-            assertNotNull(domNotificationRouter.offerNotification(domNotification, 1, TimeUnit.SECONDS));
+
+            final var notifPubService = domNotificationRouter.notificationPublishService();
+            assertNotNull(notifPubService.putNotification(domNotification));
+            assertNotNull(notifPubService.offerNotification(domNotification));
+            assertNotNull(notifPubService.offerNotification(domNotification, 1, TimeUnit.SECONDS));
         }
     }
 
     @Test
     public void testOfferNotificationWithBlocking() throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
-        final TestListener testListener = new TestListener(latch);
-        final DOMNotification domNotification = mock(DOMNotification.class);
+        final var latch = new CountDownLatch(1);
+        final var testListener = new TestListener(latch);
+        final var domNotification = mock(DOMNotification.class);
         doReturn("test").when(domNotification).toString();
         doReturn(Absolute.of(TestModel.TEST_QNAME)).when(domNotification).getType();
         doReturn(TEST_CHILD).when(domNotification).getBody();
 
-        try (TestRouter testRouter = new TestRouter(1)) {
-            assertNotNull(testRouter.registerNotificationListener(testListener, Absolute.of(TestModel.TEST_QNAME)));
-            assertNotNull(testRouter.registerNotificationListener(testListener, Absolute.of(TestModel.TEST2_QNAME)));
+        try (var testRouter = new TestRouter(1)) {
+            final var notifService = testRouter.notificationService();
+            final var notifPubService = testRouter.notificationPublishService();
+
+            assertNotNull(notifService.registerNotificationListener(testListener,
+                List.of(Absolute.of(TestModel.TEST_QNAME))));
+            assertNotNull(notifService.registerNotificationListener(testListener,
+                List.of(Absolute.of(TestModel.TEST2_QNAME))));
 
             assertNotEquals(DOMNotificationPublishService.REJECTED,
-                testRouter.offerNotification(domNotification, 3, TimeUnit.SECONDS));
+                notifPubService.offerNotification(domNotification, 3, TimeUnit.SECONDS));
             assertTrue("Listener was not notified", latch.await(5, TimeUnit.SECONDS));
             assertEquals("Received notifications", 1, testListener.getReceivedNotifications().size());
 
             assertEquals(DOMNotificationPublishService.REJECTED,
-                    testRouter.offerNotification(domNotification, 1, TimeUnit.SECONDS));
+                notifPubService.offerNotification(domNotification, 1, TimeUnit.SECONDS));
             assertEquals("Received notifications", 1, testListener.getReceivedNotifications().size());
         }
     }
@@ -169,8 +169,8 @@ public class DOMNotificationRouterTest {
     }
 
     private static class TestListener implements DOMNotificationListener {
-        private final CountDownLatch latch;
         private final List<DOMNotification>  receivedNotifications = new ArrayList<>();
+        private final CountDownLatch latch;
 
         TestListener(final CountDownLatch latch) {
             this.latch = latch;
@@ -182,7 +182,7 @@ public class DOMNotificationRouterTest {
             latch.countDown();
         }
 
-        public List<DOMNotification> getReceivedNotifications() {
+        List<DOMNotification> getReceivedNotifications() {
             return receivedNotifications;
         }
     }
@@ -199,7 +199,7 @@ public class DOMNotificationRouterTest {
         ListenableFuture<? extends Object> publish(final DOMNotification notification,
                 final Collection<Reg<?>> subscribers) {
             if (triggerRejected) {
-                return REJECTED;
+                return DOMNotificationPublishService.REJECTED;
             }
 
             triggerRejected = true;
@@ -207,10 +207,10 @@ public class DOMNotificationRouterTest {
         }
 
         @Override
-        public ListenableFuture<? extends Object> putNotification(final DOMNotification notification)
+        public ListenableFuture<? extends Object> putNotificationImpl(final DOMNotification notification)
                 throws InterruptedException {
             Thread.sleep(2000);
-            return super.putNotification(notification);
+            return super.putNotificationImpl(notification);
         }
     }
 }
index 5cd76cf41955a6bb5721cd8313ef64c8c6bceb9b..edce7f522a0f5a1826e83cf27fa4540efdfe1793 100644 (file)
@@ -155,8 +155,9 @@ public class DOMRpcRouterTest {
             assertEquals(List.of(), rpcRouter.actionListeners());
 
             final var listener = mock(AvailabilityListener.class);
-            final var reg = rpcRouter.actionService().getExtensions()
-                .getInstance(DOMActionAvailabilityExtension.class).registerAvailabilityListener(listener);
+            final var availability = rpcRouter.actionService().extension(DOMActionAvailabilityExtension.class);
+            assertNotNull(availability);
+            final var reg = availability.registerAvailabilityListener(listener);
             assertNotNull(reg);
             assertEquals(List.of(reg), rpcRouter.actionListeners());
 
index c08ed8f7c05d6b8015614c028af84290b968e26c..132f8dad5a78b62ae0c0545b39ed9014ac3a4600 100644 (file)
@@ -7,12 +7,8 @@
  */
 package org.opendaylight.mdsal.dom.spi;
 
-import static com.google.common.base.Preconditions.checkState;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.ImmutableClassToInstanceMap;
-import org.eclipse.jdt.annotation.NonNullByDefault;
+import java.util.Collection;
+import java.util.List;
 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
 import org.opendaylight.mdsal.dom.api.DOMSchemaServiceExtension;
 import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
@@ -25,21 +21,21 @@ import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider;
  *
  * @author Michael Vorburger.ch
  */
-@Beta
-@NonNullByDefault
 public abstract class AbstractDOMSchemaService implements DOMSchemaService, EffectiveModelContextProvider {
     public abstract static class WithYangTextSources extends AbstractDOMSchemaService
             implements DOMYangTextSourceProvider {
         @Override
-        public ClassToInstanceMap<DOMSchemaServiceExtension> getExtensions() {
-            return ImmutableClassToInstanceMap.of(DOMYangTextSourceProvider.class, this);
+        public Collection<? extends DOMSchemaServiceExtension> supportedExtensions() {
+            return List.of(this);
         }
     }
 
     @Override
     public final EffectiveModelContext getEffectiveModelContext() {
-        final EffectiveModelContext ret = getGlobalContext();
-        checkState(ret != null, "Global context is not available in %s", this);
+        final var ret = getGlobalContext();
+        if (ret == null) {
+            throw new IllegalStateException("Global context is not available in " + this);
+        }
         return ret;
     }
 }
index 7fa48dab6a539ec344116099cfbff27b04396a74..3333a613c44a95fcf2a50506601638e9895b3fc3 100644 (file)
@@ -10,9 +10,8 @@ package org.opendaylight.mdsal.dom.spi;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.annotations.Beta;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.ImmutableClassToInstanceMap;
 import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
 import org.opendaylight.mdsal.dom.api.DOMSchemaServiceExtension;
@@ -45,8 +44,8 @@ public class FixedDOMSchemaService extends AbstractDOMSchemaService {
         }
 
         @Override
-        public ClassToInstanceMap<DOMSchemaServiceExtension> getExtensions() {
-            return ImmutableClassToInstanceMap.of(DOMYangTextSourceProvider.class, this);
+        public List<DOMSchemaServiceExtension> supportedExtensions() {
+            return List.of(this);
         }
 
         @Override
index 2cfa31c3be669425f31be6cbe7c8dead82c7d296..3456f149b212e53529d0f6fc56535e51de59e2c5 100644 (file)
@@ -9,7 +9,7 @@ package org.opendaylight.mdsal.dom.spi;
 
 import com.google.common.annotations.Beta;
 import java.util.Set;
-import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.opendaylight.mdsal.dom.api.DOMActionImplementation;
 import org.opendaylight.mdsal.dom.api.DOMActionInstance;
 import org.opendaylight.mdsal.dom.api.DOMActionProviderService;
@@ -17,12 +17,13 @@ import org.opendaylight.mdsal.dom.api.DOMActionProviderServiceExtension;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
 
 @Beta
+@NonNullByDefault
 public abstract class ForwardingDOMActionProviderService
-        extends ForwardingDOMExtensibleService<DOMActionProviderService, DOMActionProviderServiceExtension>
+        extends ForwardingDOMService<DOMActionProviderService, DOMActionProviderServiceExtension>
         implements DOMActionProviderService {
     @Override
-    public <T extends @NonNull DOMActionImplementation> ObjectRegistration<T> registerActionImplementation(
-            final T implementation, final Set<@NonNull DOMActionInstance> instances) {
+    public <T extends DOMActionImplementation> ObjectRegistration<T> registerActionImplementation(
+            final T implementation, final Set<DOMActionInstance> instances) {
         return delegate().registerActionImplementation(implementation, instances);
     }
 }
index 20fdf49b2392eb0bd99ff91702f2d91338a52dec..ad7ea82ecf799b8594116fe54a2eb1e431dd9e37 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.mdsal.dom.spi;
 
 import com.google.common.annotations.Beta;
 import com.google.common.util.concurrent.ListenableFuture;
+import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.opendaylight.mdsal.dom.api.DOMActionResult;
 import org.opendaylight.mdsal.dom.api.DOMActionService;
 import org.opendaylight.mdsal.dom.api.DOMActionServiceExtension;
@@ -17,9 +18,9 @@ import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
 
 @Beta
+@NonNullByDefault
 public abstract class ForwardingDOMActionService
-        extends ForwardingDOMExtensibleService<DOMActionService, DOMActionServiceExtension>
-        implements DOMActionService {
+        extends ForwardingDOMService<DOMActionService, DOMActionServiceExtension> implements DOMActionService {
     @Override
     public ListenableFuture<? extends DOMActionResult> invokeAction(final Absolute type,
             final DOMDataTreeIdentifier path, final ContainerNode input) {
index 5241e1e5377970f0e6042a8c2a53d5e7b7c06018..b4b149e36b0b4412ac485def4ad3ef5387bc27c4 100644 (file)
@@ -16,11 +16,9 @@ import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
 import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
 
 /**
- * Utility {@link DOMDataBroker} implementation which forwards all interface
- * method invocation to a delegate instance.
+ * Utility {@link DOMDataBroker} implementation which forwards all interface method invocation to a delegate instance.
  */
-public abstract class ForwardingDOMDataBroker
-        extends ForwardingDOMExtensibleService<DOMDataBroker, DOMDataBrokerExtension>
+public abstract class ForwardingDOMDataBroker extends ForwardingDOMService<DOMDataBroker, DOMDataBrokerExtension>
         implements DOMDataBroker {
     @Override
     public DOMDataTreeReadTransaction newReadOnlyTransaction() {
diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMExtensibleService.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMExtensibleService.java
deleted file mode 100644 (file)
index 398b2d3..0000000
+++ /dev/null
@@ -1,28 +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.dom.spi;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.ForwardingObject;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.dom.api.DOMExtensibleService;
-import org.opendaylight.mdsal.dom.api.DOMServiceExtension;
-
-@Beta
-public abstract class ForwardingDOMExtensibleService<T extends DOMExtensibleService<T, E>,
-        E extends DOMServiceExtension<T, E>> extends ForwardingObject
-            implements DOMExtensibleService<T, E> {
-    @Override
-    public ClassToInstanceMap<E> getExtensions() {
-        return delegate().getExtensions();
-    }
-
-    @Override
-    protected abstract @NonNull T delegate();
-}
diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMService.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ForwardingDOMService.java
new file mode 100644 (file)
index 0000000..ee5eb7c
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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.dom.spi;
+
+import com.google.common.collect.ForwardingObject;
+import java.util.Collection;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.dom.api.DOMService;
+
+public abstract class ForwardingDOMService<T extends DOMService<T, E>, E extends DOMService.Extension<T, E>>
+        extends ForwardingObject implements DOMService<T, E> {
+    @Override
+    @SuppressWarnings("hiding")
+    public final <T extends E> @Nullable T extension(final Class<T> type) {
+        return DOMService.super.extension(type);
+    }
+
+    @Override
+    @SuppressWarnings("hiding")
+    public final <T extends E> Optional<T> findExtension(final Class<T> type) {
+        return DOMService.super.findExtension(type);
+    }
+
+    @Override
+    public final Collection<? extends E> supportedExtensions() {
+        return supportedExtensions(delegate().supportedExtensions());
+    }
+
+    protected @NonNull Collection<? extends E> supportedExtensions(final @NonNull Collection<? extends E> extensions) {
+        return extensions;
+    }
+
+    @Override
+    protected abstract @NonNull T delegate();
+}
index fc07c70fb3f91f4095b11270ac0a0edb86fcb7ff..978daf9ce639bb18fa531bc0da2696a5446162e4 100644 (file)
@@ -12,23 +12,24 @@ import static java.util.Objects.requireNonNull;
 import com.google.common.collect.ClassToInstanceMap;
 import com.google.common.collect.ImmutableClassToInstanceMap;
 import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
 import org.opendaylight.mdsal.dom.api.DOMService;
+import org.opendaylight.mdsal.dom.api.DOMService.Extension;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
 public final class SimpleDOMMountPoint implements DOMMountPoint {
-
-    private final YangInstanceIdentifier identifier;
-    private final ClassToInstanceMap<DOMService> services;
+    private final ImmutableClassToInstanceMap<DOMService<?, ?>> services;
+    private final @NonNull YangInstanceIdentifier identifier;
 
     private SimpleDOMMountPoint(final YangInstanceIdentifier identifier,
-            final ClassToInstanceMap<DOMService> services) {
+            final ClassToInstanceMap<DOMService<?, ?>> services) {
         this.identifier =  requireNonNull(identifier);
         this.services = ImmutableClassToInstanceMap.copyOf(services);
     }
 
     public static SimpleDOMMountPoint create(final YangInstanceIdentifier identifier,
-            final ClassToInstanceMap<DOMService> services) {
+            final ClassToInstanceMap<DOMService<?, ?>> services) {
         return new SimpleDOMMountPoint(identifier, services);
     }
 
@@ -38,7 +39,7 @@ public final class SimpleDOMMountPoint implements DOMMountPoint {
     }
 
     @Override
-    public <T extends DOMService> Optional<T> getService(final Class<T> cls) {
+    public <T extends DOMService<T, E>, E extends Extension<T, E>> Optional<T> getService(final Class<T> cls) {
         return Optional.ofNullable(services.getInstance(cls));
     }
 }
index 0af5e59f2e770123275d01ef7f6a41f710e09765..1255874cdb2dd5c36ffc171f32bc2ee1a2d62761 100644 (file)
@@ -7,43 +7,59 @@
  */
 package org.opendaylight.mdsal.dom.spi;
 
-import static org.mockito.ArgumentMatchers.any;
+import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
 
-import com.google.common.collect.ImmutableClassToInstanceMap;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.jupiter.MockitoExtension;
 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMDataBrokerExtension;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
 
-@RunWith(MockitoJUnitRunner.StrictStubs.class)
-public class ForwardingDOMDataBrokerTest extends ForwardingDOMDataBroker {
-    @Mock(name = "domDataBroker")
-    public DOMDataBroker domDataBroker;
+@ExtendWith(MockitoExtension.class)
+class ForwardingDOMDataBrokerTest {
+    private interface Extension extends DOMDataBrokerExtension {
+        // Nothing else
+    }
+
+    @Mock
+    private DOMTransactionChain chain;
+    @Mock
+    private DOMTransactionChainListener chainListener;
+    @Mock
+    private Extension extension;
+    @Mock
+    private DOMDataBroker domDataBroker;
+    @Mock
+    private DOMDataTreeReadTransaction readTx;
+    @Mock
+    private DOMDataTreeWriteTransaction writeTx;
 
     @Test
-    public void basicTest() throws Exception {
-        doReturn(null).when(domDataBroker).createTransactionChain(any());
-        this.createTransactionChain(null);
-        verify(domDataBroker).createTransactionChain(any());
-
-        doReturn(ImmutableClassToInstanceMap.of()).when(domDataBroker).getExtensions();
-        this.getExtensions();
-        verify(domDataBroker).getExtensions();
-
-        doReturn(null).when(domDataBroker).newReadOnlyTransaction();
-        this.newReadOnlyTransaction();
-        verify(domDataBroker).newReadOnlyTransaction();
-
-        doReturn(null).when(domDataBroker).newWriteOnlyTransaction();
-        this.newWriteOnlyTransaction();
-        verify(domDataBroker).newWriteOnlyTransaction();
-    }
+    void basicTest() throws Exception {
+        final var impl = new ForwardingDOMDataBroker() {
+            @Override
+            protected DOMDataBroker delegate() {
+                return domDataBroker;
+            }
+        };
+
+        doReturn(chain).when(domDataBroker).createTransactionChain(chainListener);
+        assertSame(chain, impl.createTransactionChain(chainListener));
+
+        doReturn(List.of(extension)).when(domDataBroker).supportedExtensions();
+        assertSame(extension, impl.extension(Extension.class));
+
+        doReturn(readTx).when(domDataBroker).newReadOnlyTransaction();
+        assertSame(readTx, impl.newReadOnlyTransaction());
 
-    @Override
-    protected DOMDataBroker delegate() {
-        return domDataBroker;
+        doReturn(writeTx).when(domDataBroker).newWriteOnlyTransaction();
+        assertSame(writeTx, impl.newWriteOnlyTransaction());
     }
 }
\ No newline at end of file
index fe02e9908f05dc09fc030f02344801d28eaaee1d..64d76da09f855fb080c8d20403e7a9d2b91c64cb 100644 (file)
@@ -7,33 +7,37 @@
  */
 package org.opendaylight.mdsal.dom.spi;
 
+import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
 
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.jupiter.MockitoExtension;
 import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
 import org.opendaylight.mdsal.dom.api.DOMRpcImplementation;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
 
-@RunWith(MockitoJUnitRunner.StrictStubs.class)
-public class ForwardingDOMRpcImplementationTest extends ForwardingDOMRpcImplementation {
-    @Mock(name = "domRpcImplementation")
-    public DOMRpcImplementation domRpcImplementation;
+@ExtendWith(MockitoExtension.class)
+class ForwardingDOMRpcImplementationTest {
+    @Mock
+    private DOMRpcImplementation domRpcImplementation;
+    @Mock
+    private DOMRpcIdentifier domRpcIdentifier;
+    @Mock
+    private ListenableFuture<DOMRpcResult> rpcFuture;
 
     @Test
-    public void basicTest() throws Exception {
-        final DOMRpcIdentifier domRpcIdentifier = mock(DOMRpcIdentifier.class);
+    void basicTest() {
+        var impl = new ForwardingDOMRpcImplementation() {
+            @Override
+            protected DOMRpcImplementation delegate() {
+                return domRpcImplementation;
+            }
+        };
 
-        doReturn(null).when(domRpcImplementation).invokeRpc(domRpcIdentifier, null);
-        this.invokeRpc(domRpcIdentifier, null);
-        verify(domRpcImplementation).invokeRpc(domRpcIdentifier, null);
-    }
-
-    @Override
-    protected DOMRpcImplementation delegate() {
-        return domRpcImplementation;
+        doReturn(rpcFuture).when(domRpcImplementation).invokeRpc(domRpcIdentifier, null);
+        assertSame(rpcFuture, impl.invokeRpc(domRpcIdentifier, null));
     }
 }
\ No newline at end of file
index a8ce559a08f5df89402a08398c217f11969a9a71..0cc6a2bc8269cbc2ccb85c73b22c8c2c44a8a838 100644 (file)
@@ -7,28 +7,37 @@
  */
 package org.opendaylight.mdsal.dom.spi;
 
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
 
 import com.google.common.collect.ImmutableClassToInstanceMap;
-import org.junit.Test;
+import java.util.Optional;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
 import org.opendaylight.mdsal.dom.api.DOMService;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 
-public class SimpleDOMMountPointTest {
-    @Test
-    public void basicTest() throws Exception {
-        final var domService = mock(DOMService.class);
-        final var classToInstanceMap = ImmutableClassToInstanceMap.of(DOMService.class, domService);
+@ExtendWith(MockitoExtension.class)
+class SimpleDOMMountPointTest {
+    private interface MockService extends DOMService<MockService, MockService.Extension> {
+        interface Extension extends DOMService.Extension<MockService, Extension> {
+            // Marker
+        }
+    }
 
-        final SimpleDOMMountPoint simpleDOMMountPoint =
-                SimpleDOMMountPoint.create(YangInstanceIdentifier.of(), classToInstanceMap);
-        assertNotNull(simpleDOMMountPoint);
+    @Mock
+    private MockService service;
+
+    @Test
+    void basicTest() {
+        final var impl = SimpleDOMMountPoint.create(YangInstanceIdentifier.of(),
+            ImmutableClassToInstanceMap.of(MockService.class, service));
+        assertNotNull(impl);
 
-        assertSame(YangInstanceIdentifier.of(), simpleDOMMountPoint.getIdentifier());
-        assertTrue(simpleDOMMountPoint.getService(DOMService.class).isPresent());
-        assertSame(domService, simpleDOMMountPoint.getService(DOMService.class).orElseThrow());
+        assertSame(YangInstanceIdentifier.of(), impl.getIdentifier());
+        assertEquals(Optional.of(service), impl.getService(MockService.class));
     }
 }
\ No newline at end of file
index be143ee71a2d95a987cfd2dec9e0b34dd1defac1..924307d1d31305f51f186bbe648c15f9d786f74a 100644 (file)
@@ -81,7 +81,7 @@ public final class NettyReplicationSource {
                                     final int listenPort, final Duration keepaliveInterval,
                                     final int maxMissedKeepalives) {
         LOG.debug("Source {}", enabled ? "enabled" : "disabled");
-        final DOMDataTreeChangeService dtcs = broker.getExtensions().getInstance(DOMDataTreeChangeService.class);
+        final var dtcs = broker.extension(DOMDataTreeChangeService.class);
         verify(dtcs != null, "Missing DOMDataTreeChangeService in broker %s", broker);
         checkArgument(maxMissedKeepalives > 0, "max-missed-keepalives %s must be greater than 0", maxMissedKeepalives);
         return enabled ? singleton.registerClusterSingletonService(new SourceSingletonService(bootstrap,
index 94311cbcfc3f73cd3202593573e376b37e3915c8..135ad04cb7973a020d24c846908405432f08916a 100644 (file)
@@ -13,17 +13,16 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import org.eclipse.jdt.annotation.Nullable;
 
 /**
- * Implementation of {@link CloseTracked} which can be used as a field in
- * another class which implements {@link CloseTracked} and delegates its methods
- * to this.
+ * Implementation of {@link CloseTracked} which can be used as a field in another class which implements
+ * {@link CloseTracked} and delegates its methods to this.
  *
- * <p>This is useful if that class already has another parent class.
- * If it does not, then it's typically more convenient to just extend AbstractCloseTracked.
+ * <p>
+ * This is useful if that class already has another parent class. If it does not, then it's typically more convenient to
+ *  just extend AbstractCloseTracked.
  *
  * @author Michael Vorburger.ch
  */
 final class CloseTrackedTrait<T extends CloseTracked<T>> implements CloseTracked<T> {
-
     // NB: It's important that we keep a Throwable here, and not directly the StackTraceElement[] !
     // This is because creating a new Throwable() is a lot less expensive in terms of runtime overhead
     // than actually calling its getStackTrace(), which we can delay until we really need to.
@@ -36,19 +35,20 @@ final class CloseTrackedTrait<T extends CloseTracked<T>> implements CloseTracked
         if (transactionChainRegistry.isDebugContextEnabled()) {
             // NB: We're NOT doing the (expensive) getStackTrace() here just yet (only below)
             // TODO When we're on Java 9, then instead use the new java.lang.StackWalker API..
-            this.allocationContext = new Throwable();
+            allocationContext = new Throwable();
         } else {
-            this.allocationContext = null;
+            allocationContext = null;
         }
         this.realCloseTracked = requireNonNull(realCloseTracked, "realCloseTracked");
-        this.closeTrackedRegistry = requireNonNull(transactionChainRegistry, "transactionChainRegistry");
-        this.closeTrackedRegistry.add(this);
+        closeTrackedRegistry = requireNonNull(transactionChainRegistry, "transactionChainRegistry");
+        closeTrackedRegistry.add(this);
     }
 
     @Override
     @SuppressFBWarnings("PZLA_PREFER_ZERO_LENGTH_ARRAYS")
     public @Nullable StackTraceElement[] getAllocationContextStackTrace() {
-        return allocationContext != null ? allocationContext.getStackTrace() : null;
+        final var local = allocationContext;
+        return local != null ? local.getStackTrace() : null;
     }
 
     public void removeFromTrackedRegistry() {
index 9b33cabe80dc06de24c4a37b5b376b9897b91372..e7560e7b0324464c333a4dd07ebc0eff90606207 100644 (file)
@@ -9,8 +9,6 @@ package org.opendaylight.mdsal.trace.impl;
 
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.MutableClassToInstanceMap;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.io.PrintStream;
 import java.util.ArrayList;
@@ -40,7 +38,6 @@ import org.slf4j.LoggerFactory;
 
 @SuppressWarnings("checkstyle:JavadocStyle")
 //...because otherwise it whines about the elements in the @code block even though it's completely valid Javadoc
-
 /**
  * TracingBroker logs "write" operations and listener registrations to the md-sal. It logs the instance identifier path,
  * the objects themselves, as well as the stack trace of the call invoking the registration or write operation.
@@ -94,7 +91,6 @@ import org.slf4j.LoggerFactory;
  *        watchRegistrations and allow all registrations to be logged.
  *     </li>
  * </ul>
- *
  */
 public class TracingBroker implements TracingDOMDataBroker {
     @SuppressFBWarnings("SLF4J_LOGGER_SHOULD_BE_PRIVATE")
@@ -312,29 +308,24 @@ public class TracingBroker implements TracingDOMDataBroker {
     }
 
     @Override
-    public ClassToInstanceMap<DOMDataBrokerExtension> getExtensions() {
-        final ClassToInstanceMap<DOMDataBrokerExtension> delegateExt = delegate.getExtensions();
-        final DOMDataTreeChangeService treeChangeSvc = delegateExt.getInstance(DOMDataTreeChangeService.class);
-        if (treeChangeSvc == null) {
-            return delegateExt;
-        }
-
-        final ClassToInstanceMap<DOMDataBrokerExtension> res = MutableClassToInstanceMap.create(delegateExt);
-        res.put(DOMDataTreeChangeService.class, new DOMDataTreeChangeService() {
-            @Override
-            public <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerDataTreeChangeListener(
-                    final DOMDataTreeIdentifier domDataTreeIdentifier, final L listener) {
-                if (isRegistrationWatched(domDataTreeIdentifier.getRootIdentifier(),
-                        domDataTreeIdentifier.getDatastoreType())) {
-                    LOG.warn("{} registration (registerDataTreeChangeListener) for {} from {}.",
+    public <T extends DOMDataBrokerExtension> T extension(final Class<T> type) {
+        final var ext = delegate.extension(type);
+        if (DOMDataTreeChangeService.class.equals(type) && ext instanceof DOMDataTreeChangeService treeChange) {
+            return type.cast(new DOMDataTreeChangeService() {
+                @Override
+                public <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerDataTreeChangeListener(
+                        final DOMDataTreeIdentifier domDataTreeIdentifier, final L listener) {
+                    final var rootId = domDataTreeIdentifier.getRootIdentifier();
+                    if (isRegistrationWatched(rootId, domDataTreeIdentifier.getDatastoreType())) {
+                        LOG.warn("{} registration (registerDataTreeChangeListener) for {} from {}.",
                             listener instanceof ClusteredDOMDataTreeChangeListener ? "Clustered" : "Non-clustered",
-                            toPathString(domDataTreeIdentifier.getRootIdentifier()), getStackSummary());
+                            toPathString(rootId), getStackSummary());
+                    }
+                    return treeChange.registerDataTreeChangeListener(domDataTreeIdentifier, listener);
                 }
-                return treeChangeSvc.registerDataTreeChangeListener(domDataTreeIdentifier, listener);
-            }
-        });
-
-        return res;
+            });
+        }
+        return ext;
     }
 
     @Override