2 * Copyright (c) 2015 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.impl.schema;
10 import static com.google.common.base.Preconditions.checkArgument;
12 import com.google.common.collect.ImmutableList;
13 import com.google.common.collect.ImmutableMap;
14 import java.util.Collection;
15 import java.util.Iterator;
17 import java.util.Map.Entry;
18 import java.util.Optional;
19 import java.util.concurrent.ConcurrentHashMap;
20 import org.opendaylight.yangtools.yang.common.QName;
21 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
27 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
35 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
36 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
37 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
39 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
40 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
41 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
42 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
44 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
45 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
46 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
47 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
50 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
53 * Base strategy for converting an instance identifier into a normalized node structure for container-like types.
55 abstract class InstanceIdToCompositeNodes<T extends PathArgument> extends InstanceIdToNodes<T> {
56 InstanceIdToCompositeNodes(final T identifier) {
61 @SuppressWarnings("unchecked")
62 final NormalizedNode<?, ?> create(final PathArgument first, final Iterator<PathArgument> others,
63 final Optional<NormalizedNode<?, ?>> lastChild, final Optional<Entry<QName, ModifyAction>> operation) {
65 final QName type = getIdentifier().getNodeType();
67 final QName firstType = first.getNodeType();
68 checkArgument(type.equals(firstType), "Node QName must be %s was %s", type, firstType);
72 @SuppressWarnings("rawtypes")
73 final NormalizedNodeContainerBuilder builder = createBuilder(first);
75 if (others.hasNext()) {
76 final PathArgument childPath = others.next();
77 final InstanceIdToNodes<?> childOp = getChildOperation(childPath);
78 builder.addChild(childOp.create(childPath, others, lastChild, operation));
80 if (lastChild.isPresent()) {
81 builder.withValue(ImmutableList.copyOf((Collection<?>) lastChild.get().getValue()));
83 if (operation.isPresent()) {
84 checkArgument(builder instanceof AttributesBuilder<?>);
85 addModifyOpIfPresent(operation, (AttributesBuilder<?>) builder);
89 return builder.build();
92 @SuppressWarnings("checkstyle:illegalCatch")
93 private InstanceIdToNodes<?> getChildOperation(final PathArgument childPath) {
94 final InstanceIdToNodes<?> childOp;
96 childOp = getChild(childPath);
97 } catch (final RuntimeException e) {
98 throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
100 checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
104 abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(PathArgument compositeNode);
106 abstract static class DataContainerNormalizationOperation<T extends PathArgument>
107 extends InstanceIdToCompositeNodes<T> {
109 private final Map<PathArgument, InstanceIdToNodes<?>> byArg = new ConcurrentHashMap<>();
110 private final DataNodeContainer schema;
112 DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
114 this.schema = schema;
118 final InstanceIdToNodes<?> getChild(final PathArgument child) {
119 InstanceIdToNodes<?> potential = byArg.get(child);
120 if (potential != null) {
123 potential = fromLocalSchema(child);
124 return register(potential);
127 private InstanceIdToNodes<?> fromLocalSchema(final PathArgument child) {
128 if (child instanceof AugmentationIdentifier) {
129 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
132 return fromSchemaAndQNameChecked(schema, child.getNodeType());
135 private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
136 if (potential != null) {
137 byArg.put(potential.getIdentifier(), potential);
143 static final class ListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
144 ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
145 super(identifier, schema);
149 DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> createBuilder(
150 final PathArgument currentArg) {
151 final NodeIdentifierWithPredicates arg = (NodeIdentifierWithPredicates) currentArg;
152 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
153 .mapEntryBuilder().withNodeIdentifier(arg);
154 for (final Entry<QName, Object> keyValue : arg.getKeyValues().entrySet()) {
155 builder.addChild(Builders.leafBuilder()
156 .withNodeIdentifier(NodeIdentifier.create(keyValue.getKey())).withValue(keyValue.getValue())
168 static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
169 UnkeyedListItemNormalization(final ListSchemaNode schema) {
170 super(NodeIdentifier.create(schema.getQName()), schema);
174 DataContainerNodeAttrBuilder<NodeIdentifier, UnkeyedListEntryNode> createBuilder(
175 final PathArgument compositeNode) {
176 return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
185 static final class ContainerTransformation extends DataContainerNormalizationOperation<NodeIdentifier> {
186 ContainerTransformation(final ContainerSchemaNode schema) {
187 super(NodeIdentifier.create(schema.getQName()), schema);
191 DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> createBuilder(final PathArgument compositeNode) {
192 return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
201 static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
202 OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
207 ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
208 return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
212 static class UnorderedLeafListMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
213 private final InstanceIdToNodes<?> innerOp;
215 UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
216 super(NodeIdentifier.create(potential.getQName()));
217 innerOp = new InstanceIdToSimpleNodes.LeafListEntryNormalization(potential);
221 ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
222 return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
226 final InstanceIdToNodes<?> getChild(final PathArgument child) {
227 return child instanceof NodeWithValue ? innerOp : null;
231 final boolean isMixin() {
236 static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> {
237 AugmentationNormalization(final AugmentationSchemaNode augmentation, final DataNodeContainer schema) {
238 super(DataSchemaContextNode.augmentationIdentifierFrom(augmentation),
239 EffectiveAugmentationSchema.create(augmentation, schema));
243 DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> createBuilder(
244 final PathArgument compositeNode) {
245 return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
254 static class UnorderedMapMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
255 private final ListItemNormalization innerNode;
257 UnorderedMapMixinNormalization(final ListSchemaNode list) {
258 super(NodeIdentifier.create(list.getQName()));
259 this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName()), list);
263 CollectionNodeBuilder<MapEntryNode, ? extends MapNode> createBuilder(final PathArgument compositeNode) {
264 return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
268 final InstanceIdToNodes<?> getChild(final PathArgument child) {
269 return child.getNodeType().equals(getIdentifier().getNodeType()) ? innerNode : null;
273 final boolean isMixin() {
278 static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
279 OrderedMapMixinNormalization(final ListSchemaNode list) {
284 CollectionNodeBuilder<MapEntryNode, OrderedMapNode> createBuilder(final PathArgument compositeNode) {
285 return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
289 static final class ChoiceNodeNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
290 private final ImmutableMap<PathArgument, InstanceIdToNodes<?>> byArg;
292 ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
293 super(NodeIdentifier.create(schema.getQName()));
294 final ImmutableMap.Builder<PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
296 for (final CaseSchemaNode caze : schema.getCases().values()) {
297 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
298 final InstanceIdToNodes<?> childOp = fromDataSchemaNode(cazeChild);
299 byArgBuilder.put(childOp.getIdentifier(), childOp);
302 byArg = byArgBuilder.build();
306 InstanceIdToNodes<?> getChild(final PathArgument child) {
307 return byArg.get(child);
311 DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> createBuilder(final PathArgument compositeNode) {
312 return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());