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