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