X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=restconf%2Frestconf-nb-rfc8040%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Frestconf%2Fnb%2Frfc8040%2Frests%2Futils%2FPatchDataTransactionUtil.java;h=4d165dc1e7db83463c40115fe825aee94beb0e22;hb=a8a56843c3dc31f61a01d6eff31cb79a5381398a;hp=0444d0ad5cab2aedd28a8ccdbd2589af1adff7d3;hpb=b7537d2482ffb05582749ce80a7ca44c64a5ad6c;p=netconf.git diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/PatchDataTransactionUtil.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/PatchDataTransactionUtil.java index 0444d0ad5c..4d165dc1e7 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/PatchDataTransactionUtil.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/PatchDataTransactionUtil.java @@ -15,9 +15,7 @@ import java.util.List; import javax.ws.rs.core.Response.Status; import org.opendaylight.mdsal.common.api.CommitInfo; import org.opendaylight.mdsal.common.api.LogicalDatastoreType; -import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction; -import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction; -import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction; +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; @@ -26,45 +24,44 @@ import org.opendaylight.restconf.common.patch.PatchContext; 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.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 editCollection = new ArrayList<>(); boolean noError = true; - final DOMDataTreeReadWriteTransaction tx = transactionNode.getTransactionChain().newReadWriteTransaction(); + strategy.prepareReadWriteExecution(); 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, strategy); editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null)); } catch (final RestconfDocumentedException e) { editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), @@ -74,8 +71,7 @@ public final class PatchDataTransactionUtil { break; case DELETE: try { - deleteDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, patchEntity.getTargetNode(), - tx); + deleteDataWithinTransaction(patchEntity.getTargetNode(), strategy); editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null)); } catch (final RestconfDocumentedException e) { editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), @@ -85,8 +81,8 @@ public final class PatchDataTransactionUtil { break; case MERGE: try { - mergeDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, - patchEntity.getTargetNode(), patchEntity.getNode(), tx, schemaContextRef); + mergeDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(), + schemaContext, strategy); editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null)); } catch (final RestconfDocumentedException e) { editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), @@ -96,8 +92,8 @@ public final class PatchDataTransactionUtil { break; case REPLACE: try { - replaceDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, - patchEntity.getTargetNode(), patchEntity.getNode(), schemaContextRef, tx); + replaceDataWithinTransaction(patchEntity.getTargetNode(), patchEntity.getNode(), + schemaContext, strategy); editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null)); } catch (final RestconfDocumentedException e) { editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), @@ -107,8 +103,7 @@ public final class PatchDataTransactionUtil { break; case REMOVE: try { - removeDataWithinTransaction(LogicalDatastoreType.CONFIGURATION, patchEntity.getTargetNode(), - tx); + removeDataWithinTransaction(patchEntity.getTargetNode(), strategy); editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), true, null)); } catch (final RestconfDocumentedException e) { editCollection.add(new PatchStatusEntity(patchEntity.getEditId(), @@ -131,10 +126,11 @@ public final class PatchDataTransactionUtil { // if no errors then submit transaction, otherwise cancel if (noError) { final ResponseFactory response = new ResponseFactory(Status.OK); - final FluentFuture future = tx.commit(); + final FluentFuture future = strategy.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.getTransactionChain()); } 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, @@ -143,168 +139,102 @@ public final class PatchDataTransactionUtil { 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); + strategy.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 strategy Object that perform the actual DS operations */ - private static void createDataWithinTransaction(final LogicalDatastoreType dataStore, - final YangInstanceIdentifier path, + private static void createDataWithinTransaction(final YangInstanceIdentifier path, final NormalizedNode payload, - final DOMDataTreeReadWriteTransaction rwTransaction, - final SchemaContextRef schemaContextRef) { - LOG.trace("POST {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload); - createData(payload, schemaContextRef.get(), path, rwTransaction, dataStore, true); + final EffectiveModelContext schemaContext, + final RestconfStrategy strategy) { + LOG.trace("POST {} within Restconf Patch: {} with payload {}", LogicalDatastoreType.CONFIGURATION.name(), + path, payload); + createData(payload, path, strategy, schemaContext, true); } /** - * 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 strategy Object that perform the actual DS operations */ - private static void deleteDataWithinTransaction(final LogicalDatastoreType dataStore, - final YangInstanceIdentifier path, - final DOMDataTreeReadWriteTransaction 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 RestconfStrategy strategy) { + LOG.trace("Delete {} within Restconf Patch: {}", LogicalDatastoreType.CONFIGURATION.name(), path); + strategy.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 strategy Object that perform the actual DS operations */ - private static void mergeDataWithinTransaction(final LogicalDatastoreType dataStore, - final YangInstanceIdentifier path, + private static void mergeDataWithinTransaction(final YangInstanceIdentifier path, final NormalizedNode payload, - final DOMDataTreeWriteTransaction 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); + final EffectiveModelContext schemaContext, + final RestconfStrategy strategy) { + LOG.trace("Merge {} within Restconf Patch: {} with payload {}", LogicalDatastoreType.CONFIGURATION.name(), + path, payload); + TransactionUtil.ensureParentsByMerge(path, schemaContext, strategy); + strategy.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 strategy Object that perform the actual DS operations */ - private static void removeDataWithinTransaction(final LogicalDatastoreType dataStore, - final YangInstanceIdentifier path, - final DOMDataTreeWriteTransaction writeTransaction) { - LOG.trace("Remove {} within Restconf Patch: {}", dataStore.name(), path); - writeTransaction.delete(dataStore, path); + private static void removeDataWithinTransaction(final YangInstanceIdentifier path, + final RestconfStrategy strategy) { + LOG.trace("Remove {} within Restconf Patch: {}", LogicalDatastoreType.CONFIGURATION.name(), path); + strategy.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 + * + * @param path Path for data to be created + * @param payload Data to be created + * @param strategy Object that perform the actual DS operations */ - private static void replaceDataWithinTransaction(final LogicalDatastoreType dataStore, - final YangInstanceIdentifier path, + private static void replaceDataWithinTransaction(final YangInstanceIdentifier path, final NormalizedNode payload, - final SchemaContextRef schemaContextRef, - final DOMDataTreeReadWriteTransaction rwTransaction) { - LOG.trace("PUT {} within Restconf Patch: {} with payload {}", dataStore.name(), path, payload); - createData(payload, schemaContextRef.get(), path, rwTransaction, dataStore, false); + final EffectiveModelContext schemaContext, + final RestconfStrategy strategy) { + LOG.trace("PUT {} within Restconf Patch: {} with payload {}", + LogicalDatastoreType.CONFIGURATION.name(), path, payload); + createData(payload, path, strategy, schemaContext, 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 data Data to be created + * @param path Path for data to be created + * @param strategy Object that perform the actual DS operations * @param errorIfExists Enable checking for existence of data (throws error if already exists) */ - private static void createData(final NormalizedNode payload, final SchemaContext schemaContext, + private static void createData(final NormalizedNode data, final YangInstanceIdentifier path, - final DOMDataTreeReadWriteTransaction 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); - } + final RestconfStrategy strategy, + final EffectiveModelContext schemaContext, + final boolean errorIfExists) { + if (errorIfExists) { + strategy.create(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext); } 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 DOMDataTreeReadTransaction rwTransaction, - final LogicalDatastoreType store, final YangInstanceIdentifier path) { - final FluentFuture future = rwTransaction.exists(store, path); - final FutureDataFactory response = new FutureDataFactory<>(); - - FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response); - - if (!response.result) { - LOG.trace("Operation via Restconf was not executed because data at {} does not exist", 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 DOMDataTreeReadTransaction rwTransaction, - final LogicalDatastoreType store, final YangInstanceIdentifier path) { - final FluentFuture future = rwTransaction.exists(store, path); - final FutureDataFactory response = new FutureDataFactory<>(); - - FutureCallbackTx.addCallback(future, PatchData.PATCH_TX_TYPE, response); - - if (response.result) { - LOG.trace("Operation via Restconf was not executed because data at {} already exists", path); - throw new RestconfDocumentedException("Data already exists", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, - path); + strategy.replace(LogicalDatastoreType.CONFIGURATION, path, data, schemaContext); } } }