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