X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-dom-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fmd%2Fsal%2Fdom%2Fstore%2Fimpl%2FSchemaAwareApplyOperation.java;h=dd7eb3f71b68012b497bee6b5fb2119bcf9455c9;hp=114595f75b3bed2fb4aa3150f872f6e876f30efc;hb=b23703bef6c3aaafe2dc83608a03b738ad42f945;hpb=8b3405d23e3018afdc4cb5e99bab442ced26e304 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 114595f75b..dd7eb3f71b 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 @@ -2,22 +2,39 @@ package org.opendaylight.controller.md.sal.dom.store.impl; import static com.google.common.base.Preconditions.checkArgument; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ExecutionException; +import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType; 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.data.api.InstanceIdentifier.AugmentationIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode; +import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode; +import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode; +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.api.schema.NormalizedNodeContainer; +import org.opendaylight.yangtools.yang.data.impl.schema.Builders; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder; +import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableChoiceNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder; import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder; +import org.opendaylight.yangtools.yang.model.api.AugmentationSchema; +import org.opendaylight.yangtools.yang.model.api.AugmentationTarget; +import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode; import org.opendaylight.yangtools.yang.model.api.ChoiceNode; import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; import org.opendaylight.yangtools.yang.model.api.DataNodeContainer; @@ -26,7 +43,13 @@ import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; +import com.google.common.base.Function; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import com.google.common.primitives.UnsignedLong; @@ -48,27 +71,93 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper throw new IllegalArgumentException("Not supported schema node type for " + schemaNode.getClass()); } - @Override - public Optional getChild(final PathArgument child) { - throw new IllegalArgumentException(); + public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree, + final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) { + AugmentationSchema augSchema = null; + allAugments : for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) { + boolean containsAll = true; + for(DataSchemaNode child : potential.getChildNodes()) { + if(identifier.getPossibleChildNames().contains(child.getQName())) { + augSchema = potential; + break allAugments; + } + } + } + if(augSchema != null) { + return new AugmentationModificationStrategy(augSchema,resolvedTree); + } + return null; } + + protected final ModificationApplyOperation resolveChildOperation(final PathArgument child) { Optional potential = getChild(child); checkArgument(potential.isPresent(), "Operation for child %s is not defined.", child); return potential.get(); } + @Override + public void verifyStructure(final NodeModification modification) throws IllegalArgumentException { + if (modification.getModificationType() == ModificationType.WRITE) { + verifyWritenStructure(modification.getWritenValue()); + } + } + + protected abstract void verifyWritenStructure(NormalizedNode writenValue); + + @Override + public boolean isApplicable(final NodeModification modification, final Optional current) { + switch (modification.getModificationType()) { + case DELETE: + return isDeleteApplicable(modification, current); + case SUBTREE_MODIFIED: + return isSubtreeModificationApplicable(modification, current); + case WRITE: + return isWriteApplicable(modification, current); + case UNMODIFIED: + return true; + default: + return false; + } + } + + protected boolean isWriteApplicable(final NodeModification modification, final Optional current) { + Optional original = modification.getOriginal(); + if (original.isPresent() && current.isPresent()) { + return isNotConflicting(original.get(), current.get()); + } else if (current.isPresent()) { + return false; + } + return true; + + } + + protected final boolean isNotConflicting(final StoreMetadataNode original, final StoreMetadataNode current) { + return original.getNodeVersion().equals(current.getNodeVersion()) + && original.getSubtreeVersion().equals(current.getSubtreeVersion()); + } + + protected abstract boolean isSubtreeModificationApplicable(final NodeModification modification, + final Optional current); + + private boolean isDeleteApplicable(final NodeModification modification, final Optional current) { + // FiXME: Add delete conflict detection. + return true; + } + @Override public final Optional apply(final NodeModification modification, - final Optional currentMeta) { + final Optional currentMeta, final UnsignedLong subtreeVersion) { + switch (modification.getModificationType()) { case DELETE: - return Optional.absent(); + return modification.storeSnapshot(Optional.absent()); case SUBTREE_MODIFIED: - return Optional.of(applySubtreeChange(modification, currentMeta.get())); + Preconditions.checkArgument(currentMeta.isPresent(),"Metadata not available for modification",modification); + return modification.storeSnapshot(Optional.of(applySubtreeChange(modification, currentMeta.get(), subtreeVersion))); case WRITE: - return Optional.of(applyWrite(modification, currentMeta)); + return modification.storeSnapshot(Optional.of(applyWrite(modification, currentMeta, subtreeVersion))); case UNMODIFIED: return currentMeta; default: @@ -77,18 +166,26 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } protected abstract StoreMetadataNode applyWrite(NodeModification modification, - Optional currentMeta); + Optional currentMeta, UnsignedLong subtreeVersion); - protected abstract StoreMetadataNode applySubtreeChange(NodeModification modification, StoreMetadataNode currentMeta); + protected abstract StoreMetadataNode applySubtreeChange(NodeModification modification, + StoreMetadataNode currentMeta, UnsignedLong subtreeVersion); public static abstract class ValueNodeModificationStrategy extends SchemaAwareApplyOperation { private final T schema; + private final Class> nodeClass; - protected ValueNodeModificationStrategy(final T schema) { + protected ValueNodeModificationStrategy(final T schema, final Class> nodeClass) { super(); this.schema = schema; + this.nodeClass = nodeClass; + } + + @Override + protected void verifyWritenStructure(final NormalizedNode writenValue) { + checkArgument(nodeClass.isInstance(writenValue), "Node should must be of type %s", nodeClass); } @Override @@ -98,89 +195,141 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } @Override - protected StoreMetadataNode applySubtreeChange(final NodeModification modification, final StoreMetadataNode currentMeta) { + protected StoreMetadataNode applySubtreeChange(final NodeModification modification, + final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) { throw new UnsupportedOperationException("Node " + schema.getPath() + "is leaf type node. Subtree change is not allowed."); } @Override - protected StoreMetadataNode applyWrite(final NodeModification modification, final Optional currentMeta) { - return StoreMetadataNode.builder() - // FIXME Add .increaseNodeVersion() + protected StoreMetadataNode applyWrite(final NodeModification modification, + final Optional currentMeta, final UnsignedLong subtreeVersion) { + UnsignedLong nodeVersion = subtreeVersion; + if (currentMeta.isPresent()) { + nodeVersion = StoreUtils.increase(currentMeta.get().getNodeVersion()); + } + + return StoreMetadataNode.builder().setNodeVersion(nodeVersion).setSubtreeVersion(subtreeVersion) .setData(modification.getWritenValue()).build(); } + @Override + protected boolean isSubtreeModificationApplicable(final NodeModification modification, + final Optional current) { + return false; + } + } public static class LeafSetEntryModificationStrategy extends ValueNodeModificationStrategy { + @SuppressWarnings({ "unchecked", "rawtypes" }) protected LeafSetEntryModificationStrategy(final LeafListSchemaNode schema) { - super(schema); + super(schema, (Class) LeafSetEntryNode.class); } } public static class LeafModificationStrategy extends ValueNodeModificationStrategy { + @SuppressWarnings({ "unchecked", "rawtypes" }) protected LeafModificationStrategy(final LeafSchemaNode schema) { - super(schema); + super(schema, (Class) LeafNode.class); } } public static abstract class NormalizedNodeContainerModificationStrategy extends SchemaAwareApplyOperation { + private final Class> nodeClass; + + protected NormalizedNodeContainerModificationStrategy(final Class> nodeClass) { + this.nodeClass = nodeClass; + } + + @Override + public void verifyStructure(final NodeModification modification) throws IllegalArgumentException { + if (modification.getModificationType() == ModificationType.WRITE) { + + } + for (NodeModification childModification : modification.getModifications()) { + resolveChildOperation(childModification.getIdentifier()).verifyStructure(childModification); + } + } + + @SuppressWarnings("rawtypes") + @Override + protected void verifyWritenStructure(final NormalizedNode writenValue) { + checkArgument(nodeClass.isInstance(writenValue), "Node should must be of type %s", nodeClass); + checkArgument(writenValue instanceof NormalizedNodeContainer); + NormalizedNodeContainer writenCont = (NormalizedNodeContainer) writenValue; + for (Object child : writenCont.getValue()) { + checkArgument(child instanceof NormalizedNode); + NormalizedNode childNode = (NormalizedNode) child; + } + } + @Override - protected StoreMetadataNode applyWrite(final NodeModification modification, final Optional currentMeta) { + protected StoreMetadataNode applyWrite(final NodeModification modification, + final Optional currentMeta, final UnsignedLong subtreeVersion) { // NormalizedNode newValue = modification.getWritenValue(); - StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursivelly(newValue, UnsignedLong.valueOf(0)); + UnsignedLong nodeVersion = subtreeVersion; + if (currentMeta.isPresent()) { + nodeVersion = StoreUtils.increase(currentMeta.get().getNodeVersion()); + } + StoreMetadataNode newValueMeta = StoreMetadataNode.createRecursively(newValue, nodeVersion, nodeVersion); - if(!modification.hasAdditionalModifications()) { + if (!modification.hasAdditionalModifications()) { return newValueMeta; } - StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(newValueMeta, - createBuilder(modification.getIdentifier())); + @SuppressWarnings("rawtypes") + NormalizedNodeContainerBuilder dataBuilder = createBuilder(modification.getIdentifier()); + StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder) // + .setNodeVersion(nodeVersion) // + .setSubtreeVersion(subtreeVersion); - Set processedPreexisting = applyPreexistingChildren(modification, newValueMeta.getChildren(), builder); - applyNewChildren(modification, processedPreexisting, builder); + Set processedPreexisting = applyPreexistingChildren(modification, newValueMeta.getChildren(), + builder, nodeVersion); + applyNewChildren(modification, processedPreexisting, builder, nodeVersion); return builder.build(); } @Override - @SuppressWarnings("rawtypes") - public StoreMetadataNode applySubtreeChange(final NodeModification modification, final StoreMetadataNode currentMeta) { - - StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(currentMeta, - createBuilder(modification.getIdentifier())); - builder.setIdentifier(modification.getIdentifier()); - + public StoreMetadataNode applySubtreeChange(final NodeModification modification, + final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) { + + UnsignedLong updatedSubtreeVersion = StoreUtils.increase(currentMeta.getSubtreeVersion()); + @SuppressWarnings("rawtypes") + NormalizedNodeContainerBuilder dataBuilder = createBuilder(modification.getIdentifier()); + StoreNodeCompositeBuilder builder = StoreNodeCompositeBuilder.from(dataBuilder) + .setIdentifier(modification.getIdentifier()).setNodeVersion(currentMeta.getNodeVersion()) + .setSubtreeVersion(updatedSubtreeVersion); // We process preexisting nodes - Set processedPreexisting = applyPreexistingChildren(modification, - currentMeta.getChildren(), builder); - applyNewChildren(modification, processedPreexisting, builder); + Set processedPreexisting = applyPreexistingChildren(modification, currentMeta.getChildren(), + builder, updatedSubtreeVersion); + applyNewChildren(modification, processedPreexisting, builder, updatedSubtreeVersion); return builder.build(); } private void applyNewChildren(final NodeModification modification, final Set ignore, - final StoreNodeCompositeBuilder builder) { + final StoreNodeCompositeBuilder builder, final UnsignedLong subtreeVersion) { for (NodeModification childModification : modification.getModifications()) { PathArgument childIdentifier = childModification.getIdentifier(); // We skip allready processed modifications if (ignore.contains(childIdentifier)) { continue; } - Optional childResult = resolveChildOperation(childIdentifier) // - .apply(childModification, Optional. absent()); - if (childResult.isPresent()) { - builder.add(childResult.get()); - } + + builder.addIfPresent(resolveChildOperation(childIdentifier) // + .apply(childModification, Optional. absent(), subtreeVersion)); } } private Set applyPreexistingChildren(final NodeModification modification, - final Iterable children, final StoreNodeCompositeBuilder nodeBuilder) { + final Iterable children, final StoreNodeCompositeBuilder nodeBuilder, + final UnsignedLong subtreeVersion) { Builder processedModifications = ImmutableSet. builder(); for (StoreMetadataNode childMeta : children) { PathArgument childIdentifier = childMeta.getIdentifier(); @@ -189,8 +338,9 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper // Node is modified if (childModification.isPresent()) { processedModifications.add(childIdentifier); - Optional change = resolveChildOperation(childIdentifier) // - .apply(childModification.get(), Optional.of(childMeta)); + Optional result = resolveChildOperation(childIdentifier) // + .apply(childModification.get(), Optional.of(childMeta), subtreeVersion); + nodeBuilder.addIfPresent(result); } else { // Child is unmodified - reuse existing metadata and data // snapshot @@ -200,6 +350,22 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper return processedModifications.build(); } + @Override + protected boolean isSubtreeModificationApplicable(final NodeModification modification, + final Optional current) { + if (false == current.isPresent()) { + return false; + } + boolean result = true; + StoreMetadataNode currentMeta = current.get(); + for (NodeModification childMod : modification.getModifications()) { + PathArgument childId = childMod.getIdentifier(); + Optional childMeta = currentMeta.getChild(childId); + result &= resolveChildOperation(childId).isApplicable(childMod, childMeta); + } + return result; + } + @SuppressWarnings("rawtypes") protected abstract NormalizedNodeContainerBuilder createBuilder(PathArgument identifier); } @@ -208,9 +374,26 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper NormalizedNodeContainerModificationStrategy { private final T schema; - - protected DataNodeContainerModificationStrategy(final T schema) { - super(); + private final LoadingCache childCache = CacheBuilder.newBuilder().build( + CacheLoader.from(new Function() { + + @Override + public ModificationApplyOperation apply(final PathArgument identifier) { + if (identifier instanceof AugmentationIdentifier && schema instanceof AugmentationTarget) { + return from(schema, (AugmentationTarget) schema, (AugmentationIdentifier) identifier); + } + + DataSchemaNode child = schema.getDataChildByName(identifier.getNodeType()); + if (child == null) { + return null; + } + return from(child); + } + })); + + protected DataNodeContainerModificationStrategy(final T schema, + final Class> nodeClass) { + super(nodeClass); this.schema = schema; } @@ -220,11 +403,11 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper @Override public Optional getChild(final PathArgument identifier) { - DataSchemaNode child = schema.getDataChildByName(identifier.getNodeType()); - if (child == null || child.isAugmenting()) { + try { + return Optional. fromNullable(childCache.get(identifier)); + } catch (ExecutionException e) { return Optional.absent(); } - return Optional. of(from(child)); } @Override @@ -242,7 +425,7 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper DataNodeContainerModificationStrategy { public ContainerModificationStrategy(final ContainerSchemaNode schemaNode) { - super(schemaNode); + super(schemaNode, ContainerNode.class); } @Override @@ -255,19 +438,52 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper } + public static class AugmentationModificationStrategy extends + DataNodeContainerModificationStrategy { + + protected AugmentationModificationStrategy(final AugmentationSchema schema, final DataNodeContainer resolved) { + super(schema, AugmentationNode.class); + // FIXME: Use resolved children instead of unresolved. + + } + + + @Override + protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) { + return Builders.augmentationBuilder().withNodeIdentifier((AugmentationIdentifier) identifier); + } + + } + public static class ChoiceModificationStrategy extends NormalizedNodeContainerModificationStrategy { private final ChoiceNode schema; + private final Map childNodes; public ChoiceModificationStrategy(final ChoiceNode schemaNode) { + super(org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode.class); this.schema = schemaNode; + ImmutableMap.Builder child = ImmutableMap.builder(); + + for(ChoiceCaseNode caze : schemaNode.getCases()) { + for(DataSchemaNode cazeChild : caze.getChildNodes()) { + SchemaAwareApplyOperation childNode = from(cazeChild); + child.put(new NodeIdentifier(cazeChild.getQName()),childNode); + } + } + childNodes = child.build(); + } + + @Override + public Optional getChild(final PathArgument child) { + return Optional.fromNullable(childNodes.get(child)); } @Override @SuppressWarnings("rawtypes") protected DataContainerNodeBuilder createBuilder(final PathArgument identifier) { checkArgument(identifier instanceof NodeIdentifier); - return ImmutableContainerNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); + return ImmutableChoiceNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); } } @@ -275,7 +491,7 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper public static class ListEntryModificationStrategy extends DataNodeContainerModificationStrategy { protected ListEntryModificationStrategy(final ListSchemaNode schema) { - super(schema); + super(schema, MapEntryNode.class); } @Override @@ -290,10 +506,13 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper private final Optional entryStrategy; + @SuppressWarnings({ "unchecked", "rawtypes" }) protected LeafSetModificationStrategy(final LeafListSchemaNode schema) { + super((Class) LeafSetNode.class); entryStrategy = Optional. of(new LeafSetEntryModificationStrategy(schema)); } + @SuppressWarnings("rawtypes") @Override protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) { return ImmutableLeafSetNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier); @@ -314,9 +533,11 @@ public abstract class SchemaAwareApplyOperation implements ModificationApplyOper private final Optional entryStrategy; protected ListMapModificationStrategy(final ListSchemaNode schema) { + super(MapNode.class); entryStrategy = Optional. of(new ListEntryModificationStrategy(schema)); } + @SuppressWarnings("rawtypes") @Override protected NormalizedNodeContainerBuilder createBuilder(final PathArgument identifier) { return ImmutableMapNodeBuilder.create().withNodeIdentifier((NodeIdentifier) identifier);