14ee3961e0aeef01d402692c7616afb7cb45fc33
[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
9 package org.opendaylight.yangtools.yang.parser.builder.impl;
10
11 import com.google.common.base.Charsets;
12 import com.google.common.base.Preconditions;
13 import com.google.common.io.ByteSource;
14 import java.io.IOException;
15 import java.net.URI;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.Date;
19 import java.util.Deque;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.LinkedHashSet;
23 import java.util.LinkedList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Objects;
27 import java.util.Set;
28 import java.util.TreeSet;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.common.QNameModule;
31 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
32 import org.opendaylight.yangtools.yang.model.api.Deviation;
33 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
34 import org.opendaylight.yangtools.yang.model.api.FeatureDefinition;
35 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.Module;
37 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
38 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
39 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
40 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
41 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
42 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
43 import org.opendaylight.yangtools.yang.model.util.ModuleImportImpl;
44 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
45 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
46 import org.opendaylight.yangtools.yang.parser.builder.api.DataNodeContainerBuilder;
47 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
48 import org.opendaylight.yangtools.yang.parser.builder.api.DocumentedNodeBuilder;
49 import org.opendaylight.yangtools.yang.parser.builder.api.ExtensionBuilder;
50 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
51 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
52 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
53 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
54 import org.opendaylight.yangtools.yang.parser.builder.api.UnknownSchemaNodeBuilder;
55 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
56 import org.opendaylight.yangtools.yang.parser.builder.util.AbstractDocumentedDataNodeContainerBuilder;
57 import org.opendaylight.yangtools.yang.parser.builder.util.Comparators;
58 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
59
60 /**
61  * Builder of Module object. If this module is dependent on external
62  * module/modules, these dependencies must be resolved before module is built,
63  * otherwise result may not be valid.
64  */
65 public class ModuleBuilder extends AbstractDocumentedDataNodeContainerBuilder implements DocumentedNodeBuilder {
66     private static final QNameModule EMPTY_QNAME_MODULE = QNameModule.create(null, null).intern();
67     private static final String GROUPING_STR = "Grouping";
68     private static final String TYPEDEF_STR = "typedef";
69     private ModuleImpl instance;
70     private final String name;
71     private final String sourcePath;
72     private static final SchemaPath SCHEMA_PATH = SchemaPath.create(Collections.<QName> emptyList(), true);
73     private String prefix;
74     private QNameModule qnameModule = EMPTY_QNAME_MODULE;
75
76     private final boolean submodule;
77     private String belongsTo;
78     private ModuleBuilder parent;
79
80     private final Deque<Builder> actualPath = new LinkedList<>();
81     private final Set<TypeAwareBuilder> dirtyNodes = new HashSet<>();
82
83     final Map<String, ModuleImport> imports = new HashMap<>();
84     final Map<String, ModuleBuilder> importedModules = new HashMap<>();
85
86     final Set<ModuleBuilder> addedSubmodules = new HashSet<>();
87     final Set<Module> submodules = new HashSet<>();
88     final Map<String, Date> includedModules = new HashMap<>();
89
90     private final Set<AugmentationSchema> augments = new LinkedHashSet<>();
91     private final List<AugmentationSchemaBuilder> augmentBuilders = new ArrayList<>();
92     private final List<AugmentationSchemaBuilder> allAugments = new ArrayList<>();
93
94     private final List<GroupingBuilder> allGroupings = new ArrayList<>();
95
96     private final List<UsesNodeBuilder> allUsesNodes = new ArrayList<>();
97
98     private final Set<RpcDefinition> rpcs = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
99     private final Set<RpcDefinitionBuilder> addedRpcs = new HashSet<>();
100
101     private final Set<NotificationDefinition> notifications = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
102     private final Set<NotificationBuilder> addedNotifications = new HashSet<>();
103
104     private final Set<IdentitySchemaNode> identities = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
105     private final Set<IdentitySchemaNodeBuilder> addedIdentities = new HashSet<>();
106
107     private final Set<FeatureDefinition> features = new TreeSet<>(Comparators.SCHEMA_NODE_COMP);
108     private final Set<FeatureBuilder> addedFeatures = new HashSet<>();
109
110     private final Set<Deviation> deviations = new HashSet<>();
111     private final Set<DeviationBuilder> deviationBuilders = new HashSet<>();
112
113     private final List<ExtensionDefinition> extensions = new ArrayList<>();
114     private final List<ExtensionBuilder> addedExtensions = new ArrayList<>();
115
116     private final List<UnknownSchemaNodeBuilder> allUnknownNodes = new ArrayList<>();
117
118     private final List<ListSchemaNodeBuilder> allLists = new ArrayList<>();
119
120     private String source;
121     private String yangVersion;
122     private String organization;
123     private String contact;
124
125     public ModuleBuilder(final String name, final String sourcePath) {
126         this(name, false, sourcePath);
127     }
128
129     public ModuleBuilder(final String name, final boolean submodule, final String sourcePath) {
130         super(name, 0, null);
131         this.name = name;
132         this.sourcePath = sourcePath;
133         this.submodule = submodule;
134         actualPath.push(this);//FIXME: this escapes constructor
135     }
136
137     public ModuleBuilder(final Module base) {
138         super(base.getName(), 0, QName.create(base.getQNameModule(), base.getName()),
139                 SCHEMA_PATH, base);
140         this.name = base.getName();
141         this.sourcePath = base.getModuleSourcePath();
142
143         submodule = false;
144         yangVersion = base.getYangVersion();
145         actualPath.push(this);//FIXME: this escapes constructor
146         prefix = base.getPrefix();
147         qnameModule = base.getQNameModule();
148
149         augments.addAll(base.getAugmentations());
150         rpcs.addAll(base.getRpcs());
151         notifications.addAll(base.getNotifications());
152
153         for (IdentitySchemaNode identityNode : base.getIdentities()) {
154             addedIdentities.add(new IdentitySchemaNodeBuilder(name, identityNode));
155         }
156
157         features.addAll(base.getFeatures());
158         deviations.addAll(base.getDeviations());
159         extensions.addAll(base.getExtensionSchemaNodes());
160         unknownNodes.addAll(base.getUnknownSchemaNodes());
161         source = base.getSource();
162     }
163
164     @Override
165     protected String getStatementName() {
166         return "module";
167     }
168
169     /**
170      * Build new Module object based on this builder.
171      */
172     @Override
173     public Module build() {
174         if(instance != null) {
175             return instance;
176         }
177
178         buildChildren();
179
180         // SUBMODULES
181         for (ModuleBuilder submodule : addedSubmodules) {
182             submodules.add(submodule.build());
183         }
184
185         // FEATURES
186         for (FeatureBuilder fb : addedFeatures) {
187             features.add(fb.build());
188         }
189
190         // NOTIFICATIONS
191         for (NotificationBuilder entry : addedNotifications) {
192             notifications.add(entry.build());
193         }
194
195         // AUGMENTATIONS
196         for (AugmentationSchemaBuilder builder : augmentBuilders) {
197             augments.add(builder.build());
198         }
199
200         // RPCs
201         for (RpcDefinitionBuilder rpc : addedRpcs) {
202             rpcs.add(rpc.build());
203         }
204
205         // DEVIATIONS
206         for (DeviationBuilder entry : deviationBuilders) {
207             deviations.add(entry.build());
208         }
209
210         // EXTENSIONS
211         for (ExtensionBuilder eb : addedExtensions) {
212             extensions.add(eb.build());
213         }
214         Collections.sort(extensions, Comparators.SCHEMA_NODE_COMP);
215
216
217         // IDENTITIES
218         for (IdentitySchemaNodeBuilder id : addedIdentities) {
219             identities.add(id.build());
220         }
221
222         // UNKNOWN NODES
223         for (UnknownSchemaNodeBuilder unb : addedUnknownNodes) {
224             unknownNodes.add(unb.build());
225         }
226         Collections.sort(unknownNodes, Comparators.SCHEMA_NODE_COMP);
227
228         instance = new ModuleImpl(name, sourcePath, this);
229         return instance;
230     }
231
232     public String getModuleSourcePath() {
233         return sourcePath;
234     }
235
236     @Override
237     public ModuleBuilder getParent() {
238         return parent;
239     }
240
241     public void setParent(final ModuleBuilder parent) {
242         this.parent = parent;
243     }
244
245     @Override
246     public void setParent(final Builder parent) {
247         throw new YangParseException(name, 0, "Can not set parent to module");
248     }
249
250     @Override
251     public SchemaPath getPath() {
252         return SCHEMA_PATH;
253     }
254
255     public void enterNode(final Builder node) {
256         actualPath.push(node);
257     }
258
259     public void exitNode() {
260         actualPath.pop();
261     }
262
263     public Builder getActualNode() {
264         if (actualPath.isEmpty()) {
265             return null;
266         } else {
267             return actualPath.peekFirst();
268         }
269     }
270
271     public Set<TypeAwareBuilder> getDirtyNodes() {
272         return dirtyNodes;
273     }
274
275     public Set<AugmentationSchema> getAugments() {
276         return augments;
277     }
278
279     public List<AugmentationSchemaBuilder> getAugmentBuilders() {
280         return augmentBuilders;
281     }
282
283     public List<AugmentationSchemaBuilder> getAllAugments() {
284         return allAugments;
285     }
286
287     public Set<IdentitySchemaNode> getIdentities() {
288         return identities;
289     }
290
291     public Set<IdentitySchemaNodeBuilder> getAddedIdentities() {
292         return addedIdentities;
293     }
294
295     public Set<FeatureDefinition> getFeatures() {
296         return features;
297     }
298
299     public Set<FeatureBuilder> getAddedFeatures() {
300         return addedFeatures;
301     }
302
303     public List<GroupingBuilder> getAllGroupings() {
304         return allGroupings;
305     }
306
307     public List<UsesNodeBuilder> getAllUsesNodes() {
308         return allUsesNodes;
309     }
310
311     public Set<Deviation> getDeviations() {
312         return deviations;
313     }
314
315     public Set<DeviationBuilder> getDeviationBuilders() {
316         return deviationBuilders;
317     }
318
319     public List<ExtensionDefinition> getExtensions() {
320         return extensions;
321     }
322
323     public List<ExtensionBuilder> getAddedExtensions() {
324         return addedExtensions;
325     }
326
327     public List<UnknownSchemaNodeBuilder> getAllUnknownNodes() {
328         return allUnknownNodes;
329     }
330
331     public List<ListSchemaNodeBuilder> getAllLists() {
332         return allLists;
333     }
334
335     public String getName() {
336         return name;
337     }
338
339     public URI getNamespace() {
340         return qnameModule.getNamespace();
341     }
342
343     public QNameModule getQNameModule() {
344         return qnameModule;
345     }
346
347     public void setQNameModule(final QNameModule qnameModule) {
348         this.qnameModule = Preconditions.checkNotNull(qnameModule);
349     }
350
351     public void setNamespace(final URI namespace) {
352         this.qnameModule = QNameModule.create(namespace, qnameModule.getRevision()).intern();
353     }
354
355     public String getPrefix() {
356         return prefix;
357     }
358
359     public Date getRevision() {
360         return qnameModule.getRevision();
361     }
362
363     public ModuleImport getImport(final String prefix) {
364         return imports.get(prefix);
365     }
366
367     public Map<String, ModuleImport> getImports() {
368         return imports;
369     }
370
371     public ModuleBuilder getImportedModule(final String prefix) {
372         return importedModules.get(prefix);
373     }
374
375     public void addImportedModule(final String prefix, final ModuleBuilder module) {
376         checkPrefix(prefix);
377         importedModules.put(prefix, module);
378     }
379
380     public Map<String, Date> getIncludedModules() {
381         return includedModules;
382     }
383
384     public void addInclude(final String name, final Date revision) {
385         includedModules.put(name, revision);
386     }
387
388     public void addSubmodule(final ModuleBuilder submodule) {
389         addedSubmodules.add(submodule);
390     }
391
392     protected String getSource() {
393         return source;
394     }
395
396     public boolean isSubmodule() {
397         return submodule;
398     }
399
400     public String getBelongsTo() {
401         return belongsTo;
402     }
403
404     public void setBelongsTo(final String belongsTo) {
405         this.belongsTo = belongsTo;
406     }
407
408     public void markActualNodeDirty() {
409         final TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) getActualNode();
410         dirtyNodes.add(nodeBuilder);
411     }
412
413     public void setRevision(final Date revision) {
414         this.qnameModule = QNameModule.create(qnameModule.getNamespace(), revision).intern();
415     }
416
417     public void setPrefix(final String prefix) {
418         this.prefix = prefix;
419     }
420
421     public void setYangVersion(final String yangVersion) {
422         this.yangVersion = yangVersion;
423     }
424
425     public void setOrganization(final String organization) {
426         this.organization = organization;
427     }
428
429     public void setContact(final String contact) {
430         this.contact = contact;
431     }
432
433     public void addModuleImport(final String moduleName, final Date revision, final String prefix) {
434         checkPrefix(prefix);
435         checkNotSealed();
436         final ModuleImport moduleImport = new ModuleImportImpl(moduleName, revision, prefix);
437         imports.put(prefix, moduleImport);
438     }
439
440     private void checkPrefix(final String prefix) {
441         if (prefix == null || prefix.isEmpty()) {
442             throw new IllegalArgumentException("Cannot add imported module with undefined prefix");
443         }
444         if (prefix.equals(this.prefix)) {
445             throw new IllegalArgumentException("Cannot add imported module with prefix equals to module prefix");
446         }
447     }
448
449     public ExtensionBuilder addExtension(final QName qname, final int line, final SchemaPath path) {
450         checkNotSealed();
451         Builder parentBuilder = getActualNode();
452         if (!(parentBuilder.equals(this))) {
453             throw new YangParseException(name, line, "extension can be defined only in module or submodule");
454         }
455
456         final String extName = qname.getLocalName();
457         for (ExtensionBuilder addedExtension : addedExtensions) {
458             if (addedExtension.getQName().getLocalName().equals(extName)) {
459                 raiseYangParserException("extension", "node", extName, line, addedExtension.getLine());
460             }
461         }
462         final ExtensionBuilder builder = new ExtensionBuilderImpl(name, line, qname, path);
463         builder.setParent(parentBuilder);
464         addedExtensions.add(builder);
465         return builder;
466     }
467
468     public ContainerSchemaNodeBuilder addContainerNode(final int line, final QName qname, final SchemaPath schemaPath) {
469         checkNotSealed();
470         final ContainerSchemaNodeBuilder builder = new ContainerSchemaNodeBuilder(name, line, qname, schemaPath);
471
472         Builder parentBuilder = getActualNode();
473         builder.setParent(parentBuilder);
474         addChildToParent(parentBuilder, builder, qname.getLocalName());
475
476         return builder;
477     }
478
479     public ListSchemaNodeBuilder addListNode(final int line, final QName qname, final SchemaPath schemaPath) {
480         checkNotSealed();
481         final ListSchemaNodeBuilder builder = new ListSchemaNodeBuilder(name, line, qname, schemaPath);
482
483         Builder parentBuilder = getActualNode();
484         builder.setParent(parentBuilder);
485         addChildToParent(parentBuilder, builder, qname.getLocalName());
486         allLists.add(builder);
487
488         return builder;
489     }
490
491     public LeafSchemaNodeBuilder addLeafNode(final int line, final QName qname, final SchemaPath schemaPath) {
492         checkNotSealed();
493         final LeafSchemaNodeBuilder builder = new LeafSchemaNodeBuilder(name, line, qname, schemaPath);
494
495         Builder parentBuilder = getActualNode();
496         builder.setParent(parentBuilder);
497         addChildToParent(parentBuilder, builder, qname.getLocalName());
498
499         return builder;
500     }
501
502     public LeafListSchemaNodeBuilder addLeafListNode(final int line, final QName qname, final SchemaPath schemaPath) {
503         checkNotSealed();
504         final LeafListSchemaNodeBuilder builder = new LeafListSchemaNodeBuilder(name, line, qname, schemaPath);
505
506         Builder parentBuilder = getActualNode();
507         builder.setParent(parentBuilder);
508         addChildToParent(parentBuilder, builder, qname.getLocalName());
509
510         return builder;
511     }
512
513     public GroupingBuilder addGrouping(final int line, final QName qname, final SchemaPath path) {
514         checkNotSealed();
515         final GroupingBuilder builder = new GroupingBuilderImpl(name, line, qname, path);
516
517         Builder parentBuilder = getActualNode();
518         builder.setParent(parentBuilder);
519
520         String groupingName = qname.getLocalName();
521         if (parentBuilder.equals(this)) {
522             for (GroupingBuilder addedGrouping : getGroupingBuilders()) {
523                 if (addedGrouping.getQName().getLocalName().equals(groupingName)) {
524                     raiseYangParserException("", GROUPING_STR, groupingName, line, addedGrouping.getLine());
525                 }
526             }
527             addGrouping(builder);
528         } else {
529             if (parentBuilder instanceof DataNodeContainerBuilder) {
530                 DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parentBuilder;
531                 for (GroupingBuilder addedGrouping : parentNode.getGroupingBuilders()) {
532                     if (addedGrouping.getQName().getLocalName().equals(groupingName)) {
533                         raiseYangParserException("", GROUPING_STR, groupingName, line, addedGrouping.getLine());
534                     }
535                 }
536                 parentNode.addGrouping(builder);
537             } else if (parentBuilder instanceof RpcDefinitionBuilder) {
538                 RpcDefinitionBuilder parentNode = (RpcDefinitionBuilder) parentBuilder;
539                 for (GroupingBuilder child : parentNode.getGroupings()) {
540                     if (child.getQName().getLocalName().equals(groupingName)) {
541                         raiseYangParserException("", GROUPING_STR, groupingName, line, child.getLine());
542                     }
543                 }
544                 parentNode.addGrouping(builder);
545             } else {
546                 throw new YangParseException(name, line, "Unresolved parent of grouping " + groupingName);
547             }
548         }
549
550         allGroupings.add(builder);
551         return builder;
552     }
553
554     public AugmentationSchemaBuilder addAugment(final int line, final String augmentTargetStr,
555             final SchemaPath targetPath, final int order) {
556         checkNotSealed();
557         final AugmentationSchemaBuilder builder = new AugmentationSchemaBuilderImpl(name, line, augmentTargetStr,
558                 targetPath, order);
559
560         Builder parentBuilder = getActualNode();
561         builder.setParent(parentBuilder);
562
563         if (parentBuilder.equals(this)) {
564             // augment can be declared only under 'module' ...
565             if (!(augmentTargetStr.startsWith("/"))) {
566                 throw new YangParseException(
567                         name,
568                         line,
569                         "If the 'augment' statement is on the top level in a module, the absolute form of a schema node identifier MUST be used.");
570             }
571             augmentBuilders.add(builder);
572         } else {
573             // ... or 'uses' statement
574             if (parentBuilder instanceof UsesNodeBuilder) {
575                 if (augmentTargetStr.startsWith("/")) {
576                     throw new YangParseException(name, line,
577                             "If 'augment' statement is a substatement to the 'uses' statement, it cannot contain absolute path ("
578                                     + augmentTargetStr + ")");
579                 }
580                 ((UsesNodeBuilder) parentBuilder).addAugment(builder);
581             } else {
582                 throw new YangParseException(name, line, "Augment can be declared only under module or uses statement.");
583             }
584         }
585         allAugments.add(builder);
586
587         return builder;
588     }
589
590     public UsesNodeBuilder addUsesNode(final int line, final SchemaPath grouping) {
591         checkNotSealed();
592         final UsesNodeBuilder usesBuilder = new UsesNodeBuilderImpl(name, line, grouping);
593
594         Builder parentBuilder = getActualNode();
595         usesBuilder.setParent(parentBuilder);
596
597         if (parentBuilder.equals(this)) {
598             addUsesNode(usesBuilder);
599         } else {
600             if (!(parentBuilder instanceof DataNodeContainerBuilder)) {
601                 throw new YangParseException(name, line, "Unresolved parent of uses '" + grouping + "'.");
602             }
603             ((DataNodeContainerBuilder) parentBuilder).addUsesNode(usesBuilder);
604         }
605         if (parentBuilder instanceof AugmentationSchemaBuilder) {
606             usesBuilder.setAugmenting(true);
607         }
608
609         allUsesNodes.add(usesBuilder);
610         return usesBuilder;
611     }
612
613     public void addRefine(final RefineHolderImpl refine) {
614         checkNotSealed();
615         final Builder parentBuilder = getActualNode();
616         if (!(parentBuilder instanceof UsesNodeBuilder)) {
617             throw new YangParseException(name, refine.getLine(), "refine can be defined only in uses statement");
618         }
619         ((UsesNodeBuilder) parentBuilder).addRefine(refine);
620         refine.setParent(parentBuilder);
621     }
622
623     public RpcDefinitionBuilder addRpc(final int line, final QName qname, final SchemaPath path) {
624         checkNotSealed();
625         Builder parentBuilder = getActualNode();
626         if (!(parentBuilder.equals(this))) {
627             throw new YangParseException(name, line, "rpc can be defined only in module or submodule");
628         }
629
630         final RpcDefinitionBuilder rpcBuilder = new RpcDefinitionBuilder(name, line, qname, path);
631         rpcBuilder.setParent(parentBuilder);
632
633         String rpcName = qname.getLocalName();
634         checkNotConflictingInDataNamespace(rpcName, line);
635         addedRpcs.add(rpcBuilder);
636         return rpcBuilder;
637     }
638
639     private void checkNotConflictingInDataNamespace(final String rpcName, final int line) {
640         for (DataSchemaNodeBuilder addedChild : getChildNodeBuilders()) {
641             if (addedChild.getQName().getLocalName().equals(rpcName)) {
642                 raiseYangParserException("rpc", "node", rpcName, line, addedChild.getLine());
643             }
644         }
645         for (RpcDefinitionBuilder rpc : addedRpcs) {
646             if (rpc.getQName().getLocalName().equals(rpcName)) {
647                 raiseYangParserException("", "rpc", rpcName, line, rpc.getLine());
648             }
649         }
650         for (NotificationBuilder addedNotification : addedNotifications) {
651             if (addedNotification.getQName().getLocalName().equals(rpcName)) {
652                 raiseYangParserException("rpc", "notification", rpcName, line, addedNotification.getLine());
653             }
654         }
655     }
656
657     public ContainerSchemaNodeBuilder addRpcInput(final int line, final QName qname, final SchemaPath schemaPath) {
658         checkNotSealed();
659         final Builder parentBuilder = getActualNode();
660         if (!(parentBuilder instanceof RpcDefinitionBuilder)) {
661             throw new YangParseException(name, line, "input can be defined only in rpc statement");
662         }
663         final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parentBuilder;
664
665         final ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(name, line, qname, schemaPath);
666         inputBuilder.setParent(rpc);
667
668         rpc.setInput(inputBuilder);
669         return inputBuilder;
670     }
671
672     public ContainerSchemaNodeBuilder addRpcOutput(final SchemaPath schemaPath, final QName qname, final int line) {
673         checkNotSealed();
674         final Builder parentBuilder = getActualNode();
675         if (!(parentBuilder instanceof RpcDefinitionBuilder)) {
676             throw new YangParseException(name, line, "output can be defined only in rpc statement");
677         }
678         final RpcDefinitionBuilder rpc = (RpcDefinitionBuilder) parentBuilder;
679
680         final ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(name, line, qname, schemaPath);
681         outputBuilder.setParent(rpc);
682
683         rpc.setOutput(outputBuilder);
684         return outputBuilder;
685     }
686
687     public void addNotification(final NotificationDefinition notification) {
688         checkNotSealed();
689         notifications.add(notification);
690     }
691
692     public NotificationBuilder addNotification(final int line, final QName qname, final SchemaPath path) {
693         checkNotSealed();
694         final Builder parentBuilder = getActualNode();
695         if (!(parentBuilder.equals(this))) {
696             throw new YangParseException(name, line, "notification can be defined only in module or submodule");
697         }
698
699         String notificationName = qname.getLocalName();
700         checkNotConflictingInDataNamespace(notificationName, line);
701
702         final NotificationBuilder builder = new NotificationBuilder(name, line, qname, path);
703         builder.setParent(parentBuilder);
704         addedNotifications.add(builder);
705
706         return builder;
707     }
708
709     public FeatureBuilder addFeature(final int line, final QName qname, final SchemaPath path) {
710         Builder parentBuilder = getActualNode();
711         if (!(parentBuilder.equals(this))) {
712             throw new YangParseException(name, line, "feature can be defined only in module or submodule");
713         }
714
715         final FeatureBuilder builder = new FeatureBuilder(name, line, qname, path);
716         builder.setParent(parentBuilder);
717
718         String featureName = qname.getLocalName();
719         for (FeatureBuilder addedFeature : addedFeatures) {
720             if (addedFeature.getQName().getLocalName().equals(featureName)) {
721                 raiseYangParserException("", "feature", featureName, line, addedFeature.getLine());
722             }
723         }
724         addedFeatures.add(builder);
725         return builder;
726     }
727
728     public ChoiceBuilder addChoice(final int line, final QName qname, final SchemaPath path) {
729         final ChoiceBuilder builder = new ChoiceBuilder(name, line, qname, path);
730
731         Builder parentBuilder = getActualNode();
732         builder.setParent(parentBuilder);
733         addChildToParent(parentBuilder, builder, qname.getLocalName());
734
735         return builder;
736     }
737
738     public ChoiceCaseBuilder addCase(final int line, final QName qname, final SchemaPath path) {
739         Builder parentBuilder = getActualNode();
740         if (parentBuilder == null || parentBuilder.equals(this)) {
741             throw new YangParseException(name, line, "'case' parent not found");
742         }
743
744         final ChoiceCaseBuilder builder = new ChoiceCaseBuilder(name, line, qname, path);
745         builder.setParent(parentBuilder);
746
747         if (parentBuilder instanceof ChoiceBuilder) {
748             ((ChoiceBuilder) parentBuilder).addCase(builder);
749         } else if (parentBuilder instanceof AugmentationSchemaBuilder) {
750             ((AugmentationSchemaBuilder) parentBuilder).addChildNode(builder);
751         } else {
752             throw new YangParseException(name, line, "Unresolved parent of 'case' " + qname.getLocalName());
753         }
754
755         return builder;
756     }
757
758     public AnyXmlBuilder addAnyXml(final int line, final QName qname, final SchemaPath schemaPath) {
759         final AnyXmlBuilder builder = new AnyXmlBuilder(name, line, qname, schemaPath);
760
761         Builder parentBuilder = getActualNode();
762         builder.setParent(parentBuilder);
763         addChildToParent(parentBuilder, builder, qname.getLocalName());
764
765         return builder;
766     }
767
768     @Override
769     public void addTypedef(final TypeDefinitionBuilder typedefBuilder) {
770         String nodeName = typedefBuilder.getQName().getLocalName();
771         for (TypeDefinitionBuilder tdb : getTypeDefinitionBuilders()) {
772             if (tdb.getQName().getLocalName().equals(nodeName)) {
773                 raiseYangParserException("", TYPEDEF_STR, nodeName, typedefBuilder.getLine(), tdb.getLine());
774             }
775         }
776         super.addTypedef(typedefBuilder);
777     }
778
779     public TypeDefinitionBuilderImpl addTypedef(final int line, final QName qname, final SchemaPath path) {
780         final TypeDefinitionBuilderImpl builder = new TypeDefinitionBuilderImpl(name, line, qname, path);
781
782         Builder parentBuilder = getActualNode();
783         builder.setParent(parentBuilder);
784
785         String typedefName = qname.getLocalName();
786         if (parentBuilder.equals(this)) {
787             addTypedef(builder);
788         } else {
789             if (parentBuilder instanceof DataNodeContainerBuilder) {
790                 DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parentBuilder;
791                 for (TypeDefinitionBuilder child : parentNode.getTypeDefinitionBuilders()) {
792                     if (child.getQName().getLocalName().equals(typedefName)) {
793                         raiseYangParserException("", TYPEDEF_STR, typedefName, line, child.getLine());
794                     }
795                 }
796                 parentNode.addTypedef(builder);
797             } else if (parentBuilder instanceof RpcDefinitionBuilder) {
798                 RpcDefinitionBuilder rpcParent = (RpcDefinitionBuilder) parentBuilder;
799                 for (TypeDefinitionBuilder tdb : rpcParent.getTypeDefinitions()) {
800                     if (tdb.getQName().getLocalName().equals(builder.getQName().getLocalName())) {
801                         raiseYangParserException("", TYPEDEF_STR, typedefName, line, tdb.getLine());
802                     }
803                 }
804                 rpcParent.addTypedef(builder);
805             } else {
806                 throw new YangParseException(name, line, "Unresolved parent of typedef " + typedefName);
807             }
808         }
809
810         return builder;
811     }
812
813     public void setType(final TypeDefinition<?> type) {
814         Builder parentBuilder = getActualNode();
815         if (!(parentBuilder instanceof TypeAwareBuilder)) {
816             throw new YangParseException("Failed to set type '" + type.getQName().getLocalName()
817                     + "'. Invalid parent node: " + parentBuilder);
818         }
819         ((TypeAwareBuilder) parentBuilder).setType(type);
820     }
821
822     public UnionTypeBuilder addUnionType(final int line, final QNameModule module) {
823         final Builder parentBuilder = getActualNode();
824         if (parentBuilder == null) {
825             throw new YangParseException(name, line, "Unresolved parent of union type");
826         } else {
827             final UnionTypeBuilder union = new UnionTypeBuilder(name, line);
828             if (parentBuilder instanceof TypeAwareBuilder) {
829                 ((TypeAwareBuilder) parentBuilder).setTypedef(union);
830                 return union;
831             } else {
832                 throw new YangParseException(name, line, "Invalid parent of union type.");
833             }
834         }
835     }
836
837     public void addIdentityrefType(final int line, final SchemaPath schemaPath, final String baseString) {
838         final IdentityrefTypeBuilder identityref = new IdentityrefTypeBuilder(name, line, baseString, schemaPath);
839
840         final Builder parentBuilder = getActualNode();
841         if (parentBuilder == null) {
842             throw new YangParseException(name, line, "Unresolved parent of identityref type.");
843         } else {
844             if (parentBuilder instanceof TypeAwareBuilder) {
845                 final TypeAwareBuilder typeParent = (TypeAwareBuilder) parentBuilder;
846                 typeParent.setTypedef(identityref);
847                 dirtyNodes.add(typeParent);
848             } else {
849                 throw new YangParseException(name, line, "Invalid parent of identityref type.");
850             }
851         }
852     }
853
854     public DeviationBuilder addDeviation(final int line, final SchemaPath targetPath) {
855         Builder parentBuilder = getActualNode();
856         if (!(parentBuilder.equals(this))) {
857             throw new YangParseException(name, line, "deviation can be defined only in module or submodule");
858         }
859
860         final DeviationBuilder builder = new DeviationBuilder(name, line, targetPath);
861         builder.setParent(parentBuilder);
862         deviationBuilders.add(builder);
863         return builder;
864     }
865
866     public IdentitySchemaNodeBuilder addIdentity(final QName qname, final int line, final SchemaPath path) {
867         Builder parentBuilder = getActualNode();
868         if (!(parentBuilder.equals(this))) {
869             throw new YangParseException(name, line, "identity can be defined only in module or submodule");
870         }
871         String identityName = qname.getLocalName();
872         for (IdentitySchemaNodeBuilder idBuilder : addedIdentities) {
873             if (idBuilder.getQName().equals(qname)) {
874                 raiseYangParserException("", "identity", identityName, line, idBuilder.getLine());
875             }
876         }
877
878         final IdentitySchemaNodeBuilder builder = new IdentitySchemaNodeBuilder(name, line, qname, path);
879         builder.setParent(parentBuilder);
880         addedIdentities.add(builder);
881         return builder;
882     }
883
884     @Override
885     public void addUnknownNodeBuilder(final UnknownSchemaNodeBuilder builder) {
886         addedUnknownNodes.add(builder);
887         allUnknownNodes.add(builder);
888     }
889
890     public UnknownSchemaNodeBuilderImpl addUnknownSchemaNode(final int line, final QName qname, final SchemaPath path) {
891         final Builder parentBuilder = getActualNode();
892         final UnknownSchemaNodeBuilderImpl builder = new UnknownSchemaNodeBuilderImpl(name, line, qname, path);
893         builder.setParent(parentBuilder);
894         allUnknownNodes.add(builder);
895
896         if (parentBuilder.equals(this)) {
897             addedUnknownNodes.add(builder);
898         } else {
899             if (parentBuilder instanceof SchemaNodeBuilder) {
900                 parentBuilder.addUnknownNodeBuilder(builder);
901             } else if (parentBuilder instanceof DataNodeContainerBuilder) {
902                 parentBuilder.addUnknownNodeBuilder(builder);
903             } else if (parentBuilder instanceof RefineHolderImpl) {
904                 parentBuilder.addUnknownNodeBuilder(builder);
905             } else {
906                 throw new YangParseException(name, line, "Unresolved parent of unknown node '" + qname.getLocalName()
907                         + "'");
908             }
909         }
910
911         return builder;
912     }
913
914     public Set<RpcDefinition> getRpcs() {
915         return rpcs;
916     }
917
918     public Set<RpcDefinitionBuilder> getAddedRpcs() {
919         return addedRpcs;
920     }
921
922     public Set<NotificationDefinition> getNotifications() {
923         return notifications;
924     }
925
926     public Set<NotificationBuilder> getAddedNotifications() {
927         return addedNotifications;
928     }
929
930     @Override
931     public String toString() {
932         return "module " + name;
933     }
934
935     public void setSource(final ByteSource byteSource) throws IOException {
936         setSource(byteSource.asCharSource(Charsets.UTF_8).read());
937     }
938
939     public void setSource(final String source) {
940         this.source = source;
941     }
942
943     /**
944      * Add child to parent. Method checks for duplicates and add given child
945      * node to parent. If node with same name is found, throws exception. If
946      * parent is null, child node will be added directly to module.
947      *
948      * @param parent
949      * @param child
950      * @param childName
951      */
952     private void addChildToParent(final Builder parent, final DataSchemaNodeBuilder child, final String childName) {
953         final int lineNum = child.getLine();
954         if (parent.equals(this)) {
955             addChildToModule(child, childName, lineNum);
956         } else {
957             addChildToSubnodeOfModule(parent, child, childName, lineNum);
958         }
959     }
960
961     public String getYangVersion() {
962         return yangVersion;
963     }
964
965     public String getContact() {
966         return contact;
967     }
968
969     public String getOrganization() {
970         return organization;
971     }
972
973     /**
974      * Adds child node <code>child</code> to the set of nodes child nodes.
975      *
976      * The method reduces the complexity of the method
977      * {@link #addChildToParent(Builder, DataSchemaNodeBuilder, String)
978      * addChildToParent}.
979      *
980      * @param child
981      *            data schema node builder for child node
982      * @param childName
983      *            string with name of child node
984      * @param lineNum
985      *            line number in YANG file where is the node with the name equal
986      *            to <code>childName</code> is defined
987      */
988     private void addChildToModule(final DataSchemaNodeBuilder child, final String childName, final int lineNum) {
989         // if parent == null => node is defined under module
990         // All leafs, leaf-lists, lists, containers, choices, rpcs,
991         // notifications, and anyxmls defined within a parent node or at the
992         // top level of the module or its submodules share the same
993         // identifier namespace.
994         for (DataSchemaNodeBuilder childNode : getChildNodeBuilders()) {
995             if (childNode.getQName().getLocalName().equals(childName)) {
996                 raiseYangParserException("'" + child + "'", "node", childName, lineNum, childNode.getLine());
997             }
998         }
999         for (RpcDefinitionBuilder rpc : addedRpcs) {
1000             if (rpc.getQName().getLocalName().equals(childName)) {
1001                 raiseYangParserException("'" + child + "'", "rpc", childName, lineNum, rpc.getLine());
1002             }
1003         }
1004         for (NotificationBuilder notification : addedNotifications) {
1005             if (notification.getQName().getLocalName().equals(childName)) {
1006                 raiseYangParserException("'" + child + "'", "notification", childName, lineNum, notification.getLine());
1007             }
1008         }
1009         addChildNode(child);
1010     }
1011
1012     /**
1013      * Adds child node <code>child</code> to the group of child nodes of the
1014      * <code>parent</code>
1015      *
1016      * The method reduces the complexity of the method
1017      * {@link #addChildToParent(Builder, DataSchemaNodeBuilder, String)
1018      * addChildToParent}. *
1019      *
1020      * @param parent
1021      *            builder of node which is parent for <code>child</code>
1022      * @param child
1023      *            data schema node builder for child node
1024      * @param childName
1025      *            string with name of child node
1026      * @param lineNum
1027      *            line number in YANG file where is the node with the name equal
1028      *            to <code>childName</code> is defined
1029      */
1030     private void addChildToSubnodeOfModule(final Builder parent, final DataSchemaNodeBuilder child,
1031             final String childName, final int lineNum) {
1032         // no need for checking rpc and notification because they can be
1033         // defined only under module or submodule
1034         if (parent instanceof DataNodeContainerBuilder) {
1035             DataNodeContainerBuilder parentNode = (DataNodeContainerBuilder) parent;
1036             for (DataSchemaNodeBuilder childNode : parentNode.getChildNodeBuilders()) {
1037                 if (childNode.getQName().getLocalName().equals(childName)) {
1038                     raiseYangParserException("'" + child + "'", "node", childName, lineNum, childNode.getLine());
1039                 }
1040             }
1041             parentNode.addChildNode(child);
1042         } else if (parent instanceof ChoiceBuilder) {
1043             ChoiceBuilder parentNode = (ChoiceBuilder) parent;
1044             for (ChoiceCaseBuilder caseBuilder : parentNode.getCases()) {
1045                 if (caseBuilder.getQName().getLocalName().equals(childName)) {
1046                     raiseYangParserException("'" + child + "'", "node", childName, lineNum, caseBuilder.getLine());
1047                 }
1048             }
1049             parentNode.addCase(child);
1050         } else {
1051             throw new YangParseException(name, lineNum, "Unresolved parent of node '" + childName + "'.");
1052         }
1053     }
1054
1055     private void raiseYangParserException(final String cantAddType, final String type, final String name,
1056             final int currentLine, final int duplicateLine) {
1057
1058         StringBuilder msgPrefix = new StringBuilder("");
1059         if (cantAddType != null && !cantAddType.isEmpty()) {
1060             msgPrefix.append("Can not add ");
1061             msgPrefix.append(cantAddType);
1062             msgPrefix.append(": ");
1063         }
1064
1065         String msg = String.format("%s%s with same name '%s' already declared at line %d.", msgPrefix, type, name,
1066                 duplicateLine);
1067         throw new YangParseException(getModuleName(), currentLine, msg);
1068     }
1069
1070     @Override
1071     public int hashCode() {
1072         final int prime = 31;
1073         int result = 1;
1074         result = prime * result + Objects.hashCode(name);
1075         result = prime * result + qnameModule.hashCode();
1076         result = prime * result + Objects.hashCode(prefix);
1077
1078         return result;
1079     }
1080
1081     @Override
1082     public boolean equals(final Object obj) {
1083         if (this == obj) {
1084             return true;
1085         }
1086         if (obj == null) {
1087             return false;
1088         }
1089         if (getClass() != obj.getClass()) {
1090             return false;
1091         }
1092         ModuleBuilder other = (ModuleBuilder) obj;
1093         if (name == null) {
1094             if (other.name != null) {
1095                 return false;
1096             }
1097         } else if (!name.equals(other.name)) {
1098             return false;
1099         }
1100         if (!qnameModule.equals(other.qnameModule)) {
1101             return false;
1102         }
1103         if (prefix == null) {
1104             if (other.prefix != null) {
1105                 return false;
1106             }
1107         } else if (!prefix.equals(other.prefix)) {
1108             return false;
1109         }
1110         return true;
1111     }
1112
1113     public List<UnknownSchemaNode> getExtensionInstances() {
1114         return unknownNodes;
1115     }
1116 }