2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import java.util.List;
14 import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataPreconditionFailedException;
15 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
16 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.DataNodeContainerModificationStrategy.ContainerModificationStrategy;
17 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.DataNodeContainerModificationStrategy.UnkeyedListItemModificationStrategy;
18 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.ChoiceModificationStrategy;
19 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.OrderedLeafSetModificationStrategy;
20 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.OrderedMapModificationStrategy;
21 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.NormalizedNodeContainerModificationStrategy.UnorderedLeafSetModificationStrategy;
22 import org.opendaylight.controller.md.sal.dom.store.impl.tree.data.ValueNodeModificationStrategy.LeafModificationStrategy;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
26 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
28 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
29 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
30 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
31 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
32 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
34 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 import com.google.common.base.Optional;
42 import com.google.common.base.Preconditions;
43 import com.google.common.primitives.UnsignedLong;
45 abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
46 private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareApplyOperation.class);
48 public static SchemaAwareApplyOperation from(final DataSchemaNode schemaNode) {
49 if (schemaNode instanceof ContainerSchemaNode) {
50 return new ContainerModificationStrategy((ContainerSchemaNode) schemaNode);
51 } else if (schemaNode instanceof ListSchemaNode) {
52 return fromListSchemaNode((ListSchemaNode) schemaNode);
53 } else if (schemaNode instanceof ChoiceNode) {
54 return new ChoiceModificationStrategy((ChoiceNode) schemaNode);
55 } else if (schemaNode instanceof LeafListSchemaNode) {
56 return fromLeafListSchemaNode((LeafListSchemaNode) schemaNode);
57 } else if (schemaNode instanceof LeafSchemaNode) {
58 return new LeafModificationStrategy((LeafSchemaNode) schemaNode);
60 throw new IllegalArgumentException("Not supported schema node type for " + schemaNode.getClass());
63 public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
64 final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
65 AugmentationSchema augSchema = null;
68 for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
69 for (DataSchemaNode child : potential.getChildNodes()) {
70 if (identifier.getPossibleChildNames().contains(child.getQName())) {
71 augSchema = potential;
77 if (augSchema != null) {
78 return new DataNodeContainerModificationStrategy.AugmentationModificationStrategy(augSchema, resolvedTree);
83 private static SchemaAwareApplyOperation fromListSchemaNode(final ListSchemaNode schemaNode) {
84 List<QName> keyDefinition = schemaNode.getKeyDefinition();
85 if (keyDefinition == null || keyDefinition.isEmpty()) {
86 return new UnkeyedListModificationStrategy(schemaNode);
88 if (schemaNode.isUserOrdered()) {
89 return new OrderedMapModificationStrategy(schemaNode);
92 return new NormalizedNodeContainerModificationStrategy.UnorderedMapModificationStrategy(schemaNode);
95 private static SchemaAwareApplyOperation fromLeafListSchemaNode(final LeafListSchemaNode schemaNode) {
96 if(schemaNode.isUserOrdered()) {
97 return new OrderedLeafSetModificationStrategy(schemaNode);
99 return new UnorderedLeafSetModificationStrategy(schemaNode);
103 private static final void checkNotConflicting(final InstanceIdentifier path,final StoreMetadataNode original, final StoreMetadataNode current) throws DataPreconditionFailedException {
104 checkDataPrecondition(path, original.getNodeVersion().equals(current.getNodeVersion()),"Node was replaced by other transaction.");
105 checkDataPrecondition(path,original.getSubtreeVersion().equals(current.getSubtreeVersion()), "Node children was modified by other transaction");
108 protected final ModificationApplyOperation resolveChildOperation(final PathArgument child) {
109 Optional<ModificationApplyOperation> potential = getChild(child);
110 checkArgument(potential.isPresent(), "Operation for child %s is not defined.", child);
111 return potential.get();
115 public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
116 if (modification.getModificationType() == ModificationType.WRITE) {
117 verifyWrittenStructure(modification.getWrittenValue());
122 public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
123 switch (modification.getModificationType()) {
125 checkDeleteApplicable(modification, current);
126 case SUBTREE_MODIFIED:
127 checkSubtreeModificationApplicable(path,modification, current);
130 checkWriteApplicable(path,modification, current);
133 checkMergeApplicable(path,modification,current);
138 throw new UnsupportedOperationException("Suplied modification type "+modification.getModificationType()+ "is not supported.");
143 protected void checkMergeApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
144 Optional<StoreMetadataNode> original = modification.getOriginal();
145 if (original.isPresent() && current.isPresent()) {
147 * We need to do conflict detection only and only if the value of leaf changed
148 * before two transactions. If value of leaf is unchanged between two transactions
149 * it should not cause transaction to fail, since result of this merge
150 * leads to same data.
152 if(!original.get().getData().equals(current.get().getData())) {
154 checkNotConflicting(path,original.get(), current.get());
159 protected void checkWriteApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
160 Optional<StoreMetadataNode> original = modification.getOriginal();
161 if (original.isPresent() && current.isPresent()) {
162 checkNotConflicting(path,original.get(), current.get());
163 } else if(original.isPresent()) {
164 throw new DataPreconditionFailedException(path,"Node was deleted by other transaction.");
168 private void checkDeleteApplicable(final NodeModification modification, final Optional<StoreMetadataNode> current) {
169 // Delete is always applicable, we do not expose it to subclasses
170 if (current.isPresent()) {
171 LOG.trace("Delete operation turned to no-op on missing node {}", modification);
176 public final Optional<StoreMetadataNode> apply(final NodeModification modification,
177 final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
179 switch (modification.getModificationType()) {
181 return modification.storeSnapshot(Optional.<StoreMetadataNode> absent());
182 case SUBTREE_MODIFIED:
183 Preconditions.checkArgument(currentMeta.isPresent(), "Metadata not available for modification",
185 return modification.storeSnapshot(Optional.of(applySubtreeChange(modification, currentMeta.get(),
188 if(currentMeta.isPresent()) {
189 return modification.storeSnapshot(Optional.of(applyMerge(modification,currentMeta.get(),subtreeVersion)));
190 } // Fallback to write is intentional - if node is not preexisting merge is same as write
192 return modification.storeSnapshot(Optional.of(applyWrite(modification, currentMeta, subtreeVersion)));
196 throw new IllegalArgumentException("Provided modification type is not supported.");
200 protected abstract StoreMetadataNode applyMerge(NodeModification modification,
201 StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
203 protected abstract StoreMetadataNode applyWrite(NodeModification modification,
204 Optional<StoreMetadataNode> currentMeta, UnsignedLong subtreeVersion);
206 protected abstract StoreMetadataNode applySubtreeChange(NodeModification modification,
207 StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
209 protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path,final NodeModification modification,
210 final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
212 protected abstract void verifyWrittenStructure(NormalizedNode<?, ?> writtenValue);
214 public static class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
216 private final Optional<ModificationApplyOperation> entryStrategy;
218 protected UnkeyedListModificationStrategy(final ListSchemaNode schema) {
219 entryStrategy = Optional.<ModificationApplyOperation> of(new UnkeyedListItemModificationStrategy(schema));
223 protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
224 final UnsignedLong subtreeVersion) {
225 return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
229 protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
230 final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
231 throw new UnsupportedOperationException("UnkeyedList does not support subtree change.");
235 protected StoreMetadataNode applyWrite(final NodeModification modification,
236 final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
237 return StoreMetadataNode.createRecursively(modification.getWrittenValue(), subtreeVersion);
241 public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
242 if (child instanceof NodeIdentifier) {
243 return entryStrategy;
245 return Optional.absent();
249 protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
254 protected void checkSubtreeModificationApplicable(final InstanceIdentifier path,final NodeModification modification,
255 final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
256 throw new DataPreconditionFailedException(path, "Subtree modification is not allowed.");
260 public static boolean checkDataPrecondition(final InstanceIdentifier path, final boolean condition, final String message) throws DataPreconditionFailedException {
262 throw new DataPreconditionFailedException(path, message);