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