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