PATCH methods should communicate ETag/Last-Modified where applicable.
Introduce DataPatchResult to communicate these for plain PATCH.
JIRA: NETCONF-1207
Change-Id: I3ed2e80385f2b5acdd90c04adab49b491ebd5a79
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
import org.opendaylight.restconf.server.api.ConfigurationMetadata;
import org.opendaylight.restconf.server.api.DataGetResult;
+import org.opendaylight.restconf.server.api.DataPatchResult;
import org.opendaylight.restconf.server.api.DataPostResult;
import org.opendaylight.restconf.server.api.DataPostResult.CreateResource;
import org.opendaylight.restconf.server.api.DataPostResult.InvokeOperation;
}
}
- private static void completeDataPATCH(final RestconfFuture<Empty> future, final AsyncResponse ar) {
+ private static void completeDataPATCH(final RestconfFuture<DataPatchResult> future, final AsyncResponse ar) {
future.addCallback(new JaxRsRestconfCallback<>(ar) {
@Override
- Response transform(final Empty result) {
- return Response.ok().build();
+ Response transform(final DataPatchResult result) {
+ final var builder = Response.ok();
+ fillConfigurationMetadata(builder, result);
+ return builder.build();
}
});
}
import org.opendaylight.restconf.server.api.DataGetParams;
import org.opendaylight.restconf.server.api.DataGetResult;
import org.opendaylight.restconf.server.api.DataPatchPath;
+import org.opendaylight.restconf.server.api.DataPatchResult;
import org.opendaylight.restconf.server.api.DataPostPath;
import org.opendaylight.restconf.server.api.DataPostResult;
import org.opendaylight.restconf.server.api.DataPostResult.CreateResource;
private static final Logger LOG = LoggerFactory.getLogger(RestconfStrategy.class);
private static final @NonNull DataPutResult PUT_CREATED = new DataPutResult(true);
private static final @NonNull DataPutResult PUT_REPLACED = new DataPutResult(false);
+ private static final @NonNull DataPatchResult PATCH_EMPTY = new DataPatchResult();
private final @NonNull ImmutableMap<QName, RpcImplementation> localRpcs;
private final @NonNull ApiPathNormalizer pathNormalizer;
abstract ListenableFuture<Boolean> exists(YangInstanceIdentifier path);
@VisibleForTesting
- final @NonNull RestconfFuture<Empty> merge(final YangInstanceIdentifier path, final NormalizedNode data) {
- final var ret = new SettableRestconfFuture<Empty>();
+ final @NonNull RestconfFuture<DataPatchResult> merge(final YangInstanceIdentifier path, final NormalizedNode data) {
+ final var ret = new SettableRestconfFuture<DataPatchResult>();
merge(ret, requireNonNull(path), requireNonNull(data));
return ret;
}
- private void merge(final @NonNull SettableRestconfFuture<Empty> future, final @NonNull YangInstanceIdentifier path,
- final @NonNull NormalizedNode data) {
+ private void merge(final @NonNull SettableRestconfFuture<DataPatchResult> future,
+ final @NonNull YangInstanceIdentifier path, final @NonNull NormalizedNode data) {
final var tx = prepareWriteExecution();
// FIXME: this method should be further specialized to eliminate this call -- it is only needed for MD-SAL
tx.ensureParentsByMerge(path);
Futures.addCallback(tx.commit(), new FutureCallback<CommitInfo>() {
@Override
public void onSuccess(final CommitInfo result) {
- future.set(Empty.value());
+ // TODO: extract details once CommitInfo can communicate them
+ future.set(PATCH_EMPTY);
}
@Override
* @return A {@link RestconfFuture}
* @throws NullPointerException if any argument is {@code null}
*/
- public final @NonNull RestconfFuture<Empty> dataPATCH(final ApiPath apiPath, final ResourceBody body) {
+ public final @NonNull RestconfFuture<DataPatchResult> dataPATCH(final ApiPath apiPath, final ResourceBody body) {
final DataPath path;
try {
path = pathNormalizer.normalizeDataPath(apiPath);
--- /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 java.time.Instant;
+import org.eclipse.jdt.annotation.Nullable;
+
+/**
+ * Result of a {@code PATCH} request as defined in
+ * <a href="https://www.rfc-editor.org/rfc/rfc8040#section-4.6.1">RFC8040, section 4.6.1</a>.
+ *
+ * @param entityTag response {@code ETag} header, or {@code null} if not applicable
+ * @param lastModified response {@code Last-Modified} header, or {@code null} if not applicable
+ */
+public record DataPatchResult(
+ @Nullable EntityTag entityTag,
+ @Nullable Instant lastModified) implements ConfigurationMetadata {
+ public DataPatchResult() {
+ this(null, null);
+ }
+}
* @param body data node for put to config DS
* @return A {@link RestconfFuture} of the operation
*/
- // FIXME: NETCONF-1207: result should carry ConfigurationMetadata
- RestconfFuture<Empty> dataPATCH(ResourceBody body);
+ RestconfFuture<DataPatchResult> dataPATCH(ResourceBody body);
/**
* Partially modify the target data resource, as defined in
* @param body data node for put to config DS
* @return A {@link RestconfFuture} of the operation
*/
- // FIXME: NETCONF-1207: result should carry ConfigurationMetadata
- RestconfFuture<Empty> dataPATCH(ApiPath identifier, ResourceBody body);
+ RestconfFuture<DataPatchResult> dataPATCH(ApiPath identifier, ResourceBody body);
/**
* Ordered list of edits that are applied to the datastore by the server, as defined in
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy.StrategyAndTail;
import org.opendaylight.restconf.server.api.DataGetParams;
import org.opendaylight.restconf.server.api.DataGetResult;
+import org.opendaylight.restconf.server.api.DataPatchResult;
import org.opendaylight.restconf.server.api.DataPostResult;
import org.opendaylight.restconf.server.api.DataPostResult.CreateResource;
import org.opendaylight.restconf.server.api.DataPutResult;
}
@Override
- public RestconfFuture<Empty> dataPATCH(final ResourceBody body) {
+ public RestconfFuture<DataPatchResult> dataPATCH(final ResourceBody body) {
return localStrategy().dataPATCH(ApiPath.empty(), body);
}
@Override
- public RestconfFuture<Empty> dataPATCH(final ApiPath identifier, final ResourceBody body) {
+ public RestconfFuture<DataPatchResult> dataPATCH(final ApiPath identifier, final ResourceBody body) {
final StrategyAndTail strategyAndTail;
try {
strategyAndTail = localStrategy().resolveStrategy(identifier);