From 454903c516e9405ff4a1af6392a31b00c04852fa Mon Sep 17 00:00:00 2001 From: Tom Pantelis Date: Tue, 7 Mar 2017 09:57:54 -0500 Subject: [PATCH] Add new DOMDataTreeCommitCohort#canCoomit method If a cohort registers for yang list entries, there may be multiple list entry modifications in a transaction thus the canCommit method needs to take a Collection of DOMDataTreeCandidates for consistency. For avoid breaking current implementations, I added the new method with a default implementation that invokes the single DOMDataTreeCandidate canCommit method with a warning that the new canCommit method should be implemented. The single canCommit method is now deprecated with a default implementation that logs an error and returns success. Change-Id: If83d380a0ca8ba55be9e99b3d1da4d309e9a6487 Signed-off-by: Tom Pantelis --- .../mdsal/common/api/PostCanCommitStep.java | 2 +- .../dom/api/DOMDataTreeCommitCohort.java | 92 ++++++++++++++++--- 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/PostCanCommitStep.java b/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/PostCanCommitStep.java index eac087d2cf..cba9dbf1ae 100644 --- a/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/PostCanCommitStep.java +++ b/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/PostCanCommitStep.java @@ -44,7 +44,7 @@ public interface PostCanCommitStep extends ThreePhaseCommitStep { * Successful future, returning {@link #NOOP} implementation of {@link PostCanCommitStep}s. * **/ - CheckedFuture NOOP_SUCCESS_FUTURE = + CheckedFuture NOOP_SUCCESS_FUTURE = Futures.immediateCheckedFuture(NOOP); /** diff --git a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeCommitCohort.java b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeCommitCohort.java index 251061d9f6..868586cdb9 100644 --- a/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeCommitCohort.java +++ b/dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeCommitCohort.java @@ -8,11 +8,21 @@ package org.opendaylight.mdsal.dom.api; import com.google.common.annotations.Beta; +import com.google.common.collect.Iterables; +import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import javax.annotation.Nonnull; import org.opendaylight.mdsal.common.api.DataValidationFailedException; import org.opendaylight.mdsal.common.api.PostCanCommitStep; +import org.opendaylight.yangtools.util.concurrent.ExceptionMapper; +import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture; import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.slf4j.LoggerFactory; /** * Commit cohort participating in commit of data modification, which can validate data tree @@ -23,10 +33,10 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; * {@link DOMDataTreeCommitCohort}s are hooked up into commit of data tree changes and MAY * negatively affect performance of data broker / store. * Implementations of this interface are discouraged, unless you really need ability to veto data - * tree changes, or to provide external state change in sync with visibility of commited data. + * tree changes, or to provide external state change in sync with visibility of committed data. * *

Implementation requirements

- *

Correctness assumptions

Implementation SHOULD use only {@link DOMDataTreeCandidate} and + *

Correctness assumptions

Implementation SHOULD use only the {@link DOMDataTreeCandidate} instances and * provided {@link SchemaContext} for validation purposes. * Use of any other external mutable state is discouraged, implementation MUST NOT use any * transaction related APIs on same data broker / data store instance during invocation of @@ -36,17 +46,17 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; * and such calls may fail. *

Correct model usage

If implementation is performing YANG-model driven validation * implementation SHOULD use provided schema context. - * Any other instance of {@link SchemaContext} obtained by other means, may not be valid for - * associated DOMDataTreeCandidate and it may lead to incorrect validation or processing of provided + * Any other instance of {@link SchemaContext} obtained by other means, may not be valid for the + * associated DOMDataTreeCandidates and it may lead to incorrect validation or processing of provided * data. - *

DataTreeCandidate assumptions

Implementation SHOULD NOT make any assumptions on + *

DataTreeCandidate assumptions

Implementation SHOULD NOT make any assumptions on a * {@link DOMDataTreeCandidate} being successfully committed until associated * {@link PostCanCommitStep#preCommit()} and * {@link org.opendaylight.mdsal.common.api.PostPreCommitStep#commit()} callback was invoked. *

Usage patterns

*

Data Tree Validator

- * Validator is implementation, which only validates {@link DOMDataTreeCandidate} and does not - * retain any state derived from edited data - does not care if {@link DOMDataTreeCandidate} was + * Validator is implementation, which only validates {@link DOMDataTreeCandidate} instances and does not + * retain any state derived from edited data - does not care if a {@link DOMDataTreeCandidate} was * rejected afterwards or transaction was cancelled. * Implementation may opt-out from receiving {@code preCommit()}, {@code commit()}, {@code abort()} * callbacks by returning {@link PostCanCommitStep#NOOP}. @@ -59,7 +69,25 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext; public interface DOMDataTreeCommitCohort { /** - * Validates supplied data tree candidate and associates cohort-specific steps with data broker + * DO NOT implement or invoke this method. It is deprecated in favor of + * {@link #canCommit(Object, Collection, SchemaContext)} and only exists for backwards compatibility. The + * default implementation returns {@link PostCanCommitStep#NOOP_SUCCESS_FUTURE} and is invoked by the + * default implementation of {@link #canCommit(Object, Collection, SchemaContext)}. + * + * @deprecated Implement and invoke {@link #canCommit(Object, Collection, SchemaContext)} instead. + */ + @Deprecated + @Nonnull + default CheckedFuture canCommit(@Nonnull Object txId, + @Nonnull DOMDataTreeCandidate candidate, @Nonnull SchemaContext ctx) { + LoggerFactory.getLogger(getClass()).error( + "The default implementation of DOMDataTreeCommitCohort#canCommit(Object, DOMDataTreeCandidate, " + + "SchemaContext) was invoked on {}", getClass()); + return PostCanCommitStep.NOOP_SUCCESS_FUTURE; + } + + /** + * Validates supplied data tree candidates and associates cohort-specific steps with data broker * transaction. * If {@link DataValidationFailedException} is thrown by implementation, commit of supplied data * will be prevented, with the DataBroker transaction providing the thrown exception as the @@ -79,16 +107,50 @@ public interface DOMDataTreeCommitCohort { * * @param txId Transaction identifier. SHOULD be used only for reporting and correlation. * Implementation MUST NOT use {@code txId} for validation. - * @param candidate Data Tree candidate to be validated and committed. + * @param candidates Data Tree candidates to be validated and committed. * @param ctx Schema Context to which Data Tree candidate should conform. - * @return Checked future which will successfully complete with user-supplied implementation of - * {@link PostCanCommitStep} if data are valid, or failed check future with - * {@link DataValidationFailedException} if and only if provided - * {@link DOMDataTreeCandidate} did not pass validation. Users are encouraged to use + * @return Checked future which will successfully complete with the user-supplied implementation of + * {@link PostCanCommitStep} if all candidates are valid, or a failed checked future with a + * {@link DataValidationFailedException} if and only if a provided + * {@link DOMDataTreeCandidate} instance did not pass validation. Users are encouraged to use * more specific subclasses of this exception to provide additional information about * validation failure reason. */ @Nonnull - CheckedFuture canCommit(@Nonnull Object txId, - @Nonnull DOMDataTreeCandidate candidate, @Nonnull SchemaContext ctx); + default CheckedFuture canCommit(@Nonnull Object txId, + @Nonnull Collection candidates, @Nonnull SchemaContext ctx) { + LoggerFactory.getLogger(getClass()).warn("DOMDataTreeCommitCohort implementation {} should override " + + "canCommit(Object, Collection, SchemaContext)", getClass()); + + // For backwards compatibility, the default implementation is to invoke the deprecated + // canCommit(Object, DOMDataTreeCandidate, SchemaContext) method for each DOMDataTreeCandidate and return the + // last PostCanCommitStep. + List> futures = new ArrayList<>(); + for (DOMDataTreeCandidate candidate : candidates) { + futures.add(canCommit(txId, candidate, ctx)); + } + + final ListenableFuture resultFuture = Futures.transform(Futures.allAsList(futures), + (AsyncFunction, PostCanCommitStep>)input -> + Futures.immediateFuture(input.get(input.size() - 1))); + return MappingCheckedFuture.create(resultFuture, new DataValidationFailedExceptionMapper("canCommit", + Iterables.getLast(candidates).getRootPath())); + } + + /** + * An ExceptionMapper that translates an Exception to a DataValidationFailedException. + */ + class DataValidationFailedExceptionMapper extends ExceptionMapper { + private final DOMDataTreeIdentifier failedTreeId; + + public DataValidationFailedExceptionMapper(String opName, DOMDataTreeIdentifier failedTreeId) { + super(opName, DataValidationFailedException.class); + this.failedTreeId = failedTreeId; + } + + @Override + protected DataValidationFailedException newWithCause(String message, Throwable cause) { + return new DataValidationFailedException(DOMDataTreeIdentifier.class, failedTreeId, message, cause); + } + } } -- 2.36.6