Merge "Removed unused dependency."
[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 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;
22 import java.util.Map;
23 import java.util.Set;
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.schema.MapEntryNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
30 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
31 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
32 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
33 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
34 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
35 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
38 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
41 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
42
43 /**
44 * Base strategy for converting an instance identifier into a normalized node structure for container-like types.
45 */
46 abstract class InstanceIdToCompositeNodes<T extends YangInstanceIdentifier.PathArgument> extends
47         InstanceIdToNodes<T> {
48
49     protected InstanceIdToCompositeNodes(final T identifier) {
50         super(identifier);
51     }
52
53     private static YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
54         final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
55         for (final DataSchemaNode child : augmentation.getChildNodes()) {
56             potentialChildren.add(child.getQName());
57         }
58         return new YangInstanceIdentifier.AugmentationIdentifier(potentialChildren.build());
59     }
60
61     private static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation, final DataNodeContainer schema) {
62         final Set<DataSchemaNode> children = new HashSet<>();
63         for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
64             children.add(schema.getDataChildByName(augNode.getQName()));
65         }
66         return new EffectiveAugmentationSchema(augmentation, children);
67     }
68
69     @Override
70     @SuppressWarnings("unchecked")
71     public final NormalizedNode<?, ?> create(final YangInstanceIdentifier instanceId, final Optional<NormalizedNode<?, ?>> lastChild, final Optional<Map.Entry<QName,ModifyAction>> operation) {
72         checkNotNull(instanceId);
73         final Iterator<YangInstanceIdentifier.PathArgument> iterator = instanceId.getPathArguments().iterator();
74         final YangInstanceIdentifier.PathArgument legacyData = iterator.next();
75
76         if (!isMixin(this) && getIdentifier().getNodeType() != null) {
77             checkArgument(getIdentifier().getNodeType().equals(legacyData.getNodeType()),
78                     "Node QName must be %s was %s", getIdentifier().getNodeType(), legacyData.getNodeType());
79         }
80         final NormalizedNodeContainerBuilder builder = createBuilder(legacyData);
81
82         if (iterator.hasNext()) {
83             final YangInstanceIdentifier.PathArgument childPath = iterator.next();
84             final InstanceIdToNodes childOp = getChildOperation(childPath);
85
86             final YangInstanceIdentifier childId = YangInstanceIdentifier.create(Iterables.skip(instanceId.getPathArguments(), 1));
87             builder.addChild(childOp.create(childId, lastChild, operation));
88         } else {
89             if(lastChild.isPresent()) {
90                 builder.withValue(Lists.newArrayList((Collection<?>) lastChild.get().getValue()));
91             }
92             if(operation.isPresent()) {
93                 Preconditions.checkArgument(builder instanceof AttributesBuilder<?>);
94                 addModifyOpIfPresent(operation, ((AttributesBuilder<?>) builder));
95             }
96         }
97
98         return builder.build();
99     }
100
101     private InstanceIdToNodes getChildOperation(final YangInstanceIdentifier.PathArgument childPath) {
102         final InstanceIdToNodes childOp;
103         try {
104             childOp = getChild(childPath);
105         } catch (final RuntimeException e) {
106             throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
107         }
108         checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
109         return childOp;
110     }
111
112     protected abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode);
113
114     static abstract class DataContainerNormalizationOperation<T extends YangInstanceIdentifier.PathArgument> extends
115             InstanceIdToCompositeNodes<T> {
116
117         private final DataNodeContainer schema;
118         private final Map<YangInstanceIdentifier.PathArgument, InstanceIdToNodes<?>> byArg;
119
120         protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
121             super(identifier);
122             this.schema = schema;
123             this.byArg = new ConcurrentHashMap<>();
124         }
125
126         @Override
127         public InstanceIdToNodes<?> getChild(final YangInstanceIdentifier.PathArgument child) {
128             InstanceIdToNodes<?> potential = byArg.get(child);
129             if (potential != null) {
130                 return potential;
131             }
132             potential = fromLocalSchema(child);
133             return register(potential);
134         }
135
136         private InstanceIdToNodes<?> fromLocalSchema(final YangInstanceIdentifier.PathArgument child) {
137             if (child instanceof YangInstanceIdentifier.AugmentationIdentifier) {
138                 return fromSchemaAndQNameChecked(schema, ((YangInstanceIdentifier.AugmentationIdentifier) child).getPossibleChildNames()
139                         .iterator().next());
140             }
141             return fromSchemaAndQNameChecked(schema, child.getNodeType());
142         }
143
144         private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
145             if (potential != null) {
146                 byArg.put(potential.getIdentifier(), potential);
147             }
148             return potential;
149         }
150     }
151
152     static final class ListItemNormalization extends
153             DataContainerNormalizationOperation<YangInstanceIdentifier.NodeIdentifierWithPredicates> {
154
155         protected ListItemNormalization(final YangInstanceIdentifier.NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
156             super(identifier, schema);
157         }
158
159         @Override
160         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument currentArg) {
161             final DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
162                     .mapEntryBuilder().withNodeIdentifier((YangInstanceIdentifier.NodeIdentifierWithPredicates) currentArg);
163             for (final Map.Entry<QName, Object> keyValue : ((YangInstanceIdentifier.NodeIdentifierWithPredicates) currentArg).getKeyValues().entrySet()) {
164                 builder.addChild(Builders.leafBuilder()
165                         //
166                         .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(keyValue.getKey())).withValue(keyValue.getValue())
167                         .build());
168             }
169             return builder;
170         }
171
172     }
173
174     static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<YangInstanceIdentifier.NodeIdentifier> {
175
176         protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
177             super(new YangInstanceIdentifier.NodeIdentifier(schema.getQName()), schema);
178         }
179
180         @Override
181         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode) {
182             return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
183         }
184
185     }
186
187     static final class ContainerTransformation extends DataContainerNormalizationOperation<YangInstanceIdentifier.NodeIdentifier> {
188
189         protected ContainerTransformation(final ContainerSchemaNode schema) {
190             super(new YangInstanceIdentifier.NodeIdentifier(schema.getQName()), schema);
191         }
192
193         @Override
194         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode) {
195             return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
196         }
197     }
198
199     static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
200
201
202         public OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
203             super(potential);
204         }
205
206         @Override
207         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode) {
208             return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
209         }
210     }
211
212     static class UnorderedLeafListMixinNormalization extends InstanceIdToCompositeNodes<YangInstanceIdentifier.NodeIdentifier> implements MixinNormalizationOp {
213
214         private final InstanceIdToNodes<?> innerOp;
215
216         public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
217             super(new YangInstanceIdentifier.NodeIdentifier(potential.getQName()));
218             innerOp = new InstanceIdToSimpleNodes.LeafListEntryNormalization(potential);
219         }
220
221         @Override
222         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode) {
223             return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
224         }
225
226         @Override
227         public InstanceIdToNodes<?> getChild(final YangInstanceIdentifier.PathArgument child) {
228             if (child instanceof YangInstanceIdentifier.NodeWithValue) {
229                 return innerOp;
230             }
231             return null;
232         }
233     }
234
235     static final class AugmentationNormalization extends DataContainerNormalizationOperation<YangInstanceIdentifier.AugmentationIdentifier> implements MixinNormalizationOp {
236
237         public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
238             super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation, schema));
239         }
240
241         @Override
242         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode) {
243             return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
244         }
245     }
246
247     static class UnorderedMapMixinNormalization extends InstanceIdToCompositeNodes<YangInstanceIdentifier.NodeIdentifier> implements MixinNormalizationOp {
248
249         private final ListItemNormalization innerNode;
250
251         public UnorderedMapMixinNormalization(final ListSchemaNode list) {
252             super(new YangInstanceIdentifier.NodeIdentifier(list.getQName()));
253             this.innerNode = new ListItemNormalization(new YangInstanceIdentifier.NodeIdentifierWithPredicates(list.getQName(),
254                     Collections.<QName, Object>emptyMap()), list);
255         }
256
257         @Override
258         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode) {
259             return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
260         }
261
262         @Override
263         public InstanceIdToNodes<?> getChild(final YangInstanceIdentifier.PathArgument child) {
264             if (child.getNodeType().equals(getIdentifier().getNodeType())) {
265                 return innerNode;
266             }
267             return null;
268         }
269     }
270
271     static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
272
273         public OrderedMapMixinNormalization(final ListSchemaNode list) {
274             super(list);
275         }
276
277         @Override
278         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode) {
279             return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
280         }
281
282     }
283
284     static class ChoiceNodeNormalization extends InstanceIdToCompositeNodes<YangInstanceIdentifier.NodeIdentifier> implements MixinNormalizationOp {
285
286         private final ImmutableMap<YangInstanceIdentifier.PathArgument, InstanceIdToNodes<?>> byArg;
287
288         protected ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
289             super(new YangInstanceIdentifier.NodeIdentifier(schema.getQName()));
290             final ImmutableMap.Builder<YangInstanceIdentifier.PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
291
292             for (final ChoiceCaseNode caze : schema.getCases()) {
293                 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
294                     final InstanceIdToNodes<?> childOp = fromDataSchemaNode(cazeChild);
295                     byArgBuilder.put(childOp.getIdentifier(), childOp);
296                 }
297             }
298             byArg = byArgBuilder.build();
299         }
300
301         @Override
302         public InstanceIdToNodes<?> getChild(final YangInstanceIdentifier.PathArgument child) {
303             return byArg.get(child);
304         }
305
306         @Override
307         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final YangInstanceIdentifier.PathArgument compositeNode) {
308             return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
309         }
310     }
311 }