Bug 6867: Extend yang statement parser to support different yang versions
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / RootStatementContext.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.reactor;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Verify;
13 import com.google.common.collect.ImmutableList;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Map;
17 import javax.annotation.Nonnull;
18 import javax.annotation.Nullable;
19 import org.opendaylight.yangtools.yang.common.QNameModule;
20 import org.opendaylight.yangtools.yang.common.YangVersion;
21 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
22 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
23 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
24 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
25 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
26 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
27 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
28 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
29 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
31 import org.opendaylight.yangtools.yang.parser.spi.source.IncludedModuleContext;
32
33 /**
34  * Root statement class for a YANG source. All statements defined in that YANG source are mapped underneath an instance
35  * of this class, hence recursive lookups from them cross this class.
36  */
37 public class RootStatementContext<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> extends
38         StatementContextBase<A, D, E> {
39
40     public static final YangVersion DEFAULT_VERSION = YangVersion.VERSION_1;
41
42     private final SourceSpecificContext sourceContext;
43     private final A argument;
44
45     private YangVersion version;
46
47     /**
48      * References to RootStatementContext of submodules which are included in this source.
49      */
50     private Collection<RootStatementContext<?, ?, ?>> includedContexts = ImmutableList.of();
51
52     RootStatementContext(final ContextBuilder<A, D, E> builder, final SourceSpecificContext sourceContext) {
53         super(builder);
54         this.sourceContext = Preconditions.checkNotNull(sourceContext);
55         this.argument = builder.getDefinition().parseArgumentValue(this, builder.getRawArgument());
56     }
57
58     RootStatementContext(final ContextBuilder<A, D, E> builder, final SourceSpecificContext sourceContext,
59             final YangVersion version) {
60         this(builder, sourceContext);
61         this.setRootVersion(version);
62     }
63
64     RootStatementContext(final RootStatementContext<A, D, E> original, final QNameModule newQNameModule,
65         final CopyType typeOfCopy) {
66         super(original);
67
68         sourceContext = Preconditions.checkNotNull(original.sourceContext);
69         this.argument = original.argument;
70
71         final Collection<StatementContextBase<?, ?, ?>> declared = original.declaredSubstatements();
72         final Collection<StatementContextBase<?, ?, ?>> effective = original.effectiveSubstatements();
73         final Collection<StatementContextBase<?, ?, ?>> buffer = new ArrayList<>(declared.size() + effective.size());
74
75         for (final StatementContextBase<?, ?, ?> stmtContext : declared) {
76             if (StmtContextUtils.areFeaturesSupported(stmtContext)) {
77                 buffer.add(stmtContext.createCopy(newQNameModule, this, typeOfCopy));
78             }
79         }
80         for (final StmtContext<?, ?, ?> stmtContext : effective) {
81             buffer.add(stmtContext.createCopy(newQNameModule, this, typeOfCopy));
82         }
83
84         addEffectiveSubstatements(buffer);
85     }
86
87     /**
88      * @return null as root cannot have parent
89      */
90     @Override
91     public StatementContextBase<?, ?, ?> getParentContext() {
92         return null;
93     }
94
95     /**
96      * @return namespace storage of source context
97      */
98     @Override
99     public NamespaceStorageNode getParentNamespaceStorage() {
100         return sourceContext;
101     }
102
103     /**
104      * @return registry of source context
105      */
106     @Override
107     public Registry getBehaviourRegistry() {
108         return sourceContext;
109     }
110
111     @Override
112     public StorageNodeType getStorageNodeType() {
113         return StorageNodeType.ROOT_STATEMENT_LOCAL;
114     }
115     /**
116      * @return this as its own root
117      */
118     @Nonnull
119     @Override
120     public RootStatementContext<?, ?, ?> getRoot() {
121         return this;
122     }
123
124     SourceSpecificContext getSourceContext() {
125         return sourceContext;
126     }
127
128     @Override
129     public A getStatementArgument() {
130         return argument;
131     }
132
133     /**
134      * @return copy of this considering {@link CopyType} (augment, uses)
135      *
136      * @throws org.opendaylight.yangtools.yang.parser.spi.source.SourceException instance of SourceException
137      */
138     @Override
139     public StatementContextBase<?, ?, ?> createCopy(final StatementContextBase<?, ?, ?> newParent,
140             final CopyType typeOfCopy) {
141         return createCopy(null, newParent, typeOfCopy);
142     }
143
144     /**
145      * @return copy of this considering {@link CopyType} (augment, uses)
146      *
147      * @throws org.opendaylight.yangtools.yang.parser.spi.source.SourceException instance of SourceException
148      */
149     @Override
150     public StatementContextBase<A, D, E> createCopy(final QNameModule newQNameModule,
151             final StatementContextBase<?, ?, ?> newParent, final CopyType typeOfCopy) {
152         final RootStatementContext<A, D, E> copy = new RootStatementContext<>(this, newQNameModule, typeOfCopy);
153
154         copy.appendCopyHistory(typeOfCopy, this.getCopyHistory());
155
156         if (this.getOriginalCtx() != null) {
157             copy.setOriginalCtx(this.getOriginalCtx());
158         } else {
159             copy.setOriginalCtx(this);
160         }
161         definition().onStatementAdded(copy);
162         return copy;
163     }
164
165     @Nonnull
166     @Override
167     public Optional<SchemaPath> getSchemaPath() {
168         return Optional.of(SchemaPath.ROOT);
169     }
170
171     /**
172      * @return true
173      */
174     @Override
175     public boolean isRootContext() {
176         return true;
177     }
178
179     @Override
180     public boolean isConfiguration() {
181         return true;
182     }
183
184     @Override
185     public boolean isEnabledSemanticVersioning() {
186         return sourceContext.isEnabledSemanticVersioning();
187     }
188
189     @Override
190     public <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(final Class<N> type, final K key,
191             final V value) {
192         if (IncludedModuleContext.class.isAssignableFrom(type)) {
193             if (includedContexts.isEmpty()) {
194                 includedContexts = new ArrayList<>(1);
195             }
196             Verify.verify(value instanceof RootStatementContext);
197             includedContexts.add((RootStatementContext<?, ?, ?>) value);
198         }
199         super.addToLocalStorage(type, key, value);
200     }
201
202     @Override
203     public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(final Class<N> type, final K key) {
204         final V potentialLocal = super.getFromLocalStorage(type, key);
205         if (potentialLocal != null) {
206             return potentialLocal;
207         }
208         for (final NamespaceStorageNode includedSource : includedContexts) {
209             final V potential = includedSource.getFromLocalStorage(type, key);
210             if (potential != null) {
211                 return potential;
212             }
213         }
214         return null;
215     }
216
217     @Nullable
218     @Override
219     public <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(final Class<N> type) {
220         final Map<K, V> potentialLocal = super.getAllFromLocalStorage(type);
221         if (potentialLocal != null) {
222             return potentialLocal;
223         }
224         for (final NamespaceStorageNode includedSource : includedContexts) {
225             final Map<K, V> potential = includedSource.getAllFromLocalStorage(type);
226             if (potential != null) {
227                 return potential;
228             }
229         }
230         return null;
231     }
232
233     @Override
234     public YangVersion getRootVersion() {
235         return version == null ? DEFAULT_VERSION : version;
236     }
237
238     @Override
239     public void setRootVersion(final YangVersion version) {
240         Preconditions.checkArgument(sourceContext.getSupportedVersions().contains(version),
241                 "Unsupported yang version %s in %s", version, getStatementSourceReference());
242         Preconditions.checkState(this.version == null, "Version of root %s has been already set to %s", argument,
243                 this.version);
244         this.version = Preconditions.checkNotNull(version);
245     }
246 }