Merge "BUG-582: do not use linear search of child nodes"
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / builder / impl / AugmentationSchemaBuilderImpl.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.Iterator;
15 import java.util.List;
16 import java.util.Set;
17
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
20 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
22 import org.opendaylight.yangtools.yang.model.api.NamespaceRevisionAware;
23 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
24 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
25 import org.opendaylight.yangtools.yang.model.api.Status;
26 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
27 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.UsesNode;
29 import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl;
30 import org.opendaylight.yangtools.yang.parser.builder.api.AbstractDataNodeContainerBuilder;
31 import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder;
32 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
33 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
34 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
35 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
36 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
37 import org.opendaylight.yangtools.yang.parser.util.ParserUtils;
38 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
39
40 import com.google.common.base.Optional;
41 import com.google.common.base.Preconditions;
42 import com.google.common.collect.ImmutableList;
43 import com.google.common.collect.ImmutableSet;
44
45 public final class AugmentationSchemaBuilderImpl extends AbstractDataNodeContainerBuilder implements
46         AugmentationSchemaBuilder {
47     private final int order;
48     private AugmentationSchemaImpl instance;
49     private String whenCondition;
50
51     private String description;
52     private String reference;
53     private Status status = Status.CURRENT;
54
55     private final String augmentTargetStr;
56     private final SchemaPath targetPath;
57     private SchemaPath targetNodeSchemaPath;
58
59     private boolean resolved;
60     private AugmentationSchemaBuilder copyOf;
61
62     public AugmentationSchemaBuilderImpl(final String moduleName, final int line, final String augmentTargetStr, final int order) {
63         super(moduleName, line, null);
64         this.order = order;
65         this.augmentTargetStr = augmentTargetStr;
66         targetPath = ParserUtils.parseXPathString(augmentTargetStr);
67     }
68
69     @Override
70     public Set<GroupingDefinition> getGroupings() {
71         return Collections.emptySet();
72     }
73
74     @Override
75     public Set<GroupingBuilder> getGroupingBuilders() {
76         return Collections.emptySet();
77     }
78
79     @Override
80     public void addGrouping(final GroupingBuilder grouping) {
81         throw new YangParseException(getModuleName(), grouping.getLine(), "augment can not contains grouping statement");
82     }
83
84     @Override
85     public SchemaPath getPath() {
86         return targetNodeSchemaPath;
87     }
88
89     @Override
90     public AugmentationSchema build() {
91         if (instance != null) {
92             return instance;
93         }
94
95         instance = new AugmentationSchemaImpl(targetPath, order);
96
97         instance.description = description;
98         instance.reference = reference;
99         instance.status = status;
100
101         Builder parent = getParent();
102         if (parent instanceof ModuleBuilder) {
103             ModuleBuilder moduleBuilder = (ModuleBuilder) parent;
104             instance.namespace = moduleBuilder.getNamespace();
105             instance.revision = moduleBuilder.getRevision();
106         }
107
108         if (parent instanceof UsesNodeBuilder) {
109             ModuleBuilder mb = ParserUtils.getParentModule(this);
110             List<QName> newPath = new ArrayList<>();
111             List<QName> parsedPath = targetPath.getPath();
112             for (QName name : parsedPath) {
113                 newPath.add(new QName(mb.getNamespace(), mb.getRevision(), name.getPrefix(), name.getLocalName()));
114             }
115             instance.targetPath = SchemaPath.create(newPath, false);
116         } else {
117             instance.targetPath = targetNodeSchemaPath;
118         }
119
120         if (copyOf != null) {
121             instance.setCopyOf(copyOf.build());
122         }
123
124         RevisionAwareXPath whenStmt;
125         if (whenCondition == null) {
126             whenStmt = null;
127         } else {
128             whenStmt = new RevisionAwareXPathImpl(whenCondition, false);
129         }
130         instance.whenCondition = whenStmt;
131
132         // CHILD NODES
133         for (DataSchemaNodeBuilder node : addedChildNodes) {
134             childNodes.put(node.getQName(), node.build());
135         }
136         instance.childNodes = ImmutableSet.copyOf(childNodes.values());
137
138         // USES
139         for (UsesNodeBuilder builder : addedUsesNodes) {
140             usesNodes.add(builder.build());
141         }
142         instance.uses = ImmutableSet.copyOf(usesNodes);
143
144         // UNKNOWN NODES
145         for (UnknownSchemaNodeBuilder b : addedUnknownNodes) {
146             unknownNodes.add(b.build());
147         }
148         instance.unknownNodes = ImmutableList.copyOf(unknownNodes);
149
150         return instance;
151     }
152
153     @Override
154     public boolean isResolved() {
155         return resolved;
156     }
157
158     @Override
159     public void setResolved(final boolean resolved) {
160         this.resolved = resolved;
161     }
162
163     @Override
164     public String getWhenCondition() {
165         return whenCondition;
166     }
167
168     @Override
169     public void addWhenCondition(final String whenCondition) {
170         this.whenCondition = whenCondition;
171     }
172
173     @Override
174     public Set<TypeDefinitionBuilder> getTypeDefinitionBuilders() {
175         return Collections.emptySet();
176     }
177
178     @Override
179     public void addTypedef(final TypeDefinitionBuilder type) {
180         throw new YangParseException(getModuleName(), type.getLine(), "Augmentation can not contains typedef statement.");
181     }
182
183     @Override
184     public String getDescription() {
185         return description;
186     }
187
188     @Override
189     public void setDescription(final String description) {
190         this.description = description;
191     }
192
193     @Override
194     public String getReference() {
195         return reference;
196     }
197
198     @Override
199     public void setReference(final String reference) {
200         this.reference = reference;
201     }
202
203     @Override
204     public Status getStatus() {
205         return status;
206     }
207
208     @Override
209     public void setStatus(final Status status) {
210         this.status = Preconditions.checkNotNull(status, "status cannot be null");
211     }
212
213     @Override
214     public String getTargetPathAsString() {
215         return augmentTargetStr;
216     }
217
218     @Override
219     public SchemaPath getTargetPath() {
220         return targetPath;
221     }
222
223     @Override
224     public SchemaPath getTargetNodeSchemaPath() {
225         return targetNodeSchemaPath;
226     }
227
228     @Override
229     public void setTargetNodeSchemaPath(final SchemaPath path) {
230         this.targetNodeSchemaPath = path;
231     }
232
233     @Override
234     public int getOrder() {
235         return order;
236     }
237
238     @Override
239     public int hashCode() {
240         final int prime = 17;
241         int result = 1;
242         result = prime * result + ((augmentTargetStr == null) ? 0 : augmentTargetStr.hashCode());
243         result = prime * result + ((whenCondition == null) ? 0 : whenCondition.hashCode());
244         result = prime * result + ((addedChildNodes == null) ? 0 : addedChildNodes.hashCode());
245         return result;
246     }
247
248     @Override
249     public boolean equals(final Object obj) {
250         if (this == obj) {
251             return true;
252         }
253         if (obj == null) {
254             return false;
255         }
256         if (getClass() != obj.getClass()) {
257             return false;
258         }
259         AugmentationSchemaBuilderImpl other = (AugmentationSchemaBuilderImpl) obj;
260         if (augmentTargetStr == null) {
261             if (other.augmentTargetStr != null) {
262                 return false;
263             }
264         } else if (!augmentTargetStr.equals(other.augmentTargetStr)) {
265             return false;
266         }
267         if (whenCondition == null) {
268             if (other.whenCondition != null) {
269                 return false;
270             }
271         } else if (!whenCondition.equals(other.whenCondition)) {
272             return false;
273         }
274         if (addedChildNodes == null) {
275             if (other.addedChildNodes != null) {
276                 return false;
277             }
278         } else if (!addedChildNodes.equals(other.addedChildNodes)) {
279             return false;
280         }
281         return true;
282     }
283
284     @Override
285     public String toString() {
286         return "augment " + augmentTargetStr;
287     }
288
289     public void setCopyOf(final AugmentationSchemaBuilder old) {
290         copyOf = old;
291     }
292
293     private static final class AugmentationSchemaImpl implements AugmentationSchema, NamespaceRevisionAware,
294             Comparable<AugmentationSchemaImpl> {
295         private final int order;
296         private SchemaPath targetPath;
297         private RevisionAwareXPath whenCondition;
298         private ImmutableSet<DataSchemaNode> childNodes;
299         private ImmutableSet<UsesNode> uses;
300         private String description;
301         private String reference;
302         private Status status;
303
304         private URI namespace;
305         private Date revision;
306         private ImmutableList<UnknownSchemaNode> unknownNodes;
307         private AugmentationSchema copyOf;
308
309         public AugmentationSchemaImpl(final SchemaPath targetPath, final int order) {
310             this.targetPath = targetPath;
311             this.order = order;
312         }
313
314         public void setCopyOf(final AugmentationSchema build) {
315             this.copyOf = build;
316         }
317
318         @Override
319         public Optional<AugmentationSchema> getOriginalDefinition() {
320             return Optional.fromNullable(this.copyOf);
321         }
322
323         @Override
324         public SchemaPath getTargetPath() {
325             return targetPath;
326         }
327
328         @Override
329         public RevisionAwareXPath getWhenCondition() {
330             return whenCondition;
331         }
332
333         @Override
334         public Set<DataSchemaNode> getChildNodes() {
335             return childNodes;
336         }
337
338         /**
339          * Always returns an empty set, because augment can not contains
340          * grouping statement.
341          */
342         @Override
343         public Set<GroupingDefinition> getGroupings() {
344             return Collections.emptySet();
345         }
346
347         @Override
348         public Set<UsesNode> getUses() {
349             return uses;
350         }
351
352         /**
353          * Always returns an empty set, because augment can not contains type
354          * definitions.
355          */
356         @Override
357         public Set<TypeDefinition<?>> getTypeDefinitions() {
358             return Collections.emptySet();
359         }
360
361         @Override
362         public String getDescription() {
363             return description;
364         }
365
366         @Override
367         public String getReference() {
368             return reference;
369         }
370
371         @Override
372         public Status getStatus() {
373             return status;
374         }
375
376         @Override
377         public List<UnknownSchemaNode> getUnknownSchemaNodes() {
378             return unknownNodes;
379         }
380
381         @Override
382         public DataSchemaNode getDataChildByName(final QName name) {
383             return getChildNode(childNodes, name);
384         }
385
386         @Override
387         public DataSchemaNode getDataChildByName(final String name) {
388             return getChildNode(childNodes, name);
389         }
390
391         @Override
392         public URI getNamespace() {
393             return namespace;
394         }
395
396         @Override
397         public Date getRevision() {
398             return revision;
399         }
400
401         @Override
402         public int hashCode() {
403             final int prime = 17;
404             int result = 1;
405             result = prime * result + ((targetPath == null) ? 0 : targetPath.hashCode());
406             result = prime * result + ((whenCondition == null) ? 0 : whenCondition.hashCode());
407             result = prime * result + ((childNodes == null) ? 0 : childNodes.hashCode());
408             return result;
409         }
410
411         @Override
412         public boolean equals(final Object obj) {
413             if (this == obj) {
414                 return true;
415             }
416             if (obj == null) {
417                 return false;
418             }
419             if (getClass() != obj.getClass()) {
420                 return false;
421             }
422             AugmentationSchemaImpl other = (AugmentationSchemaImpl) obj;
423             if (targetPath == null) {
424                 if (other.targetPath != null) {
425                     return false;
426                 }
427             } else if (!targetPath.equals(other.targetPath)) {
428                 return false;
429             }
430             if (whenCondition == null) {
431                 if (other.whenCondition != null) {
432                     return false;
433                 }
434             } else if (!whenCondition.equals(other.whenCondition)) {
435                 return false;
436             }
437             if (childNodes == null) {
438                 if (other.childNodes != null) {
439                     return false;
440                 }
441             } else if (!childNodes.equals(other.childNodes)) {
442                 return false;
443             }
444             return true;
445         }
446
447         @Override
448         public String toString() {
449             StringBuilder sb = new StringBuilder(AugmentationSchemaImpl.class.getSimpleName());
450             sb.append("[");
451             sb.append("targetPath=" + targetPath);
452             sb.append(", when=" + whenCondition);
453             sb.append("]");
454             return sb.toString();
455         }
456
457         @Override
458         public int compareTo(final AugmentationSchemaImpl o) {
459             Iterator<QName> thisIt = this.targetPath.getPath().iterator();
460             Iterator<QName> otherIt = o.getTargetPath().getPath().iterator();
461             while (thisIt.hasNext()) {
462                 if (otherIt.hasNext()) {
463                     int comp = thisIt.next().compareTo(otherIt.next());
464                     if (comp != 0) {
465                         return comp;
466                     }
467                 } else {
468                     return 1;
469                 }
470             }
471             if (otherIt.hasNext()) {
472                 return -1;
473             }
474             return this.order - o.order;
475         }
476     }
477
478 }