Refactor RpcRoutingStrategy 13/103313/2
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 21 Nov 2022 18:47:31 +0000 (19:47 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 22 Nov 2022 13:45:17 +0000 (14:45 +0100)
RpcRoutingStrategy is not really a nice construct -- it essentially
extracts context information, not much more. As such, dealing with two
subclasses is a drag.

Intruduce ContentRoutedRpcContext to capture the interesting information
in a record and adjust users to deal with the fact that normal RPCs do
not have this construct.

Change-Id: I2c8d24a61e6905063c9eb93fb0513dffe4831b66
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/RpcServiceAdapter.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/DOMRpcRoutingTable.java
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ContentRoutedRpcContext.java [new file with mode: 0644]
dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/RpcRoutingStrategy.java [deleted file]
dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/ContentRoutedRpcContextTest.java [moved from dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/RpcRoutingStrategyTest.java with 53% similarity]

index f0023fa1856419e467d5e0fef08d857cabe2a157..9e7bbc367d433939b57956c1b0e1dc210ddf767e 100644 (file)
@@ -27,7 +27,7 @@ import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSeriali
 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
 import org.opendaylight.mdsal.dom.api.DOMRpcResult;
 import org.opendaylight.mdsal.dom.api.DOMRpcService;
-import org.opendaylight.mdsal.dom.spi.RpcRoutingStrategy;
+import org.opendaylight.mdsal.dom.spi.ContentRoutedRpcContext;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -68,10 +68,10 @@ class RpcServiceAdapter implements InvocationHandler {
     }
 
     private RpcInvocationStrategy createStrategy(final Method method, final RpcDefinition schema) {
-        final QName rpcType = schema.getQName();
-        final RpcRoutingStrategy strategy = RpcRoutingStrategy.from(schema.asEffectiveStatement());
-        return strategy.isContextBasedRouted() ? new RoutedStrategy(rpcType, method, strategy.getLeaf())
-                : new NonRoutedStrategy(rpcType);
+        final var rpcName = schema.getQName();
+        final var contentContext = ContentRoutedRpcContext.forRpc(schema.asEffectiveStatement());
+        return contentContext == null ? new NonRoutedStrategy(rpcName)
+            : new RoutedStrategy(rpcName, method, contentContext.leaf());
     }
 
     RpcService getProxy() {
index af9bb33b1b85df96bf3fd7e45c5dd235ba25b308..495b040eff590a120f503f160fc020408aa4e92b 100644 (file)
@@ -17,7 +17,7 @@ import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.dom.api.DOMRpcAvailabilityListener;
 import org.opendaylight.mdsal.dom.api.DOMRpcIdentifier;
 import org.opendaylight.mdsal.dom.api.DOMRpcImplementation;
-import org.opendaylight.mdsal.dom.spi.RpcRoutingStrategy;
+import org.opendaylight.mdsal.dom.spi.ContentRoutedRpcContext;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
@@ -60,13 +60,10 @@ final class DOMRpcRoutingTable extends AbstractDOMRoutingTable<DOMRpcIdentifier,
             return new UnknownDOMRpcRoutingTableEntry(key, implementations);
         }
 
-        final RpcRoutingStrategy strategy = RpcRoutingStrategy.from(rpcDef);
-        if (strategy.isContextBasedRouted()) {
-            return new RoutedDOMRpcRoutingTableEntry(rpcDef.argument(), YangInstanceIdentifier.of(strategy.getLeaf()),
+        final var contentContext = ContentRoutedRpcContext.forRpc(rpcDef);
+        return contentContext == null ? new GlobalDOMRpcRoutingTableEntry(rpcDef.argument(), implementations)
+            : new RoutedDOMRpcRoutingTableEntry(rpcDef.argument(), YangInstanceIdentifier.of(contentContext.leaf()),
                 implementations);
-        }
-
-        return new GlobalDOMRpcRoutingTableEntry(rpcDef.argument(), implementations);
     }
 
     private static @Nullable RpcEffectiveStatement findRpcDefinition(final EffectiveModelContext context,
diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ContentRoutedRpcContext.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/ContentRoutedRpcContext.java
new file mode 100644 (file)
index 0000000..122b2d3
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2022 PANTHEON.tech, s.r.o.
+ *
+ * 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 static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.odlext.model.api.ContextReferenceEffectiveStatement;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.stmt.InputEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+
+/**
+ * Information pertaining to the concept of {@code Routed RPCs}. "Routed" in this context means being bound to a certain
+ * data tree node, identified by a {@code leaf} within the RPC input. This is very much similar to a RFC7950
+ * {@code action}, except it operates strictly within the confines of RFC6020.
+ *
+ * @param identity QName which refers RPC Routing context {@code identity}
+ * @param leaf QName of the leaf in which RPC Route is stored
+ */
+public record ContentRoutedRpcContext(@NonNull QName identity, @NonNull QName leaf) {
+    public ContentRoutedRpcContext {
+        requireNonNull(identity);
+        requireNonNull(identity);
+    }
+
+    /**
+     * Attempt to construct a {@link ContentRoutedRpcContext} for a particular {@code rpc}.
+     *
+     * @param rpc RPC statement
+     * @return A {@link ContentRoutedRpcContext}, or {@code null} if the RPC does not contain context information
+     */
+    public static @Nullable ContentRoutedRpcContext forRpc(final RpcEffectiveStatement rpc) {
+        final var input = rpc.findFirstEffectiveSubstatement(InputEffectiveStatement.class)
+            .orElseThrow(() -> new IllegalArgumentException("Cannot find input in " + rpc));
+
+        for (var stmt : input.effectiveSubstatements()) {
+            // TODO: LeafEffectiveStatement instead? Because that is what we are promising for #leaf()'s QName
+            if (stmt instanceof SchemaTreeEffectiveStatement<?> schemaStmt) {
+                final var context =
+                    stmt.findFirstEffectiveSubstatementArgument(ContextReferenceEffectiveStatement.class);
+                if (context.isPresent()) {
+                    return new ContentRoutedRpcContext(context.orElseThrow(), schemaStmt.argument());
+                }
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/RpcRoutingStrategy.java b/dom/mdsal-dom-spi/src/main/java/org/opendaylight/mdsal/dom/spi/RpcRoutingStrategy.java
deleted file mode 100644 (file)
index f352893..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) 2014 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.spi;
-
-import static java.util.Objects.requireNonNull;
-
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.concepts.Identifiable;
-import org.opendaylight.yangtools.odlext.model.api.ContextReferenceEffectiveStatement;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.stmt.InputEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
-
-public abstract sealed class RpcRoutingStrategy implements Identifiable<QName> {
-    private final @NonNull QName identifier;
-
-    private RpcRoutingStrategy(final QName identifier) {
-        this.identifier = requireNonNull(identifier);
-    }
-
-    /**
-     * Returns leaf QName in which RPC Route is stored.
-     * @return leaf QName in which RPC Route is stored
-     * @throws UnsupportedOperationException If RPC is not content routed.
-     *      ({@link #isContextBasedRouted()} returned <code>false</code>)
-     */
-    public abstract QName getLeaf();
-
-    /**
-     * Returns identity QName which represents RPC Routing context.
-     * @return identity QName which represents RPC Routing context
-     * @throws UnsupportedOperationException If RPC is not content routed.
-     *      ({@link #isContextBasedRouted()} returned <code>false</code>)
-     */
-    public abstract QName getContext();
-
-    @Override
-    public final QName getIdentifier() {
-        return identifier;
-    }
-
-    /**
-     * Returns true if RPC is routed by context.
-     *
-     * @return true if RPC is routed by content.
-     */
-    public abstract boolean isContextBasedRouted();
-
-    public static @NonNull RpcRoutingStrategy from(final RpcEffectiveStatement rpc) {
-        // FIXME: deprecate context-reference
-        return of(rpc.argument(), rpc.findFirstEffectiveSubstatement(InputEffectiveStatement.class)
-            .orElseThrow(() -> new IllegalArgumentException("Cannot find input in " + rpc)));
-    }
-
-    private static @NonNull RpcRoutingStrategy of(final QName rpcName, final InputEffectiveStatement input) {
-        for (var stmt : input.effectiveSubstatements()) {
-            if (stmt instanceof SchemaTreeEffectiveStatement<?> schemaStmt) {
-                final var context =
-                    stmt.findFirstEffectiveSubstatementArgument(ContextReferenceEffectiveStatement.class);
-                if (context.isPresent()) {
-                    return new RoutedRpcStrategy(rpcName, context.orElseThrow(), schemaStmt.argument());
-                }
-            }
-        }
-        return new GlobalRpcStrategy(rpcName);
-    }
-
-    private static final class RoutedRpcStrategy extends RpcRoutingStrategy {
-        private final QName context;
-        private final QName leaf;
-
-        private RoutedRpcStrategy(final QName identifier, final QName ctx, final QName leaf) {
-            super(identifier);
-            context = requireNonNull(ctx);
-            this.leaf = requireNonNull(leaf);
-        }
-
-        @Override
-        public QName getContext() {
-            return context;
-        }
-
-        @Override
-        public QName getLeaf() {
-            return leaf;
-        }
-
-        @Override
-        public boolean isContextBasedRouted() {
-            return true;
-        }
-    }
-
-    private static final class GlobalRpcStrategy extends RpcRoutingStrategy {
-        GlobalRpcStrategy(final QName identifier) {
-            super(identifier);
-        }
-
-        @Override
-        public boolean isContextBasedRouted() {
-            return false;
-        }
-
-        @Override
-        public QName getContext() {
-            throw new UnsupportedOperationException("Non-routed strategy does not have a context");
-        }
-
-        @Override
-        public QName getLeaf() {
-            throw new UnsupportedOperationException("Non-routed strategy does not have a context");
-        }
-    }
-}
similarity index 53%
rename from dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/RpcRoutingStrategyTest.java
rename to dom/mdsal-dom-spi/src/test/java/org/opendaylight/mdsal/dom/spi/ContentRoutedRpcContextTest.java
index 07bebbd34a6d04a3ccefd96d617866b6c3911a86..be1b6b368297b70454602805d052463447f3b347 100644 (file)
@@ -8,12 +8,9 @@
 package org.opendaylight.mdsal.dom.spi;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
 
-import com.google.common.collect.Iterables;
 import java.util.List;
 import java.util.stream.Collectors;
 import org.junit.AfterClass;
@@ -21,23 +18,22 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.yang.extension.yang.ext.rev130709.$YangModuleInfoImpl;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
 import org.opendaylight.yangtools.yang.parser.api.YangParserConfiguration;
 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
 
-public class RpcRoutingStrategyTest {
+public class ContentRoutedRpcContextTest {
     private static List<RpcEffectiveStatement> RPCS;
 
     @BeforeClass
     public static void beforeClass() {
-        final EffectiveModelContext ctx = YangParserTestUtils.parseYangSources(YangParserConfiguration.DEFAULT, null,
+        final var ctx = YangParserTestUtils.parseYangSources(YangParserConfiguration.DEFAULT, null,
             YangTextSchemaSource.delegateForByteSource("yang-ext.yang",
                 $YangModuleInfoImpl.getInstance().getYangTextByteSource()),
-            YangTextSchemaSource.forResource(RpcRoutingStrategy.class, "/rpc-routing-strategy.yang"));
+            YangTextSchemaSource.forResource(ContentRoutedRpcContext.class, "/rpc-routing-strategy.yang"));
 
-        RPCS = Iterables.getOnlyElement(ctx.findModuleStatements("foo"))
+        RPCS = ctx.findModuleStatements("foo").iterator().next()
             .streamEffectiveSubstatements(RpcEffectiveStatement.class)
             .collect(Collectors.toUnmodifiableList());
     }
@@ -49,23 +45,15 @@ public class RpcRoutingStrategyTest {
 
     @Test
     public void unroutedRpcStrategyTest() {
-        final RpcRoutingStrategy strategy = RpcRoutingStrategy.from(Iterables.get(RPCS, 1));
-        assertNotNull(strategy);
-
-        assertEquals(QName.create("foo", "unrouted"), strategy.getIdentifier());
-        assertFalse(strategy.isContextBasedRouted());
-        assertThrows(UnsupportedOperationException.class, () -> strategy.getLeaf());
-        assertThrows(UnsupportedOperationException.class, () -> strategy.getContext());
+        assertNull(ContentRoutedRpcContext.forRpc(RPCS.get(1)));
     }
 
     @Test
     public void routedRpcStrategyTest() {
-        final RpcRoutingStrategy strategy = RpcRoutingStrategy.from(Iterables.get(RPCS, 0));
-        assertNotNull(strategy);
+        final var context = ContentRoutedRpcContext.forRpc(RPCS.get(0));
+        assertNotNull(context);
 
-        assertEquals(QName.create("foo", "routed"), strategy.getIdentifier());
-        assertTrue(strategy.isContextBasedRouted());
-        assertEquals(QName.create("foo", "identity"), strategy.getContext());
-        assertEquals(QName.create("foo", "ctx"), strategy.getLeaf());
+        assertEquals(QName.create("foo", "identity"), context.identity());
+        assertEquals(QName.create("foo", "ctx"), context.leaf());
     }
 }
\ No newline at end of file