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