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