Bug 2366: Initial implementation of Statement Reactor
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / ModifierImpl.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 static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.EffectiveModel;
11 import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.FullDeclaration;
12
13 import com.google.common.base.Function;
14 import com.google.common.base.Preconditions;
15 import java.util.HashSet;
16 import java.util.Iterator;
17 import java.util.Set;
18 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
19 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
20 import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace;
21 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
24 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
25 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
26 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
27 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
28 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
29 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.ContextMutation;
30 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.OnNamespaceItemAdded;
31 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.OnPhaseFinished;
32
33 class ModifierImpl implements ModelActionBuilder {
34
35     private final ModelProcessingPhase phase;
36     private final Set<AbstractPrerequisite<?>> unsatisfied = new HashSet<>();
37     private final Set<AbstractPrerequisite<?>> mutations = new HashSet<>();
38
39     private InferenceAction action;
40     private boolean actionApplied = false;
41
42     ModifierImpl(ModelProcessingPhase phase) {
43         this.phase = Preconditions.checkNotNull(phase);
44     }
45
46     private <D> AbstractPrerequisite<D> addReq(AbstractPrerequisite<D> prereq) {
47         unsatisfied.add(prereq);
48         return prereq;
49     }
50
51     private <T> AbstractPrerequisite<T> addMutation(AbstractPrerequisite<T> mutation) {
52         mutations.add(mutation);
53         return mutation;
54     }
55
56
57
58     private void checkNotRegistered() {
59         Preconditions.checkState(action == null, "Action was already registered.");
60     }
61
62     private IllegalStateException shouldNotHappenProbablyBug(SourceException e) {
63         return new IllegalStateException("Source exception during registering prerequisite. This is probably bug.",e);
64     }
65
66     private void tryToResolve() throws InferenceException {
67         if(action == null) {
68             return; // Action was not yet defined
69         }
70         if(removeSatisfied()) {
71             applyAction();
72         }
73     }
74
75     private boolean removeSatisfied() {
76         Iterator<AbstractPrerequisite<?>> prereq = unsatisfied.iterator();
77         boolean allSatisfied = true;
78         while(prereq.hasNext()) {
79             if(prereq.next().isDone()) {
80                 prereq.remove(); // We are removing current prerequisite from list.
81             } else {
82                 allSatisfied  = false;
83             }
84         }
85         return allSatisfied;
86     }
87
88     ModelProcessingPhase getPhase() {
89         return phase;
90     }
91
92     boolean isApplied() {
93
94         return actionApplied;
95     }
96
97     void failModifier() throws InferenceException {
98         removeSatisfied();
99         action.prerequisiteFailed(unsatisfied);
100         action = null;
101     }
102
103     private void applyAction() throws InferenceException {
104
105         action.apply();
106         // Mark all mutations as performed, so context node could move to next.
107         actionApplied = true;
108     }
109
110     @SuppressWarnings({ "unchecked", "rawtypes" })
111     private <K, C extends StmtContext<?,?,?>, N extends StatementNamespace<K, ?, ?>> AbstractPrerequisite<C> requiresCtxImpl(StmtContext<?, ?, ?> context, Class<N> namespace, K key,ModelProcessingPhase phase)  {
112         checkNotRegistered();
113         try {
114             AddedToNamespace<C> addedToNs = new AddedToNamespace<C>(phase);
115             addReq(addedToNs);
116             contextImpl(context).onNamespaceItemAddedAction((Class) namespace,key,addedToNs);
117             return addedToNs;
118         } catch (SourceException e) {
119             throw shouldNotHappenProbablyBug(e);
120         }
121     }
122
123     private <C extends StmtContext<?, ?, ?>> AbstractPrerequisite<C> requiresCtxImpl(C context, ModelProcessingPhase phase) {
124         Preconditions.checkState(action == null, "Action was already registered.");
125         try {
126             PhaseFinished<C> phaseFin = new PhaseFinished<C>();
127             addReq(phaseFin);
128             contextImpl(context).addPhaseCompletedListener(FullDeclaration,phaseFin);
129             return phaseFin;
130         } catch (SourceException e) {
131             throw shouldNotHappenProbablyBug(e);
132         }
133     }
134
135     @SuppressWarnings({ "rawtypes", "unchecked" })
136     private <K, C extends StmtContext.Mutable<?, ?, ?> , N extends StatementNamespace<K, ?, ? >> AbstractPrerequisite<C> mutatesCtxImpl(
137                 StmtContext<?, ?, ?> context, Class<N> namespace, K key, ModelProcessingPhase phase) {
138             try {
139                 PhaseModificationInNamespace<C> mod = new PhaseModificationInNamespace<C>(phase);
140                 addMutation(mod);
141                 contextImpl(context).onNamespaceItemAddedAction((Class) namespace,key,mod);
142                 return mod;
143             } catch (SourceException e) {
144                 throw shouldNotHappenProbablyBug(e);
145             }
146         }
147
148     private static StatementContextBase<?,?,?> contextImpl(StmtContext<?,?,?> context) {
149         Preconditions.checkArgument(context instanceof StatementContextBase,"Supplied context was not provided by this reactor.");
150         return StatementContextBase.class.cast(context);
151     }
152
153     @Override
154     public <C extends Mutable<?, ?, ?>, CT extends C> Prerequisite<C> mutatesCtx(CT context, ModelProcessingPhase phase) {
155         try {
156             return addMutation(new PhaseMutation<C>(contextImpl(context),phase));
157         } catch (InferenceException e) {
158             throw shouldNotHappenProbablyBug(e);
159         }
160     }
161
162     @Override
163     public  <A,D extends DeclaredStatement<A>,E extends EffectiveStatement<A, D>> AbstractPrerequisite<StmtContext<A, D, E>> requiresCtx(StmtContext<A, D, E> context, ModelProcessingPhase phase) {
164         return requiresCtxImpl(context, phase);
165     }
166
167
168     @Override
169     public <K, N extends StatementNamespace<K, ?, ? >> Prerequisite<StmtContext<?,?,?>> requiresCtx(StmtContext<?, ?, ?> context, Class<N> namespace, K key, ModelProcessingPhase phase) {
170         return requiresCtxImpl(context, namespace, key, phase);
171     }
172
173     @Override
174     public <D extends DeclaredStatement<?>> Prerequisite<D> requiresDeclared(StmtContext<?, ? extends D, ?> context) {
175         return requiresCtxImpl(context,FullDeclaration).transform(StmtContextUtils.<D>buildDeclared());
176     }
177
178     @Override
179     public <K, D extends DeclaredStatement<?>, N extends StatementNamespace<K, ? extends D, ?>> AbstractPrerequisite<StmtContext<?, D, ?>> requiresDeclaredCtx(
180             StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
181         return requiresCtxImpl(context, namespace, key,FullDeclaration);
182     }
183
184     @Override
185     public <K, D extends DeclaredStatement<?>, N extends StatementNamespace<K, ? extends D, ?>> Prerequisite<D> requiresDeclared(
186             StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
187         final AbstractPrerequisite<StmtContext<?,D,?>> rawContext = requiresCtxImpl(context, namespace, key,FullDeclaration);
188         return rawContext.transform(StmtContextUtils.<D>buildDeclared());
189     }
190
191     @Override
192     public <E extends EffectiveStatement<?, ?>> Prerequisite<E> requiresEffective(StmtContext<?, ?, ? extends E> stmt) {
193         return requiresCtxImpl(stmt,EffectiveModel).transform(StmtContextUtils.<E>buildEffective());
194     }
195
196     @Override
197     public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> AbstractPrerequisite<StmtContext<?, ?, E>> requiresEffectiveCtx(
198             StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
199         return requiresCtxImpl(contextImpl(context),namespace,key,EffectiveModel);
200     }
201
202     @Override
203     public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> Prerequisite<E> requiresEffective(
204             StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
205         final AbstractPrerequisite<StmtContext<?,?,E>> rawContext = requiresCtxImpl(context, namespace, key,EffectiveModel);
206         return rawContext.transform(StmtContextUtils.<E>buildEffective());
207     }
208
209
210     @Override
211     public <N extends IdentifierNamespace<?, ?>> Prerequisite<Mutable<?, ?, ?>> mutatesNs(Mutable<?, ?, ?> context,
212             Class<N> namespace) {
213         try {
214             return addMutation(new NamespaceMutation<N>(contextImpl(context),namespace));
215         } catch (SourceException e) {
216             throw shouldNotHappenProbablyBug(e);
217         }
218     }
219
220     @Override
221     public <T extends Mutable<?, ?, ?>> Prerequisite<T> mutatesEffectiveCtx(T stmt) {
222         return mutatesCtx(stmt, EffectiveModel);
223     }
224
225
226    @Override
227     public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> AbstractPrerequisite<Mutable<?, ?, E>> mutatesEffectiveCtx(
228             StmtContext<?, ?, ?> context, Class<N> namespace, K key) {
229         return mutatesCtxImpl(context, namespace, key, EffectiveModel);
230     }
231
232
233
234     @Override
235     public void apply(InferenceAction action) throws InferenceException {
236         this.action = Preconditions.checkNotNull(action);
237         tryToResolve();
238     }
239
240     private abstract class AbstractPrerequisite<T> implements Prerequisite<T> {
241
242         private T value;
243         private boolean done = false;
244
245         @Override
246         public T get() {
247             Preconditions.checkState(isDone());
248             return value;
249         }
250
251         @Override
252         public boolean isDone() {
253             return done;
254         }
255
256         protected void resolvePrereq(T value) throws InferenceException {
257             Preconditions.checkState(!isDone());
258             this.value = value;
259             this.done = true;
260             tryToResolve();
261         }
262
263         protected <O> Prerequisite<O> transform(final Function<? super T,O> transformation) {
264
265             return new Prerequisite<O>() {
266
267                 @Override
268                 public O get() {
269                     return transformation.apply(AbstractPrerequisite.this.get());
270                 }
271
272                 @Override
273                 public boolean isDone() {
274                     return AbstractPrerequisite.this.isDone();
275                 }
276
277             };
278         }
279
280     }
281
282     private class PhaseMutation<C> extends AbstractPrerequisite<C> implements ContextMutation {
283
284         @SuppressWarnings("unchecked")
285         public PhaseMutation(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase) throws InferenceException {
286             context.addMutation(phase, this);
287             resolvePrereq((C) context);
288         }
289
290         @Override
291         public boolean isFinished() {
292             return isApplied();
293         }
294
295
296     }
297     private class PhaseFinished<C extends StmtContext<?, ?, ?>> extends AbstractPrerequisite<C> implements OnPhaseFinished {
298
299         @SuppressWarnings("unchecked")
300         @Override
301         public void phaseFinished(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase) throws SourceException {
302             resolvePrereq((C) (context));
303         }
304     }
305
306     private class NamespaceMutation<N extends IdentifierNamespace<?,?>> extends  AbstractPrerequisite<StmtContext.Mutable<?, ?, ?>>  {
307
308         public NamespaceMutation(StatementContextBase<?, ?, ?> ctx, Class<N> namespace) throws InferenceException {
309             resolvePrereq(ctx);
310         }
311
312     }
313
314     private class AddedToNamespace<C extends StmtContext<?,?,?>> extends  AbstractPrerequisite<C> implements OnNamespaceItemAdded,OnPhaseFinished {
315
316         private final ModelProcessingPhase phase;
317
318         public <K, N extends StatementNamespace<K, ?, ?>> AddedToNamespace(ModelProcessingPhase phase) {
319             this.phase = phase;
320         }
321
322         @Override
323         public void namespaceItemAdded(StatementContextBase<?, ?, ?> context, Class<?> namespace, Object key,
324                 Object value) throws SourceException {
325             StatementContextBase<?, ?, ?> targetContext = (StatementContextBase<?, ?, ?>) value;
326             targetContext.addPhaseCompletedListener(phase, this);
327         }
328
329         @SuppressWarnings("unchecked")
330         @Override
331         public void phaseFinished(StatementContextBase<?, ?, ?> context, ModelProcessingPhase phase) throws SourceException {
332             resolvePrereq((C) context);
333         }
334
335     }
336
337     private class PhaseModificationInNamespace<C extends Mutable<?,?,?>> extends AbstractPrerequisite<C> implements OnNamespaceItemAdded, ContextMutation {
338
339         private final ModelProcessingPhase modPhase;
340
341         public <K, N extends StatementNamespace<K, ?, ?>> PhaseModificationInNamespace(ModelProcessingPhase phase) throws SourceException {
342             Preconditions.checkArgument(phase != null, "Model processing phase must not be null");
343             this.modPhase = phase;
344         }
345
346         @SuppressWarnings("unchecked")
347         @Override
348         public void namespaceItemAdded(StatementContextBase<?, ?, ?> context, Class<?> namespace, Object key,
349                 Object value) throws SourceException {
350             context.addMutation(modPhase,this);
351             resolvePrereq((C) context);
352         }
353
354         @Override
355         public boolean isFinished() {
356             return isApplied();
357         }
358     }
359
360 }