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