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