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