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