Allow URL provider to be updated dynamically 02/113002/5
authorRobert Varga <robert.varga@pantheon.tech>
Tue, 6 Aug 2024 20:51:14 +0000 (22:51 +0200)
committerRobert Varga <nite@hq.sk>
Wed, 7 Aug 2024 08:47:13 +0000 (08:47 +0000)
Constructor injection is causing a restart, which in turn leads to CSS
provider restart (as it is briefly unused).

Make the URL provider ReferencePolicy.DYNAMIC, allowing it to be updated
without further churn.

JIRA: NETCONF-1356
Change-Id: I2ec8123ae5d6d1cc588491338b4e637e4ccad7bf
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
apps/yanglib-mdsal-writer/src/main/java/org/opendaylight/netconf/yanglib/writer/EmptyYangLibrarySchemaSourceUrlProvider.java [new file with mode: 0644]
apps/yanglib-mdsal-writer/src/main/java/org/opendaylight/netconf/yanglib/writer/YangLibraryWriter.java
apps/yanglib-mdsal-writer/src/main/java/org/opendaylight/netconf/yanglib/writer/YangLibraryWriterSingleton.java
apps/yanglib-mdsal-writer/src/test/java/org/opendaylight/netconf/yanglib/writer/YangLibraryWriterTest.java

diff --git a/apps/yanglib-mdsal-writer/src/main/java/org/opendaylight/netconf/yanglib/writer/EmptyYangLibrarySchemaSourceUrlProvider.java b/apps/yanglib-mdsal-writer/src/main/java/org/opendaylight/netconf/yanglib/writer/EmptyYangLibrarySchemaSourceUrlProvider.java
new file mode 100644 (file)
index 0000000..98c4534
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2024 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.netconf.yanglib.writer;
+
+import com.google.common.base.MoreObjects;
+import java.util.Set;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
+import org.opendaylight.yangtools.yang.common.Revision;
+
+@NonNullByDefault
+final class EmptyYangLibrarySchemaSourceUrlProvider implements YangLibrarySchemaSourceUrlProvider {
+    static final YangLibrarySchemaSourceUrlProvider INSTANCE = new EmptyYangLibrarySchemaSourceUrlProvider();
+
+    private EmptyYangLibrarySchemaSourceUrlProvider() {
+        // Hidden on purpose
+    }
+
+    @Override
+    public Set<Uri> getSchemaSourceUrl(final String moduleSetName, final String moduleName,
+            final @Nullable Revision revision) {
+        return Set.of();
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this).toString();
+    }
+}
index beb5a645bd5e2e2029f2d95c973dca7c3a6e1988..08d47459e3c5358793b702fe3d15913e2eae69da 100644 (file)
@@ -44,16 +44,18 @@ final class YangLibraryWriter implements FutureCallback<Empty> {
 
     private final AtomicLong idCounter = new AtomicLong();
     private final AtomicBoolean closed = new AtomicBoolean();
-    private final @NonNull YangLibrarySchemaSourceUrlProvider urlProvider;
+    private final DOMSchemaService schemaService;
     private final DataBroker dataBroker;
     private final boolean writeLegacy;
     private final Registration reg;
 
     // FIXME: this really should be a dynamically-populated shard (i.e. no write operations whatsoever)!
+    private @NonNull YangLibrarySchemaSourceUrlProvider urlProvider;
     private TransactionChain currentChain;
 
     YangLibraryWriter(final DOMSchemaService schemaService, final DataBroker dataBroker,
             final boolean writeLegacy, final YangLibrarySchemaSourceUrlProvider urlProvider) {
+        this.schemaService = requireNonNull(schemaService);
         this.dataBroker = requireNonNull(dataBroker);
         this.urlProvider = requireNonNull(urlProvider);
         this.writeLegacy = writeLegacy;
@@ -104,7 +106,17 @@ final class YangLibraryWriter implements FutureCallback<Empty> {
         return future;
     }
 
-    private void onModelContextUpdated(final EffectiveModelContext context) {
+    synchronized void setUrlProvider(final @NonNull YangLibrarySchemaSourceUrlProvider urlProvider) {
+        LOG.debug("Triggering update with {}", urlProvider);
+        this.urlProvider = requireNonNull(urlProvider);
+        updateModelContext(schemaService.getGlobalContext());
+    }
+
+    private synchronized void onModelContextUpdated(final EffectiveModelContext context) {
+        updateModelContext(context);
+    }
+
+    private void updateModelContext(final EffectiveModelContext context) {
         if (context.findModule(YangLibrary.QNAME.getModule()).isPresent()) {
             updateYangLibrary(context);
         } else {
@@ -112,7 +124,7 @@ final class YangLibraryWriter implements FutureCallback<Empty> {
         }
     }
 
-    private synchronized void updateYangLibrary(final EffectiveModelContext context) {
+    private void updateYangLibrary(final EffectiveModelContext context) {
         if (closed.get()) {
             // Already shut down, do not do anything
             LOG.debug("ietf-yang-library writer closed, skipping update");
index 178e69644ccfc35ed64194b11f8e874a1ed51be3..ef7902293516a533d7524ce65797903e817f8e14 100644 (file)
@@ -9,10 +9,8 @@ package org.opendaylight.netconf.yanglib.writer;
 
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.annotations.VisibleForTesting;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Optional;
-import java.util.Set;
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -30,6 +28,7 @@ import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
 import org.osgi.service.component.annotations.Reference;
 import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
 import org.osgi.service.component.annotations.ReferencePolicyOption;
 import org.osgi.service.metatype.annotations.AttributeDefinition;
 import org.osgi.service.metatype.annotations.Designate;
@@ -53,11 +52,11 @@ public final class YangLibraryWriterSingleton implements ClusterSingletonService
     private static final Logger LOG = LoggerFactory.getLogger(YangLibraryWriterSingleton.class);
     private static final @NonNull ServiceGroupIdentifier SGI = new ServiceGroupIdentifier("yanglib-mdsal-writer");
 
-    private final @NonNull YangLibrarySchemaSourceUrlProvider urlProvider;
     private final DOMSchemaService schemaService;
     private final DataBroker dataBroker;
     private final boolean writeLegacy;
 
+    private @NonNull YangLibrarySchemaSourceUrlProvider urlProvider;
     private YangLibraryWriter instance;
     private Registration reg;
 
@@ -87,12 +86,29 @@ public final class YangLibraryWriterSingleton implements ClusterSingletonService
     @Activate
     public YangLibraryWriterSingleton(@Reference final ClusterSingletonServiceProvider cssProvider,
             @Reference final DOMSchemaService schemaService, @Reference final DataBroker dataBroker,
-            @Reference(cardinality = ReferenceCardinality.OPTIONAL, policyOption = ReferencePolicyOption.GREEDY)
-                final @Nullable YangLibrarySchemaSourceUrlProvider urlProvider,
             final Configuration configuration) {
-        this(cssProvider, schemaService, dataBroker, configuration.write$_$legacy(), urlProvider);
+        this(cssProvider, schemaService, dataBroker, configuration.write$_$legacy(), null);
     }
 
+    @Reference(cardinality = ReferenceCardinality.OPTIONAL, policyOption = ReferencePolicyOption.GREEDY,
+               policy = ReferencePolicy.DYNAMIC, unbind = "unsetUrlProvider")
+    synchronized void setUrlProvider(final YangLibrarySchemaSourceUrlProvider urlProvider) {
+        LOG.info("Binding URL provider {}", urlProvider);
+        updateUrlProvider(requireNonNull(urlProvider));
+    }
+
+    synchronized void unsetUrlProvider(final YangLibrarySchemaSourceUrlProvider oldUrlProvider) {
+        LOG.info("Unbinding URL provider {}", oldUrlProvider);
+        updateUrlProvider(EmptyYangLibrarySchemaSourceUrlProvider.INSTANCE);
+    }
+
+    private void updateUrlProvider(final @NonNull YangLibrarySchemaSourceUrlProvider newUrlProvider) {
+        urlProvider = newUrlProvider;
+        final var local = instance;
+        if (local != null) {
+            local.setUrlProvider(newUrlProvider);
+        }
+    }
 
     @Deactivate
     @PreDestroy
@@ -110,12 +126,7 @@ public final class YangLibraryWriterSingleton implements ClusterSingletonService
 
     private static @NonNull YangLibrarySchemaSourceUrlProvider orEmptyProvider(
             final @Nullable YangLibrarySchemaSourceUrlProvider urlProvider) {
-        return urlProvider != null ? urlProvider : emptyProvider();
-    }
-
-    @VisibleForTesting
-    static @NonNull YangLibrarySchemaSourceUrlProvider emptyProvider() {
-        return (moduleSetName, moduleName, revision) -> Set.of();
+        return urlProvider != null ? urlProvider : EmptyYangLibrarySchemaSourceUrlProvider.INSTANCE;
     }
 
     @Override
index 19f5f17c143fcf0079ab68eb8c24d77d298f7e8a..3f5972771b1938b0bcbd06271a0d434f4f23ba4e 100644 (file)
@@ -98,7 +98,7 @@ class YangLibraryWriterTest {
     void noUpdate() {
         writer = new YangLibraryWriter(new FixedDOMSchemaService(parseYangResources(YangLibraryWriterTest.class,
             "/test-module.yang", "/test-submodule.yang")), dataBroker, NO_LEGACY,
-            YangLibraryWriterSingleton.emptyProvider());
+            EmptyYangLibrarySchemaSourceUrlProvider.INSTANCE);
         verifyNoInteractions(dataBroker);
     }
 
@@ -113,7 +113,7 @@ class YangLibraryWriterTest {
         writer = new YangLibraryWriter(new FixedDOMSchemaService(parseYangResources(YangLibraryWriterTest.class,
             "/test-module.yang", "/test-submodule.yang", "/test-more.yang", "/ietf-yang-library@2019-01-04.yang",
             "/ietf-datastores@2018-02-14.yang", "/ietf-yang-types.yang", "/ietf-inet-types.yang")), dataBroker,
-            writeLegacy, withUrls ? URL_PROVIDER : YangLibraryWriterSingleton.emptyProvider());
+            writeLegacy, withUrls ? URL_PROVIDER : EmptyYangLibrarySchemaSourceUrlProvider.INSTANCE);
 
         verify(writeTransaction).put(eq(OPERATIONAL), eq(YANG_LIBRARY_PATH), yangLibraryCaptor.capture());
         assertEquals(expectedData, yangLibraryCaptor.getValue());
@@ -144,7 +144,7 @@ class YangLibraryWriterTest {
         doReturn(registration).when(schemaService).registerSchemaContextListener(any());
 
         assertNotNull(new YangLibraryWriter(schemaService, dataBroker, writeLegacy,
-            YangLibraryWriterSingleton.emptyProvider()).shutdown());
+            EmptyYangLibrarySchemaSourceUrlProvider.INSTANCE).shutdown());
         verify(writeTransaction).delete(OPERATIONAL, YANG_LIBRARY_PATH);
         verify(writeTransaction).delete(OPERATIONAL, MODULES_STATE_PATH);
         verify(writeTransaction).commit();