BUG 484 Anyxml normalized node
[controller.git] / opendaylight / md-sal / sal-common-impl / src / main / java / org / opendaylight / controller / md / sal / common / impl / util / compat / DataNormalizationOperation.java
1 /*
2  * Copyright (c) 2014 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.controller.md.sal.common.impl.util.compat;
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.collect.FluentIterable;
15 import com.google.common.collect.ImmutableMap;
16 import com.google.common.collect.ImmutableSet;
17 import java.util.Collections;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Map.Entry;
22 import java.util.Set;
23 import java.util.concurrent.ConcurrentHashMap;
24 import org.opendaylight.yangtools.concepts.Identifiable;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
27 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
30 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
31 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
32 import org.opendaylight.yangtools.yang.data.api.Node;
33 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.AnyXmlNode;
35 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
36 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
37 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
38 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
39 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
40 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
41 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
42 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
44 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
45 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
46 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
47 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
48 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
52 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
53
54 public abstract class DataNormalizationOperation<T extends PathArgument> implements Identifiable<T> {
55
56     private final T identifier;
57
58     @Override
59     public T getIdentifier() {
60         return identifier;
61     };
62
63     protected DataNormalizationOperation(final T identifier) {
64         super();
65         this.identifier = identifier;
66     }
67
68     public boolean isMixin() {
69         return false;
70     }
71
72
73     public boolean isKeyedEntry() {
74         return false;
75     }
76
77     protected Set<QName> getQNameIdentifiers() {
78         return Collections.singleton(identifier.getNodeType());
79     }
80
81     public abstract DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException;
82
83     public abstract DataNormalizationOperation<?> getChild(QName child) throws DataNormalizationException;
84
85     public abstract NormalizedNode<?, ?> normalize(Node<?> legacyData);
86
87     public abstract boolean isLeaf();
88
89     private static abstract class SimpleTypeNormalization<T extends PathArgument> extends DataNormalizationOperation<T> {
90
91         protected SimpleTypeNormalization(final T identifier) {
92             super(identifier);
93         }
94
95         @Override
96         public NormalizedNode<?, ?> normalize(final Node<?> legacyData) {
97             checkArgument(legacyData != null);
98             checkArgument(legacyData instanceof SimpleNode<?>);
99             return normalizeImpl((SimpleNode<?>) legacyData);
100         }
101
102         protected abstract NormalizedNode<?, ?> normalizeImpl(SimpleNode<?> node);
103
104         @Override
105         public DataNormalizationOperation<?> getChild(final PathArgument child) {
106             return null;
107         }
108
109         @Override
110         public DataNormalizationOperation<?> getChild(final QName child) {
111             return null;
112         }
113
114         @Override
115         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
116             return null;
117         }
118
119         @Override
120         public boolean isLeaf() {
121             return true;
122         }
123
124     }
125
126     private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
127
128         protected LeafNormalization(final NodeIdentifier identifier) {
129             super(identifier);
130         }
131
132         @Override
133         protected NormalizedNode<?, ?> normalizeImpl(final SimpleNode<?> node) {
134             return ImmutableNodes.leafNode(node.getNodeType(), node.getValue());
135         }
136
137     }
138
139     private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
140
141         public LeafListEntryNormalization(final LeafListSchemaNode potential) {
142             super(new NodeWithValue(potential.getQName(), null));
143         }
144
145         @Override
146         protected NormalizedNode<?, ?> normalizeImpl(final SimpleNode<?> node) {
147             NodeWithValue nodeId = new NodeWithValue(node.getNodeType(), node.getValue());
148             return Builders.leafSetEntryBuilder().withNodeIdentifier(nodeId).withValue(node.getValue()).build();
149         }
150
151
152         @Override
153         public boolean isKeyedEntry() {
154             return true;
155         }
156     }
157
158     private static abstract class CompositeNodeNormalizationOperation<T extends PathArgument> extends
159             DataNormalizationOperation<T> {
160
161         protected CompositeNodeNormalizationOperation(final T identifier) {
162             super(identifier);
163         }
164
165         @SuppressWarnings({ "rawtypes", "unchecked" })
166         @Override
167         public final NormalizedNode<?, ?> normalize(final Node<?> legacyData) {
168             checkArgument(legacyData != null);
169             if (!isMixin() && getIdentifier().getNodeType() != null) {
170                 checkArgument(getIdentifier().getNodeType().equals(legacyData.getNodeType()),
171                         "Node QName must be %s was %s", getIdentifier().getNodeType(), legacyData.getNodeType());
172             }
173             checkArgument(legacyData instanceof CompositeNode, "Node %s should be composite", legacyData);
174             CompositeNode compositeNode = (CompositeNode) legacyData;
175             NormalizedNodeContainerBuilder builder = createBuilder(compositeNode);
176
177             Set<DataNormalizationOperation<?>> usedMixins = new HashSet<>();
178             for (Node<?> childLegacy : compositeNode.getValue()) {
179                 final DataNormalizationOperation childOp;
180
181                 try {
182                     childOp = getChild(childLegacy.getNodeType());
183                 } catch (DataNormalizationException e) {
184                     throw new IllegalArgumentException(String.format("Failed to normalize data %s", compositeNode.getValue()), e);
185                 }
186
187                 // We skip unknown nodes if this node is mixin since
188                 // it's nodes and parent nodes are interleaved
189                 if (childOp == null && isMixin()) {
190                     continue;
191                 }
192
193                 checkArgument(childOp != null, "Node %s is not allowed inside %s", childLegacy.getNodeType(),
194                         getIdentifier());
195                 if (childOp.isMixin()) {
196                     if (usedMixins.contains(childOp)) {
197                         // We already run / processed that mixin, so to avoid
198                         // duplicity we are skipping next nodes.
199                         continue;
200                     }
201                     builder.addChild(childOp.normalize(compositeNode));
202                     usedMixins.add(childOp);
203                 } else {
204                     builder.addChild(childOp.normalize(childLegacy));
205                 }
206             }
207             return builder.build();
208         }
209
210         @Override
211         public boolean isLeaf() {
212             return false;
213         }
214
215         @SuppressWarnings("rawtypes")
216         protected abstract NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode);
217
218     }
219
220     private static abstract class DataContainerNormalizationOperation<T extends PathArgument> extends
221             CompositeNodeNormalizationOperation<T> {
222
223         private final DataNodeContainer schema;
224         private final Map<QName, DataNormalizationOperation<?>> byQName;
225         private final Map<PathArgument, DataNormalizationOperation<?>> byArg;
226
227         protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
228             super(identifier);
229             this.schema = schema;
230             this.byArg = new ConcurrentHashMap<>();
231             this.byQName = new ConcurrentHashMap<>();
232         }
233
234         @Override
235         public DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException {
236             DataNormalizationOperation<?> potential = byArg.get(child);
237             if (potential != null) {
238                 return potential;
239             }
240             potential = fromLocalSchema(child);
241             return register(potential);
242         }
243
244         private DataNormalizationOperation<?> fromLocalSchema(final PathArgument child) throws DataNormalizationException {
245             if (child instanceof AugmentationIdentifier) {
246                 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
247                         .iterator().next());
248             }
249             return fromSchemaAndQNameChecked(schema, child.getNodeType());
250         }
251
252         @Override
253         public DataNormalizationOperation<?> getChild(final QName child) throws DataNormalizationException {
254             DataNormalizationOperation<?> potential = byQName.get(child);
255             if (potential != null) {
256                 return potential;
257             }
258             potential = fromLocalSchemaAndQName(schema, child);
259             return register(potential);
260         }
261
262         protected DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema2, final QName child) throws DataNormalizationException {
263             return fromSchemaAndQNameChecked(schema2, child);
264         }
265
266         private DataNormalizationOperation<?> register(final DataNormalizationOperation<?> potential) {
267             if (potential != null) {
268                 byArg.put(potential.getIdentifier(), potential);
269                 for (QName qName : potential.getQNameIdentifiers()) {
270                     byQName.put(qName, potential);
271                 }
272             }
273             return potential;
274         }
275
276     }
277
278     private static final class ListItemNormalization extends
279             DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
280
281         private final List<QName> keyDefinition;
282
283         protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
284             super(identifier, schema);
285             keyDefinition = schema.getKeyDefinition();
286         }
287
288         @Override
289         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
290             ImmutableMap.Builder<QName, Object> keys = ImmutableMap.builder();
291             for (QName key : keyDefinition) {
292
293                 SimpleNode<?> valueNode = checkNotNull(compositeNode.getFirstSimpleByName(key),
294                         "List node %s MUST contain leaf %s with value.", getIdentifier().getNodeType(), key);
295                 keys.put(key, valueNode.getValue());
296             }
297
298             return Builders.mapEntryBuilder().withNodeIdentifier(
299                     new NodeIdentifierWithPredicates(getIdentifier().getNodeType(), keys.build()));
300         }
301
302         @Override
303         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
304             DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
305                     .mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates) currentArg);
306             for (Entry<QName, Object> keyValue : ((NodeIdentifierWithPredicates) currentArg).getKeyValues().entrySet()) {
307                 builder.addChild(Builders.leafBuilder()
308                         //
309                         .withNodeIdentifier(new NodeIdentifier(keyValue.getKey())).withValue(keyValue.getValue())
310                         .build());
311             }
312             return builder.build();
313         }
314
315
316         @Override
317         public boolean isKeyedEntry() {
318             return true;
319         }
320     }
321
322     private static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
323
324         protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
325             super(new NodeIdentifier(schema.getQName()), schema);
326         }
327
328         @Override
329         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
330             return Builders.unkeyedListEntryBuilder().withNodeIdentifier(getIdentifier());
331         }
332
333         @Override
334         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
335             return Builders.unkeyedListEntryBuilder().withNodeIdentifier((NodeIdentifier) currentArg).build();
336         }
337
338     }
339
340     private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
341
342         protected ContainerNormalization(final ContainerSchemaNode schema) {
343             super(new NodeIdentifier(schema.getQName()), schema);
344         }
345
346         @Override
347         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
348             return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
349         }
350
351         @Override
352         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
353             return Builders.containerBuilder().withNodeIdentifier((NodeIdentifier) currentArg).build();
354         }
355
356     }
357
358     private static abstract class MixinNormalizationOp<T extends PathArgument> extends
359             CompositeNodeNormalizationOperation<T> {
360
361         protected MixinNormalizationOp(final T identifier) {
362             super(identifier);
363         }
364
365         @Override
366         public final boolean isMixin() {
367             return true;
368         }
369
370     }
371
372
373     private static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
374
375
376         public OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
377             super(potential);
378         }
379
380         @Override
381         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
382             return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier());
383         }
384
385         @Override
386         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
387             return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier()).build();
388         }
389     }
390
391     private static class UnorderedLeafListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
392
393         private final DataNormalizationOperation<?> innerOp;
394
395         public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
396             super(new NodeIdentifier(potential.getQName()));
397             innerOp = new LeafListEntryNormalization(potential);
398         }
399
400         @Override
401         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
402             return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
403         }
404
405         @Override
406         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
407             return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier()).build();
408         }
409
410         @Override
411         public DataNormalizationOperation<?> getChild(final PathArgument child) {
412             if (child instanceof NodeWithValue) {
413                 return innerOp;
414             }
415             return null;
416         }
417
418         @Override
419         public DataNormalizationOperation<?> getChild(final QName child) {
420             if (getIdentifier().getNodeType().equals(child)) {
421                 return innerOp;
422             }
423             return null;
424         }
425     }
426
427     private static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> {
428
429         public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
430             //super();
431             super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema));
432         }
433
434         @Override
435         public boolean isMixin() {
436             return true;
437         }
438
439
440
441         @Override
442         protected DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema, final QName child)
443                 throws DataNormalizationException {
444             Optional<DataSchemaNode> potential = findChildSchemaNode(schema, child);
445             if (!potential.isPresent()) {
446                 return null;
447             }
448
449             DataSchemaNode result = potential.get();
450             // We try to look up if this node was added by augmentation
451             if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
452                 return fromAugmentation(schema, (AugmentationTarget) schema, result);
453             }
454             return fromDataSchemaNode(result);
455         }
456
457         @Override
458         protected Set<QName> getQNameIdentifiers() {
459             return getIdentifier().getPossibleChildNames();
460         }
461
462         @SuppressWarnings("rawtypes")
463         @Override
464         protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
465             return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
466         }
467
468         @Override
469         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
470             return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier()).build();
471         }
472
473     }
474
475     private static class UnorderedMapMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
476
477         private final ListItemNormalization innerNode;
478
479         public UnorderedMapMixinNormalization(final ListSchemaNode list) {
480             super(new NodeIdentifier(list.getQName()));
481             this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
482                     Collections.<QName, Object> emptyMap()), list);
483         }
484
485         @SuppressWarnings("rawtypes")
486         @Override
487         protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
488             return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
489         }
490
491         @Override
492         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
493             return Builders.mapBuilder().withNodeIdentifier(getIdentifier()).build();
494         }
495
496         @Override
497         public DataNormalizationOperation<?> getChild(final PathArgument child) {
498             if (child.getNodeType().equals(getIdentifier().getNodeType())) {
499                 return innerNode;
500             }
501             return null;
502         }
503
504         @Override
505         public DataNormalizationOperation<?> getChild(final QName child) {
506             if (getIdentifier().getNodeType().equals(child)) {
507                 return innerNode;
508             }
509             return null;
510         }
511
512     }
513
514
515     private static class UnkeyedListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
516
517         private final UnkeyedListItemNormalization innerNode;
518
519         public UnkeyedListMixinNormalization(final ListSchemaNode list) {
520             super(new NodeIdentifier(list.getQName()));
521             this.innerNode = new UnkeyedListItemNormalization(list);
522         }
523
524         @SuppressWarnings("rawtypes")
525         @Override
526         protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
527             return Builders.unkeyedListBuilder().withNodeIdentifier(getIdentifier());
528         }
529
530         @Override
531         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
532             return Builders.unkeyedListBuilder().withNodeIdentifier(getIdentifier()).build();
533         }
534
535         @Override
536         public DataNormalizationOperation<?> getChild(final PathArgument child) {
537             if (child.getNodeType().equals(getIdentifier().getNodeType())) {
538                 return innerNode;
539             }
540             return null;
541         }
542
543         @Override
544         public DataNormalizationOperation<?> getChild(final QName child) {
545             if (getIdentifier().getNodeType().equals(child)) {
546                 return innerNode;
547             }
548             return null;
549         }
550
551     }
552
553     private static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
554
555         public OrderedMapMixinNormalization(final ListSchemaNode list) {
556             super(list);
557         }
558
559         @SuppressWarnings("rawtypes")
560         @Override
561         protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
562             return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier());
563         }
564
565         @Override
566         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
567             return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier()).build();
568         }
569
570     }
571
572     private static class ChoiceNodeNormalization extends MixinNormalizationOp<NodeIdentifier> {
573
574         private final ImmutableMap<QName, DataNormalizationOperation<?>> byQName;
575         private final ImmutableMap<PathArgument, DataNormalizationOperation<?>> byArg;
576
577         protected ChoiceNodeNormalization(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
578             super(new NodeIdentifier(schema.getQName()));
579             ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
580             ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder = ImmutableMap.builder();
581
582             for (ChoiceCaseNode caze : schema.getCases()) {
583                 for (DataSchemaNode cazeChild : caze.getChildNodes()) {
584                     DataNormalizationOperation<?> childOp = fromDataSchemaNode(cazeChild);
585                     byArgBuilder.put(childOp.getIdentifier(), childOp);
586                     for (QName qname : childOp.getQNameIdentifiers()) {
587                         byQNameBuilder.put(qname, childOp);
588                     }
589                 }
590             }
591             byQName = byQNameBuilder.build();
592             byArg = byArgBuilder.build();
593         }
594
595         @Override
596         public DataNormalizationOperation<?> getChild(final PathArgument child) {
597             return byArg.get(child);
598         }
599
600         @Override
601         public DataNormalizationOperation<?> getChild(final QName child) {
602             return byQName.get(child);
603         }
604
605         @Override
606         protected NormalizedNodeContainerBuilder<?, ?, ?, ?> createBuilder(final CompositeNode compositeNode) {
607             return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
608         }
609
610         @Override
611         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
612             return Builders.choiceBuilder().withNodeIdentifier(getIdentifier()).build();
613         }
614     }
615
616     private static class AnyXmlNormalization extends DataNormalizationOperation<NodeIdentifier> {
617
618         protected AnyXmlNormalization( NodeIdentifier identifier ) {
619             super( identifier );
620         }
621
622         @Override
623         public DataNormalizationOperation<?> getChild( PathArgument child ) throws DataNormalizationException {
624             return null;
625         }
626
627         @Override
628         public DataNormalizationOperation<?> getChild( QName child ) throws DataNormalizationException {
629             return null;
630         }
631
632         @Override
633         public NormalizedNode<?, ?> normalize( Node<?> legacyData ) {
634             NormalizedNodeAttrBuilder<NodeIdentifier, Node<?>, AnyXmlNode> builder =
635                     Builders.anyXmlBuilder().withNodeIdentifier(
636                                                 new NodeIdentifier( legacyData.getNodeType() ) );
637             builder.withValue(legacyData);
638             return builder.build();
639         }
640
641         @Override
642         public boolean isLeaf() {
643             return false;
644         }
645
646         @Override
647         public NormalizedNode<?, ?> createDefault( PathArgument currentArg ) {
648             return null;
649         }
650     }
651
652     private static final Optional<DataSchemaNode> findChildSchemaNode(final DataNodeContainer parent,final QName child) {
653         DataSchemaNode potential = parent.getDataChildByName(child);
654         if (potential == null) {
655             Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices = FluentIterable.from(
656                     parent.getChildNodes()).filter(org.opendaylight.yangtools.yang.model.api.ChoiceNode.class);
657             potential = findChoice(choices, child);
658         }
659         return Optional.fromNullable(potential);
660     }
661
662     private static DataNormalizationOperation<?> fromSchemaAndQNameChecked(final DataNodeContainer schema,
663             final QName child) throws DataNormalizationException {
664
665         Optional<DataSchemaNode> potential = findChildSchemaNode(schema, child);
666         if (!potential.isPresent()) {
667             throw new DataNormalizationException(String.format("Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child, schema,schema.getChildNodes()));
668         }
669
670         DataSchemaNode result = potential.get();
671         // We try to look up if this node was added by augmentation
672         if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
673             return fromAugmentation(schema, (AugmentationTarget) schema, result);
674         }
675         return fromDataSchemaNode(result);
676     }
677
678     private static org.opendaylight.yangtools.yang.model.api.ChoiceNode findChoice(
679             final Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices, final QName child) {
680         org.opendaylight.yangtools.yang.model.api.ChoiceNode foundChoice = null;
681         choiceLoop: for (org.opendaylight.yangtools.yang.model.api.ChoiceNode choice : choices) {
682             for (ChoiceCaseNode caze : choice.getCases()) {
683                 if (findChildSchemaNode(caze, child).isPresent()) {
684                     foundChoice = choice;
685                     break choiceLoop;
686                 }
687             }
688         }
689         return foundChoice;
690     }
691
692     public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
693         ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
694         for (DataSchemaNode child : augmentation.getChildNodes()) {
695             potentialChildren.add(child.getQName());
696         }
697         return new AugmentationIdentifier(null, potentialChildren.build());
698     }
699
700     private static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation, final DataNodeContainer schema) {
701         Set<DataSchemaNode> children = new HashSet<>();
702         for (DataSchemaNode augNode : augmentation.getChildNodes()) {
703             children.add(schema.getDataChildByName(augNode.getQName()));
704         }
705         return new DataSchemaContainerProxy(children);
706     }
707
708     /**
709      * Returns a DataNormalizationOperation for provided child node
710      *
711      * If supplied child is added by Augmentation this operation returns
712      * a DataNormalizationOperation for augmentation,
713      * otherwise returns a DataNormalizationOperation for child as
714      * call for {@link #fromDataSchemaNode(DataSchemaNode)}.
715      *
716      *
717      * @param parent
718      * @param parentAug
719      * @param child
720      * @return
721      */
722     private static DataNormalizationOperation<?> fromAugmentation(final DataNodeContainer parent,
723             final AugmentationTarget parentAug, final DataSchemaNode child) {
724         AugmentationSchema augmentation = null;
725         for (AugmentationSchema aug : parentAug.getAvailableAugmentations()) {
726             DataSchemaNode potential = aug.getDataChildByName(child.getQName());
727             if (potential != null) {
728                 augmentation = aug;
729                 break;
730             }
731
732         }
733         if (augmentation != null) {
734             return new AugmentationNormalization(augmentation, parent);
735         } else {
736             return fromDataSchemaNode(child);
737         }
738     }
739
740     public static DataNormalizationOperation<?> fromDataSchemaNode(final DataSchemaNode potential) {
741         if (potential instanceof ContainerSchemaNode) {
742             return new ContainerNormalization((ContainerSchemaNode) potential);
743         } else if (potential instanceof ListSchemaNode) {
744
745             return fromListSchemaNode((ListSchemaNode) potential);
746         } else if (potential instanceof LeafSchemaNode) {
747             return new LeafNormalization(new NodeIdentifier(potential.getQName()));
748         } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
749             return new ChoiceNodeNormalization((org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential);
750         } else if (potential instanceof LeafListSchemaNode) {
751             return fromLeafListSchemaNode((LeafListSchemaNode) potential);
752         } else if (potential instanceof AnyXmlSchemaNode) {
753             return new AnyXmlNormalization( new NodeIdentifier(potential.getQName() ) );
754         }
755         return null;
756     }
757
758     private static DataNormalizationOperation<?> fromListSchemaNode(final ListSchemaNode potential) {
759         List<QName> keyDefinition = potential.getKeyDefinition();
760         if(keyDefinition == null || keyDefinition.isEmpty()) {
761             return new UnkeyedListMixinNormalization(potential);
762         }
763         if(potential.isUserOrdered()) {
764             return new OrderedMapMixinNormalization(potential);
765         }
766         return new UnorderedMapMixinNormalization(potential);
767     }
768
769     private static DataNormalizationOperation<?> fromLeafListSchemaNode(final LeafListSchemaNode potential) {
770         if(potential.isUserOrdered()) {
771             return new OrderedLeafListMixinNormalization(potential);
772         }
773         return new UnorderedLeafListMixinNormalization(potential);
774     }
775
776
777     public static DataNormalizationOperation<?> from(final SchemaContext ctx) {
778         return new ContainerNormalization(ctx);
779     }
780
781     public abstract NormalizedNode<?, ?> createDefault(PathArgument currentArg);
782 }