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