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