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