Merge "Bug 2362 - Milestone: Basic constraints validation"
[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 org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
11
12 import com.google.common.base.Preconditions;
13 import com.google.common.collect.HashMultimap;
14 import com.google.common.collect.ImmutableMap;
15 import com.google.common.collect.Multimap;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.Iterator;
19 import java.util.Map;
20 import java.util.Objects;
21 import javax.annotation.Nullable;
22 import org.opendaylight.yangtools.concepts.Mutable;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
25 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
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.QNameToStatementDefinition;
36 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinitionMap;
37 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
38 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
39 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
40 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.ContextBuilder;
41
42 public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBehaviour.Registry, Mutable {
43
44     public enum PhaseCompletionProgress {
45         NO_PROGRESS,
46         PROGRESS,
47         FINISHED
48     }
49
50     private final StatementStreamSource source;
51     private final BuildGlobalContext currentContext;
52     private final Collection<NamespaceStorageNode> importedNamespaces = new ArrayList<>();
53     private final Multimap<ModelProcessingPhase, ModifierImpl> modifiers = HashMultimap.create();
54
55     private RootStatementContext<?,?, ?> root;
56
57     private ModelProcessingPhase inProgressPhase;
58     private ModelProcessingPhase finishedPhase;
59     private QNameToStatementDefinitionMap qNameToStmtDefMap = new QNameToStatementDefinitionMap();
60
61
62     SourceSpecificContext(BuildGlobalContext currentContext,StatementStreamSource source) {
63         this.source = source;
64         this.currentContext = currentContext;
65     }
66
67     StatementDefinitionContext<?,?,?> getDefinition(QName name) {
68         return currentContext.getStatementDefinition(name);
69     }
70
71     ContextBuilder<?, ?, ?> createDeclaredChild(StatementContextBase<?, ?, ?> current, QName name, StatementSourceReference ref) {
72         StatementDefinitionContext<?,?,?> def = getDefinition(name);
73         Preconditions.checkArgument(def != null, "Statement %s does not have type mapping defined.",name);
74         if(current == null) {
75             return createDeclaredRoot(def,ref);
76         }
77         return current.substatementBuilder(def, ref);
78     }
79
80     @SuppressWarnings({ "rawtypes", "unchecked" })
81     private ContextBuilder<?,?, ?> createDeclaredRoot(StatementDefinitionContext<?,?,?> def, StatementSourceReference ref) {
82         return new ContextBuilder(def,ref) {
83
84             @Override
85             public StatementContextBase build() throws SourceException {
86                 if(root == null) {
87                     root = new RootStatementContext(this, SourceSpecificContext.this);
88                 } else {
89                     Preconditions.checkState(root.getIdentifier().equals(getIdentifier()), "Root statement was already defined as %s.", root.getIdentifier());
90                 }
91                 root.resetLists();
92                 return root;
93             }
94
95         };
96     }
97
98     RootStatementContext<?,?,?> getRoot() {
99         return root;
100     }
101
102     DeclaredStatement<?> buildDeclared() {
103         return root.buildDeclared();
104     }
105
106     EffectiveStatement<?,?> buildEffective() {
107         return root.buildEffective();
108     }
109
110     void startPhase(ModelProcessingPhase phase) {
111         @Nullable ModelProcessingPhase previousPhase = phase.getPreviousPhase();
112         Preconditions.checkState(Objects.equals(previousPhase, finishedPhase));
113         Preconditions.checkState(modifiers.get(previousPhase).isEmpty());
114         inProgressPhase = phase;
115     }
116
117     @Override
118     public <K, V, N extends IdentifierNamespace<K, V>> void addToLocalStorage(Class<N> type, K key, V value) {
119         if(ImportedNamespaceContext.class.isAssignableFrom(type)) {
120             importedNamespaces.add((NamespaceStorageNode) value);
121         }
122         getRoot().addToLocalStorage(type, key, value);
123     }
124
125     @Override
126     public StorageNodeType getStorageNodeType() {
127         return StorageNodeType.SOURCE_LOCAL_SPECIAL;
128     }
129
130     @Override
131     public <K, V, N extends IdentifierNamespace<K, V>> V getFromLocalStorage(Class<N> type, K key) {
132         final V potentialLocal = getRoot().getFromLocalStorage(type, key);
133         if(potentialLocal != null) {
134             return potentialLocal;
135         }
136         for(NamespaceStorageNode importedSource : importedNamespaces) {
137             V potential = importedSource.getFromLocalStorage(type, key);
138             if(potential != null) {
139                 return potential;
140             }
141         }
142         return null;
143     }
144
145     @Override
146     public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour(Class<N> type) {
147         return currentContext.getNamespaceBehaviour(type);
148     }
149
150     @Override
151     public NamespaceStorageNode getParentNamespaceStorage() {
152         return currentContext;
153     }
154
155     PhaseCompletionProgress tryToCompletePhase(ModelProcessingPhase phase) throws SourceException {
156         Collection<ModifierImpl> currentPhaseModifiers = modifiers.get(phase);
157
158         boolean hasProgressed = hasProgress(currentPhaseModifiers);
159
160         boolean phaseCompleted = root.tryToCompletePhase(phase);
161
162         hasProgressed = hasProgress(currentPhaseModifiers);
163
164         if(phaseCompleted && (currentPhaseModifiers.isEmpty())) {
165             finishedPhase = phase;
166             return PhaseCompletionProgress.FINISHED;
167
168         }
169         if(hasProgressed) {
170             return PhaseCompletionProgress.PROGRESS;
171         }
172         return PhaseCompletionProgress.NO_PROGRESS;
173     }
174
175
176     private boolean hasProgress(Collection<ModifierImpl> currentPhaseModifiers) {
177
178         Iterator<ModifierImpl> modifier = currentPhaseModifiers.iterator();
179         boolean hasProgressed = false;
180         while(modifier.hasNext()) {
181             if(modifier.next().isApplied()) {
182                 modifier.remove();
183                 hasProgressed = true;
184             }
185         }
186
187         return hasProgressed;
188
189     }
190
191     ModelActionBuilder newInferenceAction(ModelProcessingPhase phase) {
192         ModifierImpl action = new ModifierImpl(phase);
193         modifiers.put(phase, action);
194         return action;
195     }
196
197     @Override
198     public String toString() {
199         return "SourceSpecificContext [source=" + source + ", current=" + inProgressPhase + ", finished="
200                 + finishedPhase + "]";
201     }
202
203     SourceException failModifiers(ModelProcessingPhase identifier) {
204         InferenceException sourceEx = new InferenceException("Fail to infer source relationships", root.getStatementSourceReference());
205
206
207         for(ModifierImpl mod : modifiers.get(identifier)) {
208             try {
209                 mod.failModifier();
210             } catch (SourceException e) {
211                 sourceEx.addSuppressed(e);
212             }
213         }
214         return sourceEx;
215     }
216
217     void loadStatements() throws SourceException {
218         switch (inProgressPhase) {
219         case SOURCE_LINKAGE:
220             source.writeLinkage(new StatementContextWriter(this, inProgressPhase),stmtDef());
221             break;
222         case STATEMENT_DEFINITION:
223             source.writeLinkageAndStatementDefinitions(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes());
224             break;
225         case FULL_DECLARATION:
226             source.writeFull(new StatementContextWriter(this, inProgressPhase), stmtDef(), prefixes());
227             break;
228         default:
229             break;
230         }
231     }
232
233     private PrefixToModule prefixes() {
234         // TODO Auto-generated method stub
235         return null;
236     }
237
238     private QNameToStatementDefinition stmtDef() {
239         ImmutableMap<QName, StatementSupport<?, ?, ?>> definitions = currentContext.getSupportsForPhase(
240                 inProgressPhase).getDefinitions();
241         for (Map.Entry<QName, StatementSupport<?,?,?>> entry : definitions.entrySet()) {
242             qNameToStmtDefMap.put(entry.getKey(), entry.getValue());
243         }
244         return qNameToStmtDefMap;
245     }
246 }