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