Implemented ordering of yang module data nodes. Added Comparators utility class.
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / parser / builder / impl / ModuleBuilder.java
1 /*
2  * Copyright (c) 2013 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.yang.parser.builder.impl;
9
10 import java.net.URI;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Date;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.LinkedHashSet;
17 import java.util.LinkedList;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.TreeMap;
22 import java.util.TreeSet;
23
24 import org.opendaylight.controller.yang.common.QName;
25 import org.opendaylight.controller.yang.model.api.AugmentationSchema;
26 import org.opendaylight.controller.yang.model.api.DataSchemaNode;
27 import org.opendaylight.controller.yang.model.api.Deviation;
28 import org.opendaylight.controller.yang.model.api.ExtensionDefinition;
29 import org.opendaylight.controller.yang.model.api.FeatureDefinition;
30 import org.opendaylight.controller.yang.model.api.GroupingDefinition;
31 import org.opendaylight.controller.yang.model.api.IdentitySchemaNode;
32 import org.opendaylight.controller.yang.model.api.Module;
33 import org.opendaylight.controller.yang.model.api.ModuleImport;
34 import org.opendaylight.controller.yang.model.api.NotificationDefinition;
35 import org.opendaylight.controller.yang.model.api.RpcDefinition;
36 import org.opendaylight.controller.yang.model.api.SchemaPath;
37 import org.opendaylight.controller.yang.model.api.TypeDefinition;
38 import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
39 import org.opendaylight.controller.yang.model.api.UsesNode;
40 import org.opendaylight.controller.yang.parser.builder.api.AugmentationSchemaBuilder;
41 import org.opendaylight.controller.yang.parser.builder.api.Builder;
42 import org.opendaylight.controller.yang.parser.builder.api.DataNodeContainerBuilder;
43 import org.opendaylight.controller.yang.parser.builder.api.DataSchemaNodeBuilder;
44 import org.opendaylight.controller.yang.parser.builder.api.GroupingBuilder;
45 import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
46 import org.opendaylight.controller.yang.parser.builder.api.TypeAwareBuilder;
47 import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
48 import org.opendaylight.controller.yang.parser.builder.api.UsesNodeBuilder;
49 import org.opendaylight.controller.yang.parser.util.Comparators;
50 import org.opendaylight.controller.yang.parser.util.RefineHolder;
51 import org.opendaylight.controller.yang.parser.util.YangParseException;
52
53 /**
54  * This builder builds Module object. If this module is dependent on external
55  * module/modules, these dependencies must be resolved before module is built,
56  * otherwise result may not be valid.
57  */
58 public class ModuleBuilder implements DataNodeContainerBuilder {
59     private final ModuleImpl instance;
60     private final String name;
61     private URI namespace;
62     private String prefix;
63     private Date revision;
64
65     private int augmentsResolved;
66
67     private final Set<ModuleImport> imports = new HashSet<ModuleImport>();
68
69     /**
70      * Holds all child (DataSchemaNode) nodes: anyxml, choice, case, container,
71      * list, leaf, leaf-list.
72      */
73     private final Set<DataSchemaNodeBuilder> childNodes = new HashSet<DataSchemaNodeBuilder>();
74
75     private final Set<GroupingBuilder> addedGroupings = new HashSet<GroupingBuilder>();
76     private final List<AugmentationSchemaBuilder> addedAugments = new ArrayList<AugmentationSchemaBuilder>();
77     private final List<AugmentationSchemaBuilder> allAugments = new ArrayList<AugmentationSchemaBuilder>();
78     private final Set<UsesNodeBuilder> addedUsesNodes = new HashSet<UsesNodeBuilder>();
79     private final List<UsesNodeBuilder> allUsesNodes = new ArrayList<UsesNodeBuilder>();
80     private final Set<RpcDefinitionBuilder> addedRpcs = new HashSet<RpcDefinitionBuilder>();
81     private final Set<NotificationBuilder> addedNotifications = new HashSet<NotificationBuilder>();
82     private final Set<IdentitySchemaNodeBuilder> addedIdentities = new HashSet<IdentitySchemaNodeBuilder>();
83     private final Set<FeatureBuilder> addedFeatures = new HashSet<FeatureBuilder>();
84     private final Map<List<String>, DeviationBuilder> addedDeviations = new HashMap<List<String>, DeviationBuilder>();
85     private final Set<TypeDefinitionBuilder> addedTypedefs = new HashSet<TypeDefinitionBuilder>();
86     private final Map<List<String>, UnionTypeBuilder> addedUnionTypes = new HashMap<List<String>, UnionTypeBuilder>();
87     private final List<ExtensionBuilder> addedExtensions = new ArrayList<ExtensionBuilder>();
88     private final Map<List<String>, List<UnknownSchemaNodeBuilder>> addedUnknownNodes = new HashMap<List<String>, List<UnknownSchemaNodeBuilder>>();
89
90     private final Map<List<String>, TypeAwareBuilder> dirtyNodes = new HashMap<List<String>, TypeAwareBuilder>();
91
92     private final LinkedList<Builder> actualPath = new LinkedList<Builder>();
93
94     public ModuleBuilder(final String name) {
95         this.name = name;
96         instance = new ModuleImpl(name);
97     }
98
99     /**
100      * Build new Module object based on this builder.
101      */
102     @Override
103     public Module build() {
104         instance.setPrefix(prefix);
105         instance.setRevision(revision);
106         instance.setImports(imports);
107         instance.setNamespace(namespace);
108
109         // TYPEDEFS
110         final Set<TypeDefinition<?>> typedefs = new TreeSet<TypeDefinition<?>>(Comparators.SCHEMA_NODE_COMP);
111         for (TypeDefinitionBuilder tdb : addedTypedefs) {
112             typedefs.add(tdb.build());
113         }
114         instance.setTypeDefinitions(typedefs);
115
116         // CHILD NODES
117         final Map<QName, DataSchemaNode> children = new TreeMap<QName, DataSchemaNode>(Comparators.QNAME_COMP);
118         for (DataSchemaNodeBuilder child : childNodes) {
119             children.put(child.getQName(), child.build());
120         }
121         instance.setChildNodes(children);
122
123         // GROUPINGS
124         final Set<GroupingDefinition> groupings = new TreeSet<GroupingDefinition>(Comparators.SCHEMA_NODE_COMP);
125         for (GroupingBuilder gb : addedGroupings) {
126             groupings.add(gb.build());
127         }
128         instance.setGroupings(groupings);
129
130         // USES
131         final Set<UsesNode> usesDefinitions = new HashSet<UsesNode>();
132         for (UsesNodeBuilder unb : addedUsesNodes) {
133             usesDefinitions.add(unb.build());
134         }
135         instance.setUses(usesDefinitions);
136
137         // FEATURES
138         final Set<FeatureDefinition> features = new TreeSet<FeatureDefinition>(Comparators.SCHEMA_NODE_COMP);
139         for (FeatureBuilder fb : addedFeatures) {
140             features.add(fb.build());
141         }
142         instance.setFeatures(features);
143
144         // NOTIFICATIONS
145         final Set<NotificationDefinition> notifications = new TreeSet<NotificationDefinition>(
146                 Comparators.SCHEMA_NODE_COMP);
147         for (NotificationBuilder entry : addedNotifications) {
148             notifications.add(entry.build());
149         }
150         instance.setNotifications(notifications);
151
152         // AUGMENTATIONS
153         final Set<AugmentationSchema> augmentations = new HashSet<AugmentationSchema>();
154         for (AugmentationSchemaBuilder builder : addedAugments) {
155             augmentations.add(builder.build());
156         }
157         instance.setAugmentations(augmentations);
158
159         // RPCs
160         final Set<RpcDefinition> rpcs = new TreeSet<RpcDefinition>(Comparators.SCHEMA_NODE_COMP);
161         for (RpcDefinitionBuilder rpc : addedRpcs) {
162             rpcs.add(rpc.build());
163         }
164         instance.setRpcs(rpcs);
165
166         // DEVIATIONS
167         final Set<Deviation> deviations = new HashSet<Deviation>();
168         for (Map.Entry<List<String>, DeviationBuilder> entry : addedDeviations.entrySet()) {
169             deviations.add(entry.getValue().build());
170         }
171         instance.setDeviations(deviations);
172
173         // EXTENSIONS
174         final List<ExtensionDefinition> extensions = new ArrayList<ExtensionDefinition>();
175         for (ExtensionBuilder eb : addedExtensions) {
176             extensions.add(eb.build());
177         }
178         Collections.sort(extensions, Comparators.SCHEMA_NODE_COMP);
179         instance.setExtensionSchemaNodes(extensions);
180
181         // IDENTITIES
182         final Set<IdentitySchemaNode> identities = new TreeSet<IdentitySchemaNode>(Comparators.SCHEMA_NODE_COMP);
183         for (IdentitySchemaNodeBuilder id : addedIdentities) {
184             identities.add(id.build());
185         }
186         instance.setIdentities(identities);
187
188         // UNKNOWN NODES
189         final List<UnknownSchemaNode> unknownNodes = buildModuleUnknownNodes(addedUnknownNodes);
190         instance.setUnknownSchemaNodes(unknownNodes);
191
192         return instance;
193     }
194
195     @Override
196     public int getLine() {
197         return 0;
198     }
199
200     @Override
201     public Builder getParent() {
202         return null;
203     }
204
205     @Override
206     public void setParent(Builder parent) {
207         throw new YangParseException(name, 0, "Can not set parent to module");
208     }
209
210     @Override
211     public QName getQName() {
212         return new QName(namespace, revision, prefix, name);
213     }
214
215     @Override
216     public SchemaPath getPath() {
217         return null;
218     }
219
220     @Override
221     public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
222         return addedTypedefs;
223     }
224
225     public void enterNode(final Builder node) {
226         actualPath.push(node);
227     }
228
229     public void exitNode() {
230         actualPath.pop();
231     }
232
233     public Builder getActualNode() {
234         if (actualPath.isEmpty()) {
235             return null;
236         } else {
237             return actualPath.get(0);
238         }
239     }
240
241     public Builder getActualParent() {
242         if (actualPath.size() < 2) {
243             return null;
244         } else {
245             return actualPath.get(1);
246         }
247     }
248
249     @Override
250     public Set<GroupingDefinition> getGroupings() {
251         return Collections.emptySet();
252     }
253
254     @Override
255     public Set<GroupingBuilder> getGroupingBuilders() {
256         return addedGroupings;
257     }
258
259     @Override
260     public Set<DataSchemaNode> getChildNodes() {
261         return Collections.emptySet();
262     }
263
264     public Set<DataSchemaNodeBuilder> getChildNodeBuilders() {
265         return childNodes;
266     }
267
268     public Map<List<String>, TypeAwareBuilder> getDirtyNodes() {
269         return dirtyNodes;
270     }
271
272     public List<AugmentationSchemaBuilder> getAllAugments() {
273         return allAugments;
274     }
275
276     public Set<IdentitySchemaNodeBuilder> getIdentities() {
277         return addedIdentities;
278     }
279
280     public List<UsesNodeBuilder> getAllUsesNodes() {
281         return allUsesNodes;
282     }
283
284     public List<UnknownSchemaNodeBuilder> getUnknownNodes() {
285         List<UnknownSchemaNodeBuilder> result = new ArrayList<UnknownSchemaNodeBuilder>();
286         for (List<UnknownSchemaNodeBuilder> entry : addedUnknownNodes.values()) {
287             result.addAll(entry);
288         }
289         return result;
290     }
291
292     public String getName() {
293         return name;
294     }
295
296     public URI getNamespace() {
297         return namespace;
298     }
299
300     public void setNamespace(final URI namespace) {
301         this.namespace = namespace;
302     }
303
304     public String getPrefix() {
305         return prefix;
306     }
307
308     public Date getRevision() {
309         return revision;
310     }
311
312     public int getAugmentsResolved() {
313         return augmentsResolved;
314     }
315
316     public void augmentResolved() {
317         augmentsResolved++;
318     }
319
320     public void addDirtyNode(final List<String> path) {
321         final List<String> dirtyNodePath = new ArrayList<String>(path);
322         final TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) actualPath.getFirst();
323         dirtyNodes.put(dirtyNodePath, nodeBuilder);
324     }
325
326     public void setRevision(final Date revision) {
327         this.revision = revision;
328     }
329
330     public void setPrefix(final String prefix) {
331         this.prefix = prefix;
332     }
333
334     public void setYangVersion(final String yangVersion) {
335         instance.setYangVersion(yangVersion);
336     }
337
338     public void setDescription(final String description) {
339         instance.setDescription(description);
340     }
341
342     public void setReference(final String reference) {
343         instance.setReference(reference);
344     }
345
346     public void setOrganization(final String organization) {
347         instance.setOrganization(organization);
348     }
349
350     public void setContact(final String contact) {
351         instance.setContact(contact);
352     }
353
354     public boolean addModuleImport(final String moduleName, final Date revision, final String prefix) {
355         final ModuleImport moduleImport = createModuleImport(moduleName, revision, prefix);
356         return imports.add(moduleImport);
357     }
358
359     public Set<ModuleImport> getModuleImports() {
360         return imports;
361     }
362
363     public ExtensionBuilder addExtension(final QName qname, final int line) {
364         final ExtensionBuilder builder = new ExtensionBuilder(line, qname);
365         addedExtensions.add(builder);
366         return builder;
367     }
368
369     @Override
370     public void addChildNode(DataSchemaNodeBuilder child) {
371         for (DataSchemaNodeBuilder childNode : childNodes) {
372             if (childNode.getQName().getLocalName().equals(child.getQName().getLocalName())) {
373                 throw new YangParseException(name, child.getLine(), "Duplicate node found at line "
374                         + childNode.getLine());
375             }
376         }
377         childNodes.add(child);
378     }
379
380     public ContainerSchemaNodeBuilder addContainerNode(final int line, final QName containerName,
381             final SchemaPath schemaPath) {
382         final ContainerSchemaNodeBuilder builder = new ContainerSchemaNodeBuilder(line, containerName, schemaPath);
383
384         Builder parent = getActualNode();
385         builder.setParent(parent);
386         addChildToParent(parent, builder, containerName.getLocalName());
387
388         return builder;
389     }
390
391     public ListSchemaNodeBuilder addListNode(final int line, final QName listName, final SchemaPath schemaPath) {
392         final ListSchemaNodeBuilder builder = new ListSchemaNodeBuilder(line, listName, schemaPath);
393
394         Builder parent = getActualNode();
395         builder.setParent(parent);
396         addChildToParent(parent, builder, listName.getLocalName());
397
398         return builder;
399     }
400
401     public LeafSchemaNodeBuilder addLeafNode(final int line, final QName leafName, final SchemaPath schemaPath) {
402         final LeafSchemaNodeBuilder builder = new LeafSchemaNodeBuilder(leafName, schemaPath, line);
403
404         Builder parent = getActualNode();
405         builder.setParent(parent);
406         addChildToParent(parent, builder, leafName.getLocalName());
407
408         return builder;
409     }
410
411     public LeafListSchemaNodeBuilder addLeafListNode(final int line, final QName leafListName,
412             final SchemaPath schemaPath) {
413         final LeafListSchemaNodeBuilder builder = new LeafListSchemaNodeBuilder(line, leafListName, schemaPath);
414
415         Builder parent = getActualNode();
416         builder.setParent(parent);
417         addChildToParent(parent, builder, leafListName.getLocalName());
418
419         return builder;
420     }
421
422     @Override
423     public void addGrouping(GroupingBuilder groupingBuilder) {
424         for (GroupingBuilder gb : addedGroupings) {
425             if (gb.getQName().getLocalName().equals(groupingBuilder.getQName().getLocalName())) {
426                 throw new YangParseException(name, groupingBuilder.getLine(), "Duplicate node found at line "
427                         + gb.getLine());
428             }
429         }
430         addedGroupings.add(groupingBuilder);
431     }
432
433     public GroupingBuilder addGrouping(final int line, final QName qname) {
434         final GroupingBuilder builder = new GroupingBuilderImpl(qname, line);
435
436         Builder parent = getActualNode();
437         builder.setParent(parent);
438
439         if (parent == null) {
440             for (GroupingBuilder child : addedGroupings) {
441                 if (child.getQName().getLocalName().equals(qname.getLocalName())) {
442                     throw new YangParseException(name, line, "Duplicate node found at line " + child.getLine());
443                 }
444             }
445             addedGroupings.add(builder);
446         } else {
447             if (parent instanceof DataNodeContainerBuilder) {
448                 DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
449                 for (DataSchemaNodeBuilder child : parentNode.getChildNodeBuilders()) {
450                     if (child.getQName().getLocalName().equals(qname.getLocalName())) {
451                         throw new YangParseException(name, line, "Duplicate node found at line " + child.getLine());
452                     }
453                 }
454                 parentNode.addGrouping(builder);
455             } else if (parent instanceof RpcDefinitionBuilder) {
456                 RpcDefinitionBuilder parentNode = (RpcDefinitionBuilder) parent;
457                 for (GroupingBuilder child : parentNode.getGroupings()) {
458                     if (child.getQName().getLocalName().equals(qname.getLocalName())) {
459                         throw new YangParseException(name, line, "Duplicate node found at line " + child.getLine());
460                     }
461                 }
462                 parentNode.addGrouping(builder);
463             } else {
464                 throw new YangParseException(name, line, "Unresolved parent of grouping " + qname.getLocalName());
465             }
466         }
467
468         return builder;
469     }
470
471     public AugmentationSchemaBuilder addAugment(final int line, final String augmentTargetStr) {
472         final AugmentationSchemaBuilder builder = new AugmentationSchemaBuilderImpl(line, augmentTargetStr);
473
474         Builder parent = getActualNode();
475         builder.setParent(parent);
476
477         if (parent == null) {
478             addedAugments.add(builder);
479         } else {
480             // augment can only be in 'module' or 'uses' statement
481             if (parent instanceof UsesNodeBuilder) {
482                 ((UsesNodeBuilder) parent).addAugment(builder);
483             } else {
484                 throw new YangParseException(name, line, "Augment can be declared only under module or uses.");
485             }
486         }
487         allAugments.add(builder);
488
489         return builder;
490     }
491
492     @Override
493     public void addUsesNode(UsesNodeBuilder usesBuilder) {
494         addedUsesNodes.add(usesBuilder);
495         allUsesNodes.add(usesBuilder);
496     }
497
498     public UsesNodeBuilder addUsesNode(final int line, final String groupingPathStr) {
499         final UsesNodeBuilder usesBuilder = new UsesNodeBuilderImpl(line, groupingPathStr);
500
501         Builder parent = getActualNode();
502         usesBuilder.setParent(parent);
503
504         if (parent == null) {
505             addedUsesNodes.add(usesBuilder);
506         } else {
507             if (!(parent instanceof DataNodeContainerBuilder)) {
508                 throw new YangParseException(name, line, "Unresolved parent of uses '" + groupingPathStr + "'.");
509             }
510             if (parent instanceof AugmentationSchemaBuilder) {
511                 usesBuilder.setAugmenting(true);
512             }
513             ((DataNodeContainerBuilder) parent).addUsesNode(usesBuilder);
514         }
515         allUsesNodes.add(usesBuilder);
516         return usesBuilder;
517     }
518
519     public void addRefine(final RefineHolder refine, final List<String> parentPath) {
520         final List<String> path = new ArrayList<String>(parentPath);
521
522         if (actualPath.isEmpty()) {
523             throw new YangParseException(name, refine.getLine(), "refine can be defined only in uses statement");
524         } else {
525             final Builder parent = getActualNode();
526             if (parent instanceof UsesNodeBuilder) {
527                 ((UsesNodeBuilder) parent).addRefine(refine);
528             } else {
529                 throw new YangParseException(name, refine.getLine(), "refine can be defined only in uses statement");
530             }
531             refine.setParent(parent);
532         }
533
534         path.add(refine.getName());
535     }
536
537     public RpcDefinitionBuilder addRpc(final int line, final QName qname) {
538         Builder parent = getActualNode();
539         if (parent != null) {
540             throw new YangParseException(name, line, "rpc can be defined only in module or submodule");
541         }
542
543         final RpcDefinitionBuilder rpcBuilder = new RpcDefinitionBuilder(line, qname);
544         for (RpcDefinitionBuilder rpc : addedRpcs) {
545             if (rpc.getQName().getLocalName().equals(qname.getLocalName())) {
546                 throw new YangParseException(name, line, "Duplicate node found at line " + rpc.getLine());
547             }
548         }
549         addedRpcs.add(rpcBuilder);
550         return rpcBuilder;
551     }
552
553     public ContainerSchemaNodeBuilder addRpcInput(final SchemaPath schemaPath, final QName inputQName, final int line) {
554         final Builder parent = getActualNode();
555         if (!(parent instanceof RpcDefinitionBuilder)) {
556             throw new YangParseException(name, line, "input can be defined only in rpc statement");
557         }
558         final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parent;
559
560         final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(line, inputQName, schemaPath);
561         inputBuilder.setParent(rpc);
562
563         rpc.setInput(inputBuilder);
564         return inputBuilder;
565     }
566
567     public ContainerSchemaNodeBuilder addRpcOutput(final SchemaPath schemaPath, final QName outputQName, final int line) {
568         final Builder parent = actualPath.getFirst();
569         if (!(parent instanceof RpcDefinitionBuilder)) {
570             throw new YangParseException(name, line, "output can be defined only in rpc statement");
571         }
572         final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parent;
573
574         final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(line, outputQName, schemaPath);
575         outputBuilder.setParent(rpc);
576
577         rpc.setOutput(outputBuilder);
578         return outputBuilder;
579     }
580
581     public NotificationBuilder addNotification(final QName notificationName, final List<String> parentPath,
582             final int line) {
583         if (!(actualPath.isEmpty())) {
584             throw new YangParseException(name, line, "notification can be defined only in module or submodule");
585         }
586         for (NotificationBuilder nb : addedNotifications) {
587             if (nb.getQName().equals(notificationName)) {
588                 throw new YangParseException(name, line, "Duplicate node found at line " + nb.getLine());
589             }
590         }
591
592         final NotificationBuilder builder = new NotificationBuilder(line, notificationName);
593         addedNotifications.add(builder);
594
595         return builder;
596     }
597
598     public FeatureBuilder addFeature(final int line, final QName featureName) {
599         Builder parent = getActualNode();
600         if (parent != null) {
601             throw new YangParseException(name, line, "feature can be defined only in module or submodule");
602         }
603
604         final FeatureBuilder builder = new FeatureBuilder(line, featureName);
605         for (FeatureBuilder fb : addedFeatures) {
606             if (fb.getQName().getLocalName().equals(featureName.getLocalName())) {
607                 throw new YangParseException(name, line, "Duplicate node found at line " + fb.getLine());
608             }
609         }
610         addedFeatures.add(builder);
611         return builder;
612     }
613
614     public ChoiceBuilder addChoice(final int line, final QName choiceName) {
615         final ChoiceBuilder builder = new ChoiceBuilder(line, choiceName);
616
617         Builder parent = getActualNode();
618         builder.setParent(parent);
619         addChildToParent(parent, builder, choiceName.getLocalName());
620
621         return builder;
622     }
623
624     public ChoiceCaseBuilder addCase(final int line, final QName caseName) {
625         Builder parent = getActualNode();
626         if (parent == null) {
627             throw new YangParseException(name, line, "'case' parent not found");
628         }
629
630         final ChoiceCaseBuilder builder = new ChoiceCaseBuilder(line, caseName);
631         builder.setParent(parent);
632
633         if (parent instanceof ChoiceBuilder) {
634             ((ChoiceBuilder) parent).addChildNode(builder);
635         } else if (parent instanceof AugmentationSchemaBuilder) {
636             ((AugmentationSchemaBuilder) parent).addChildNode(builder);
637         } else {
638             throw new YangParseException(name, line, "Unresolved parent of 'case' " + caseName.getLocalName());
639         }
640
641         return builder;
642     }
643
644     public AnyXmlBuilder addAnyXml(final int line, final QName anyXmlName, final SchemaPath schemaPath) {
645         final AnyXmlBuilder builder = new AnyXmlBuilder(line, anyXmlName, schemaPath);
646
647         Builder parent = getActualNode();
648         builder.setParent(parent);
649         addChildToParent(parent, builder, anyXmlName.getLocalName());
650
651         return builder;
652     }
653
654     @Override
655     public void addTypedef(TypeDefinitionBuilder typedefBuilder) {
656         for (TypeDefinitionBuilder tdb : addedTypedefs) {
657             if (tdb.getQName().getLocalName().equals(typedefBuilder.getQName().getLocalName())) {
658                 throw new YangParseException(name, typedefBuilder.getLine(), "Duplicate node found at line "
659                         + tdb.getLine());
660             }
661         }
662         addedTypedefs.add(typedefBuilder);
663     }
664
665     public TypeDefinitionBuilderImpl addTypedef(final int line, final QName typeDefName) {
666         final TypeDefinitionBuilderImpl builder = new TypeDefinitionBuilderImpl(typeDefName, line);
667
668         Builder parent = getActualNode();
669         builder.setParent(parent);
670
671         if (parent == null) {
672             for (TypeDefinitionBuilder tdb : addedTypedefs) {
673                 if (tdb.getQName().getLocalName().equals(builder.getQName().getLocalName())) {
674                     throw new YangParseException(name, builder.getLine(), "Duplicate node found at line "
675                             + tdb.getLine());
676                 }
677             }
678             addedTypedefs.add(builder);
679         } else {
680             if (parent instanceof DataNodeContainerBuilder) {
681                 DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
682                 for (DataSchemaNodeBuilder child : parentNode.getChildNodeBuilders()) {
683                     if (child.getQName().getLocalName().equals(typeDefName.getLocalName())) {
684                         throw new YangParseException(name, line, "Duplicate node found at line " + child.getLine());
685                     }
686                 }
687                 parentNode.addTypedef(builder);
688             } else if (parent instanceof RpcDefinitionBuilder) {
689                 RpcDefinitionBuilder rpcParent = (RpcDefinitionBuilder) parent;
690                 for (TypeDefinitionBuilder tdb : rpcParent.getTypeDefinitions()) {
691                     if (tdb.getQName().getLocalName().equals(builder.getQName().getLocalName())) {
692                         throw new YangParseException(name, builder.getLine(), "Duplicate node found at line "
693                                 + tdb.getLine());
694                     }
695                 }
696                 rpcParent.addTypedef(builder);
697             } else {
698                 throw new YangParseException(name, line, "Unresolved parent of typedef " + typeDefName.getLocalName());
699             }
700         }
701
702         return builder;
703     }
704
705     public void setType(final TypeDefinition<?> type) {
706         Builder parent = getActualNode();
707         if (parent == null || !(parent instanceof TypeAwareBuilder)) {
708             throw new YangParseException("Failed to set type '" + type.getQName().getLocalName()
709                     + "'. Unknown parent node: " + parent);
710         }
711         ((TypeAwareBuilder) parent).setType(type);
712     }
713
714     public UnionTypeBuilder addUnionType(final List<String> currentPath, final URI namespace, final Date revision,
715             final int line) {
716         final List<String> pathToUnion = new ArrayList<String>(currentPath);
717         final UnionTypeBuilder union = new UnionTypeBuilder(line);
718
719         if (actualPath.isEmpty()) {
720             throw new YangParseException(line, "union error");
721         } else {
722             final Builder parent = actualPath.getFirst();
723             if (parent instanceof TypeAwareBuilder) {
724
725                 ((TypeAwareBuilder) parent).setTypedef(union);
726
727                 final List<String> path = new ArrayList<String>(pathToUnion);
728                 path.add("union");
729
730                 addedUnionTypes.put(path, union);
731                 return union;
732             } else {
733                 throw new YangParseException(name, line, "Unresolved parent of union type.");
734             }
735         }
736     }
737
738     public void addIdentityrefType(final String baseString, final List<String> parentPath, final SchemaPath schemaPath,
739             final int line) {
740         final List<String> pathToIdentityref = new ArrayList<String>(parentPath);
741         final IdentityrefTypeBuilder identityref = new IdentityrefTypeBuilder(baseString, schemaPath, line);
742
743         if (actualPath.isEmpty()) {
744             throw new YangParseException(line, "identityref error");
745         } else {
746             final Builder parent = actualPath.getFirst();
747             if (parent instanceof TypeAwareBuilder) {
748                 final TypeAwareBuilder typeParent = (TypeAwareBuilder) parent;
749                 typeParent.setTypedef(identityref);
750                 dirtyNodes.put(pathToIdentityref, typeParent);
751             } else {
752                 throw new YangParseException(name, line, "Unresolved parent of identityref type.");
753             }
754         }
755     }
756
757     public DeviationBuilder addDeviation(final String targetPath, final List<String> parentPath, final int line) {
758         Builder parent = getActualNode();
759         if (parent != null) {
760             throw new YangParseException(name, line, "deviation can be defined only in module or submodule");
761         }
762
763         final List<String> pathToDeviation = new ArrayList<String>(parentPath);
764         pathToDeviation.add(targetPath);
765         final DeviationBuilder builder = new DeviationBuilder(targetPath, line);
766         addedDeviations.put(pathToDeviation, builder);
767         return builder;
768     }
769
770     public IdentitySchemaNodeBuilder addIdentity(final QName qname, final List<String> parentPath, final int line) {
771         Builder parent = getActualNode();
772         if (parent != null) {
773             throw new YangParseException(name, line, "identity can be defined only in module or submodule");
774         }
775         for (IdentitySchemaNodeBuilder idBuilder : addedIdentities) {
776             if (idBuilder.getQName().equals(qname)) {
777                 throw new YangParseException(name, line, "Duplicate node found at line " + idBuilder.getLine());
778             }
779         }
780
781         final IdentitySchemaNodeBuilder builder = new IdentitySchemaNodeBuilder(line, qname);
782         addedIdentities.add(builder);
783         return builder;
784     }
785
786     @Override
787     public void addUnknownSchemaNode(UnknownSchemaNodeBuilder builder) {
788         final List<String> unPath = new ArrayList<String>();
789         for (QName name : builder.getPath().getPath()) {
790             unPath.add(name.getLocalName());
791         }
792         if (addedUnknownNodes.containsKey(unPath)) {
793             addedUnknownNodes.get(unPath).add(builder);
794         } else {
795             List<UnknownSchemaNodeBuilder> nodes = new ArrayList<UnknownSchemaNodeBuilder>();
796             nodes.add(builder);
797             addedUnknownNodes.put(unPath, nodes);
798         }
799     }
800
801     public UnknownSchemaNodeBuilder addUnknownSchemaNode(final QName qname, final List<String> parentPath,
802             final int line) {
803         final Builder parent = getActualNode();
804         final UnknownSchemaNodeBuilder builder = new UnknownSchemaNodeBuilder(line, qname);
805         builder.setParent(parent);
806
807         if (parent != null) {
808             if (parent instanceof SchemaNodeBuilder) {
809                 ((SchemaNodeBuilder) parent).addUnknownSchemaNode(builder);
810             } else if (parent instanceof RefineHolder) {
811                 ((RefineHolder) parent).addUnknownSchemaNode(builder);
812             } else {
813                 throw new YangParseException(name, line, "Unresolved parent of unknown node '" + qname.getLocalName()
814                         + "'");
815             }
816         }
817         final List<String> unPath = new ArrayList<String>(parentPath);
818         unPath.add(qname.getLocalName());
819
820         if (addedUnknownNodes.containsKey(unPath)) {
821             addedUnknownNodes.get(unPath).add(builder);
822         } else {
823             List<UnknownSchemaNodeBuilder> nodes = new ArrayList<UnknownSchemaNodeBuilder>();
824             nodes.add(builder);
825             addedUnknownNodes.put(unPath, nodes);
826         }
827         return builder;
828     }
829
830     @Override
831     public String toString() {
832         return ModuleBuilder.class.getSimpleName() + "[" + name + "]";
833     }
834
835     private final class ModuleImpl implements Module {
836         private URI namespace;
837         private final String name;
838         private Date revision;
839         private String prefix;
840         private String yangVersion;
841         private String description;
842         private String reference;
843         private String organization;
844         private String contact;
845         private Set<ModuleImport> imports = Collections.emptySet();
846         private Set<FeatureDefinition> features = Collections.emptySet();
847         private Set<TypeDefinition<?>> typeDefinitions = Collections.emptySet();
848         private Set<NotificationDefinition> notifications = Collections.emptySet();
849         private Set<AugmentationSchema> augmentations = Collections.emptySet();
850         private Set<RpcDefinition> rpcs = Collections.emptySet();
851         private Set<Deviation> deviations = Collections.emptySet();
852         private Map<QName, DataSchemaNode> childNodes = Collections.emptyMap();
853         private Set<GroupingDefinition> groupings = Collections.emptySet();
854         private Set<UsesNode> uses = Collections.emptySet();
855         private List<ExtensionDefinition> extensionNodes = Collections.emptyList();
856         private Set<IdentitySchemaNode> identities = Collections.emptySet();
857         private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
858
859         private ModuleImpl(String name) {
860             this.name = name;
861         }
862
863         @Override
864         public URI getNamespace() {
865             return namespace;
866         }
867
868         private void setNamespace(URI namespace) {
869             this.namespace = namespace;
870         }
871
872         @Override
873         public String getName() {
874             return name;
875         }
876
877         @Override
878         public Date getRevision() {
879             return revision;
880         }
881
882         private void setRevision(Date revision) {
883             this.revision = revision;
884         }
885
886         @Override
887         public String getPrefix() {
888             return prefix;
889         }
890
891         private void setPrefix(String prefix) {
892             this.prefix = prefix;
893         }
894
895         @Override
896         public String getYangVersion() {
897             return yangVersion;
898         }
899
900         private void setYangVersion(String yangVersion) {
901             this.yangVersion = yangVersion;
902         }
903
904         @Override
905         public String getDescription() {
906             return description;
907         }
908
909         private void setDescription(String description) {
910             this.description = description;
911         }
912
913         @Override
914         public String getReference() {
915             return reference;
916         }
917
918         private void setReference(String reference) {
919             this.reference = reference;
920         }
921
922         @Override
923         public String getOrganization() {
924             return organization;
925         }
926
927         private void setOrganization(String organization) {
928             this.organization = organization;
929         }
930
931         @Override
932         public String getContact() {
933             return contact;
934         }
935
936         private void setContact(String contact) {
937             this.contact = contact;
938         }
939
940         @Override
941         public Set<ModuleImport> getImports() {
942             return imports;
943         }
944
945         private void setImports(Set<ModuleImport> imports) {
946             if (imports != null) {
947                 this.imports = imports;
948             }
949         }
950
951         @Override
952         public Set<FeatureDefinition> getFeatures() {
953             return features;
954         }
955
956         private void setFeatures(Set<FeatureDefinition> features) {
957             if (features != null) {
958                 this.features = features;
959             }
960         }
961
962         @Override
963         public Set<TypeDefinition<?>> getTypeDefinitions() {
964             return typeDefinitions;
965         }
966
967         private void setTypeDefinitions(Set<TypeDefinition<?>> typeDefinitions) {
968             if (typeDefinitions != null) {
969                 this.typeDefinitions = typeDefinitions;
970             }
971         }
972
973         @Override
974         public Set<NotificationDefinition> getNotifications() {
975             return notifications;
976         }
977
978         private void setNotifications(Set<NotificationDefinition> notifications) {
979             if (notifications != null) {
980                 this.notifications = notifications;
981             }
982         }
983
984         @Override
985         public Set<AugmentationSchema> getAugmentations() {
986             return augmentations;
987         }
988
989         private void setAugmentations(Set<AugmentationSchema> augmentations) {
990             if (augmentations != null) {
991                 this.augmentations = augmentations;
992             }
993         }
994
995         @Override
996         public Set<RpcDefinition> getRpcs() {
997             return rpcs;
998         }
999
1000         private void setRpcs(Set<RpcDefinition> rpcs) {
1001             if (rpcs != null) {
1002                 this.rpcs = rpcs;
1003             }
1004         }
1005
1006         @Override
1007         public Set<Deviation> getDeviations() {
1008             return deviations;
1009         }
1010
1011         private void setDeviations(Set<Deviation> deviations) {
1012             if (deviations != null) {
1013                 this.deviations = deviations;
1014             }
1015         }
1016
1017         @Override
1018         public Set<DataSchemaNode> getChildNodes() {
1019             return new LinkedHashSet<DataSchemaNode>(childNodes.values());
1020         }
1021
1022         private void setChildNodes(Map<QName, DataSchemaNode> childNodes) {
1023             if (childNodes != null) {
1024                 this.childNodes = childNodes;
1025             }
1026         }
1027
1028         @Override
1029         public Set<GroupingDefinition> getGroupings() {
1030             return groupings;
1031         }
1032
1033         private void setGroupings(Set<GroupingDefinition> groupings) {
1034             if (groupings != null) {
1035                 this.groupings = groupings;
1036             }
1037         }
1038
1039         @Override
1040         public Set<UsesNode> getUses() {
1041             return uses;
1042         }
1043
1044         private void setUses(Set<UsesNode> uses) {
1045             if (uses != null) {
1046                 this.uses = uses;
1047             }
1048         }
1049
1050         @Override
1051         public List<ExtensionDefinition> getExtensionSchemaNodes() {
1052             return extensionNodes;
1053         }
1054
1055         private void setExtensionSchemaNodes(final List<ExtensionDefinition> extensionNodes) {
1056             if (extensionNodes != null) {
1057                 this.extensionNodes = extensionNodes;
1058             }
1059         }
1060
1061         @Override
1062         public Set<IdentitySchemaNode> getIdentities() {
1063             return identities;
1064         }
1065
1066         private void setIdentities(final Set<IdentitySchemaNode> identities) {
1067             if (identities != null) {
1068                 this.identities = identities;
1069             }
1070         }
1071
1072         @Override
1073         public List<UnknownSchemaNode> getUnknownSchemaNodes() {
1074             return unknownNodes;
1075         }
1076
1077         private void setUnknownSchemaNodes(final List<UnknownSchemaNode> unknownNodes) {
1078             if (unknownNodes != null) {
1079                 this.unknownNodes = unknownNodes;
1080             }
1081         }
1082
1083         @Override
1084         public DataSchemaNode getDataChildByName(QName name) {
1085             return childNodes.get(name);
1086         }
1087
1088         @Override
1089         public DataSchemaNode getDataChildByName(String name) {
1090             DataSchemaNode result = null;
1091             for (Map.Entry<QName, DataSchemaNode> entry : childNodes.entrySet()) {
1092                 if (entry.getKey().getLocalName().equals(name)) {
1093                     result = entry.getValue();
1094                     break;
1095                 }
1096             }
1097             return result;
1098         }
1099
1100         @Override
1101         public int hashCode() {
1102             final int prime = 31;
1103             int result = 1;
1104             result = prime * result + ((namespace == null) ? 0 : namespace.hashCode());
1105             result = prime * result + ((name == null) ? 0 : name.hashCode());
1106             result = prime * result + ((revision == null) ? 0 : revision.hashCode());
1107             result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
1108             result = prime * result + ((yangVersion == null) ? 0 : yangVersion.hashCode());
1109             return result;
1110         }
1111
1112         @Override
1113         public boolean equals(Object obj) {
1114             if (this == obj) {
1115                 return true;
1116             }
1117             if (obj == null) {
1118                 return false;
1119             }
1120             if (getClass() != obj.getClass()) {
1121                 return false;
1122             }
1123             ModuleImpl other = (ModuleImpl) obj;
1124             if (namespace == null) {
1125                 if (other.namespace != null) {
1126                     return false;
1127                 }
1128             } else if (!namespace.equals(other.namespace)) {
1129                 return false;
1130             }
1131             if (name == null) {
1132                 if (other.name != null) {
1133                     return false;
1134                 }
1135             } else if (!name.equals(other.name)) {
1136                 return false;
1137             }
1138             if (revision == null) {
1139                 if (other.revision != null) {
1140                     return false;
1141                 }
1142             } else if (!revision.equals(other.revision)) {
1143                 return false;
1144             }
1145             if (prefix == null) {
1146                 if (other.prefix != null) {
1147                     return false;
1148                 }
1149             } else if (!prefix.equals(other.prefix)) {
1150                 return false;
1151             }
1152             if (yangVersion == null) {
1153                 if (other.yangVersion != null) {
1154                     return false;
1155                 }
1156             } else if (!yangVersion.equals(other.yangVersion)) {
1157                 return false;
1158             }
1159             return true;
1160         }
1161
1162         @Override
1163         public String toString() {
1164             StringBuilder sb = new StringBuilder(ModuleImpl.class.getSimpleName());
1165             sb.append("[");
1166             sb.append("name=" + name);
1167             sb.append(", namespace=" + namespace);
1168             sb.append(", revision=" + revision);
1169             sb.append(", prefix=" + prefix);
1170             sb.append(", yangVersion=" + yangVersion);
1171             sb.append("]");
1172             return sb.toString();
1173         }
1174     }
1175
1176     private void addChildToParent(final Builder parent, final DataSchemaNodeBuilder child, final String childLocalName) {
1177         final int line = child.getLine();
1178         if (parent == null) {
1179             // if parent == null => node is defined under module
1180             // All leafs, leaf-lists, lists, containers, choices, rpcs,
1181             // notifications, and anyxmls defined within a parent node or at the
1182             // top level of the module or its submodules share the same
1183             // identifier namespace.
1184             for (DataSchemaNodeBuilder childNode : childNodes) {
1185                 if (childNode.getQName().getLocalName().equals(childLocalName)) {
1186                     throw new YangParseException(name, line, "Duplicate node found at line " + childNode.getLine());
1187                 }
1188             }
1189             for (RpcDefinitionBuilder rpc : addedRpcs) {
1190                 if (rpc.getQName().getLocalName().equals(childLocalName)) {
1191                     throw new YangParseException(name, line, "Duplicate node found at line " + rpc.getLine());
1192                 }
1193             }
1194             for (NotificationBuilder notification : addedNotifications) {
1195                 if (notification.getQName().getLocalName().equals(childLocalName)) {
1196                     throw new YangParseException(name, line, "Duplicate node found at line " + notification.getLine());
1197                 }
1198             }
1199             childNodes.add(child);
1200         } else {
1201             // no need for checking rpc and notification because they can be
1202             // defined only under module or submodule
1203             if (parent instanceof DataNodeContainerBuilder) {
1204                 DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
1205                 for (DataSchemaNodeBuilder childNode : parentNode.getChildNodeBuilders()) {
1206                     if (childNode.getQName().getLocalName().equals(childLocalName)) {
1207                         throw new YangParseException(name, line, "Duplicate node found at line " + childNode.getLine());
1208                     }
1209                 }
1210                 parentNode.addChildNode(child);
1211             } else if (parent instanceof ChoiceBuilder) {
1212                 ChoiceBuilder parentNode = (ChoiceBuilder) parent;
1213                 for (ChoiceCaseBuilder caseBuilder : parentNode.getCases()) {
1214                     if (caseBuilder.getQName().getLocalName().equals(childLocalName)) {
1215                         throw new YangParseException(name, line, "Duplicate node found at line "
1216                                 + caseBuilder.getLine());
1217                     }
1218                 }
1219                 parentNode.addChildNode(child);
1220             } else {
1221                 throw new YangParseException(name, line, "Unresolved parent of node '" + childLocalName + "'.");
1222             }
1223         }
1224     }
1225
1226     private ModuleImport createModuleImport(final String moduleName, final Date revision, final String prefix) {
1227         final ModuleImport moduleImport = new ModuleImport() {
1228             @Override
1229             public String getModuleName() {
1230                 return moduleName;
1231             }
1232
1233             @Override
1234             public Date getRevision() {
1235                 return revision;
1236             }
1237
1238             @Override
1239             public String getPrefix() {
1240                 return prefix;
1241             }
1242
1243             @Override
1244             public int hashCode() {
1245                 final int prime = 31;
1246                 int result = 1;
1247                 result = prime * result + ((moduleName == null) ? 0 : moduleName.hashCode());
1248                 result = prime * result + ((revision == null) ? 0 : revision.hashCode());
1249                 result = prime * result + ((prefix == null) ? 0 : prefix.hashCode());
1250                 return result;
1251             }
1252
1253             @Override
1254             public boolean equals(Object obj) {
1255                 if (this == obj) {
1256                     return true;
1257                 }
1258                 if (obj == null) {
1259                     return false;
1260                 }
1261                 if (getClass() != obj.getClass()) {
1262                     return false;
1263                 }
1264                 ModuleImport other = (ModuleImport) obj;
1265                 if (getModuleName() == null) {
1266                     if (other.getModuleName() != null) {
1267                         return false;
1268                     }
1269                 } else if (!getModuleName().equals(other.getModuleName())) {
1270                     return false;
1271                 }
1272                 if (getRevision() == null) {
1273                     if (other.getRevision() != null) {
1274                         return false;
1275                     }
1276                 } else if (!getRevision().equals(other.getRevision())) {
1277                     return false;
1278                 }
1279                 if (getPrefix() == null) {
1280                     if (other.getPrefix() != null) {
1281                         return false;
1282                     }
1283                 } else if (!getPrefix().equals(other.getPrefix())) {
1284                     return false;
1285                 }
1286                 return true;
1287             }
1288
1289             @Override
1290             public String toString() {
1291                 return "ModuleImport[moduleName=" + moduleName + ", revision=" + revision + ", prefix=" + prefix + "]";
1292             }
1293         };
1294         return moduleImport;
1295     }
1296
1297     /**
1298      * Traverse through given addedUnknownNodes and add only unknown nodes
1299      * defined under module statement.
1300      *
1301      * @param addedUnknownNodes
1302      *            unknown node builders
1303      * @return list of all unknown nodes defined in module in lexicographical
1304      *         order
1305      */
1306     private List<UnknownSchemaNode> buildModuleUnknownNodes(
1307             final Map<List<String>, List<UnknownSchemaNodeBuilder>> addedUnknownNodes) {
1308         final List<UnknownSchemaNode> result = new ArrayList<UnknownSchemaNode>();
1309         for (Map.Entry<List<String>, List<UnknownSchemaNodeBuilder>> entry : addedUnknownNodes.entrySet()) {
1310             final List<String> path = entry.getKey();
1311             final List<UnknownSchemaNodeBuilder> child = entry.getValue();
1312
1313             if (path.size() == 2) {
1314                 for (UnknownSchemaNodeBuilder node : child) {
1315                     result.add(node.build());
1316                 }
1317             }
1318         }
1319         Collections.sort(result, Comparators.SCHEMA_NODE_COMP);
1320         return result;
1321     }
1322
1323 }