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