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.ChoiceSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
35 abstract class AbstractContainerNodeModification<S, N extends DataContainerNode<?>> implements Modification<S, N> {
38 public final Optional<N> modify(final S schema, final Optional<N> actual, final Optional<N> modification,
39 final OperationStack operationStack) throws DataModificationException {
41 operationStack.enteringNode(modification);
44 QName nodeQName = getQName(schema);
46 switch (operationStack.getCurrentOperation()) {
48 DataModificationException.DataMissingException.check(nodeQName, actual);
51 result = Optional.absent();
55 DataModificationException.DataExistsException.check(nodeQName, actual, null);
58 result = modification;
62 DataModificationException.DataMissingException.check(nodeQName, actual);
65 // Recursively modify all child nodes
66 result = modifyContainer(schema, actual, modification, operationStack);
70 throw new UnsupportedOperationException(String.format("Unable to perform operation: %s on: %s, unknown",
71 operationStack.getCurrentOperation(), schema));
74 operationStack.exitingNode(modification);
78 protected abstract QName getQName(S schema);
80 private Optional<N> modifyContainer(final S schema, final Optional<N> actual, final Optional<N> modification,
81 final OperationStack operationStack) throws DataModificationException {
83 if (!actual.isPresent()) {
87 if (!modification.isPresent()) {
91 Set<YangInstanceIdentifier.PathArgument> toProcess = getChildrenToProcess(schema, actual, modification);
93 List<? extends DataContainerChild<?, ?>> merged = modifyContainerChildNodes(schema, operationStack,
94 actual.get(), modification.get(), toProcess);
95 return build(schema, merged);
98 private List<? extends DataContainerChild<?, ?>> modifyContainerChildNodes(final S schema, final OperationStack operationStack,
99 final N actual, final N modification, final Set<YangInstanceIdentifier.PathArgument> toProcess) throws DataModificationException {
100 List<DataContainerChild<?, ?>> result = Lists.newArrayList();
102 for (YangInstanceIdentifier.PathArgument childToProcessId : toProcess) {
103 Object schemaOfChildToProcess = findSchema(schema, childToProcessId);
105 Optional<? extends DataContainerChild<?, ?>> modifiedValues = modifyContainerNode(operationStack, actual,
106 modification, childToProcessId, schemaOfChildToProcess);
108 if (modifiedValues.isPresent()) {
109 result.add(modifiedValues.get());
116 private Optional<? extends DataContainerChild<?, ?>> modifyContainerNode(final OperationStack operationStack, final N actual,
117 final N modification, final YangInstanceIdentifier.PathArgument childToProcess, final Object schemaChild)
118 throws DataModificationException {
120 Optional<DataContainerChild<?, ?>> storedChildren = actual.getChild(childToProcess);
121 Optional<DataContainerChild<?, ?>> modifiedChildren = modification.getChild(childToProcess);
123 return NodeDispatcher.dispatchChildModification(schemaChild, storedChildren, modifiedChildren, operationStack);
126 private Object findSchema(final S schema, final YangInstanceIdentifier.PathArgument childToProcessId) {
127 if (childToProcessId instanceof YangInstanceIdentifier.AugmentationIdentifier) {
128 return findSchemaForAugment(schema, (YangInstanceIdentifier.AugmentationIdentifier) childToProcessId);
130 return findSchemaForChild(schema, childToProcessId.getNodeType());
134 protected abstract Object findSchemaForChild(S schema, QName nodeType);
136 protected abstract Object findSchemaForAugment(S schema, YangInstanceIdentifier.AugmentationIdentifier childToProcessId);
138 private Optional<N> build(final S schema, final List<? extends DataContainerChild<?, ?>> result) {
139 DataContainerNodeBuilder<?, N> b = getBuilder(schema);
141 // TODO skip empty container nodes ? e.g. if container looses all its child nodes
142 // if(result.isEmpty()) {
143 // return Optional.absent();
146 for (DataContainerChild<?, ?> dataContainerChild : result) {
147 b.withChild(dataContainerChild);
149 return Optional.of(b.build());
152 protected abstract DataContainerNodeBuilder<?, N> getBuilder(S schema);
154 protected Set<YangInstanceIdentifier.PathArgument> getChildrenToProcess(final S schema, final Optional<N> actual,
155 final Optional<N> modification) throws DataModificationException {
156 Set<YangInstanceIdentifier.PathArgument> qNames = Sets.newLinkedHashSet();
158 qNames.addAll(getChildQNames(actual));
159 qNames.addAll(getChildQNames(modification));
163 private Set<? extends YangInstanceIdentifier.PathArgument> getChildQNames(final Optional<N> actual) {
164 Set<YangInstanceIdentifier.PathArgument> qNames = Sets.newLinkedHashSet();
166 for (DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> child : actual.get().getValue()) {
167 qNames.add(child.getIdentifier());
173 private static final class NodeDispatcher {
175 private static final LeafNodeModification LEAF_NODE_MODIFICATION = new LeafNodeModification();
176 private static final LeafSetNodeModification LEAF_SET_NODE_MODIFICATION = new LeafSetNodeModification();
177 private static final AugmentationNodeModification AUGMENTATION_NODE_MODIFICATION = new AugmentationNodeModification();
178 private static final MapNodeModification MAP_NODE_MODIFICATION = new MapNodeModification();
179 private static final UnkeyedListNodeModification UNKEYED_LIST_NODE_MODIFICATION = new UnkeyedListNodeModification();
180 private static final ContainerNodeModification CONTAINER_NODE_MODIFICATION = new ContainerNodeModification();
181 private static final ChoiceNodeModification CHOICE_NODE_MODIFICATION = new ChoiceNodeModification();
183 private NodeDispatcher() {
184 throw new UnsupportedOperationException("Utility class should not be instantiated!");
187 static Optional<? extends DataContainerChild<?, ?>> dispatchChildModification(final Object schemaChild,
188 final Optional<DataContainerChild<?, ?>> actual, final Optional<DataContainerChild<?, ?>> modification,
189 final OperationStack operations) throws DataModificationException {
191 if (schemaChild instanceof LeafSchemaNode) {
192 return onLeafNode((LeafSchemaNode) schemaChild, actual, modification, operations);
193 } else if (schemaChild instanceof ContainerSchemaNode) {
194 return onContainerNode((ContainerSchemaNode) schemaChild, actual, modification, operations);
195 } else if (schemaChild instanceof LeafListSchemaNode) {
196 return onLeafSetNode((LeafListSchemaNode) schemaChild, actual, modification, operations);
197 } else if (schemaChild instanceof AugmentationSchema) {
198 return onAugmentationNode((AugmentationSchema) schemaChild, actual, modification, operations);
199 } else if (schemaChild instanceof ListSchemaNode) {
200 if (((ListSchemaNode)schemaChild).getKeyDefinition().isEmpty()) {
201 return onUnkeyedNode((ListSchemaNode) schemaChild, actual, modification, operations);
203 return onMapNode((ListSchemaNode) schemaChild, actual, modification, operations);
205 } else if (schemaChild instanceof ChoiceSchemaNode) {
206 return onChoiceNode((ChoiceSchemaNode) schemaChild, actual,
207 modification, operations);
210 throw new IllegalArgumentException("Unknown schema node type " + schemaChild);
213 private static Optional<? extends DataContainerChild<?, ?>> onChoiceNode(
214 final ChoiceSchemaNode schemaChild,
215 final Optional<? extends DataContainerChild<?, ?>> actual,
216 final Optional<? extends DataContainerChild<?, ?>> modification, final OperationStack operations)
217 throws DataModificationException {
218 checkType(actual, ChoiceNode.class);
219 checkType(modification, ChoiceNode.class);
220 return CHOICE_NODE_MODIFICATION.modify(schemaChild, (Optional<ChoiceNode>) actual,
221 (Optional<ChoiceNode>) modification, operations);
224 private static Optional<? extends DataContainerChild<?, ?>> onMapNode(final ListSchemaNode schemaChild,
225 final Optional<? extends DataContainerChild<?, ?>> actual,
226 final Optional<? extends DataContainerChild<?, ?>> modification, final OperationStack operations)
227 throws DataModificationException {
228 checkType(actual, MapNode.class);
229 checkType(modification, MapNode.class);
230 return MAP_NODE_MODIFICATION.modify(schemaChild, (Optional<MapNode>) actual,
231 (Optional<MapNode>) modification, operations);
234 private static Optional<? extends DataContainerChild<?, ?>> onUnkeyedNode(final ListSchemaNode schemaChild,
235 final Optional<? extends DataContainerChild<?, ?>> actual,
236 final Optional<? extends DataContainerChild<?, ?>> modification, final OperationStack operations)
237 throws DataModificationException {
238 checkType(actual, UnkeyedListNode.class);
239 checkType(modification, UnkeyedListNode.class);
240 return UNKEYED_LIST_NODE_MODIFICATION.modify(schemaChild, (Optional<UnkeyedListNode>) actual,
241 (Optional<UnkeyedListNode>) modification, operations);
244 private static Optional<? extends DataContainerChild<?, ?>> onAugmentationNode(final AugmentationSchema schemaChild,
245 final Optional<? extends DataContainerChild<?, ?>> actual,
246 final Optional<? extends DataContainerChild<?, ?>> modification, final OperationStack operations)
247 throws DataModificationException {
248 checkType(actual, AugmentationNode.class);
249 checkType(modification, AugmentationNode.class);
250 return AUGMENTATION_NODE_MODIFICATION.modify(schemaChild, (Optional<AugmentationNode>) actual,
251 (Optional<AugmentationNode>) modification, operations);
254 private static Optional<? extends DataContainerChild<?, ?>> onLeafSetNode(final LeafListSchemaNode schemaChild,
255 final Optional<? extends DataContainerChild<?, ?>> actual,
256 final Optional<? extends DataContainerChild<?, ?>> modification, final OperationStack operations)
257 throws DataModificationException {
258 checkType(actual, LeafSetNode.class);
259 checkType(modification, LeafSetNode.class);
260 return LEAF_SET_NODE_MODIFICATION.modify(schemaChild, (Optional<LeafSetNode<?>>) actual,
261 (Optional<LeafSetNode<?>>) modification, operations);
264 private static Optional<? extends DataContainerChild<?, ?>> onContainerNode(final ContainerSchemaNode schemaChild,
265 final Optional<? extends DataContainerChild<?, ?>> actual,
266 final Optional<? extends DataContainerChild<?, ?>> modification, final OperationStack operations)
267 throws DataModificationException {
268 checkType(actual, ContainerNode.class);
269 checkType(modification, ContainerNode.class);
270 return CONTAINER_NODE_MODIFICATION.modify(schemaChild, (Optional<ContainerNode>) actual,
271 (Optional<ContainerNode>) modification, operations);
274 private static Optional<? extends DataContainerChild<?, ?>> onLeafNode(final LeafSchemaNode schemaChild,
275 final Optional<? extends DataContainerChild<?, ?>> actual,
276 final Optional<? extends DataContainerChild<?, ?>> modification, final OperationStack operations)
277 throws DataModificationException {
278 checkType(actual, LeafNode.class);
279 checkType(modification, LeafNode.class);
280 return LEAF_NODE_MODIFICATION.modify(schemaChild, (Optional<LeafNode<?>>) actual,
281 (Optional<LeafNode<?>>) modification, operations);
284 private static void checkType(final Optional<? extends DataContainerChild<?, ?>> actual, final Class<?> leafNodeClass) {
285 if (actual.isPresent()) {
286 Preconditions.checkArgument(leafNodeClass.isAssignableFrom(actual.get().getClass()),
287 "Unexpected node type, should be: %s, but was: %s, for: %s", leafNodeClass, actual.getClass(),