X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2FSchemaAwareApplyOperation.java;h=afe9653394ec4a3363d34a48d9cd937b73363de1;hb=9e326273260d1ff5d34da8f0c39648a94e97ac68;hp=4bb5aed20c72d9a8424063818cf0c84e31630b47;hpb=fe8a0e74d2a1591bf77d727d388294a123b19f37;p=controller.git diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java index 4bb5aed20c..afe9653394 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/SchemaAwareApplyOperation.java @@ -20,6 +20,7 @@ import org.opendaylight.controller.md.sal.dom.store.impl.tree.NodeModification; import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreMetadataNode; import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreNodeCompositeBuilder; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates; @@ -141,55 +142,61 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper protected abstract void verifyWritenStructure(NormalizedNode writenValue); @Override - public boolean isApplicable(final NodeModification modification, final Optional current) { + public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional current) throws DataPreconditionFailedException { switch (modification.getModificationType()) { case DELETE: - return isDeleteApplicable(modification, current); + checkDeleteApplicable(modification, current); case SUBTREE_MODIFIED: - return isSubtreeModificationApplicable(modification, current); + checkSubtreeModificationApplicable(path,modification, current); + return; case WRITE: - return isWriteApplicable(modification, current); + checkWriteApplicable(path,modification, current); + return; case MERGE: - return isMergeApplicable(modification,current); + checkMergeApplicable(path,modification,current); + return; case UNMODIFIED: - return true; + return; default: - return false; + throw new UnsupportedOperationException("Suplied modification type "+modification.getModificationType()+ "is not supported."); } + } - private boolean isMergeApplicable(final NodeModification modification, final Optional current) { + protected void checkMergeApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional current) throws DataPreconditionFailedException { Optional original = modification.getOriginal(); if (original.isPresent() && current.isPresent()) { - return isNotConflicting(original.get(), current.get()); - } else if (current.isPresent()) { - return true; + /* + * We need to do conflict detection only and only if the value of leaf changed + * before two transactions. If value of leaf is unchanged between two transactions + * it should not cause transaction to fail, since result of this merge + * leads to same data. + */ + if(!original.get().getData().equals(current.get().getData())) { + + checkNotConflicting(path,original.get(), current.get()); + } } - return true; } - protected boolean isWriteApplicable(final NodeModification modification, final Optional current) { + protected void checkWriteApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional current) throws DataPreconditionFailedException { Optional original = modification.getOriginal(); if (original.isPresent() && current.isPresent()) { - return isNotConflicting(original.get(), current.get()); - } else if (current.isPresent()) { - return false; + checkNotConflicting(path,original.get(), current.get()); + } else if(original.isPresent()) { + throw new DataPreconditionFailedException(path,"Node was deleted by other transaction."); } - return true; - } - protected final boolean isNotConflicting(final StoreMetadataNode original, final StoreMetadataNode current) { - return original.getNodeVersion().equals(current.getNodeVersion()) - && original.getSubtreeVersion().equals(current.getSubtreeVersion()); + protected static final void checkNotConflicting(final InstanceIdentifier path,final StoreMetadataNode original, final StoreMetadataNode current) throws DataPreconditionFailedException { + checkDataPrecondition(path, original.getNodeVersion().equals(current.getNodeVersion()),"Node was replaced by other transaction."); + checkDataPrecondition(path,original.getSubtreeVersion().equals(current.getSubtreeVersion()), "Node children was modified by other transaction"); } - protected abstract boolean isSubtreeModificationApplicable(final NodeModification modification, - final Optional current); + protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path,final NodeModification modification, + final Optional current) throws DataPreconditionFailedException; - private boolean isDeleteApplicable(final NodeModification modification, final Optional current) { - // FiXME: Add delete conflict detection. - return true; + private void checkDeleteApplicable(final NodeModification modification, final Optional current) { } @Override @@ -271,9 +278,9 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } @Override - protected boolean isSubtreeModificationApplicable(final NodeModification modification, - final Optional current) { - return false; + protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + throw new DataPreconditionFailedException(path, "Subtree modification is not allowed."); } } @@ -312,6 +319,14 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } } + @Override + protected void checkWriteApplicable(final InstanceIdentifier path, final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + // FIXME: Implement proper write check for replacement of node container + // prerequisite is to have transaction chain available for clients + // otherwise this will break chained writes to same node. + } + @SuppressWarnings("rawtypes") @Override protected void verifyWritenStructure(final NormalizedNode writenValue) { @@ -392,19 +407,29 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } @Override - protected boolean isSubtreeModificationApplicable(final NodeModification modification, - final Optional current) { - if (false == current.isPresent()) { - return false; - } - boolean result = true; + protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + checkDataPrecondition(path, current.isPresent(), "Node was deleted by other transaction."); + checkChildPreconditions(path,modification,current); + + } + + private void checkChildPreconditions(final InstanceIdentifier path, final NodeModification modification, final Optional current) throws DataPreconditionFailedException { StoreMetadataNode currentMeta = current.get(); for (NodeModification childMod : modification.getModifications()) { PathArgument childId = childMod.getIdentifier(); Optional childMeta = currentMeta.getChild(childId); - result &= resolveChildOperation(childId).isApplicable(childMod, childMeta); + InstanceIdentifier childPath = StoreUtils.append(path, childId); + resolveChildOperation(childId).checkApplicable(childPath,childMod, childMeta); + } + } + + @Override + protected void checkMergeApplicable(final InstanceIdentifier path, final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + if(current.isPresent()) { + checkChildPreconditions(path,modification,current); } - return result; } @SuppressWarnings("rawtypes") @@ -497,8 +522,6 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) { super(createAugmentProxy(schema,resolved), AugmentationNode.class); - // FIXME: Use resolved children instead of unresolved. - } @Override @@ -647,9 +670,9 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } @Override - protected boolean isSubtreeModificationApplicable(final NodeModification modification, - final Optional current) { - return false; + protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification, + final Optional current) throws DataPreconditionFailedException { + throw new DataPreconditionFailedException(path, "Subtree modification is not allowed."); } } @@ -726,4 +749,11 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper return new AugmentationSchemaProxy(schema, realChildSchemas); } + public static boolean checkDataPrecondition(final InstanceIdentifier path, final boolean condition, final String message) throws DataPreconditionFailedException { + if(!condition) { + throw new DataPreconditionFailedException(path, message); + } + return condition; + } + }