YANGTOOLS-706: Retrofit EffectiveStatement interfaces into parser
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / effective / ChoiceEffectiveStatementImpl.java
1 /*
2  * Copyright (c) 2015 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.stmt.rfc6020.effective;
9
10 import com.google.common.collect.ImmutableSet;
11 import com.google.common.collect.ImmutableSortedMap;
12 import java.util.LinkedHashSet;
13 import java.util.Objects;
14 import java.util.Optional;
15 import java.util.Set;
16 import java.util.SortedMap;
17 import java.util.TreeMap;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
20 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
21 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.DerivableSchemaNode;
24 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.MandatoryEffectiveStatement;
28 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
29 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
30 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
31 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangValidationBundles;
32
33 public final class ChoiceEffectiveStatementImpl extends AbstractEffectiveDataSchemaNode<ChoiceStatement> implements
34         ChoiceEffectiveStatement, ChoiceSchemaNode, DerivableSchemaNode {
35
36     private final Set<AugmentationSchemaNode> augmentations;
37     private final SortedMap<QName, ChoiceCaseNode> cases;
38     private final ChoiceCaseNode defaultCase;
39     private final ChoiceSchemaNode original;
40     private final boolean mandatory;
41
42     public ChoiceEffectiveStatementImpl(
43             final StmtContext<QName, ChoiceStatement, EffectiveStatement<QName, ChoiceStatement>> ctx) {
44         super(ctx);
45         this.original = (ChoiceSchemaNode) ctx.getOriginalCtx().map(StmtContext::buildEffective).orElse(null);
46
47         // initSubstatementCollectionsAndFields
48         final Set<AugmentationSchemaNode> augmentationsInit = new LinkedHashSet<>();
49         final SortedMap<QName, ChoiceCaseNode> casesInit = new TreeMap<>();
50
51         for (final EffectiveStatement<?, ?> effectiveStatement : effectiveSubstatements()) {
52             if (effectiveStatement instanceof AugmentationSchemaNode) {
53                 final AugmentationSchemaNode augmentationSchema = (AugmentationSchemaNode) effectiveStatement;
54                 augmentationsInit.add(augmentationSchema);
55             }
56             if (effectiveStatement instanceof ChoiceCaseNode) {
57                 final ChoiceCaseNode choiceCaseNode = (ChoiceCaseNode) effectiveStatement;
58                 // FIXME: we may be overwriting a previous entry, is that really okay?
59                 casesInit.put(choiceCaseNode.getQName(), choiceCaseNode);
60             }
61             if (YangValidationBundles.SUPPORTED_CASE_SHORTHANDS.contains(effectiveStatement.statementDefinition())) {
62                 final DataSchemaNode dataSchemaNode = (DataSchemaNode) effectiveStatement;
63                 final ChoiceCaseNode shorthandCase = new CaseShorthandImpl(dataSchemaNode);
64                 // FIXME: we may be overwriting a previous entry, is that really okay?
65                 casesInit.put(shorthandCase.getQName(), shorthandCase);
66                 if (dataSchemaNode.isAugmenting() && !this.augmenting) {
67                     resetAugmenting(dataSchemaNode);
68                 }
69             }
70         }
71
72         this.augmentations = ImmutableSet.copyOf(augmentationsInit);
73         this.cases = ImmutableSortedMap.copyOfSorted(casesInit);
74
75         final DefaultEffectiveStatementImpl defaultStmt = firstEffective(DefaultEffectiveStatementImpl.class);
76         if (defaultStmt != null) {
77             final QName qname;
78             try {
79                 qname = QName.create(getQName(), defaultStmt.argument());
80             } catch (IllegalArgumentException e) {
81                 throw new SourceException(ctx.getStatementSourceReference(), "Default statement has invalid name '%s'",
82                     defaultStmt.argument(), e);
83             }
84
85             // FIXME: this does not work with submodules, as they are
86             defaultCase = InferenceException.throwIfNull(cases.get(qname), ctx.getStatementSourceReference(),
87                 "Default statement refers to missing case %s", qname);
88         } else {
89             defaultCase = null;
90         }
91
92         final MandatoryEffectiveStatement mandatoryStmt = firstEffective(MandatoryEffectiveStatement.class);
93         mandatory = mandatoryStmt == null ? false : mandatoryStmt.argument().booleanValue();
94     }
95
96     private static void resetAugmenting(final DataSchemaNode dataSchemaNode) {
97         if (dataSchemaNode instanceof LeafEffectiveStatementImpl) {
98             final LeafEffectiveStatementImpl leaf = (LeafEffectiveStatementImpl) dataSchemaNode;
99             leaf.augmenting = false;
100         } else if (dataSchemaNode instanceof ContainerEffectiveStatementImpl) {
101             final ContainerEffectiveStatementImpl container = (ContainerEffectiveStatementImpl) dataSchemaNode;
102             container.augmenting = false;
103         } else if (dataSchemaNode instanceof LeafListEffectiveStatementImpl) {
104             final LeafListEffectiveStatementImpl leafList = (LeafListEffectiveStatementImpl) dataSchemaNode;
105             leafList.augmenting = false;
106         } else if (dataSchemaNode instanceof ListEffectiveStatementImpl) {
107             final ListEffectiveStatementImpl list = (ListEffectiveStatementImpl) dataSchemaNode;
108             list.augmenting = false;
109         } else if (dataSchemaNode instanceof AnyxmlEffectiveStatementImpl) {
110             final AnyxmlEffectiveStatementImpl anyXml = (AnyxmlEffectiveStatementImpl) dataSchemaNode;
111             anyXml.augmenting = false;
112         }
113     }
114
115     @Override
116     public Optional<ChoiceSchemaNode> getOriginal() {
117         return Optional.ofNullable(original);
118     }
119
120     @Override
121     public Set<AugmentationSchemaNode> getAvailableAugmentations() {
122         return augmentations;
123     }
124
125     @Override
126     public SortedMap<QName, ChoiceCaseNode> getCases() {
127         return cases;
128     }
129
130     @Override
131     public Optional<ChoiceCaseNode> getDefaultCase() {
132         return Optional.ofNullable(defaultCase);
133     }
134
135     @Override
136     public boolean isMandatory() {
137         return mandatory;
138     }
139
140     @Override
141     public int hashCode() {
142         final int prime = 31;
143         int result = 1;
144         result = prime * result + Objects.hashCode(getQName());
145         result = prime * result + Objects.hashCode(getPath());
146         return result;
147     }
148
149     @Override
150     public boolean equals(final Object obj) {
151         if (this == obj) {
152             return true;
153         }
154         if (obj == null) {
155             return false;
156         }
157         if (getClass() != obj.getClass()) {
158             return false;
159         }
160         final ChoiceEffectiveStatementImpl other = (ChoiceEffectiveStatementImpl) obj;
161         return Objects.equals(getQName(), other.getQName()) && Objects.equals(getPath(), other.getPath());
162     }
163
164     @Override
165     public String toString() {
166         return ChoiceEffectiveStatementImpl.class.getSimpleName() + "["
167                 + "qname=" + getQName()
168                 + "]";
169     }
170 }