import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.PatchDataTransactionUtil;
-import org.opendaylight.restconf.nb.rfc8040.rests.utils.PlainPatchDataTransactionUtil;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.PostDataTransactionUtil;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.PutDataTransactionUtil;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.ReadDataTransactionUtil;
validTopLevelNodeName(path, payload);
validateListKeysEqualityInPayloadAndUri(payload);
- final RestconfStrategy strategy = getRestconfStrategy(iid.getMountPoint());
- return PlainPatchDataTransactionUtil.patchData(path, payload.getData(), strategy, iid.getSchemaContext());
+ getRestconfStrategy(iid.getMountPoint()).merge(path, payload.getData(), iid.getSchemaContext())
+ .getOrThrow();
+ return Response.ok().build();
}
@VisibleForTesting
import static java.util.Objects.requireNonNull;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
import java.util.List;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMMountPoint;
import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.errors.RestconfFuture;
import org.opendaylight.restconf.common.errors.SettableRestconfFuture;
+import org.opendaylight.restconf.nb.rfc8040.rests.utils.TransactionUtil;
import org.opendaylight.yangtools.yang.common.Empty;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
/**
* Baseline execution strategy for various RESTCONF operations.
}
protected abstract void delete(@NonNull SettableRestconfFuture<Empty> future, @NonNull YangInstanceIdentifier path);
+
+ /**
+ * Merge data into the configuration datastore, as outlined in
+ * <a href="https://www.rfc-editor.org/rfc/rfc8040#section-4.6.1">RFC8040 section 4.6.1</a>.
+ *
+ * @param path Path to merge
+ * @param data Data to merge
+ * @param context Corresponding EffectiveModelContext
+ * @return A {@link RestconfFuture}
+ * @throws NullPointerException if any argument is {@code null}
+ */
+ public final @NonNull RestconfFuture<Empty> merge(final YangInstanceIdentifier path, final NormalizedNode data,
+ final EffectiveModelContext context) {
+ final var ret = new SettableRestconfFuture<Empty>();
+ merge(ret, requireNonNull(path), requireNonNull(data), requireNonNull(context));
+ return ret;
+ }
+
+ private void merge(final @NonNull SettableRestconfFuture<Empty> future,
+ final @NonNull YangInstanceIdentifier path, final @NonNull NormalizedNode data,
+ final @NonNull EffectiveModelContext context) {
+ final var tx = prepareWriteExecution();
+ // FIXME: this method should be further specialized to eliminate this call -- it is only needed for MD-SAL
+ TransactionUtil.ensureParentsByMerge(path, context, tx);
+ tx.merge(path, data);
+ Futures.addCallback(tx.commit(), new FutureCallback<CommitInfo>() {
+ @Override
+ public void onSuccess(final CommitInfo result) {
+ future.set(Empty.value());
+ }
+
+ @Override
+ public void onFailure(final Throwable cause) {
+ future.setFailure(TransactionUtil.decodeException(cause, "MERGE", path));
+ }
+ }, MoreExecutors.directExecutor());
+ }
}
+++ /dev/null
-/*
- * Copyright (c) 2020 Lumina Networks, Inc. and others. All rights reserved.
- * Copyright (c) 2016 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.restconf.nb.rfc8040.rests.utils;
-
-import javax.ws.rs.core.Response;
-import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
-import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfTransaction;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Util class for plain patch data to DS.
- */
-public final class PlainPatchDataTransactionUtil {
- private static final Logger LOG = LoggerFactory.getLogger(PlainPatchDataTransactionUtil.class);
-
- private PlainPatchDataTransactionUtil() {
- // Hidden on purpose
- }
-
- /**
- * Prepare variables for put data to DS. Close {@link DOMTransactionChain} if any inside of object
- * {@link RestconfStrategy} provided as a parameter if any.
- *
- * @param path data path
- * @param data data to put
- * @param schemaContext reference to {@link EffectiveModelContext}
- * @param strategy object that perform the actual DS operations
- * @return {@link Response}
- */
- public static Response patchData(final YangInstanceIdentifier path, final NormalizedNode data,
- final RestconfStrategy strategy, final EffectiveModelContext schemaContext) {
- final RestconfTransaction transaction = strategy.prepareWriteExecution();
-
- try {
- LOG.trace("Merge CONFIGURATION within Restconf Patch: {} with payload {}", path, data);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
- transaction.merge(path, data);
- } catch (final RestconfDocumentedException e) {
- transaction.cancel();
- throw new IllegalArgumentException(e);
- }
-
- TransactionUtil.syncCommit(transaction.commit(), PatchDataTransactionUtil.PATCH_TX_TYPE, path);
- return Response.ok().build();
- }
-}
import org.opendaylight.restconf.nb.rfc8040.AbstractJukeboxTest;
import org.opendaylight.restconf.nb.rfc8040.WriteDataParams;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.PatchDataTransactionUtil;
-import org.opendaylight.restconf.nb.rfc8040.rests.utils.PlainPatchDataTransactionUtil;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.PostDataTransactionUtil;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.ReadDataTransactionUtil;
import org.opendaylight.yangtools.yang.common.ErrorTag;
@Test
public final void testPatchContainerData() {
- final var response = PlainPatchDataTransactionUtil.patchData(JUKEBOX_IID, EMPTY_JUKEBOX,
- testPatchContainerDataStrategy(), JUKEBOX_SCHEMA);
- assertEquals(200, response.getStatus());
+ testPatchContainerDataStrategy().merge(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA).getOrThrow();
}
abstract @NonNull RestconfStrategy testPatchContainerDataStrategy();
@Test
public final void testPatchLeafData() {
- final var response = PlainPatchDataTransactionUtil.patchData(GAP_IID, GAP_LEAF,
- testPatchLeafDataStrategy(), JUKEBOX_SCHEMA);
- assertEquals(200, response.getStatus());
+ testPatchLeafDataStrategy().merge(GAP_IID, GAP_LEAF, JUKEBOX_SCHEMA).getOrThrow();
}
abstract @NonNull RestconfStrategy testPatchLeafDataStrategy();
@Test
public final void testPatchListData() {
- final var response = PlainPatchDataTransactionUtil.patchData(JUKEBOX_IID, JUKEBOX_WITH_PLAYLIST,
- testPatchListDataStrategy(), JUKEBOX_SCHEMA);
- assertEquals(200, response.getStatus());
+ testPatchListDataStrategy().merge(JUKEBOX_IID, JUKEBOX_WITH_PLAYLIST, JUKEBOX_SCHEMA).getOrThrow();
}
abstract @NonNull RestconfStrategy testPatchListDataStrategy();