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;
}
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() {
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;
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,
--- /dev/null
+/*
+ * 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;
+ }
+}
+++ /dev/null
-/*
- * 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");
- }
- }
-}
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;
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());
}
@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