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