import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
+import org.opendaylight.restconf.server.api.DataPutPath;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.opendaylight.yangtools.yang.data.codec.gson.JSONCodecFactorySupplier;
import org.opendaylight.yangtools.yang.data.codec.gson.JsonParserStream;
-import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
/**
* A JSON-encoded {@link ResourceBody}.
}
@Override
- void streamTo(final InputStream inputStream, final Inference inference, final PathArgument name,
+ void streamTo(final DataPutPath path, final PathArgument name, final InputStream inputStream,
final NormalizedNodeStreamWriter writer) throws IOException {
- try (var jsonParser = newParser(inference, writer)) {
+ try (var jsonParser = newParser(path, writer)) {
try (var reader = new JsonReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
jsonParser.parse(reader);
}
}
}
- private static JsonParserStream newParser(final Inference inference, final NormalizedNodeStreamWriter writer) {
- final var codecs = JSONCodecFactorySupplier.RFC7951.getShared(inference.getEffectiveModelContext());
- final var stack = inference.toSchemaInferenceStack();
- if (stack.isEmpty()) {
+ private static JsonParserStream newParser(final DataPutPath path, final NormalizedNodeStreamWriter writer) {
+ final var codecs = path.databind().jsonCodecs();
+ final var inference = path.inference();
+ if (inference.isEmpty()) {
return JsonParserStream.create(writer, codecs);
}
+ final var stack = inference.toSchemaInferenceStack();
stack.exit();
return JsonParserStream.create(writer, codecs, stack.toInference());
}
import java.util.Map;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.server.api.DataPutPath;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev170126.restconf.restconf.Data;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.data.impl.schema.NormalizationResultHolder;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaNode;
-import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* Acquire the {@link NormalizedNode} representation of this body.
*
* @param path A {@link YangInstanceIdentifier} corresponding to the body
- * @param inference An {@link Inference} the statement corresponding to the body
* @throws RestconfDocumentedException if the body cannot be decoded or it does not match {@code path}
*/
// TODO: pass down DatabindContext corresponding to inference
@SuppressWarnings("checkstyle:illegalCatch")
- public @NonNull NormalizedNode toNormalizedNode(final @NonNull YangInstanceIdentifier path,
- final @NonNull Inference inference, final @NonNull SchemaNode schemaNode) {
- final var expected = path.isEmpty() ? DATA_NID : path.getLastPathArgument();
+ public @NonNull NormalizedNode toNormalizedNode(final @NonNull DataPutPath path,
+ final @NonNull SchemaNode schemaNode) {
+ final var instance = path.instance();
+ final var expected = instance.isEmpty() ? DATA_NID : instance.getLastPathArgument();
final var holder = new NormalizationResultHolder();
try (var streamWriter = ImmutableNormalizedNodeStreamWriter.from(holder)) {
- streamTo(acquireStream(), inference, expected, streamWriter);
+ streamTo(path, expected, acquireStream(), streamWriter);
} catch (IOException e) {
LOG.debug("Error reading input", e);
throw new RestconfDocumentedException("Error parsing input: " + e.getMessage(), ErrorType.PROTOCOL,
}
validTopLevelNodeName(expected, data);
- validateListKeysEqualityInPayloadAndUri(schemaNode, path, data);
-
+ validateListKeysEqualityInPayloadAndUri(schemaNode, instance, data);
return data;
}
- abstract void streamTo(@NonNull InputStream inputStream, @NonNull Inference inference, @NonNull PathArgument name,
+ abstract void streamTo(@NonNull DataPutPath path, @NonNull PathArgument name, @NonNull InputStream inputStream,
@NonNull NormalizedNodeStreamWriter writer) throws IOException;
/**
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.dom.DOMSource;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.server.api.DataPutPath;
import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
-import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
}
@Override
- void streamTo(final InputStream inputStream, final Inference inference, final PathArgument name,
+ void streamTo(final DataPutPath path, final PathArgument name, final InputStream inputStream,
final NormalizedNodeStreamWriter writer) throws IOException {
- try (var xmlParser = XmlParserStream.create(writer, inference)) {
+ try (var xmlParser = XmlParserStream.create(writer, path.databind().xmlCodecs(), path.inference())) {
final var doc = UntrustedXML.newDocumentBuilder().parse(inputStream);
final var docRoot = doc.getDocumentElement();
final var docRootName = docRoot.getLocalName();
--- /dev/null
+/*
+ * Copyright (c) 2023 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.restconf.server.api;
+
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.restconf.api.ApiPath;
+import org.opendaylight.restconf.nb.rfc8040.databind.DataPostBody;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference;
+
+/**
+ * An {@link ApiPath} subpath of {@code /data} {@code PUT} HTTP operation, as defined in
+ * <a href="https://www.rfc-editor.org/rfc/rfc8040#section-4.5">RFC8040 section 4.5</a>.
+ *
+ * @param databind Associated {@link DatabindContext}
+ * @param inference Associated {@link Inference} pointing to the {@link EffectiveStatement} of the last ApiPath element.
+ * This can be one of:
+ * <ul>
+ * <li>a datatore, inference being {@link Inference#isEmpty() empty}</li>
+ * <li>a data resource, inference pointing to the the {@code data schema node} identified by
+ * {@code instance}</li>
+ * </ul>
+ * @param instance Associated {@link YangInstanceIdentifier}
+ * @see DataPostBody
+ */
+@NonNullByDefault
+public record DataPutPath(DatabindContext databind, Inference inference, YangInstanceIdentifier instance)
+ implements DatabindAware {
+ public DataPutPath {
+ requireNonNull(databind);
+ requireNonNull(inference);
+ requireNonNull(instance);
+ }
+}
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.restconf.server.api.DataPutPath;
import org.opendaylight.restconf.server.api.DataPutResult;
import org.opendaylight.restconf.server.api.DatabindContext;
import org.opendaylight.restconf.server.api.ModulesGetResult;
private @NonNull ResourceRequest bindResourceRequest(final InstanceIdentifierContext reqPath,
final ResourceBody body) {
- final var path = reqPath.getInstanceIdentifier();
- final var data = body.toNormalizedNode(path, reqPath.inference(), reqPath.getSchemaNode());
-
- return new ResourceRequest(getRestconfStrategy(reqPath.databind(), reqPath.getMountPoint()), path, data);
+ final var putPath = new DataPutPath(reqPath.databind(), reqPath.inference(), reqPath.getInstanceIdentifier());
+ return new ResourceRequest(getRestconfStrategy(putPath.databind(), reqPath.getMountPoint()), putPath.instance(),
+ body.toNormalizedNode(putPath, reqPath.getSchemaNode()));
}
@VisibleForTesting
import org.opendaylight.restconf.api.ApiPath;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
+import org.opendaylight.restconf.server.api.DataPutPath;
import org.opendaylight.restconf.server.api.DatabindContext;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
try (var body = bodyConstructor.apply(patchBody)) {
final var context = InstanceIdentifierContext.ofApiPath(apiPath, DATABIND, mountPointService);
- return body.toNormalizedNode(context.getInstanceIdentifier(), context.inference(), context.getSchemaNode());
+ return body.toNormalizedNode(
+ new DataPutPath(context.databind(), context.inference(), context.getInstanceIdentifier()),
+ context.getSchemaNode());
}
}