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