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