Drop unneeded generic type specifiers
[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.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;
56
57 /**
58 * Base strategy for converting an instance identifier into a normalized node structure for container-like types.
59 */
60 abstract class InstanceIdToCompositeNodes<T extends PathArgument> extends InstanceIdToNodes<T> {
61
62     protected InstanceIdToCompositeNodes(final T identifier) {
63         super(identifier);
64     }
65
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());
70         }
71         return new AugmentationIdentifier(potentialChildren.build());
72     }
73
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()));
78         }
79         return new EffectiveAugmentationSchema(augmentation, children);
80     }
81
82     @Override
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();
88
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());
92         }
93         @SuppressWarnings("rawtypes")
94         final NormalizedNodeContainerBuilder builder = createBuilder(legacyData);
95
96         if (iterator.hasNext()) {
97             final PathArgument childPath = iterator.next();
98             final InstanceIdToNodes<?> childOp = getChildOperation(childPath);
99
100             final YangInstanceIdentifier childId = YangInstanceIdentifier.create(Iterables.skip(instanceId.getPathArguments(), 1));
101             builder.addChild(childOp.create(childId, lastChild, operation));
102         } else {
103             if (lastChild.isPresent()) {
104                 builder.withValue(Lists.newArrayList((Collection<?>) lastChild.get().getValue()));
105             }
106             if (operation.isPresent()) {
107                 Preconditions.checkArgument(builder instanceof AttributesBuilder<?>);
108                 addModifyOpIfPresent(operation, ((AttributesBuilder<?>) builder));
109             }
110         }
111
112         return builder.build();
113     }
114
115     private InstanceIdToNodes<?> getChildOperation(final PathArgument childPath) {
116         final InstanceIdToNodes<?> childOp;
117         try {
118             childOp = getChild(childPath);
119         } catch (final RuntimeException e) {
120             throw new IllegalArgumentException(String.format("Failed to process child node %s", childPath), e);
121         }
122         checkArgument(childOp != null, "Node %s is not allowed inside %s", childPath, getIdentifier());
123         return childOp;
124     }
125
126     protected abstract NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final PathArgument compositeNode);
127
128     static abstract class DataContainerNormalizationOperation<T extends PathArgument> extends
129             InstanceIdToCompositeNodes<T> {
130
131         private final DataNodeContainer schema;
132         private final Map<PathArgument, InstanceIdToNodes<?>> byArg;
133
134         protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
135             super(identifier);
136             this.schema = schema;
137             this.byArg = new ConcurrentHashMap<>();
138         }
139
140         @Override
141         public InstanceIdToNodes<?> getChild(final PathArgument child) {
142             InstanceIdToNodes<?> potential = byArg.get(child);
143             if (potential != null) {
144                 return potential;
145             }
146             potential = fromLocalSchema(child);
147             return register(potential);
148         }
149
150         private InstanceIdToNodes<?> fromLocalSchema(final PathArgument child) {
151             if (child instanceof AugmentationIdentifier) {
152                 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
153                         .iterator().next());
154             }
155             return fromSchemaAndQNameChecked(schema, child.getNodeType());
156         }
157
158         private InstanceIdToNodes<?> register(final InstanceIdToNodes<?> potential) {
159             if (potential != null) {
160                 byArg.put(potential.getIdentifier(), potential);
161             }
162             return potential;
163         }
164     }
165
166     static final class ListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
167         protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
168             super(identifier, schema);
169         }
170
171         @Override
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())
178                         .build());
179             }
180             return builder;
181         }
182
183         @Override
184         boolean isMixin() {
185             return false;
186         }
187     }
188
189     static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
190
191         protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
192             super(NodeIdentifier.create(schema.getQName()), schema);
193         }
194
195         @Override
196         protected DataContainerNodeAttrBuilder<NodeIdentifier, UnkeyedListEntryNode> createBuilder(final PathArgument compositeNode) {
197             return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
198         }
199
200         @Override
201         boolean isMixin() {
202             return false;
203         }
204     }
205
206     static final class ContainerTransformation extends DataContainerNormalizationOperation<NodeIdentifier> {
207         protected ContainerTransformation(final ContainerSchemaNode schema) {
208             super(NodeIdentifier.create(schema.getQName()), schema);
209         }
210
211         @Override
212         protected DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> createBuilder(final PathArgument compositeNode) {
213             return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
214         }
215
216         @Override
217         boolean isMixin() {
218             return false;
219         }
220     }
221
222     static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
223
224
225         public OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
226             super(potential);
227         }
228
229         @Override
230         protected ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
231             return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
232         }
233     }
234
235     static class UnorderedLeafListMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
236
237         private final InstanceIdToNodes<?> innerOp;
238
239         public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
240             super(NodeIdentifier.create(potential.getQName()));
241             innerOp = new InstanceIdToSimpleNodes.LeafListEntryNormalization(potential);
242         }
243
244         @Override
245         protected ListNodeBuilder<?, ?> createBuilder(final PathArgument compositeNode) {
246             return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
247         }
248
249         @Override
250         public InstanceIdToNodes<?> getChild(final PathArgument child) {
251             if (child instanceof NodeWithValue) {
252                 return innerOp;
253             }
254             return null;
255         }
256
257         @Override
258         boolean isMixin() {
259             return true;
260         }
261     }
262
263     static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> {
264
265         public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
266             super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation, schema));
267         }
268
269         @Override
270         protected DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> createBuilder(final PathArgument compositeNode) {
271             return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
272         }
273
274         @Override
275         boolean isMixin() {
276             return true;
277         }
278     }
279
280     static class UnorderedMapMixinNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
281
282         private final ListItemNormalization innerNode;
283
284         public UnorderedMapMixinNormalization(final ListSchemaNode list) {
285             super(NodeIdentifier.create(list.getQName()));
286             this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
287                     Collections.emptyMap()), list);
288         }
289
290         @Override
291         protected CollectionNodeBuilder<MapEntryNode, ? extends MapNode> createBuilder(final PathArgument compositeNode) {
292             return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
293         }
294
295         @Override
296         public InstanceIdToNodes<?> getChild(final PathArgument child) {
297             if (child.getNodeType().equals(getIdentifier().getNodeType())) {
298                 return innerNode;
299             }
300             return null;
301         }
302
303         @Override
304         boolean isMixin() {
305             return true;
306         }
307     }
308
309     static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
310
311         public OrderedMapMixinNormalization(final ListSchemaNode list) {
312             super(list);
313         }
314
315         @Override
316         protected CollectionNodeBuilder<MapEntryNode, OrderedMapNode> createBuilder(final PathArgument compositeNode) {
317             return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
318         }
319
320     }
321
322     static final class ChoiceNodeNormalization extends InstanceIdToCompositeNodes<NodeIdentifier> {
323
324         private final ImmutableMap<PathArgument, InstanceIdToNodes<?>> byArg;
325
326         protected ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
327             super(NodeIdentifier.create(schema.getQName()));
328             final ImmutableMap.Builder<PathArgument, InstanceIdToNodes<?>> byArgBuilder = ImmutableMap.builder();
329
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);
334                 }
335             }
336             byArg = byArgBuilder.build();
337         }
338
339         @Override
340         public InstanceIdToNodes<?> getChild(final PathArgument child) {
341             return byArg.get(child);
342         }
343
344         @Override
345         protected DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> createBuilder(final PathArgument compositeNode) {
346             return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
347         }
348
349         @Override
350         boolean isMixin() {
351             return true;
352         }
353     }
354 }