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