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