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;
11 import static com.google.common.base.Preconditions.checkNotNull;
13 import com.google.common.collect.ImmutableList;
14 import com.google.common.collect.ImmutableMap;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.collect.Iterables;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.HashSet;
20 import java.util.Iterator;
22 import java.util.Map.Entry;
23 import java.util.Optional;
25 import java.util.concurrent.ConcurrentHashMap;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
34 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
39 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
42 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
43 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
44 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
45 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
46 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
47 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
48 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
52 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
53 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
54 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
55 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
56 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
59 * Base strategy for converting an instance identifier into a normalized node structure for container-like types.
61 abstract class InstanceIdToCompositeNodes<T extends PathArgument> extends InstanceIdToNodes<T> {
63 protected InstanceIdToCompositeNodes(final T identifier) {
67 private static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchemaNode augmentation) {
68 final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
69 for (final DataSchemaNode child : augmentation.getChildNodes()) {
70 potentialChildren.add(child.getQName());
72 return new AugmentationIdentifier(potentialChildren.build());
75 private static DataNodeContainer augmentationProxy(final AugmentationSchemaNode augmentation,
76 final DataNodeContainer schema) {
77 final Set<DataSchemaNode> children = new HashSet<>();
78 for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
79 children.add(schema.getDataChildByName(augNode.getQName()));
81 return new EffectiveAugmentationSchema(augmentation, children);
85 @SuppressWarnings("unchecked")
86 public final NormalizedNode<?, ?> create(final YangInstanceIdentifier instanceId,
87 final Optional<NormalizedNode<?, ?>> lastChild, final Optional<Entry<QName,ModifyAction>> operation) {
88 checkNotNull(instanceId);
89 final Iterator<PathArgument> iterator = instanceId.getPathArguments().iterator();
90 final PathArgument legacyData = iterator.next();
92 if (!isMixin() && getIdentifier().getNodeType() != null) {
93 checkArgument(getIdentifier().getNodeType().equals(legacyData.getNodeType()),
94 "Node QName must be %s was %s", getIdentifier().getNodeType(), legacyData.getNodeType());
96 @SuppressWarnings("rawtypes")
97 final NormalizedNodeContainerBuilder builder = createBuilder(legacyData);
99 if (iterator.hasNext()) {
100 final PathArgument childPath = iterator.next();
101 final InstanceIdToNodes<?> childOp = getChildOperation(childPath);
103 final YangInstanceIdentifier childId = YangInstanceIdentifier.create(
104 Iterables.skip(instanceId.getPathArguments(), 1));
105 builder.addChild(childOp.create(childId, lastChild, operation));
107 if (lastChild.isPresent()) {
108 builder.withValue(ImmutableList.copyOf((Collection<?>) lastChild.get().getValue()));
110 if (operation.isPresent()) {
111 checkArgument(builder instanceof AttributesBuilder<?>);
112 addModifyOpIfPresent(operation, (AttributesBuilder<?>) builder);
116 return builder.build();
119 @SuppressWarnings("checkstyle:illegalCatch")
120 private InstanceIdToNodes<?> getChildOperation(final PathArgument childPath) {
121 final InstanceIdToNodes<?> childOp;
123 childOp = getChild(childPath);
124 } catch (final RuntimeException e) {
125 throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
127 checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
131 protected abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(PathArgument compositeNode);
133 abstract static class DataContainerNormalizationOperation<T extends PathArgument>
134 extends InstanceIdToCompositeNodes<T> {
136 private final DataNodeContainer schema;
137 private final Map<PathArgument, InstanceIdToNodes<?>> byArg;
139 protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
141 this.schema = schema;
142 this.byArg = new ConcurrentHashMap<>();
146 public InstanceIdToNodes<?> getChild(final PathArgument child) {
147 InstanceIdToNodes<?> potential = byArg.get(child);
148 if (potential != null) {
151 potential = fromLocalSchema(child);
152 return register(potential);
155 private InstanceIdToNodes<?> fromLocalSchema(final PathArgument child) {
156 if (child instanceof AugmentationIdentifier) {
157 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
160 return fromSchemaAndQNameChecked(schema, child.getNodeType());
163 private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
164 if (potential != null) {
165 byArg.put(potential.getIdentifier(), potential);
171 static final class ListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
172 protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
173 super(identifier, schema);
177 protected DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> createBuilder(
178 final PathArgument currentArg) {
179 final NodeIdentifierWithPredicates arg = (NodeIdentifierWithPredicates) currentArg;
180 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
181 .mapEntryBuilder().withNodeIdentifier(arg);
182 for (final Entry<QName, Object> keyValue : arg.getKeyValues().entrySet()) {
183 builder.addChild(Builders.leafBuilder()
184 .withNodeIdentifier(NodeIdentifier.create(keyValue.getKey())).withValue(keyValue.getValue())
196 static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
197 UnkeyedListItemNormalization(final ListSchemaNode schema) {
198 super(NodeIdentifier.create(schema.getQName()), schema);
202 protected DataContainerNodeAttrBuilder<NodeIdentifier, UnkeyedListEntryNode> createBuilder(
203 final PathArgument compositeNode) {
204 return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
213 static final class ContainerTransformation extends DataContainerNormalizationOperation<NodeIdentifier> {
214 ContainerTransformation(final ContainerSchemaNode schema) {
215 super(NodeIdentifier.create(schema.getQName()), schema);
219 protected DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> createBuilder(
220 final PathArgument compositeNode) {
221 return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
230 static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
231 OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
236 protected ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
237 return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
241 static class UnorderedLeafListMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
242 private final InstanceIdToNodes<?> innerOp;
244 UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
245 super(NodeIdentifier.create(potential.getQName()));
246 innerOp = new InstanceIdToSimpleNodes.LeafListEntryNormalization(potential);
250 protected ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
251 return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
255 public InstanceIdToNodes<?> getChild(final PathArgument child) {
256 if (child instanceof NodeWithValue) {
268 static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> {
269 AugmentationNormalization(final AugmentationSchemaNode augmentation, final DataNodeContainer schema) {
270 super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation, schema));
274 protected DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> createBuilder(
275 final PathArgument compositeNode) {
276 return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
285 static class UnorderedMapMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
286 private final ListItemNormalization innerNode;
288 UnorderedMapMixinNormalization(final ListSchemaNode list) {
289 super(NodeIdentifier.create(list.getQName()));
290 this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
291 Collections.emptyMap()), list);
295 protected CollectionNodeBuilder<MapEntryNode, ? extends MapNode> createBuilder(
296 final PathArgument compositeNode) {
297 return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
301 public InstanceIdToNodes<?> getChild(final PathArgument child) {
302 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
314 static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
315 OrderedMapMixinNormalization(final ListSchemaNode list) {
320 protected CollectionNodeBuilder<MapEntryNode, OrderedMapNode> createBuilder(final PathArgument compositeNode) {
321 return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
326 static final class ChoiceNodeNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
327 private final ImmutableMap<PathArgument, InstanceIdToNodes<?>> byArg;
329 ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
330 super(NodeIdentifier.create(schema.getQName()));
331 final ImmutableMap.Builder<PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
333 for (final CaseSchemaNode caze : schema.getCases().values()) {
334 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
335 final InstanceIdToNodes<?> childOp = fromDataSchemaNode(cazeChild);
336 byArgBuilder.put(childOp.getIdentifier(), childOp);
339 byArg = byArgBuilder.build();
343 public InstanceIdToNodes<?> getChild(final PathArgument child) {
344 return byArg.get(child);
348 protected DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> createBuilder(final PathArgument compositeNode) {
349 return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());