Import YangInstanceIdentifier nested classes
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / InstanceIdToCompositeNodes.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.data.impl.schema;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkNotNull;
12
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;
23 import java.util.Map;
24 import java.util.Set;
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;
48
49 /**
50 * Base strategy for converting an instance identifier into a normalized node structure for container-like types.
51 */
52 abstract class InstanceIdToCompositeNodes<T extends PathArgument> extends InstanceIdToNodes<T> {
53
54     protected InstanceIdToCompositeNodes(final T identifier) {
55         super(identifier);
56     }
57
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());
62         }
63         return new AugmentationIdentifier(potentialChildren.build());
64     }
65
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()));
70         }
71         return new EffectiveAugmentationSchema(augmentation, children);
72     }
73
74     @Override
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();
80
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());
84         }
85         final NormalizedNodeContainerBuilder builder = createBuilder(legacyData);
86
87         if (iterator.hasNext()) {
88             final YangInstanceIdentifier.PathArgument childPath = iterator.next();
89             final InstanceIdToNodes childOp = getChildOperation(childPath);
90
91             final YangInstanceIdentifier childId = YangInstanceIdentifier.create(Iterables.skip(instanceId.getPathArguments(), 1));
92             builder.addChild(childOp.create(childId, lastChild, operation));
93         } else {
94             if (lastChild.isPresent()) {
95                 builder.withValue(Lists.newArrayList((Collection<?>) lastChild.get().getValue()));
96             }
97             if (operation.isPresent()) {
98                 Preconditions.checkArgument(builder instanceof AttributesBuilder<?>);
99                 addModifyOpIfPresent(operation, ((AttributesBuilder<?>) builder));
100             }
101         }
102
103         return builder.build();
104     }
105
106     private InstanceIdToNodes<?> getChildOperation(final PathArgument childPath) {
107         final InstanceIdToNodes<?> childOp;
108         try {
109             childOp = getChild(childPath);
110         } catch (final RuntimeException e) {
111             throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
112         }
113         checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
114         return childOp;
115     }
116
117     protected abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode);
118
119     static abstract class DataContainerNormalizationOperation<T extends PathArgument> extends
120             InstanceIdToCompositeNodes<T> {
121
122         private final DataNodeContainer schema;
123         private final Map<PathArgument, InstanceIdToNodes<?>> byArg;
124
125         protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
126             super(identifier);
127             this.schema = schema;
128             this.byArg = new ConcurrentHashMap<>();
129         }
130
131         @Override
132         public InstanceIdToNodes<?> getChild(final PathArgument child) {
133             InstanceIdToNodes<?> potential = byArg.get(child);
134             if (potential != null) {
135                 return potential;
136             }
137             potential = fromLocalSchema(child);
138             return register(potential);
139         }
140
141         private InstanceIdToNodes<?> fromLocalSchema(final PathArgument child) {
142             if (child instanceof AugmentationIdentifier) {
143                 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
144                         .iterator().next());
145             }
146             return fromSchemaAndQNameChecked(schema, child.getNodeType());
147         }
148
149         private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
150             if (potential != null) {
151                 byArg.put(potential.getIdentifier(), potential);
152             }
153             return potential;
154         }
155     }
156
157     static final class ListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
158         protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
159             super(identifier, schema);
160         }
161
162         @Override
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()
168                         //
169                         .withNodeIdentifier(new NodeIdentifier(keyValue.getKey())).withValue(keyValue.getValue())
170                         .build());
171             }
172             return builder;
173         }
174
175     }
176
177     static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
178
179         protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
180             super(new NodeIdentifier(schema.getQName()), schema);
181         }
182
183         @Override
184         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
185             return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
186         }
187
188     }
189
190     static final class ContainerTransformation extends DataContainerNormalizationOperation<NodeIdentifier> {
191
192         protected ContainerTransformation(final ContainerSchemaNode schema) {
193             super(new NodeIdentifier(schema.getQName()), schema);
194         }
195
196         @Override
197         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
198             return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
199         }
200     }
201
202     static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
203
204
205         public OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
206             super(potential);
207         }
208
209         @Override
210         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
211             return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
212         }
213     }
214
215     static class UnorderedLeafListMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> implements MixinNormalizationOp {
216
217         private final InstanceIdToNodes<?> innerOp;
218
219         public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
220             super(new NodeIdentifier(potential.getQName()));
221             innerOp = new InstanceIdToSimpleNodes.LeafListEntryNormalization(potential);
222         }
223
224         @Override
225         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
226             return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
227         }
228
229         @Override
230         public InstanceIdToNodes<?> getChild(final PathArgument child) {
231             if (child instanceof NodeWithValue) {
232                 return innerOp;
233             }
234             return null;
235         }
236     }
237
238     static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> implements MixinNormalizationOp {
239
240         public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
241             super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation, schema));
242         }
243
244         @Override
245         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
246             return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
247         }
248     }
249
250     static class UnorderedMapMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> implements MixinNormalizationOp {
251
252         private final ListItemNormalization innerNode;
253
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);
258         }
259
260         @Override
261         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
262             return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
263         }
264
265         @Override
266         public InstanceIdToNodes<?> getChild(final PathArgument child) {
267             if (child.getNodeType().equals(getIdentifier().getNodeType())) {
268                 return innerNode;
269             }
270             return null;
271         }
272     }
273
274     static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
275
276         public OrderedMapMixinNormalization(final ListSchemaNode list) {
277             super(list);
278         }
279
280         @Override
281         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode) {
282             return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
283         }
284
285     }
286
287     static class ChoiceNodeNormalization extends InstanceIdToCompositeNodes<YangInstanceIdentifier.NodeIdentifier> implements MixinNormalizationOp {
288
289         private final ImmutableMap<YangInstanceIdentifier.PathArgument, InstanceIdToNodes<?>> byArg;
290
291         protected ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
292             super(new YangInstanceIdentifier.NodeIdentifier(schema.getQName()));
293             final ImmutableMap.Builder<YangInstanceIdentifier.PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
294
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);
299                 }
300             }
301             byArg = byArgBuilder.build();
302         }
303
304         @Override
305         public InstanceIdToNodes<?> getChild(final PathArgument child) {
306             return byArg.get(child);
307         }
308
309         @Override
310         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode) {
311             return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
312         }
313     }
314 }