import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.nb.rfc8040.ReadDataParams;
-import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
-import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
-import org.opendaylight.restconf.nb.rfc8040.utils.parser.NetconfFieldsTranslator;
-import org.opendaylight.restconf.nb.rfc8040.utils.parser.WriterFieldsTranslator;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
return builder.build();
}
- public static QueryParameters newQueryParameters(final ReadDataParams params,
- final InstanceIdentifierContext identifier) {
- final var fields = params.fields();
- if (fields == null) {
- return QueryParameters.of(params);
- }
-
- return identifier.getMountPoint() != null
- ? QueryParameters.ofFieldPaths(params, NetconfFieldsTranslator.translate(identifier, fields))
- : QueryParameters.ofFields(params, WriterFieldsTranslator.translate(identifier, fields));
- }
-
/**
* Parse parameters from URI request and check their types and values.
*
import org.opendaylight.restconf.api.query.FieldsParam;
import org.opendaylight.restconf.api.query.FieldsParam.NodeSelector;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
-import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
import org.opendaylight.yangtools.yang.common.Empty;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
* Translate a {@link FieldsParam} to a list of child node paths saved in lists, suitable for use with
* {@link NetconfDataTreeService}.
*
- * @param identifier identifier context created from request URI
+ * @param modelContext EffectiveModelContext
+ * @param schemaNode Root DataSchemaNode
* @param input input value of fields parameter
* @return {@link List} of {@link YangInstanceIdentifier} that are relative to the last {@link PathArgument}
- * of provided {@code identifier}
+ * of provided {@code identifier}
*/
public static @NonNull List<YangInstanceIdentifier> translate(
- final @NonNull InstanceIdentifierContext identifier, final @NonNull FieldsParam input) {
- final var parsed = parseFields(identifier, input);
- return parsed.stream().map(NetconfFieldsTranslator::buildPath).toList();
+ final @NonNull EffectiveModelContext modelContext, final @NonNull DataSchemaNode schemaNode,
+ final @NonNull FieldsParam input) {
+ return parseFields(modelContext, schemaNode, input).stream()
+ .map(NetconfFieldsTranslator::buildPath)
+ .toList();
}
- private static @NonNull Set<LinkedPathElement> parseFields(final @NonNull InstanceIdentifierContext identifier,
- final @NonNull FieldsParam input) {
+ private static @NonNull Set<LinkedPathElement> parseFields(final @NonNull EffectiveModelContext modelContext,
+ final @NonNull DataSchemaNode schemaNode, final @NonNull FieldsParam input) {
final DataSchemaContext startNode;
try {
- startNode = DataSchemaContext.of((DataSchemaNode) identifier.getSchemaNode());
+ startNode = DataSchemaContext.of(schemaNode);
} catch (IllegalStateException e) {
throw new RestconfDocumentedException(
"Start node missing in " + input, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, e);
}
final var parsed = new HashSet<LinkedPathElement>();
- processSelectors(parsed, identifier.getSchemaContext(), identifier.getSchemaNode().getQName().getModule(),
+ processSelectors(parsed, modelContext, schemaNode.getQName().getModule(),
new LinkedPathElement(null, List.of(), startNode), input.nodeSelectors());
return parsed;
import org.opendaylight.restconf.api.query.FieldsParam.NodeSelector;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.jersey.providers.ParameterAwareNormalizedNodeWriter;
-import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.common.QName;
* Translate a {@link FieldsParam} to a complete list of child nodes organized into levels, suitable for use with
* {@link ParameterAwareNormalizedNodeWriter}.
*
- * @param identifier identifier context created from request URI
+ * @param modelContext EffectiveModelContext
+ * @param schemaNode Root DataSchemaNode
* @param input input value of fields parameter
* @return {@link List} of levels; each level contains set of {@link QName}
*/
- public static @NonNull List<Set<QName>> translate(final @NonNull InstanceIdentifierContext identifier,
- final @NonNull FieldsParam input) {
- final DataSchemaContext startNode = DataSchemaContext.of((DataSchemaNode) identifier.getSchemaNode());
- if (startNode == null) {
+ public static @NonNull List<Set<QName>> translate(final @NonNull EffectiveModelContext modelContext,
+ final DataSchemaNode schemaNode, final @NonNull FieldsParam input) {
+ if (schemaNode == null) {
throw new RestconfDocumentedException(
"Start node missing in " + input, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
}
-
final var parsed = new ArrayList<Set<QName>>();
- processSelectors(parsed, identifier.getSchemaContext(), identifier.getSchemaNode().getQName().getModule(),
- startNode, input.nodeSelectors(), 0);
+ processSelectors(parsed, modelContext, schemaNode.getQName().getModule(), DataSchemaContext.of(schemaNode),
+ input.nodeSelectors(), 0);
return parsed;
}
return currentNode;
}
-}
\ No newline at end of file
+}
import org.opendaylight.restconf.nb.rfc8040.databind.OperationInputBody;
import org.opendaylight.restconf.nb.rfc8040.databind.PatchBody;
import org.opendaylight.restconf.nb.rfc8040.databind.ResourceBody;
-import org.opendaylight.restconf.nb.rfc8040.databind.jaxrs.QueryParams;
import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
+import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.utils.parser.NetconfFieldsTranslator;
+import org.opendaylight.restconf.nb.rfc8040.utils.parser.WriterFieldsTranslator;
import org.opendaylight.restconf.server.api.DataPostResult;
import org.opendaylight.restconf.server.api.DataPostResult.CreateResource;
import org.opendaylight.restconf.server.api.DataPostResult.InvokeOperation;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
private @NonNull RestconfFuture<NormalizedNodePayload> readData(final InstanceIdentifierContext reqPath,
final ReadDataParams readParams) {
- final var queryParams = QueryParams.newQueryParameters(readParams, reqPath);
+ final var fields = readParams.fields();
+ final QueryParameters queryParams;
+ if (fields != null) {
+ final var modelContext = reqPath.getSchemaContext();
+ final var schemaNode = (DataSchemaNode) reqPath.getSchemaNode();
+ if (reqPath.getMountPoint() != null) {
+ queryParams = QueryParameters.ofFieldPaths(readParams, NetconfFieldsTranslator.translate(modelContext,
+ schemaNode, fields));
+ } else {
+ queryParams = QueryParameters.ofFields(readParams, WriterFieldsTranslator.translate(modelContext,
+ schemaNode, fields));
+ }
+ } else {
+ queryParams = QueryParameters.of(readParams);
+ }
+
final var fieldPaths = queryParams.fieldPaths();
final var strategy = getRestconfStrategy(reqPath.getSchemaContext(), reqPath.getMountPoint());
final NormalizedNode node;
import org.opendaylight.restconf.nb.rfc8040.ReceiveEventsParams;
import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
+import org.opendaylight.restconf.nb.rfc8040.utils.parser.WriterFieldsTranslator;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.stmt.ContainerEffectiveStatement;
assertEquals(ContentParam.CONFIG, params.content());
// depth
- final DepthParam depth = params.depth();
+ final var depth = params.depth();
assertNotNull(depth);
assertEquals(10, depth.value());
// fields
- assertNotNull(params.fields());
+ final var paramsFields = params.fields();
+ assertNotNull(paramsFields);
// fields for write filtering
final var containerSchema = mock(ContainerSchemaNode.class,
final var stack = SchemaInferenceStack.of(context);
stack.enterSchemaTree(containerQName);
+ final var iid = InstanceIdentifierContext.ofStack(stack);
- final QueryParameters queryParameters = QueryParams.newQueryParameters(params,
- InstanceIdentifierContext.ofStack(stack));
- final List<Set<QName>> fields = queryParameters.fields();
+ final var queryParameters = QueryParameters.ofFields(params, WriterFieldsTranslator.translate(
+ iid.getSchemaContext(), (DataSchemaNode) iid.getSchemaNode(), paramsFields));
+ final var fields = queryParameters.fields();
assertNotNull(fields);
assertEquals(1, fields.size());
assertEquals(Set.of(containerChild), fields.get(0));
*/
package org.opendaylight.restconf.nb.rfc8040.utils.parser;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import java.text.ParseException;
import java.util.List;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.Revision;
import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
private static final QNameModule Q_NAME_MODULE_FOO = QNameModule.create(
XMLNamespace.of("urn:foo"), Revision.of("2023-03-27"));
- private InstanceIdentifierContext identifierJukebox;
- private InstanceIdentifierContext identifierTestServices;
- private InstanceIdentifierContext identifierFoo;
+ private static final EffectiveModelContext TEST_SERVICES_SCHEMA =
+ YangParserTestUtils.parseYangResourceDirectory("/test-services");
+ private static final EffectiveModelContext FOO_SCHEMA =
+ YangParserTestUtils.parseYangResourceDirectory("/same-qname-nodes");
+ private DataSchemaNode jukeboxSchemaNode;
+ private DataSchemaNode testServices;
+ private DataSchemaNode foo;
// container augmented library
protected static final QName AUGMENTED_LIBRARY_Q_NAME = QName.create(Q_NAME_MODULE_AUGMENTED_JUKEBOX,
@Before
public void setUp() {
- identifierJukebox = InstanceIdentifierContext.ofStack(
- SchemaInferenceStack.ofDataTreePath(JUKEBOX_SCHEMA, JUKEBOX_QNAME));
-
- identifierTestServices = InstanceIdentifierContext.ofStack(
- SchemaInferenceStack.ofDataTreePath(YangParserTestUtils.parseYangResourceDirectory("/test-services"),
- TEST_DATA_Q_NAME));
-
- identifierFoo = InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(
- YangParserTestUtils.parseYangResourceDirectory("/same-qname-nodes"), FOO_Q_NAME));
+ jukeboxSchemaNode = assertInstanceOf(DataSchemaNode.class, InstanceIdentifierContext.ofStack(
+ SchemaInferenceStack.ofDataTreePath(JUKEBOX_SCHEMA, JUKEBOX_QNAME)).getSchemaNode());
+ testServices = assertInstanceOf(DataSchemaNode.class, InstanceIdentifierContext.ofStack(
+ SchemaInferenceStack.ofDataTreePath(TEST_SERVICES_SCHEMA, TEST_DATA_Q_NAME)).getSchemaNode());
+ foo = assertInstanceOf(DataSchemaNode.class, InstanceIdentifierContext.ofStack(
+ SchemaInferenceStack.ofDataTreePath(FOO_SCHEMA, FOO_Q_NAME)).getSchemaNode());
}
- protected abstract List<T> translateFields(InstanceIdentifierContext context, FieldsParam fields);
+ protected abstract List<T> translateFields(@NonNull EffectiveModelContext modelContext,
+ @NonNull DataSchemaNode schemaNode, @NonNull FieldsParam fields);
/**
* Test parse fields parameter containing only one child selected.
*/
@Test
public void testSimplePath() {
- final var result = translateFields(identifierJukebox, assertFields("library"));
+ final var result = translateFields(JUKEBOX_SCHEMA, jukeboxSchemaNode, assertFields("library"));
assertNotNull(result);
assertSimplePath(result);
}
*/
@Test
public void testDoublePath() {
- final var result = translateFields(identifierJukebox, assertFields("library;player"));
+ final var result = translateFields(JUKEBOX_SCHEMA, jukeboxSchemaNode, assertFields("library;player"));
assertNotNull(result);
assertDoublePath(result);
}
*/
@Test
public void testSubPath() {
- final var result = translateFields(identifierJukebox, assertFields("library/artist/album/name"));
+ final var result = translateFields(JUKEBOX_SCHEMA, jukeboxSchemaNode,
+ assertFields("library/artist/album/name"));
assertNotNull(result);
assertSubPath(result);
}
*/
@Test
public void testChildrenPath() {
- final var result = translateFields(identifierJukebox, assertFields("library(artist(album(name)))"));
+ final var result = translateFields(JUKEBOX_SCHEMA, jukeboxSchemaNode,
+ assertFields("library(artist(album(name)))"));
assertNotNull(result);
assertChildrenPath(result);
}
*/
@Test
public void testNamespace() {
- final var result = translateFields(identifierJukebox, assertFields("augmented-jukebox:augmented-library"));
+ final var result = translateFields(JUKEBOX_SCHEMA, jukeboxSchemaNode,
+ assertFields("augmented-jukebox:augmented-library"));
assertNotNull(result);
assertNamespace(result);
}
*/
@Test
public void testMultipleChildren1() {
- final var result = translateFields(identifierTestServices,
+ final var result = translateFields(TEST_SERVICES_SCHEMA, testServices,
assertFields("services(type-of-service;instance/instance-name;instance/provider)"));
assertNotNull(result);
assertMultipleChildren1(result);
*/
@Test
public void testMultipleChildren2() {
- final var result = translateFields(identifierTestServices,
+ final var result = translateFields(TEST_SERVICES_SCHEMA, testServices,
assertFields("services(type-of-service;instance(instance-name;provider))"));
assertNotNull(result);
assertMultipleChildren2(result);
*/
@Test
public void testMultipleChildren3() {
- final var result = translateFields(identifierTestServices,
+ final var result = translateFields(TEST_SERVICES_SCHEMA, testServices,
assertFields("services(instance/instance-name;type-of-service;next-data/next-service)"));
assertNotNull(result);
assertMultipleChildren3(result);
@Test
public void testMultipleChildren4() {
- final var result = translateFields(identifierTestServices,
+ final var result = translateFields(TEST_SERVICES_SCHEMA, testServices,
assertFields("services(type-of-service;instance(instance-name;provider);next-data(next-service))"));
assertNotNull(result);
assertMultipleChildren4(result);
@Test
public void testMultipleChildren5() {
- final var result = translateFields(identifierTestServices,
+ final var result = translateFields(TEST_SERVICES_SCHEMA, testServices,
assertFields("services(type-of-service;instance(instance-name;provider);next-data/next-service)"));
assertNotNull(result);
assertMultipleChildren5(result);
@Test
public void testAugmentedChild() {
- final var result = translateFields(identifierJukebox, assertFields("player/augmented-jukebox:speed"));
+ final var result = translateFields(JUKEBOX_SCHEMA, jukeboxSchemaNode,
+ assertFields("player/augmented-jukebox:speed"));
assertNotNull(result);
assertAugmentedChild(result);
}
@Test
public void testListFieldUnderList() {
- final var result = translateFields(identifierTestServices, assertFields("services/instance"));
+ final var result = translateFields(TEST_SERVICES_SCHEMA, testServices, assertFields("services/instance"));
assertNotNull(result);
assertListFieldUnderList(result);
}
@Test
public void testLeafList() {
- final var result = translateFields(identifierTestServices, assertFields("protocols"));
+ final var result = translateFields(TEST_SERVICES_SCHEMA, testServices, assertFields("protocols"));
assertNotNull(result);
assertLeafList(result);
}
@Test
public void testKeyedList() {
- final var result = translateFields(identifierJukebox, assertFields("library/artist(name)"));
+ final var result = translateFields(JUKEBOX_SCHEMA, jukeboxSchemaNode, assertFields("library/artist(name)"));
assertNotNull(result);
assertKeyedList(result);
}
@Test
public void testDuplicateNodes1() {
- final var result = translateFields(identifierFoo,
+ final var result = translateFields(FOO_SCHEMA, foo,
assertFields("bar(alpha;beta/gamma);baz(alpha;beta/gamma)"));
assertNotNull(result);
assertDuplicateNodes1(result);
@Test
public void testDuplicateNodes2() {
- final var result = translateFields(identifierFoo,
+ final var result = translateFields(FOO_SCHEMA, foo,
assertFields("bar(alpha;beta/delta);baz(alpha;beta/epsilon)"));
assertNotNull(result);
assertDuplicateNodes2(result);
final FieldsParam input = FieldsParam.parse("library(not-existing)");
final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
- () -> translateFields(identifierJukebox, input));
+ () -> translateFields(JUKEBOX_SCHEMA, jukeboxSchemaNode, input));
// Bad request
assertEquals(ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
assertEquals(ErrorTag.INVALID_VALUE, ex.getErrors().get(0).getErrorTag());
}
- private static FieldsParam assertFields(final String input) {
+ private static @NonNull FieldsParam assertFields(final String input) {
try {
return FieldsParam.parse(input);
} catch (ParseException e) {
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.opendaylight.restconf.api.query.FieldsParam;
-import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
/**
* Unit test for {@link NetconfFieldsTranslator}.
@RunWith(MockitoJUnitRunner.class)
public class NetconfFieldsTranslatorTest extends AbstractFieldsTranslatorTest<YangInstanceIdentifier> {
@Override
- protected List<YangInstanceIdentifier> translateFields(final InstanceIdentifierContext context,
- final FieldsParam fields) {
- return NetconfFieldsTranslator.translate(context, fields);
+ protected List<YangInstanceIdentifier> translateFields(final EffectiveModelContext modelContext,
+ final DataSchemaNode schemaNode, final FieldsParam fields) {
+ return NetconfFieldsTranslator.translate(modelContext, schemaNode, fields);
}
@Override
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.opendaylight.restconf.api.query.FieldsParam;
-import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
/**
* Unit test for {@link WriterFieldsTranslator}.
@RunWith(MockitoJUnitRunner.class)
public class WriterFieldsTranslatorTest extends AbstractFieldsTranslatorTest<Set<QName>> {
@Override
- protected List<Set<QName>> translateFields(final InstanceIdentifierContext context, final FieldsParam fields) {
- return WriterFieldsTranslator.translate(context, fields);
+ protected List<Set<QName>> translateFields(final EffectiveModelContext modelContext,
+ final DataSchemaNode schemaNode, final FieldsParam fields) {
+ return WriterFieldsTranslator.translate(modelContext, schemaNode, fields);
}
@Override