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