24315021f34f5ee879e0b960cad463dd871e429e
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / SourceSpecificContext.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 javax.annotation.Nonnull;
11 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.BinarySpecificationImpl;
12 import org.opendaylight.yangtools.yang.model.api.stmt.ExtensionStatement;
13 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.HashMultimap;
16 import com.google.common.collect.ImmutableMap;
17 import com.google.common.collect.Multimap;
18 import org.opendaylight.yangtools.concepts.Mutable;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.common.QNameModule;
21 import org.opendaylight.yangtools.yang.common.YangConstants;
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.model.api.meta.StatementDefinition;
26 import org.opendaylight.yangtools.yang.parser.spi.ExtensionNamespace;
27 import org.opendaylight.yangtools.yang.parser.spi.meta.ImportedNamespaceContext;
28 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
29 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
31 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
32 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode;
33 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
35 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
36 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModuleMap;
37 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
38 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinitionMap;
39 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
40 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
41 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
42 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.BitsSpecificationImpl;
43 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Decimal64SpecificationImpl;
44 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.EnumSpecificationImpl;
45 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.UnknownEffectiveStatementImpl;
46 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.IdentityRefSpecificationImpl;
47 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.InstanceIdentifierSpecificationImpl;
48 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.LeafrefSpecificationImpl;
49 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.TypeUtils;
50 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.UnionSpecificationImpl;
51 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.UnknownStatementImpl;
52 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
53 import javax.annotation.Nullable;
54 import java.util.ArrayList;
55 import java.util.Collection;
56 import java.util.Iterator;
57 import java.util.Map;
58 import java.util.Objects;
59
60 public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBehaviour.Registry, Mutable {
61
62     public enum PhaseCompletionProgress {
63         NO_PROGRESS,
64         PROGRESS,
65         FINISHED
66     }
67
68     private final StatementStreamSource source;
69     private final BuildGlobalContext currentContext;
70     private final Collection<NamespaceStorageNode> importedNamespaces = new ArrayList<>();
71     private final Multimap<ModelProcessingPhase, ModifierImpl> modifiers = HashMultimap.create();
72
73     private RootStatementContext<?, ?, ?> root;
74
75     private ModelProcessingPhase inProgressPhase;
76     private ModelProcessingPhase finishedPhase = ModelProcessingPhase.INIT;
77     private QNameToStatementDefinitionMap qNameToStmtDefMap = new QNameToStatementDefinitionMap();
78     private PrefixToModuleMap prefixToModuleMap = new PrefixToModuleMap();
79
80
81     SourceSpecificContext(BuildGlobalContext currentContext, StatementStreamSource source) {
82         this.source = source;
83         this.currentContext = currentContext;
84     }
85
86     ModelProcessingPhase getInProgressPhase() {
87         return inProgressPhase;
88     }
89
90     StatementDefinitionContext<?, ?, ?> getDefinition(QName name) {
91         return currentContext.getStatementDefinition(name);
92     }
93
94     ContextBuilder<?, ?, ?> createDeclaredChild(StatementContextBase<?, ?, ?> current, QName name, StatementSourceReference ref) {
95         StatementDefinitionContext<?, ?, ?> def = getDefinition(name);
96
97         if (def == null) {
98             //unknown-stmts (from import, include or local-scope)
99             if (qNameToStmtDefMap.get(Utils.trimPrefix(name)) != null) {
100                 QName key = Utils.qNameFromArgument(current, name.getLocalName());
101                 if (key != null) {
102                     final StatementContextBase<?,?,?> extension = (StatementContextBase<?, ?, ?>) currentContext
103                             .getAllFromNamespace(ExtensionNamespace.class).get(key);
104                     if (extension != null) {
105                         final QName qName = QName.create(((QName) ((SubstatementContext) extension).getStatementArgument())
106                                 .getModule().getNamespace(), ((QName) ((SubstatementContext) extension).
107                                 getStatementArgument()).getModule().getRevision(), extension.getIdentifier().getArgument());
108
109                         def = new StatementDefinitionContext<>(new UnknownStatementImpl.Definition
110                                 (getNewStatementDefinition(qName)));
111                     } else {
112                         throw new IllegalArgumentException("Not found unknown statement: " + name);
113                     }
114                 }
115             } else {
116                 //type-body-stmts
117                 def = resolveTypeBodyStmts(name.getLocalName());
118             }
119         }
120
121         Preconditions.checkArgument(def != null, "Statement %s does not have type mapping defined.", name);
122         if (current == null) {
123             return createDeclaredRoot(def, ref);
124         }
125         return current.substatementBuilder(def, ref);
126     }
127
128     StatementDefinition getNewStatementDefinition(final QName qName) {
129         return new StatementDefinition() {
130             @Nonnull
131             @Override
132             public QName getStatementName() {
133                 return qName;
134             }
135
136             @Nullable
137             @Override
138             public QName getArgumentName() {
139                 return qName;
140             }
141
142             @Nonnull
143             @Override
144             public Class<? extends DeclaredStatement<?>> getDeclaredRepresentationClass() {
145                 return UnknownStatementImpl.class;
146             }
147
148             @Nonnull
149             @Override
150             public Class<? extends EffectiveStatement<?, ?>> getEffectiveRepresentationClass() {
151                 return UnknownEffectiveStatementImpl.class;
152             }
153         };
154     }
155
156     @SuppressWarnings({"rawtypes", "unchecked"})
157     private ContextBuilder<?, ?, ?> createDeclaredRoot(StatementDefinitionContext<?, ?, ?> def, StatementSourceReference ref) {
158         return new ContextBuilder(def, ref) {
159
160             @Override
161             public StatementContextBase build() throws SourceException {
162                 if (root == null) {
163                     root = new RootStatementContext(this, SourceSpecificContext.this);
164                 } else {
165                     Preconditions.checkState(root.getIdentifier().equals(createIdentifier()), "Root statement was already defined as %s.", root.getIdentifier());
166                 }
167                 root.resetLists();
168                 return root;
169             }
170
171         };
172     }
173
174     RootStatementContext<?, ?, ?> getRoot() {
175         return root;
176     }
177
178     DeclaredStatement<?> buildDeclared() {
179         return root.buildDeclared();
180     }
181
182     EffectiveStatement<?, ?> buildEffective() {
183         return root.buildEffective();
184     }
185
186     void startPhase(final ModelProcessingPhase phase) {
187         @Nullable ModelProcessingPhase previousPhase = phase.getPreviousPhase();
188         Preconditions.checkState(Objects.equals(previousPhase, finishedPhase));
189         Preconditions.checkState(modifiers.get(previousPhase).isEmpty());
190         inProgressPhase = phase;
191     }
192
193     @Override
194     public <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(final Class<N> type, final K key, final V value) {
195         if (ImportedNamespaceContext.class.isAssignableFrom(type)) {
196             importedNamespaces.add((NamespaceStorageNode) value);
197         }
198         getRoot().addToLocalStorage(type, key, value);
199     }
200
201     @Override
202     public StorageNodeType getStorageNodeType() {
203         return StorageNodeType.SOURCE_LOCAL_SPECIAL;
204     }
205
206     @Override
207     public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(final Class<N> type, final K key) {
208         final V potentialLocal = getRoot().getFromLocalStorage(type, key);
209         if (potentialLocal != null) {
210             return potentialLocal;
211         }
212         for (NamespaceStorageNode importedSource : importedNamespaces) {
213             V potential = importedSource.getFromLocalStorage(type, key);
214             if (potential != null) {
215                 return potential;
216             }
217         }
218         return null;
219     }
220
221     @Nullable
222     @Override
223     public <K, V, N extends IdentifierNamespace<K, V>> Map<K, V> getAllFromLocalStorage(final Class<N> type) {
224         final Map<K, V> potentialLocal = getRoot().getAllFromLocalStorage(type);
225
226         if (potentialLocal != null) {
227             return potentialLocal;
228         }
229
230         for (final NamespaceStorageNode importedSource : importedNamespaces) {
231             final Map<K, V> potential = importedSource.getAllFromLocalStorage(type);
232
233             if (potential != null) {
234                 return potential;
235             }
236         }
237         return null;
238     }
239
240     @Override
241     public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(final Class<N> type) {
242         return currentContext.getNamespaceBehaviour(type);
243     }
244
245     @Override
246     public NamespaceStorageNode getParentNamespaceStorage() {
247         return currentContext;
248     }
249
250     PhaseCompletionProgress tryToCompletePhase(final ModelProcessingPhase phase) throws SourceException {
251         Collection<ModifierImpl> currentPhaseModifiers = modifiers.get(phase);
252
253         boolean hasProgressed = hasProgress(currentPhaseModifiers);
254
255         boolean phaseCompleted = root.tryToCompletePhase(phase);
256
257         hasProgressed = (hasProgress(currentPhaseModifiers) | hasProgressed);
258
259         if (phaseCompleted && (currentPhaseModifiers.isEmpty())) {
260             finishedPhase = phase;
261             return PhaseCompletionProgress.FINISHED;
262
263         }
264         if (hasProgressed) {
265             return PhaseCompletionProgress.PROGRESS;
266         }
267         return PhaseCompletionProgress.NO_PROGRESS;
268     }
269
270
271     private static boolean hasProgress(final Collection<ModifierImpl> currentPhaseModifiers) {
272
273         Iterator<ModifierImpl> modifier = currentPhaseModifiers.iterator();
274         boolean hasProgressed = false;
275         while (modifier.hasNext()) {
276             if (modifier.next().isApplied()) {
277                 modifier.remove();
278                 hasProgressed = true;
279             }
280         }
281
282         return hasProgressed;
283
284     }
285
286     ModelActionBuilder newInferenceAction(final ModelProcessingPhase phase) {
287         ModifierImpl action = new ModifierImpl(phase);
288         modifiers.put(phase, action);
289         return action;
290     }
291
292     @Override
293     public String toString() {
294         return "SourceSpecificContext [source=" + source + ", current=" + inProgressPhase + ", finished="
295                 + finishedPhase + "]";
296     }
297
298     SourceException failModifiers(final ModelProcessingPhase identifier) {
299         InferenceException sourceEx = new InferenceException("Fail to infer source relationships", root.getStatementSourceReference());
300
301
302         for (ModifierImpl mod : modifiers.get(identifier)) {
303             try {
304                 mod.failModifier();
305             } catch (SourceException e) {
306                 sourceEx.addSuppressed(e);
307             }
308         }
309         return sourceEx;
310     }
311
312     void loadStatements() throws SourceException {
313         switch (inProgressPhase) {
314             case SOURCE_LINKAGE:
315                 source.writeLinkage(new StatementContextWriter(this, inProgressPhase), stmtDef());
316                 break;
317             case STATEMENT_DEFINITION:
318                 source.writeLinkageAndStatementDefinitions(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes());
319                 break;
320             case FULL_DECLARATION:
321                 source.writeFull(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes());
322                 break;
323             default:
324                 break;
325         }
326     }
327
328     private StatementDefinitionContext<?, ?, ?> resolveTypeBodyStmts(String typeArgument) {
329         switch (typeArgument) {
330             case TypeUtils.DECIMAL64:
331                 return new StatementDefinitionContext<>(new Decimal64SpecificationImpl.Definition());
332             case TypeUtils.UNION:
333                 return new StatementDefinitionContext<>(new UnionSpecificationImpl.Definition());
334             case TypeUtils.ENUMERATION:
335                 return new StatementDefinitionContext<>(new EnumSpecificationImpl.Definition());
336             case TypeUtils.LEAF_REF:
337                 return new StatementDefinitionContext<>(new LeafrefSpecificationImpl.Definition());
338             case TypeUtils.BITS:
339                 return new StatementDefinitionContext<>(new BitsSpecificationImpl.Definition());
340             case TypeUtils.IDENTITY_REF:
341                 return new StatementDefinitionContext<>(new IdentityRefSpecificationImpl.Definition());
342             case TypeUtils.INSTANCE_IDENTIFIER:
343                 return new StatementDefinitionContext<>(new InstanceIdentifierSpecificationImpl.Definition());
344             case TypeUtils.BINARY:
345                 return new StatementDefinitionContext<>(new BinarySpecificationImpl.Definition());
346             default:
347                 return null;
348         }
349     }
350
351
352     private PrefixToModule prefixes() {
353         Map<String, QNameModule> prefixes = currentContext.getAllFromNamespace(PrefixToModule.class);
354         for (Map.Entry<String, QNameModule> prefix : prefixes.entrySet()) {
355             prefixToModuleMap.put(prefix.getKey(), prefix.getValue());
356         }
357         return prefixToModuleMap;
358     }
359
360     private QNameToStatementDefinition stmtDef() {
361         //regular YANG statements added
362         ImmutableMap<QName, StatementSupport<?, ?, ?>> definitions = currentContext.getSupportsForPhase(
363                 inProgressPhase).getDefinitions();
364         for (Map.Entry<QName, StatementSupport<?, ?, ?>> entry : definitions.entrySet()) {
365             qNameToStmtDefMap.put(entry.getKey(), entry.getValue());
366         }
367
368         //extensions added
369         if (inProgressPhase.equals(ModelProcessingPhase.FULL_DECLARATION)) {
370             Map<QName, StmtContext<?, ExtensionStatement, EffectiveStatement<QName, ExtensionStatement>>> extensions = currentContext
371                     .getAllFromNamespace(ExtensionNamespace.class);
372             if (extensions != null) {
373                 for (Map.Entry<QName, StmtContext<?, ExtensionStatement, EffectiveStatement<QName, ExtensionStatement>>> extension : extensions
374                         .entrySet()) {
375                     qNameToStmtDefMap
376                             .put(new QName(YangConstants.RFC6020_YIN_NAMESPACE,
377                                     extension.getKey().getLocalName()),
378                                     (StatementDefinition) ((StatementContextBase<?, ?, ?>) extension
379                                             .getValue()).definition()
380                                             .getFactory());
381                 }
382             }
383         }
384         return qNameToStmtDefMap;
385     }
386 }