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