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.base.Optional;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.ImmutableMap;
16 import com.google.common.collect.ImmutableSet;
17 import com.google.common.collect.Iterables;
18 import com.google.common.collect.Lists;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.HashSet;
22 import java.util.Iterator;
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.MapEntryNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
36 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
37 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
39 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
40 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
41 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
44 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
45 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
46 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
47 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
50 * Base strategy for converting an instance identifier into a normalized node structure for container-like types.
52 abstract class InstanceIdToCompositeNodes<T extends PathArgument> extends InstanceIdToNodes<T> {
54 protected InstanceIdToCompositeNodes(final T identifier) {
58 private static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
59 final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
60 for (final DataSchemaNode child : augmentation.getChildNodes()) {
61 potentialChildren.add(child.getQName());
63 return new AugmentationIdentifier(potentialChildren.build());
66 private static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation, final DataNodeContainer schema) {
67 final Set<DataSchemaNode> children = new HashSet<>();
68 for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
69 children.add(schema.getDataChildByName(augNode.getQName()));
71 return new EffectiveAugmentationSchema(augmentation, children);
75 @SuppressWarnings("unchecked")
76 public final NormalizedNode<?, ?> create(final YangInstanceIdentifier instanceId, final Optional<NormalizedNode<?, ?>> lastChild, final Optional<Map.Entry<QName,ModifyAction>> operation) {
77 checkNotNull(instanceId);
78 final Iterator<PathArgument> iterator = instanceId.getPathArguments().iterator();
79 final PathArgument legacyData = iterator.next();
81 if (!isMixin(this) && getIdentifier().getNodeType() != null) {
82 checkArgument(getIdentifier().getNodeType().equals(legacyData.getNodeType()),
83 "Node QName must be %s was %s", getIdentifier().getNodeType(), legacyData.getNodeType());
85 final NormalizedNodeContainerBuilder builder = createBuilder(legacyData);
87 if (iterator.hasNext()) {
88 final YangInstanceIdentifier.PathArgument childPath = iterator.next();
89 final InstanceIdToNodes childOp = getChildOperation(childPath);
91 final YangInstanceIdentifier childId = YangInstanceIdentifier.create(Iterables.skip(instanceId.getPathArguments(), 1));
92 builder.addChild(childOp.create(childId, lastChild, operation));
94 if (lastChild.isPresent()) {
95 builder.withValue(Lists.newArrayList((Collection<?>) lastChild.get().getValue()));
97 if (operation.isPresent()) {
98 Preconditions.checkArgument(builder instanceof AttributesBuilder<?>);
99 addModifyOpIfPresent(operation, ((AttributesBuilder<?>) builder));
103 return builder.build();
106 private InstanceIdToNodes<?> getChildOperation(final PathArgument childPath) {
107 final InstanceIdToNodes<?> childOp;
109 childOp = getChild(childPath);
110 } catch (final RuntimeException e) {
111 throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
113 checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
117 protected abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode);
119 static abstract class DataContainerNormalizationOperation<T extends PathArgument> extends
120 InstanceIdToCompositeNodes<T> {
122 private final DataNodeContainer schema;
123 private final Map<PathArgument, InstanceIdToNodes<?>> byArg;
125 protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
127 this.schema = schema;
128 this.byArg = new ConcurrentHashMap<>();
132 public InstanceIdToNodes<?> getChild(final PathArgument child) {
133 InstanceIdToNodes<?> potential = byArg.get(child);
134 if (potential != null) {
137 potential = fromLocalSchema(child);
138 return register(potential);
141 private InstanceIdToNodes<?> fromLocalSchema(final PathArgument child) {
142 if (child instanceof AugmentationIdentifier) {
143 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
146 return fromSchemaAndQNameChecked(schema, child.getNodeType());
149 private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
150 if (potential != null) {
151 byArg.put(potential.getIdentifier(), potential);
157 static final class ListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
158 protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
159 super(identifier, schema);
163 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument currentArg) {
164 final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
165 .mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates) currentArg);
166 for (final Map.Entry<QName, Object> keyValue : ((NodeIdentifierWithPredicates) currentArg).getKeyValues().entrySet()) {
167 builder.addChild(Builders.leafBuilder()
169 .withNodeIdentifier(new NodeIdentifier(keyValue.getKey())).withValue(keyValue.getValue())
177 static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
179 protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
180 super(new NodeIdentifier(schema.getQName()), schema);
184 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
185 return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
190 static final class ContainerTransformation extends DataContainerNormalizationOperation<NodeIdentifier> {
192 protected ContainerTransformation(final ContainerSchemaNode schema) {
193 super(new NodeIdentifier(schema.getQName()), schema);
197 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
198 return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
202 static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
205 public OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
210 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
211 return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
215 static class UnorderedLeafListMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> implements MixinNormalizationOp {
217 private final InstanceIdToNodes<?> innerOp;
219 public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
220 super(new NodeIdentifier(potential.getQName()));
221 innerOp = new InstanceIdToSimpleNodes.LeafListEntryNormalization(potential);
225 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
226 return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
230 public InstanceIdToNodes<?> getChild(final PathArgument child) {
231 if (child instanceof NodeWithValue) {
238 static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> implements MixinNormalizationOp {
240 public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
241 super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation, schema));
245 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
246 return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
250 static class UnorderedMapMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> implements MixinNormalizationOp {
252 private final ListItemNormalization innerNode;
254 public UnorderedMapMixinNormalization(final ListSchemaNode list) {
255 super(new NodeIdentifier(list.getQName()));
256 this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
257 Collections.<QName, Object>emptyMap()), list);
261 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
262 return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
266 public InstanceIdToNodes<?> getChild(final PathArgument child) {
267 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
274 static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
276 public OrderedMapMixinNormalization(final ListSchemaNode list) {
281 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode) {
282 return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
287 static class ChoiceNodeNormalization extends InstanceIdToCompositeNodes<YangInstanceIdentifier.NodeIdentifier> implements MixinNormalizationOp {
289 private final ImmutableMap<YangInstanceIdentifier.PathArgument, InstanceIdToNodes<?>> byArg;
291 protected ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
292 super(new YangInstanceIdentifier.NodeIdentifier(schema.getQName()));
293 final ImmutableMap.Builder<YangInstanceIdentifier.PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
295 for (final ChoiceCaseNode caze : schema.getCases()) {
296 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
297 final InstanceIdToNodes<?> childOp = fromDataSchemaNode(cazeChild);
298 byArgBuilder.put(childOp.getIdentifier(), childOp);
301 byArg = byArgBuilder.build();
305 public InstanceIdToNodes<?> getChild(final PathArgument child) {
306 return byArg.get(child);
310 protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
311 return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());