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