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.YangInstanceIdentifier.AugmentationIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
26 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
34 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
35 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
36 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.ListNodeBuilder;
37 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
38 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
39 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
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> {
53 InstanceIdToCompositeNodes(final T identifier) {
58 @SuppressWarnings("unchecked")
59 final NormalizedNode<?, ?> create(final PathArgument first, final Iterator<PathArgument> others,
60 final Optional<NormalizedNode<?, ?>> lastChild) {
62 final QName type = getIdentifier().getNodeType();
64 final QName firstType = first.getNodeType();
65 checkArgument(type.equals(firstType), "Node QName must be %s was %s", type, firstType);
69 @SuppressWarnings("rawtypes")
70 final NormalizedNodeContainerBuilder builder = createBuilder(first);
72 if (others.hasNext()) {
73 final PathArgument childPath = others.next();
74 final InstanceIdToNodes<?> childOp = getChildOperation(childPath);
75 builder.addChild(childOp.create(childPath, others, lastChild));
76 } else if (lastChild.isPresent()) {
77 builder.withValue(ImmutableList.copyOf((Collection<?>) lastChild.get().getValue()));
80 return builder.build();
83 @SuppressWarnings("checkstyle:illegalCatch")
84 private InstanceIdToNodes<?> getChildOperation(final PathArgument childPath) {
85 final InstanceIdToNodes<?> childOp;
87 childOp = getChild(childPath);
88 } catch (final RuntimeException e) {
89 throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
91 checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
95 abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(PathArgument compositeNode);
97 abstract static class DataContainerNormalizationOperation<T extends PathArgument>
98 extends InstanceIdToCompositeNodes<T> {
100 private final Map<PathArgument, InstanceIdToNodes<?>> byArg = new ConcurrentHashMap<>();
101 private final DataNodeContainer schema;
103 DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
105 this.schema = schema;
109 final InstanceIdToNodes<?> getChild(final PathArgument child) {
110 InstanceIdToNodes<?> potential = byArg.get(child);
111 if (potential != null) {
114 potential = fromLocalSchema(child);
115 return register(potential);
118 private InstanceIdToNodes<?> fromLocalSchema(final PathArgument child) {
119 if (child instanceof AugmentationIdentifier) {
120 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
123 return fromSchemaAndQNameChecked(schema, child.getNodeType());
126 private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
127 if (potential != null) {
128 byArg.put(potential.getIdentifier(), potential);
134 static final class ListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
135 ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
136 super(identifier, schema);
140 DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> createBuilder(
141 final PathArgument currentArg) {
142 final NodeIdentifierWithPredicates arg = (NodeIdentifierWithPredicates) currentArg;
143 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
144 .mapEntryBuilder().withNodeIdentifier(arg);
145 for (final Entry<QName, Object> keyValue : arg.entrySet()) {
146 builder.addChild(Builders.leafBuilder()
147 .withNodeIdentifier(NodeIdentifier.create(keyValue.getKey())).withValue(keyValue.getValue())
159 static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
160 UnkeyedListItemNormalization(final ListSchemaNode schema) {
161 super(NodeIdentifier.create(schema.getQName()), schema);
165 DataContainerNodeBuilder<NodeIdentifier, UnkeyedListEntryNode> createBuilder(
166 final PathArgument compositeNode) {
167 return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
176 static final class ContainerTransformation extends DataContainerNormalizationOperation<NodeIdentifier> {
177 ContainerTransformation(final ContainerSchemaNode schema) {
178 super(NodeIdentifier.create(schema.getQName()), schema);
182 DataContainerNodeBuilder<NodeIdentifier, ContainerNode> createBuilder(final PathArgument compositeNode) {
183 return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
192 static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
193 OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
198 ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
199 return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
203 static class UnorderedLeafListMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
204 private final InstanceIdToNodes<?> innerOp;
206 UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
207 super(NodeIdentifier.create(potential.getQName()));
208 innerOp = new InstanceIdToSimpleNodes.LeafListEntryNormalization(potential);
212 ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
213 return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
217 final InstanceIdToNodes<?> getChild(final PathArgument child) {
218 return child instanceof NodeWithValue ? innerOp : null;
222 final boolean isMixin() {
227 static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> {
228 AugmentationNormalization(final AugmentationSchemaNode augmentation, final DataNodeContainer schema) {
229 super(DataSchemaContextNode.augmentationIdentifierFrom(augmentation),
230 EffectiveAugmentationSchema.create(augmentation, schema));
234 DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> createBuilder(
235 final PathArgument compositeNode) {
236 return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
245 static class UnorderedMapMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
246 private final ListItemNormalization innerNode;
248 UnorderedMapMixinNormalization(final ListSchemaNode list) {
249 super(NodeIdentifier.create(list.getQName()));
250 this.innerNode = new ListItemNormalization(NodeIdentifierWithPredicates.of(list.getQName()), list);
254 CollectionNodeBuilder<MapEntryNode, ? extends MapNode> createBuilder(final PathArgument compositeNode) {
255 return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
259 final InstanceIdToNodes<?> getChild(final PathArgument child) {
260 return child.getNodeType().equals(getIdentifier().getNodeType()) ? innerNode : null;
264 final boolean isMixin() {
269 static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
270 OrderedMapMixinNormalization(final ListSchemaNode list) {
275 CollectionNodeBuilder<MapEntryNode, OrderedMapNode> createBuilder(final PathArgument compositeNode) {
276 return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
280 static final class ChoiceNodeNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
281 private final ImmutableMap<PathArgument, InstanceIdToNodes<?>> byArg;
283 ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
284 super(NodeIdentifier.create(schema.getQName()));
285 final ImmutableMap.Builder<PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
287 for (final CaseSchemaNode caze : schema.getCases().values()) {
288 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
289 final InstanceIdToNodes<?> childOp = fromDataSchemaNode(cazeChild);
290 byArgBuilder.put(childOp.getIdentifier(), childOp);
293 byArg = byArgBuilder.build();
297 InstanceIdToNodes<?> getChild(final PathArgument child) {
298 return byArg.get(child);
302 DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> createBuilder(final PathArgument compositeNode) {
303 return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());