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