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