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