*/
package org.opendaylight.restconf.nb.rfc8040.utils.parser;
+import static java.util.Objects.requireNonNull;
+
import java.util.Map.Entry;
import java.util.Set;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.restconf.api.ApiPath;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.server.api.DatabindContext;
* Serializer for {@link YangInstanceIdentifier} to {@link String} for restconf.
*/
public final class YangInstanceIdentifierSerializer {
+ private final @NonNull DatabindContext databind;
- private YangInstanceIdentifierSerializer() {
- // Hidden on purpose
+ public YangInstanceIdentifierSerializer(final DatabindContext databind) {
+ this.databind = requireNonNull(databind);
}
/**
* Method to create String from {@link Iterable} of {@link PathArgument} which are parsing from data with the help
* of an {@link EffectiveModelContext}.
*
- * @param databind for validate of parsing path arguments
- * @param data path to data
+ * @param path path to data
* @return {@link String}
*/
- public static String create(final DatabindContext databind, final YangInstanceIdentifier data) {
+ public String serializePath(final YangInstanceIdentifier path) {
+ if (path.isEmpty()) {
+ return "";
+ }
+
final var current = databind.schemaTree().getRoot();
final var variables = new MainVarsWrapper(current);
- final var path = new StringBuilder();
+ final var sb = new StringBuilder();
QNameModule parentModule = null;
- for (final PathArgument arg : data.getPathArguments()) {
+ for (var arg : path.getPathArguments()) {
// get module of the parent
final var currentContext = variables.getCurrent();
? composite.childByArg(arg) : null;
if (childContext == null) {
throw new RestconfDocumentedException(
- "Invalid input '%s': schema for argument '%s' (after '%s') not found".formatted(data, arg, path),
+ "Invalid input '%s': schema for argument '%s' (after '%s') not found".formatted(path, arg, sb),
ErrorType.APPLICATION, ErrorTag.UNKNOWN_ELEMENT);
}
// condition is satisfied also for the first path argument
if (!arg.getNodeType().getModule().equals(parentModule)) {
// append slash if it is not the first path argument
- if (path.length() > 0) {
- path.append('/');
+ if (sb.length() > 0) {
+ sb.append('/');
}
- path.append(prefixForNamespace(arg.getNodeType(), databind.modelContext())).append(':');
+ sb.append(prefixForNamespace(arg.getNodeType())).append(':');
} else {
- path.append('/');
+ sb.append('/');
}
- path.append(arg.getNodeType().getLocalName());
+ sb.append(arg.getNodeType().getLocalName());
if (arg instanceof NodeIdentifierWithPredicates withPredicates) {
- prepareNodeWithPredicates(path, withPredicates.entrySet());
+ prepareNodeWithPredicates(sb, withPredicates.entrySet());
} else if (arg instanceof NodeWithValue<?> withValue) {
- prepareNodeWithValue(path, withValue.getValue());
+ prepareNodeWithValue(sb, withValue.getValue());
}
}
- return path.toString();
+ return sb.toString();
}
private static void prepareNodeWithValue(final StringBuilder path, final Object value) {
* @param qname {@link QName}
* @return {@link String}
*/
- private static String prefixForNamespace(final QName qname, final EffectiveModelContext schemaContext) {
- return schemaContext.findModuleStatement(qname.getModule()).orElseThrow().argument().getLocalName();
+ private String prefixForNamespace(final QName qname) {
+ return databind.modelContext().findModuleStatement(qname.getModule()).orElseThrow().argument().getLocalName();
}
private static final class MainVarsWrapper {
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.server.api.DatabindContext;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
* Unit tests for {@link YangInstanceIdentifierSerializer}.
*/
class YangInstanceIdentifierSerializerTest {
- private static final DatabindContext DATABIND = DatabindContext.ofModel(
- YangParserTestUtils.parseYangResourceDirectory("/restconf/parser/serializer"));
+ private static final YangInstanceIdentifierSerializer SERIALIZER = new YangInstanceIdentifierSerializer(
+ DatabindContext.ofModel(YangParserTestUtils.parseYangResourceDirectory("/restconf/parser/serializer")));
/**
* Positive test of serialization of <code>YangInstanceIdentifier</code> containing container node to
*/
@Test
void serializeContainerTest() {
- assertEquals("serializer-test:contA", YangInstanceIdentifierSerializer.create(DATABIND,
+ assertEquals("serializer-test:contA", SERIALIZER.serializePath(
YangInstanceIdentifier.of(QName.create("serializer:test", "2016-06-06", "contA"))));
}
*/
@Test
void serializeContainerWithLeafTest() {
- assertEquals("serializer-test:contA/leaf-A", YangInstanceIdentifierSerializer.create(DATABIND,
+ assertEquals("serializer-test:contA/leaf-A", SERIALIZER.serializePath(
YangInstanceIdentifier.of(
QName.create("serializer:test", "2016-06-06", "contA"),
QName.create("serializer:test", "2016-06-06", "leaf-A"))));
final var list = QName.create("serializer:test", "2016-06-06", "list-A");
final var leafList = QName.create("serializer:test", "2016-06-06", "leaf-list-AA");
- assertEquals("serializer-test:contA/list-A=100/leaf-list-AA=instance",
- YangInstanceIdentifierSerializer.create(DATABIND, YangInstanceIdentifier.builder()
+ assertEquals("serializer-test:contA/list-A=100/leaf-list-AA=instance", SERIALIZER.serializePath(
+ YangInstanceIdentifier.builder()
.node(QName.create("serializer:test", "2016-06-06", "contA"))
.node(list)
.node(NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 100))
*/
@Test
void serializeListWithNoKeysTest() {
- assertEquals("serializer-test:list-no-key", YangInstanceIdentifierSerializer.create(DATABIND,
+ assertEquals("serializer-test:list-no-key", SERIALIZER.serializePath(
YangInstanceIdentifier.of(
QName.create("serializer:test", "2016-06-06", "list-no-key"),
QName.create("serializer:test", "2016-06-06", "list-no-key"))));
*/
@Test
void serializeMapWithNoKeysTest() {
- assertEquals("serializer-test:list-one-key", YangInstanceIdentifierSerializer.create(DATABIND,
+ assertEquals("serializer-test:list-one-key", SERIALIZER.serializePath(
YangInstanceIdentifier.builder()
.node(QName.create("serializer:test", "2016-06-06", "list-one-key"))
.nodeWithKey(QName.create("serializer:test", "2016-06-06", "list-one-key"), Map.of())
*/
@Test
void serializeMapWithOneKeyTest() {
- assertEquals("serializer-test:list-one-key=value", YangInstanceIdentifierSerializer.create(DATABIND,
+ assertEquals("serializer-test:list-one-key=value", SERIALIZER.serializePath(
YangInstanceIdentifier.builder()
.node(QName.create("serializer:test", "2016-06-06", "list-one-key"))
.nodeWithKey(QName.create("serializer:test", "2016-06-06", "list-one-key"),
void serializeMapWithMultipleKeysTest() {
final var list = QName.create("serializer:test", "2016-06-06", "list-multiple-keys");
- assertEquals("serializer-test:list-multiple-keys=value-1,2,true",
- YangInstanceIdentifierSerializer.create(DATABIND, YangInstanceIdentifier.builder()
+ assertEquals("serializer-test:list-multiple-keys=value-1,2,true", SERIALIZER.serializePath(
+ YangInstanceIdentifier.builder()
.node(list)
.nodeWithKey(list, ImmutableMap.of(
QName.create(list, "name"), "value-1",
*/
@Test
void serializeLeafTest() {
- assertEquals("serializer-test:leaf-0", YangInstanceIdentifierSerializer.create(DATABIND,
+ assertEquals("serializer-test:leaf-0", SERIALIZER.serializePath(
YangInstanceIdentifier.of(QName.create("serializer:test", "2016-06-06", "leaf-0"))));
}
*/
@Test
void serializeLeafListTest() {
- assertEquals("serializer-test:leaf-list-0=instance", YangInstanceIdentifierSerializer.create(DATABIND,
+ assertEquals("serializer-test:leaf-list-0=instance", SERIALIZER.serializePath(
YangInstanceIdentifier.builder()
.node(QName.create("serializer:test", "2016-06-06", "leaf-list-0"))
.node(new NodeWithValue<>(QName.create("serializer:test", "2016-06-06", "leaf-list-0"), "instance"))
*/
@Test
void serializeNullSchemaContextNegativeTest() {
- assertThrows(NullPointerException.class,
- () -> YangInstanceIdentifierSerializer.create(null, YangInstanceIdentifier.of()));
+ assertThrows(NullPointerException.class, () -> new YangInstanceIdentifierSerializer(null));
}
/**
*/
@Test
void serializeNullDataNegativeTest() {
- assertThrows(NullPointerException.class,
- () -> YangInstanceIdentifierSerializer.create(DATABIND, null));
+ assertThrows(NullPointerException.class, () -> SERIALIZER.serializePath(null));
}
/**
*/
@Test
void serializeEmptyDataTest() {
- assertEquals("", YangInstanceIdentifierSerializer.create(DATABIND, YangInstanceIdentifier.of()));
+ assertEquals("", SERIALIZER.serializePath(YangInstanceIdentifier.of()));
}
/**
*/
@Test
void serializeChildNodeNotFoundNegativeTest() {
- final var data = YangInstanceIdentifier.of(
- QName.create("serializer:test", "2016-06-06", "contA"),
- QName.create("serializer:test", "2016-06-06", "not-existing-leaf"));
-
- final var ex = assertThrows(RestconfDocumentedException.class,
- () -> YangInstanceIdentifierSerializer.create(DATABIND, data));
- final var errors = ex.getErrors();
- assertEquals(1, errors.size());
- final var error = errors.get(0);
+ final var error = assertError(YangInstanceIdentifier.of(
+ QName.create("serializer:test", "2016-06-06", "contA"),
+ QName.create("serializer:test", "2016-06-06", "not-existing-leaf")));
assertEquals("""
Invalid input '/(serializer:test?revision=2016-06-06)contA/not-existing-leaf': schema for argument \
'(serializer:test?revision=2016-06-06)not-existing-leaf' (after 'serializer-test:contA') not found""",
*/
@Test
void serializePercentEncodingTest() {
- assertEquals("serializer-test:list-one-key=foo%3Afoo bar%2Ffoo%2Cbar%2F%27bar%27",
- YangInstanceIdentifierSerializer.create(DATABIND,
- YangInstanceIdentifier.builder()
- .node(QName.create("serializer:test", "2016-06-06", "list-one-key"))
- .nodeWithKey(QName.create("serializer:test", "2016-06-06", "list-one-key"),
- QName.create("serializer:test", "2016-06-06", "list-one-key"), "foo:foo bar/foo,bar/'bar'")
- .build()));
+ assertEquals("serializer-test:list-one-key=foo%3Afoo bar%2Ffoo%2Cbar%2F%27bar%27", SERIALIZER.serializePath(
+ YangInstanceIdentifier.builder()
+ .node(QName.create("serializer:test", "2016-06-06", "list-one-key"))
+ .nodeWithKey(QName.create("serializer:test", "2016-06-06", "list-one-key"),
+ QName.create("serializer:test", "2016-06-06", "list-one-key"), "foo:foo bar/foo,bar/'bar'")
+ .build()));
}
/**
*/
@Test
void serializeNoPercentEncodingTest() {
- assertEquals("serializer-test:list-one-key=foo\"b\"bar", YangInstanceIdentifierSerializer.create(DATABIND,
+ assertEquals("serializer-test:list-one-key=foo\"b\"bar", SERIALIZER.serializePath(
YangInstanceIdentifier.builder()
.node(QName.create("serializer:test", "2016-06-06", "list-one-key"))
.nodeWithKey(QName.create("serializer:test", "2016-06-06", "list-one-key"),
final var child = QName.create("serializer:test", "2016-06-06", "augmented-leaf");
assertEquals("serializer-test-included:augmented-list=100/serializer-test:augmented-leaf",
- YangInstanceIdentifierSerializer.create(DATABIND, YangInstanceIdentifier.builder()
+ SERIALIZER.serializePath(YangInstanceIdentifier.builder()
.node(list)
.node(NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 100))
.node(child)
void serializeIncludedNodesSerializationTest() {
final var list = QName.create("serializer:test:included", "2016-06-06", "augmented-list");
- final var data = YangInstanceIdentifier.builder()
- .node(list)
- .node(NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 100))
- // child should has different namespace
- .node(QName.create("serializer:test:included", "2016-06-06", "augmented-leaf"))
- .build();
-
- final var ex = assertThrows(RestconfDocumentedException.class,
- () -> YangInstanceIdentifierSerializer.create(DATABIND, data));
- final var errors = ex.getErrors();
- assertEquals(1, errors.size());
- final var error = errors.get(0);
+ final var error = assertError(YangInstanceIdentifier.builder()
+ .node(list)
+ .node(NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 100))
+ // child should has different namespace
+ .node(QName.create("serializer:test:included", "2016-06-06", "augmented-leaf"))
+ .build());
assertEquals("""
Invalid input '/(serializer:test:included?revision=2016-06-06)augmented-list/augmented-list[{(\
serializer:test:included?revision=2016-06-06)list-key=100}]/augmented-leaf': schema for argument \
assertEquals(ErrorType.APPLICATION, error.getErrorType());
assertEquals(ErrorTag.UNKNOWN_ELEMENT, error.getErrorTag());
}
+
+ private static RestconfError assertError(final YangInstanceIdentifier path) {
+ final var ex = assertThrows(RestconfDocumentedException.class, () -> SERIALIZER.serializePath(path));
+ final var errors = ex.getErrors();
+ assertEquals(1, errors.size());
+ return errors.get(0);
+ }
+
}