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