Merge "Add parser support for non-strict schema lookup."
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / StatementContextBase.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.base.Throwables;
12 import com.google.common.collect.HashMultimap;
13 import com.google.common.collect.Multimap;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.EventListener;
18 import java.util.Iterator;
19 import java.util.LinkedHashMap;
20 import java.util.Map;
21 import javax.annotation.Nonnull;
22 import org.opendaylight.yangtools.concepts.Identifiable;
23 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
24 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
26 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
27 import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
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.StorageNodeType;
32 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
33 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
34 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
35 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
36 import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.ValueAddedListener;
37
38 public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> extends
39         NamespaceStorageSupport implements StmtContext.Mutable<A, D, E>, Identifiable<StatementIdentifier> {
40
41     interface OnNamespaceItemAdded extends EventListener{
42
43         void namespaceItemAdded(StatementContextBase<?,?,?> context, Class<?> namespace, Object key, Object value) throws SourceException;
44
45     }
46
47     interface OnPhaseFinished extends EventListener{
48
49         void phaseFinished(StatementContextBase<?,?,?> context, ModelProcessingPhase phase) throws SourceException;
50
51     }
52
53     interface ContextMutation {
54
55         boolean isFinished();
56
57     }
58
59     abstract static class ContextBuilder<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> {
60
61         private final StatementDefinitionContext<A, D, E> definition;
62         private final StatementSourceReference stmtRef;
63         private String rawArg;
64         private StatementSourceReference argRef;
65
66         public ContextBuilder(StatementDefinitionContext<A, D, E> def, StatementSourceReference sourceRef) {
67             this.definition = def;
68             this.stmtRef = sourceRef;
69         }
70
71         public void setArgument(@Nonnull String argument, @Nonnull StatementSourceReference argumentSource) {
72             Preconditions.checkArgument(definition.hasArgument(), "Statement does not take argument.");
73             this.rawArg = Preconditions.checkNotNull(argument);
74             this.argRef = Preconditions.checkNotNull(argumentSource);
75         }
76
77         public String getRawArgument() {
78             return rawArg;
79         }
80
81         public StatementSourceReference getStamementSource() {
82             return stmtRef;
83         }
84
85         public StatementSourceReference getArgumentSource() {
86             return argRef;
87         }
88
89         public StatementDefinitionContext<A, D, E> getDefinition() {
90             return definition;
91         }
92
93         public StatementIdentifier getIdentifier() {
94             return new StatementIdentifier(definition.getStatementName(), rawArg);
95         }
96
97         public abstract StatementContextBase<A, D, E> build() throws SourceException;
98
99     }
100
101     private final StatementDefinitionContext<A, D, E> definition;
102     private final StatementIdentifier identifier;
103     private final StatementSourceReference statementDeclSource;
104
105     private Map<StatementIdentifier, StatementContextBase<?, ?, ?> > substatements = new LinkedHashMap<>();
106
107     private Collection<StatementContextBase<?, ?, ?>> declared = new ArrayList<>();
108     private Collection<StatementContextBase<?, ?, ?>> effective = new ArrayList<>();
109
110     private ModelProcessingPhase completedPhase;
111
112     private Multimap<ModelProcessingPhase,OnPhaseFinished> phaseListeners = HashMultimap.create();
113     private Multimap<ModelProcessingPhase, ContextMutation> phaseMutation = HashMultimap.create();
114
115     private D declaredInstance;
116     private E effectiveInstance;
117
118
119     StatementContextBase(@Nonnull ContextBuilder<A, D, E> builder) throws SourceException {
120         this.definition = builder.getDefinition();
121         this.identifier = builder.getIdentifier();
122         this.statementDeclSource = builder.getStamementSource();
123         this.completedPhase = null;
124     }
125
126     StatementContextBase(StatementContextBase<A,D,E> original) {
127         this.definition = original.definition;
128         this.identifier = original.identifier;
129         this.statementDeclSource = original.statementDeclSource;
130         this.completedPhase = null;
131     }
132
133     @Override
134     public abstract StatementContextBase<?, ?, ?> getParentContext();
135
136     @Override
137     public abstract RootStatementContext<?, ?, ?> getRoot();
138
139
140     @Override
141     public StatementIdentifier getIdentifier() {
142         return identifier;
143     }
144
145     @Override
146     public StatementSource getStatementSource() {
147         return statementDeclSource.getStatementSource();
148     }
149
150     @Override
151     public StatementSourceReference getStatementSourceReference() {
152         return statementDeclSource;
153     }
154
155     @Override
156     public String rawStatementArgument() {
157         return identifier.getArgument();
158     }
159
160     @Override
161     public Collection<StatementContextBase<?, ?, ?>> declaredSubstatements() {
162         return Collections.unmodifiableCollection(declared);
163     }
164
165     @Override
166     public Collection<StatementContextBase<?, ?, ?>> effectiveSubstatements() {
167         return Collections.unmodifiableCollection(effective);
168     }
169
170     public void addEffectiveSubstatement(StatementContextBase<?, ?, ?> substatement){
171         effective.add(substatement);
172     }
173
174     public void addDeclaredSubstatement(StatementContextBase<?, ?, ?> substatement){
175         declared.add(substatement);
176     }
177
178     @SuppressWarnings({ "rawtypes", "unchecked" })
179     public ContextBuilder<?, ?, ?> substatementBuilder(StatementDefinitionContext<?, ?, ?> def,
180             StatementSourceReference ref) {
181         return new ContextBuilder(def, ref) {
182
183             @Override
184             public StatementContextBase build() throws SourceException {
185                 StatementContextBase<?, ?, ?> potential = substatements.get(getIdentifier());
186                 if(potential == null) {
187                     potential = new SubstatementContext(StatementContextBase.this, this);
188                     substatements.put(getIdentifier(), potential);
189                 }
190                 potential.resetLists();
191                 switch (this.getStamementSource().getStatementSource()) {
192                     case DECLARATION:
193                         declared.add(potential);
194                         break;
195                     case CONTEXT:
196                         effective.add(potential);
197                         break;
198                 }
199                 return potential;
200             }
201         };
202     }
203
204
205
206     @Override
207     public StorageNodeType getStorageNodeType() {
208         return StorageNodeType.STATEMENT_LOCAL;
209     }
210
211     @Override
212     public D buildDeclared() {
213         Preconditions.checkArgument(completedPhase == ModelProcessingPhase.FULL_DECLARATION || completedPhase == ModelProcessingPhase.EFFECTIVE_MODEL);
214         if (declaredInstance == null) {
215             declaredInstance = definition().getFactory().createDeclared(this);
216         }
217         return declaredInstance;
218     }
219
220     @Override
221     public E buildEffective() {
222         Preconditions.checkArgument(completedPhase == ModelProcessingPhase.EFFECTIVE_MODEL);
223         if (effectiveInstance == null) {
224             effectiveInstance = definition().getFactory().createEffective(this);
225         }
226         return effectiveInstance;
227     }
228
229
230     void resetLists() {
231         declared.clear();
232     }
233
234     boolean tryToCompletePhase(ModelProcessingPhase phase) throws SourceException {
235         if(phase.equals(completedPhase)) {
236             return true;
237         }
238         Iterator<ContextMutation> openMutations = phaseMutation.get(phase).iterator();
239         boolean finished = true;
240         while(openMutations.hasNext()) {
241             ContextMutation current = openMutations.next();
242             if(current.isFinished()) {
243                 openMutations.remove();
244             } else {
245                 finished = false;
246             }
247         }
248         for(StatementContextBase<?, ?, ?> child: declared) {
249             finished &= child.tryToCompletePhase(phase);
250         }
251         for(StatementContextBase<?, ?, ?> child: effective) {
252             finished &= child.tryToCompletePhase(phase);
253         }
254         if(finished) {
255             onPhaseCompleted(phase);
256             return true;
257         }
258         return false;
259     }
260
261
262     private void onPhaseCompleted(ModelProcessingPhase phase) throws SourceException {
263         completedPhase = phase;
264         Iterator<OnPhaseFinished> listener = phaseListeners.get(completedPhase).iterator();
265         while(listener.hasNext()) {
266             listener.next().phaseFinished(this, phase);
267             listener.remove();
268         }
269     }
270
271     /**
272      *
273      * Ends declared section of current node.
274      *
275      * @param ref
276      * @throws SourceException
277      *
278      */
279     void endDeclared(StatementSourceReference ref,ModelProcessingPhase phase) throws SourceException {
280         definition().onDeclarationFinished(this,phase);
281     }
282
283     protected final StatementDefinitionContext<A, D, E> definition() {
284         return definition;
285     }
286
287     @Override
288     protected void checkLocalNamespaceAllowed(Class<? extends IdentifierNamespace<?, ?>> type) {
289         definition().checkNamespaceAllowed(type);
290     }
291
292     @Override
293     protected <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceElementAdded(Class<N> type, K key, V value) {
294         //definition().onNamespaceElementAdded(this, type, key, value);
295     }
296
297     <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type, K key, final OnNamespaceItemAdded listener) throws SourceException {
298         Object potential = getFromNamespace(type, key);
299         if(potential != null) {
300             listener.namespaceItemAdded(this, type, key, potential);
301             return;
302         }
303         NamespaceBehaviour<K,V,N> behaviour = getBehaviourRegistry().getNamespaceBehaviour(type);
304         if(behaviour instanceof NamespaceBehaviourWithListeners) {
305             NamespaceBehaviourWithListeners<K, V, N> casted = (NamespaceBehaviourWithListeners<K,V,N>) behaviour;
306             casted.addValueListener(key, new ValueAddedListener(this) {
307                 @Override
308                 void onValueAdded(Object key, Object value) {
309                     try {
310                         listener.namespaceItemAdded(StatementContextBase.this, type, key, value);
311                     } catch (SourceException e) {
312                         throw Throwables.propagate(e);
313                     }
314                 }
315             });
316         }
317     }
318
319     @Override
320     public StatementDefinition getPublicDefinition() {
321         return definition().getPublicView();
322     }
323
324     @Override
325     public ModelActionBuilder newInferenceAction(ModelProcessingPhase phase) {
326         return getRoot().getSourceContext().newInferenceAction(phase);
327     }
328
329     void addPhaseCompletedListener(ModelProcessingPhase phase, OnPhaseFinished listener) throws SourceException {
330         ModelProcessingPhase finishedPhase = completedPhase;
331         while (finishedPhase != null) {
332             if(phase.equals(finishedPhase)) {
333                 listener.phaseFinished(this, finishedPhase);
334                 return;
335             }
336             finishedPhase = finishedPhase.getPreviousPhase();
337         }
338         phaseListeners.put(phase, listener);
339     }
340
341     void addMutation(ModelProcessingPhase phase, ContextMutation mutation) {
342         ModelProcessingPhase finishedPhase = completedPhase;
343         while (finishedPhase != null) {
344             if(phase.equals(finishedPhase)) {
345                 throw new IllegalStateException("Mutation registered after phase was completed.");
346             }
347             finishedPhase = finishedPhase.getPreviousPhase();
348         }
349         phaseMutation.put(phase, mutation);
350     }
351
352     @Override
353     public <K,KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(
354             Class<N> namespace, KT key, StmtContext<?, ?, ?> stmt) {
355         addContextToNamespace(namespace,(K) key, stmt);
356     }
357 }