* 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 com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FluentFuture;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.core.Response.Status;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
import org.opendaylight.restconf.common.patch.PatchEntity;
import org.opendaylight.restconf.common.patch.PatchStatusContext;
import org.opendaylight.restconf.common.patch.PatchStatusEntity;
-import org.opendaylight.restconf.nb.rfc8040.references.SchemaContextRef;
-import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
-import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.PatchData;
+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.MapEntryNode;
-import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
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.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class PatchDataTransactionUtil {
private static final Logger LOG = LoggerFactory.getLogger(PatchDataTransactionUtil.class);
+ // FIXME: why is this used from other contexts?
+ static final String PATCH_TX_TYPE = "Patch";
private PatchDataTransactionUtil() {
throw new UnsupportedOperationException("Util class.");
}
/**
- * Process edit operations of one {@link PatchContext}.
- * @param context Patch context to be processed
- * @param transactionNode Wrapper for transaction
- * @param schemaContextRef Soft reference for global schema context
+ * Process edit operations of one {@link PatchContext}. Close {@link DOMTransactionChain} if any inside of object
+ * {@link RestconfStrategy} provided as a parameter.
+ *
+ * @param context Patch context to be processed
+ * @param strategy object that perform the actual DS operations
+ * @param schemaContext Global schema context
* @return {@link PatchStatusContext}
*/
- public static PatchStatusContext patchData(final PatchContext context, final TransactionVarsWrapper transactionNode,
- final SchemaContextRef schemaContextRef) {
+ public static PatchStatusContext patchData(final PatchContext context, final RestconfStrategy strategy,
+ final EffectiveModelContext schemaContext) {
final List<PatchStatusEntity> editCollection = new ArrayList<>();
boolean noError = true;
- final DOMDataReadWriteTransaction tx = transactionNode.getTransactionChain().newReadWriteTransaction();
+ final RestconfTransaction transaction = strategy.prepareWriteExecution();
for (final PatchEntity patchEntity : context.getData()) {
if (noError) {
switch (patchEntity.getOperation()) {
case CREATE:
try {
- createDataWithinTransaction(LogicalDatastoreType.CONFIGURATION,
- patchEntity.getTargetNode(), patchEntity.getNode(), tx, schemaContextRef);
+ createDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
+ schemaContext, transaction);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
break;
case DELETE:
try {
- deleteDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, patchEntity.getTargetNode(),
- tx);
+ deleteDataWithinTransaction(patchEntity.getTargetNode(), transaction);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
break;
case MERGE:
try {
- mergeDataWithinTransaction(LogicalDatastoreType.CONFIGURATION,
- patchEntity.getTargetNode(), patchEntity.getNode(), tx, schemaContextRef);
+ mergeDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
+ schemaContext, transaction);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
break;
case REPLACE:
try {
- replaceDataWithinTransaction(LogicalDatastoreType.CONFIGURATION,
- patchEntity.getTargetNode(), patchEntity.getNode(), schemaContextRef, tx);
+ replaceDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(),
+ schemaContext, transaction);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
break;
case REMOVE:
try {
- removeDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, patchEntity.getTargetNode(),
- tx);
+ removeDataWithinTransaction(patchEntity.getTargetNode(), transaction);
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null));
} catch (final RestconfDocumentedException e) {
editCollection.add(new PatchStatusEntity(patchEntity.getEditId(),
// if no errors then submit transaction, otherwise cancel
if (noError) {
final ResponseFactory response = new ResponseFactory(Status.OK);
- final CheckedFuture<Void, TransactionCommitFailedException> future = tx.submit();
+ final FluentFuture<? extends CommitInfo> future = transaction.commit();
try {
- FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response);
+ //This method will close transactionChain if any
+ FutureCallbackTx.addCallback(future, PATCH_TX_TYPE, response, strategy, null);
} catch (final RestconfDocumentedException e) {
// if errors occurred during transaction commit then patch failed and global errors are reported
return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), false,
return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), true, null);
} else {
- tx.cancel();
- transactionNode.getTransactionChainHandler().reset();
- return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection),
- false, null);
+ transaction.cancel();
+ return new PatchStatusContext(context.getPatchId(), ImmutableList.copyOf(editCollection), false, null);
}
}
/**
* Create data within one transaction, return error if already exists.
- * @param dataStore Datastore to write data to
- * @param path Path for data to be created
- * @param payload Data to be created
- * @param rWTransaction Transaction
- * @param schemaContextRef Soft reference for global schema context
+ *
+ * @param path Path for data to be created
+ * @param payload Data to be created
+ * @param transaction A handle to a set of DS operations
*/
- private static void createDataWithinTransaction(final LogicalDatastoreType dataStore,
- final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> payload,
- final DOMDataReadWriteTransaction rwTransaction,
- final SchemaContextRef schemaContextRef) {
- LOG.trace("POST {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload);
- createData(payload, schemaContextRef.get(), path, rwTransaction, dataStore, true);
+ private static void createDataWithinTransaction(final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext,
+ final RestconfTransaction transaction) {
+ LOG.trace("POST {} within Restconf Patch: {} with payload {}", LogicalDatastoreType.CONFIGURATION.name(),
+ path, payload);
+ transaction.create(LogicalDatastoreType.CONFIGURATION, path, payload, schemaContext);
}
/**
- * Check if data exists and remove it within one transaction.
- * @param dataStore Datastore to delete data from
- * @param path Path for data to be deleted
- * @param readWriteTransaction Transaction
+ * Remove data within one transaction.
+ *
+ * @param path Path for data to be deleted
+ * @param transaction A handle to a set of DS operations
*/
- private static void deleteDataWithinTransaction(final LogicalDatastoreType dataStore,
- final YangInstanceIdentifier path,
- final DOMDataReadWriteTransaction readWriteTransaction) {
- LOG.trace("Delete {} within Restconf Patch: {}", dataStore.name(), path);
- checkItemExistsWithinTransaction(readWriteTransaction, dataStore, path);
- readWriteTransaction.delete(dataStore, path);
+ private static void deleteDataWithinTransaction(final YangInstanceIdentifier path,
+ final RestconfTransaction transaction) {
+ LOG.trace("Delete {} within Restconf Patch: {}", LogicalDatastoreType.CONFIGURATION.name(), path);
+ transaction.delete(LogicalDatastoreType.CONFIGURATION, path);
}
/**
* Merge data within one transaction.
- * @param dataStore Datastore to merge data to
- * @param path Path for data to be merged
- * @param payload Data to be merged
- * @param writeTransaction Transaction
- * @param schemaContextRef Soft reference for global schema context
+ *
+ * @param path Path for data to be merged
+ * @param payload Data to be merged
+ * @param transaction A handle to a set of DS operations
*/
- private static void mergeDataWithinTransaction(final LogicalDatastoreType dataStore,
- final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> payload,
- final DOMDataReadWriteTransaction writeTransaction,
- final SchemaContextRef schemaContextRef) {
- LOG.trace("Merge {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload);
- TransactionUtil.ensureParentsByMerge(path, schemaContextRef.get(), writeTransaction);
- writeTransaction.merge(dataStore, path, payload);
+ private static void mergeDataWithinTransaction(final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext,
+ final RestconfTransaction transaction) {
+ LOG.trace("Merge {} within Restconf Patch: {} with payload {}", LogicalDatastoreType.CONFIGURATION.name(),
+ path, payload);
+ TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
+ transaction.merge(LogicalDatastoreType.CONFIGURATION, path, payload);
}
/**
* Do NOT check if data exists and remove it within one transaction.
- * @param dataStore Datastore to delete data from
- * @param path Path for data to be deleted
- * @param writeTransaction Transaction
+ *
+ * @param path Path for data to be deleted
+ * @param transaction A handle to a set of DS operations
*/
- private static void removeDataWithinTransaction(final LogicalDatastoreType dataStore,
- final YangInstanceIdentifier path,
- final DOMDataWriteTransaction writeTransaction) {
- LOG.trace("Remove {} within Restconf Patch: {}", dataStore.name(), path);
- writeTransaction.delete(dataStore, path);
+ private static void removeDataWithinTransaction(final YangInstanceIdentifier path,
+ final RestconfTransaction transaction) {
+ LOG.trace("Remove {} within Restconf Patch: {}", LogicalDatastoreType.CONFIGURATION.name(), path);
+ transaction.remove(LogicalDatastoreType.CONFIGURATION, path);
}
/**
* Create data within one transaction, replace if already exists.
- * @param dataStore Datastore to write data to
- * @param path Path for data to be created
- * @param payload Data to be created
- * @param schemaContextRef Soft reference for global schema context
- * @param rwTransaction Transaction
- */
- private static void replaceDataWithinTransaction(final LogicalDatastoreType dataStore,
- final YangInstanceIdentifier path,
- final NormalizedNode<?, ?> payload,
- final SchemaContextRef schemaContextRef,
- final DOMDataReadWriteTransaction rwTransaction) {
- LOG.trace("PUT {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload);
- createData(payload, schemaContextRef.get(), path, rwTransaction, dataStore, false);
- }
-
- /**
- * Create data within one transaction. If {@code errorIfExists} is set to {@code true} then data will be checked
- * for existence before created, otherwise they will be overwritten.
- * @param payload Data to be created
- * @param schemaContext Global schema context
- * @param path Path for data to be created
- * @param rwTransaction Transaction
- * @param dataStore Datastore to write data to
- * @param errorIfExists Enable checking for existence of data (throws error if already exists)
+ *
+ * @param path Path for data to be created
+ * @param payload Data to be created
+ * @param transaction A handle to a set of DS operations
*/
- private static void createData(final NormalizedNode<?, ?> payload, final SchemaContext schemaContext,
- final YangInstanceIdentifier path, final DOMDataReadWriteTransaction rwTransaction,
- final LogicalDatastoreType dataStore, final boolean errorIfExists) {
- if (payload instanceof MapNode) {
- final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
- rwTransaction.merge(dataStore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
- TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
- for (final MapEntryNode child : ((MapNode) payload).getValue()) {
- final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
-
- if (errorIfExists) {
- checkItemDoesNotExistsWithinTransaction(rwTransaction, dataStore, childPath);
- }
-
- rwTransaction.put(dataStore, childPath, child);
- }
- } else {
- if (errorIfExists) {
- checkItemDoesNotExistsWithinTransaction(rwTransaction, dataStore, path);
- }
-
- TransactionUtil.ensureParentsByMerge(path, schemaContext, rwTransaction);
- rwTransaction.put(dataStore, path, payload);
- }
- }
-
- /**
- * Check if items already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
- * data does NOT already exists.
- * @param rwTransaction Transaction
- * @param store Datastore
- * @param path Path to be checked
- */
- public static void checkItemExistsWithinTransaction(final DOMDataReadWriteTransaction rwTransaction,
- final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- final CheckedFuture<Boolean, ReadFailedException> future = rwTransaction.exists(store, path);
- final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
-
- FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response);
-
- if (!response.result) {
- final String errMsg = "Operation via Restconf was not executed because data does not exist";
- LOG.trace("{}:{}", errMsg, path);
- throw new RestconfDocumentedException(
- "Data does not exist", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, path);
- }
- }
-
- /**
- * Check if items do NOT already exists at specified {@code path}. Throws {@link RestconfDocumentedException} if
- * data already exists.
- * @param rwTransaction Transaction
- * @param store Datastore
- * @param path Path to be checked
- */
- public static void checkItemDoesNotExistsWithinTransaction(final DOMDataReadWriteTransaction rwTransaction,
- final LogicalDatastoreType store, final YangInstanceIdentifier path) {
- final CheckedFuture<Boolean, ReadFailedException> future = rwTransaction.exists(store, path);
- final FutureDataFactory<Boolean> response = new FutureDataFactory<>();
-
- FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response);
-
- if (response.result) {
- final String errMsg = "Operation via Restconf was not executed because data already exists";
- LOG.trace("{}:{}", errMsg, path);
- throw new RestconfDocumentedException(
- "Data already exists", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, path);
- }
+ private static void replaceDataWithinTransaction(final YangInstanceIdentifier path, final NormalizedNode payload,
+ final EffectiveModelContext schemaContext,
+ final RestconfTransaction transaction) {
+ LOG.trace("PUT {} within Restconf Patch: {} with payload {}",
+ LogicalDatastoreType.CONFIGURATION.name(), path, payload);
+ transaction.replace(LogicalDatastoreType.CONFIGURATION, path, payload, schemaContext);
}
}