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