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;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ImmutableMap;
15 import com.google.common.collect.ImmutableSet;
16 import com.google.common.collect.Iterables;
17 import com.google.common.collect.Lists;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.HashSet;
21 import java.util.Iterator;
24 import java.util.concurrent.ConcurrentHashMap;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
33 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
37 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
39 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
40 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
41 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
42 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
43 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
44 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
45 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
46 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
47 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
48 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
49 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
52 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
53 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
54 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
55 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
58 * Base strategy for converting an instance identifier into a normalized node structure for container-like types.
60 abstract class InstanceIdToCompositeNodes<T extends PathArgument> extends InstanceIdToNodes<T> {
62 protected InstanceIdToCompositeNodes(final T identifier) {
66 private static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
67 final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
68 for (final DataSchemaNode child : augmentation.getChildNodes()) {
69 potentialChildren.add(child.getQName());
71 return new AugmentationIdentifier(potentialChildren.build());
74 private static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation, final DataNodeContainer schema) {
75 final Set<DataSchemaNode> children = new HashSet<>();
76 for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
77 children.add(schema.getDataChildByName(augNode.getQName()));
79 return new EffectiveAugmentationSchema(augmentation, children);
83 @SuppressWarnings("unchecked")
84 public final NormalizedNode<?, ?> create(final YangInstanceIdentifier instanceId, final Optional<NormalizedNode<?, ?>> lastChild, final Optional<Map.Entry<QName,ModifyAction>> operation) {
85 checkNotNull(instanceId);
86 final Iterator<PathArgument> iterator = instanceId.getPathArguments().iterator();
87 final PathArgument legacyData = iterator.next();
89 if (!isMixin() && getIdentifier().getNodeType() != null) {
90 checkArgument(getIdentifier().getNodeType().equals(legacyData.getNodeType()),
91 "Node QName must be %s was %s", getIdentifier().getNodeType(), legacyData.getNodeType());
93 @SuppressWarnings("rawtypes")
94 final NormalizedNodeContainerBuilder builder = createBuilder(legacyData);
96 if (iterator.hasNext()) {
97 final PathArgument childPath = iterator.next();
98 final InstanceIdToNodes<?> childOp = getChildOperation(childPath);
100 final YangInstanceIdentifier childId = YangInstanceIdentifier.create(Iterables.skip(instanceId.getPathArguments(), 1));
101 builder.addChild(childOp.create(childId, lastChild, operation));
103 if (lastChild.isPresent()) {
104 builder.withValue(Lists.newArrayList((Collection<?>) lastChild.get().getValue()));
106 if (operation.isPresent()) {
107 Preconditions.checkArgument(builder instanceof AttributesBuilder<?>);
108 addModifyOpIfPresent(operation, ((AttributesBuilder<?>) builder));
112 return builder.build();
115 private InstanceIdToNodes<?> getChildOperation(final PathArgument childPath) {
116 final InstanceIdToNodes<?> childOp;
118 childOp = getChild(childPath);
119 } catch (final RuntimeException e) {
120 throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
122 checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
126 protected abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode);
128 static abstract class DataContainerNormalizationOperation<T extends PathArgument> extends
129 InstanceIdToCompositeNodes<T> {
131 private final DataNodeContainer schema;
132 private final Map<PathArgument, InstanceIdToNodes<?>> byArg;
134 protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
136 this.schema = schema;
137 this.byArg = new ConcurrentHashMap<>();
141 public InstanceIdToNodes<?> getChild(final PathArgument child) {
142 InstanceIdToNodes<?> potential = byArg.get(child);
143 if (potential != null) {
146 potential = fromLocalSchema(child);
147 return register(potential);
150 private InstanceIdToNodes<?> fromLocalSchema(final PathArgument child) {
151 if (child instanceof AugmentationIdentifier) {
152 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
155 return fromSchemaAndQNameChecked(schema, child.getNodeType());
158 private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
159 if (potential != null) {
160 byArg.put(potential.getIdentifier(), potential);
166 static final class ListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
167 protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
168 super(identifier, schema);
172 protected DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> createBuilder(final PathArgument currentArg) {
173 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
174 .mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates) currentArg);
175 for (final Map.Entry<QName, Object> keyValue : ((NodeIdentifierWithPredicates) currentArg).getKeyValues().entrySet()) {
176 builder.addChild(Builders.leafBuilder()
177 .withNodeIdentifier(NodeIdentifier.create(keyValue.getKey())).withValue(keyValue.getValue())
189 static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
191 protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
192 super(NodeIdentifier.create(schema.getQName()), schema);
196 protected DataContainerNodeAttrBuilder<NodeIdentifier, UnkeyedListEntryNode> createBuilder(final PathArgument compositeNode) {
197 return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
206 static final class ContainerTransformation extends DataContainerNormalizationOperation<NodeIdentifier> {
207 protected ContainerTransformation(final ContainerSchemaNode schema) {
208 super(NodeIdentifier.create(schema.getQName()), schema);
212 protected DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> createBuilder(final PathArgument compositeNode) {
213 return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
222 static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
225 public OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
230 protected ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
231 return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
235 static class UnorderedLeafListMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
237 private final InstanceIdToNodes<?> innerOp;
239 public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
240 super(NodeIdentifier.create(potential.getQName()));
241 innerOp = new InstanceIdToSimpleNodes.LeafListEntryNormalization(potential);
245 protected ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
246 return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
250 public InstanceIdToNodes<?> getChild(final PathArgument child) {
251 if (child instanceof NodeWithValue) {
263 static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> {
265 public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
266 super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation, schema));
270 protected DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> createBuilder(final PathArgument compositeNode) {
271 return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
280 static class UnorderedMapMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
282 private final ListItemNormalization innerNode;
284 public UnorderedMapMixinNormalization(final ListSchemaNode list) {
285 super(NodeIdentifier.create(list.getQName()));
286 this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
287 Collections.<QName, Object>emptyMap()), list);
291 protected CollectionNodeBuilder<MapEntryNode, ? extends MapNode> createBuilder(final PathArgument compositeNode) {
292 return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
296 public InstanceIdToNodes<?> getChild(final PathArgument child) {
297 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
309 static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
311 public OrderedMapMixinNormalization(final ListSchemaNode list) {
316 protected CollectionNodeBuilder<MapEntryNode, OrderedMapNode> createBuilder(final PathArgument compositeNode) {
317 return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
322 static final class ChoiceNodeNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
324 private final ImmutableMap<PathArgument, InstanceIdToNodes<?>> byArg;
326 protected ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
327 super(NodeIdentifier.create(schema.getQName()));
328 final ImmutableMap.Builder<PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
330 for (final ChoiceCaseNode caze : schema.getCases()) {
331 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
332 final InstanceIdToNodes<?> childOp = fromDataSchemaNode(cazeChild);
333 byArgBuilder.put(childOp.getIdentifier(), childOp);
336 byArg = byArgBuilder.build();
340 public InstanceIdToNodes<?> getChild(final PathArgument child) {
341 return byArg.get(child);
345 protected DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> createBuilder(final PathArgument compositeNode) {
346 return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());