BUG-624 make netconf tcp address optional in config.ini with default value set to...
[controller.git] / opendaylight / md-sal / sal-dom-broker / src / main / java / org / opendaylight / controller / md / sal / dom / store / impl / tree / data / SchemaAwareApplyOperation.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11
12 import java.util.List;
13
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;
40
41 import com.google.common.base.Optional;
42 import com.google.common.base.Preconditions;
43 import com.google.common.primitives.UnsignedLong;
44
45 abstract class SchemaAwareApplyOperation implements ModificationApplyOperation {
46     private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareApplyOperation.class);
47
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);
59         }
60         throw new IllegalArgumentException("Not supported schema node type for " + schemaNode.getClass());
61     }
62
63     public static SchemaAwareApplyOperation from(final DataNodeContainer resolvedTree,
64             final AugmentationTarget augSchemas, final AugmentationIdentifier identifier) {
65         AugmentationSchema augSchema = null;
66
67         allAugments:
68             for (AugmentationSchema potential : augSchemas.getAvailableAugmentations()) {
69                 for (DataSchemaNode child : potential.getChildNodes()) {
70                     if (identifier.getPossibleChildNames().contains(child.getQName())) {
71                         augSchema = potential;
72                         break allAugments;
73                     }
74                 }
75             }
76
77         if (augSchema != null) {
78             return new DataNodeContainerModificationStrategy.AugmentationModificationStrategy(augSchema, resolvedTree);
79         }
80         return null;
81     }
82
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);
87         }
88         if (schemaNode.isUserOrdered()) {
89             return new OrderedMapModificationStrategy(schemaNode);
90         }
91
92         return new NormalizedNodeContainerModificationStrategy.UnorderedMapModificationStrategy(schemaNode);
93     }
94
95     private static SchemaAwareApplyOperation fromLeafListSchemaNode(final LeafListSchemaNode schemaNode) {
96         if(schemaNode.isUserOrdered()) {
97             return new OrderedLeafSetModificationStrategy(schemaNode);
98         } else {
99             return new UnorderedLeafSetModificationStrategy(schemaNode);
100         }
101     }
102
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");
106     }
107
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();
112     }
113
114     @Override
115     public void verifyStructure(final NodeModification modification) throws IllegalArgumentException {
116         if (modification.getModificationType() == ModificationType.WRITE) {
117             verifyWrittenStructure(modification.getWrittenValue());
118         }
119     }
120
121     @Override
122     public void checkApplicable(final InstanceIdentifier path,final NodeModification modification, final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException {
123         switch (modification.getModificationType()) {
124         case DELETE:
125             checkDeleteApplicable(modification, current);
126         case SUBTREE_MODIFIED:
127             checkSubtreeModificationApplicable(path,modification, current);
128             return;
129         case WRITE:
130             checkWriteApplicable(path,modification, current);
131             return;
132         case MERGE:
133             checkMergeApplicable(path,modification,current);
134             return;
135         case UNMODIFIED:
136             return;
137         default:
138             throw new UnsupportedOperationException("Suplied modification type "+modification.getModificationType()+ "is not supported.");
139         }
140
141     }
142
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()) {
146             /*
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.
151              */
152             if(!original.get().getData().equals(current.get().getData())) {
153
154                 checkNotConflicting(path,original.get(), current.get());
155             }
156         }
157     }
158
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.");
165         }
166     }
167
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);
172         }
173     }
174
175     @Override
176     public final Optional<StoreMetadataNode> apply(final NodeModification modification,
177             final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
178
179         switch (modification.getModificationType()) {
180         case DELETE:
181             return modification.storeSnapshot(Optional.<StoreMetadataNode> absent());
182         case SUBTREE_MODIFIED:
183             Preconditions.checkArgument(currentMeta.isPresent(), "Metadata not available for modification",
184                     modification);
185             return modification.storeSnapshot(Optional.of(applySubtreeChange(modification, currentMeta.get(),
186                     subtreeVersion)));
187         case MERGE:
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
191         case WRITE:
192             return modification.storeSnapshot(Optional.of(applyWrite(modification, currentMeta, subtreeVersion)));
193         case UNMODIFIED:
194             return currentMeta;
195         default:
196             throw new IllegalArgumentException("Provided modification type is not supported.");
197         }
198     }
199
200     protected abstract StoreMetadataNode applyMerge(NodeModification modification,
201             StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
202
203     protected abstract StoreMetadataNode applyWrite(NodeModification modification,
204             Optional<StoreMetadataNode> currentMeta, UnsignedLong subtreeVersion);
205
206     protected abstract StoreMetadataNode applySubtreeChange(NodeModification modification,
207             StoreMetadataNode currentMeta, UnsignedLong subtreeVersion);
208
209     protected abstract void checkSubtreeModificationApplicable(InstanceIdentifier path,final NodeModification modification,
210             final Optional<StoreMetadataNode> current) throws DataPreconditionFailedException;
211
212     protected abstract void verifyWrittenStructure(NormalizedNode<?, ?> writtenValue);
213
214     public static class UnkeyedListModificationStrategy extends SchemaAwareApplyOperation {
215
216         private final Optional<ModificationApplyOperation> entryStrategy;
217
218         protected UnkeyedListModificationStrategy(final ListSchemaNode schema) {
219             entryStrategy = Optional.<ModificationApplyOperation> of(new UnkeyedListItemModificationStrategy(schema));
220         }
221
222         @Override
223         protected StoreMetadataNode applyMerge(final NodeModification modification, final StoreMetadataNode currentMeta,
224                 final UnsignedLong subtreeVersion) {
225             return applyWrite(modification, Optional.of(currentMeta), subtreeVersion);
226         }
227
228         @Override
229         protected StoreMetadataNode applySubtreeChange(final NodeModification modification,
230                 final StoreMetadataNode currentMeta, final UnsignedLong subtreeVersion) {
231             throw new UnsupportedOperationException("UnkeyedList does not support subtree change.");
232         }
233
234         @Override
235         protected StoreMetadataNode applyWrite(final NodeModification modification,
236                 final Optional<StoreMetadataNode> currentMeta, final UnsignedLong subtreeVersion) {
237             return StoreMetadataNode.createRecursively(modification.getWrittenValue(), subtreeVersion);
238         }
239
240         @Override
241         public Optional<ModificationApplyOperation> getChild(final PathArgument child) {
242             if (child instanceof NodeIdentifier) {
243                 return entryStrategy;
244             }
245             return Optional.absent();
246         }
247
248         @Override
249         protected void verifyWrittenStructure(final NormalizedNode<?, ?> writtenValue) {
250
251         }
252
253         @Override
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.");
257         }
258     }
259
260     public static boolean checkDataPrecondition(final InstanceIdentifier path, final boolean condition, final String message) throws DataPreconditionFailedException {
261         if(!condition) {
262             throw new DataPreconditionFailedException(path, message);
263         }
264         return condition;
265     }
266
267 }