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