2 * Copyright (c) 2013 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.yangtools.yang.data.operations;
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Lists;
13 import com.google.common.collect.Sets;
14 import java.util.List;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
18 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
22 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
27 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
28 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
29 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
34 abstract class AbstractContainerNodeModification<S, N extends DataContainerNode<?>> implements Modification<S, N> {
37 public final Optional<N> modify(S schema, Optional<N> actual, Optional<N> modification,
38 OperationStack operationStack) throws DataModificationException {
40 operationStack.enteringNode(modification);
43 QName nodeQName = getQName(schema);
45 switch (operationStack.getCurrentOperation()) {
47 DataModificationException.DataMissingException.check(nodeQName, actual);
50 result = Optional.absent();
54 DataModificationException.DataExistsException.check(nodeQName, actual, null);
57 result = modification;
61 DataModificationException.DataMissingException.check(nodeQName, actual);
64 // Recursively modify all child nodes
65 result = modifyContainer(schema, actual, modification, operationStack);
69 throw new UnsupportedOperationException(String.format("Unable to perform operation: %s on: %s, unknown",
70 operationStack.getCurrentOperation(), schema));
73 operationStack.exitingNode(modification);
77 protected abstract QName getQName(S schema);
79 private Optional<N> modifyContainer(S schema, Optional<N> actual, Optional<N> modification,
80 OperationStack operationStack) throws DataModificationException {
82 if (!actual.isPresent()) {
86 if (!modification.isPresent()) {
90 Set<YangInstanceIdentifier.PathArgument> toProcess = getChildrenToProcess(schema, actual, modification);
92 List<? extends DataContainerChild<?, ?>> merged = modifyContainerChildNodes(schema, operationStack,
93 actual.get(), modification.get(), toProcess);
94 return build(schema, merged);
97 private List<? extends DataContainerChild<?, ?>> modifyContainerChildNodes(S schema, OperationStack operationStack,
98 N actual, N modification, Set<YangInstanceIdentifier.PathArgument> toProcess) throws DataModificationException {
99 List<DataContainerChild<?, ?>> result = Lists.newArrayList();
101 for (YangInstanceIdentifier.PathArgument childToProcessId : toProcess) {
102 Object schemaOfChildToProcess = findSchema(schema, childToProcessId);
104 Optional<? extends DataContainerChild<?, ?>> modifiedValues = modifyContainerNode(operationStack, actual,
105 modification, childToProcessId, schemaOfChildToProcess);
107 if (modifiedValues.isPresent()) {
108 result.add(modifiedValues.get());
115 private Optional<? extends DataContainerChild<?, ?>> modifyContainerNode(OperationStack operationStack, N actual,
116 N modification, YangInstanceIdentifier.PathArgument childToProcess, Object schemaChild)
117 throws DataModificationException {
119 Optional<DataContainerChild<?, ?>> storedChildren = actual.getChild(childToProcess);
120 Optional<DataContainerChild<?, ?>> modifiedChildren = modification.getChild(childToProcess);
122 return NodeDispatcher.dispatchChildModification(schemaChild, storedChildren, modifiedChildren, operationStack);
125 private Object findSchema(S schema, YangInstanceIdentifier.PathArgument childToProcessId) {
126 if (childToProcessId instanceof YangInstanceIdentifier.AugmentationIdentifier) {
127 return findSchemaForAugment(schema, (YangInstanceIdentifier.AugmentationIdentifier) childToProcessId);
129 return findSchemaForChild(schema, childToProcessId.getNodeType());
133 protected abstract Object findSchemaForChild(S schema, QName nodeType);
135 protected abstract Object findSchemaForAugment(S schema, YangInstanceIdentifier.AugmentationIdentifier childToProcessId);
137 private Optional<N> build(S schema, List<? extends DataContainerChild<?, ?>> result) {
138 DataContainerNodeBuilder<?, N> b = getBuilder(schema);
140 // TODO skip empty container nodes ? e.g. if container looses all its child nodes
141 // if(result.isEmpty()) {
142 // return Optional.absent();
145 for (DataContainerChild<?, ?> dataContainerChild : result) {
146 b.withChild(dataContainerChild);
148 return Optional.of(b.build());
151 protected abstract DataContainerNodeBuilder<?, N> getBuilder(S schema);
153 protected Set<YangInstanceIdentifier.PathArgument> getChildrenToProcess(S schema, Optional<N> actual,
154 Optional<N> modification) throws DataModificationException {
155 Set<YangInstanceIdentifier.PathArgument> qNames = Sets.newLinkedHashSet();
157 qNames.addAll(getChildQNames(actual));
158 qNames.addAll(getChildQNames(modification));
162 private Set<? extends YangInstanceIdentifier.PathArgument> getChildQNames(Optional<N> actual) {
163 Set<YangInstanceIdentifier.PathArgument> qNames = Sets.newLinkedHashSet();
165 for (DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> child : actual.get().getValue()) {
166 qNames.add(child.getIdentifier());
172 private static final class NodeDispatcher {
174 private static final LeafNodeModification LEAF_NODE_MODIFICATION = new LeafNodeModification();
175 private static final LeafSetNodeModification LEAF_SET_NODE_MODIFICATION = new LeafSetNodeModification();
176 private static final AugmentationNodeModification AUGMENTATION_NODE_MODIFICATION = new AugmentationNodeModification();
177 private static final MapNodeModification MAP_NODE_MODIFICATION = new MapNodeModification();
178 private static final UnkeyedListNodeModification UNKEYED_LIST_NODE_MODIFICATION = new UnkeyedListNodeModification();
179 private static final ContainerNodeModification CONTAINER_NODE_MODIFICATION = new ContainerNodeModification();
180 private static final ChoiceNodeModification CHOICE_NODE_MODIFICATION = new ChoiceNodeModification();
182 static Optional<? extends DataContainerChild<?, ?>> dispatchChildModification(Object schemaChild,
183 Optional<DataContainerChild<?, ?>> actual, Optional<DataContainerChild<?, ?>> modification,
184 OperationStack operations) throws DataModificationException {
186 if (schemaChild instanceof LeafSchemaNode) {
187 return onLeafNode((LeafSchemaNode) schemaChild, actual, modification, operations);
188 } else if (schemaChild instanceof ContainerSchemaNode) {
189 return onContainerNode((ContainerSchemaNode) schemaChild, actual, modification, operations);
190 } else if (schemaChild instanceof LeafListSchemaNode) {
191 return onLeafSetNode((LeafListSchemaNode) schemaChild, actual, modification, operations);
192 } else if (schemaChild instanceof AugmentationSchema) {
193 return onAugmentationNode((AugmentationSchema) schemaChild, actual, modification, operations);
194 } else if (schemaChild instanceof ListSchemaNode) {
195 if (((ListSchemaNode)schemaChild).getKeyDefinition().isEmpty()) {
196 return onUnkeyedNode((ListSchemaNode) schemaChild, actual, modification, operations);
198 return onMapNode((ListSchemaNode) schemaChild, actual, modification, operations);
200 } else if (schemaChild instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
201 return onChoiceNode((org.opendaylight.yangtools.yang.model.api.ChoiceNode) schemaChild, actual,
202 modification, operations);
205 throw new IllegalArgumentException("Unknown schema node type " + schemaChild);
208 private static Optional<? extends DataContainerChild<?, ?>> onChoiceNode(
209 org.opendaylight.yangtools.yang.model.api.ChoiceNode schemaChild,
210 Optional<? extends DataContainerChild<?, ?>> actual,
211 Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
212 throws DataModificationException {
213 checkType(actual, ChoiceNode.class);
214 checkType(modification, ChoiceNode.class);
215 return CHOICE_NODE_MODIFICATION.modify(schemaChild, (Optional<ChoiceNode>) actual,
216 (Optional<ChoiceNode>) modification, operations);
219 private static Optional<? extends DataContainerChild<?, ?>> onMapNode(ListSchemaNode schemaChild,
220 Optional<? extends DataContainerChild<?, ?>> actual,
221 Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
222 throws DataModificationException {
223 checkType(actual, MapNode.class);
224 checkType(modification, MapNode.class);
225 return MAP_NODE_MODIFICATION.modify(schemaChild, (Optional<MapNode>) actual,
226 (Optional<MapNode>) modification, operations);
229 private static Optional<? extends DataContainerChild<?, ?>> onUnkeyedNode(ListSchemaNode schemaChild,
230 Optional<? extends DataContainerChild<?, ?>> actual,
231 Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
232 throws DataModificationException {
233 checkType(actual, UnkeyedListNode.class);
234 checkType(modification, UnkeyedListNode.class);
235 return UNKEYED_LIST_NODE_MODIFICATION.modify(schemaChild, (Optional<UnkeyedListNode>) actual,
236 (Optional<UnkeyedListNode>) modification, operations);
239 private static Optional<? extends DataContainerChild<?, ?>> onAugmentationNode(AugmentationSchema schemaChild,
240 Optional<? extends DataContainerChild<?, ?>> actual,
241 Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
242 throws DataModificationException {
243 checkType(actual, AugmentationNode.class);
244 checkType(modification, AugmentationNode.class);
245 return AUGMENTATION_NODE_MODIFICATION.modify(schemaChild, (Optional<AugmentationNode>) actual,
246 (Optional<AugmentationNode>) modification, operations);
249 private static Optional<? extends DataContainerChild<?, ?>> onLeafSetNode(LeafListSchemaNode schemaChild,
250 Optional<? extends DataContainerChild<?, ?>> actual,
251 Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
252 throws DataModificationException {
253 checkType(actual, LeafSetNode.class);
254 checkType(modification, LeafSetNode.class);
255 return LEAF_SET_NODE_MODIFICATION.modify(schemaChild, (Optional<LeafSetNode<?>>) actual,
256 (Optional<LeafSetNode<?>>) modification, operations);
259 private static Optional<? extends DataContainerChild<?, ?>> onContainerNode(ContainerSchemaNode schemaChild,
260 Optional<? extends DataContainerChild<?, ?>> actual,
261 Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
262 throws DataModificationException {
263 checkType(actual, ContainerNode.class);
264 checkType(modification, ContainerNode.class);
265 return CONTAINER_NODE_MODIFICATION.modify(schemaChild, (Optional<ContainerNode>) actual,
266 (Optional<ContainerNode>) modification, operations);
269 private static Optional<? extends DataContainerChild<?, ?>> onLeafNode(LeafSchemaNode schemaChild,
270 Optional<? extends DataContainerChild<?, ?>> actual,
271 Optional<? extends DataContainerChild<?, ?>> modification, OperationStack operations)
272 throws DataModificationException {
273 checkType(actual, LeafNode.class);
274 checkType(modification, LeafNode.class);
275 return LEAF_NODE_MODIFICATION.modify(schemaChild, (Optional<LeafNode<?>>) actual,
276 (Optional<LeafNode<?>>) modification, operations);
279 private static void checkType(Optional<? extends DataContainerChild<?, ?>> actual, Class<?> leafNodeClass) {
280 if (actual.isPresent()) {
281 Preconditions.checkArgument(leafNodeClass.isAssignableFrom(actual.get().getClass()),
282 "Unexpected node type, should be: %s, but was: %s, for: %s", leafNodeClass, actual.getClass(),