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