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