Optimize ModifierImpl.AbstractPrerequisite
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / ModifierImpl.java
index d3c398996a84f3f6f84f0a08db4e89d632a5b4da..d857e2b2533cdc574865fbb2f4fb431704a180c0 100644 (file)
@@ -29,7 +29,6 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace;
-import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 import org.opendaylight.yangtools.yang.parser.stmt.reactor.StatementContextBase.ContextMutation;
@@ -88,23 +87,23 @@ final class ModifierImpl implements ModelActionBuilder {
         action = null;
     }
 
-    private <K, C extends StmtContext<?, ?, ?>, N extends StatementNamespace<K, ?, ?>> @NonNull AbstractPrerequisite<C>
-            requiresCtxImpl(final StmtContext<?, ?, ?> context, final Class<N> namespace, final K key,
-                    final ModelProcessingPhase phase)  {
+    private <K, C extends StmtContext<?, ?, ?>> @NonNull AbstractPrerequisite<C> requiresCtxImpl(
+            final StmtContext<?, ?, ?> context, final ParserNamespace<K, C> namespace, final K key,
+            final ModelProcessingPhase phase)  {
         checkNotRegistered();
 
-        AddedToNamespace<C> addedToNs = new AddedToNamespace<>(phase);
+        final var addedToNs = new AddedToNamespace<C>(this, phase);
         addReq(addedToNs);
         contextImpl(context).onNamespaceItemAddedAction(namespace, key, addedToNs);
         return addedToNs;
     }
 
-    private <K, C extends StmtContext<?, ?, ?>, N extends StatementNamespace<K, ?, ?>> @NonNull AbstractPrerequisite<C>
-            requiresCtxImpl(final StmtContext<?, ?, ?> context, final Class<N> namespace,
-                    final NamespaceKeyCriterion<K> criterion, final ModelProcessingPhase phase)  {
+    private <K, C extends StmtContext<?, ?, ?>> @NonNull AbstractPrerequisite<C> requiresCtxImpl(
+            final StmtContext<?, ?, ?> context, final ParserNamespace<K, C> namespace,
+            final NamespaceKeyCriterion<K> criterion, final ModelProcessingPhase phase)  {
         checkNotRegistered();
 
-        AddedToNamespace<C> addedToNs = new AddedToNamespace<>(phase);
+        final var addedToNs = new AddedToNamespace<C>(this, phase);
         addReq(addedToNs);
         contextImpl(context).onNamespaceItemAddedAction(namespace, phase, criterion, addedToNs);
         return addedToNs;
@@ -114,22 +113,22 @@ final class ModifierImpl implements ModelActionBuilder {
             final ModelProcessingPhase phase) {
         checkNotRegistered();
 
-        PhaseFinished<C> phaseFin = new PhaseFinished<>();
+        final var phaseFin = new PhaseFinished<C>(this);
         addReq(phaseFin);
-        contextImpl(context).addPhaseCompletedListener(phase, phaseFin);
+        addBootstrap(() -> contextImpl(context).addPhaseCompletedListener(phase, phaseFin));
         return phaseFin;
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    private <K, C extends Mutable<?, ?, ?>, N extends ParserNamespace<K, ? extends StmtContext<?, ?, ?>>>
-            AbstractPrerequisite<C> mutatesCtxImpl(final StmtContext<?, ?, ?> context, final Class<N> namespace,
-                    final K key, final ModelProcessingPhase phase) {
+    private <K, C extends Mutable<?, ?, ?>> AbstractPrerequisite<C> mutatesCtxImpl(final StmtContext<?, ?, ?> context,
+            final ParserNamespace<K, ? extends StmtContext<?, ?, ?>> namespace, final K key,
+            final ModelProcessingPhase phase) {
         checkNotRegistered();
 
-        final PhaseModificationInNamespace<C> mod = new PhaseModificationInNamespace<>(EFFECTIVE_MODEL);
+        final var mod = new PhaseModificationInNamespace<C>(this, EFFECTIVE_MODEL);
         addReq(mod);
         addMutation(mod);
-        contextImpl(context).onNamespaceItemAddedAction((Class) namespace, key, mod);
+        contextImpl(context).onNamespaceItemAddedAction((ParserNamespace) namespace, key, mod);
         return mod;
     }
 
@@ -155,31 +154,40 @@ final class ModifierImpl implements ModelActionBuilder {
     @Override
     public <C extends Mutable<?, ?, ?>, T extends C> Prerequisite<C> mutatesCtx(final T context,
             final ModelProcessingPhase phase) {
-        return addMutation(new PhaseMutation<>(contextImpl(context), phase));
+        return addMutation(new PhaseMutation<>(this, contextImpl(context), phase));
     }
 
     @Override
     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) {
+                final ModelProcessingPhase phase) {
         return requiresCtxImpl(context, phase);
     }
 
-
     @Override
-    public <K, N extends StatementNamespace<K, ?, ?>> Prerequisite<StmtContext<?, ?, ?>> requiresCtx(
-            final StmtContext<?, ?, ?> context, final Class<@NonNull N> namespace, final K key,
-            final ModelProcessingPhase phase) {
+    public <K, C extends StmtContext<?, ?, ?>> Prerequisite<C> requiresCtx(final StmtContext<?, ?, ?> context,
+            final ParserNamespace<K, C> namespace, final K key, final ModelProcessingPhase phase) {
         return requiresCtxImpl(context, namespace, key, phase);
     }
 
     @Override
-    public <K, N extends StatementNamespace<K, ?, ?>> Prerequisite<StmtContext<?, ?, ?>> requiresCtx(
-            final StmtContext<?, ?, ?> context, final Class<@NonNull N> namespace,
-            final NamespaceKeyCriterion<K> criterion, final ModelProcessingPhase phase) {
+    public <K, C extends StmtContext<?, ?, ?>> Prerequisite<C> requiresCtx(final StmtContext<?, ?, ?> context,
+            final ParserNamespace<K, C> namespace, final NamespaceKeyCriterion<K> criterion,
+            final ModelProcessingPhase phase) {
         return requiresCtxImpl(context, namespace, criterion, phase);
     }
 
+    @Override
+    public <K, C extends StmtContext<?, ?, ?>> Prerequisite<C> requiresCtxPath(final StmtContext<?, ?, ?> context,
+            final ParserNamespace<K, C> namespace, final Iterable<K> keys, final ModelProcessingPhase phase) {
+        checkNotRegistered();
+
+        final var ret = new PhaseRequirementInNamespacePath<C, K>(this, EFFECTIVE_MODEL, keys);
+        addReq(ret);
+        addBootstrap(() -> ret.hookOnto(context, namespace));
+        return ret;
+    }
+
     @Override
     public <D extends DeclaredStatement<?>> Prerequisite<D> requiresDeclared(
             final StmtContext<?, ? extends D, ?> context) {
@@ -188,18 +196,15 @@ final class ModifierImpl implements ModelActionBuilder {
 
     @Override
     @Deprecated
-    public <K, D extends DeclaredStatement<?>, N extends StatementNamespace<K, ? extends D, ?>> Prerequisite<D>
-            requiresDeclared(final StmtContext<?, ?, ?> context, final Class<N> namespace, final K key) {
-        final AbstractPrerequisite<StmtContext<?, D, ?>> rawContext = requiresCtxImpl(context, namespace, key,
-            FULL_DECLARATION);
-        return rawContext.transform(StmtContext::declared);
+    public <K, D extends DeclaredStatement<?>> Prerequisite<D> requiresDeclared(final StmtContext<?, ?, ?> context,
+            final ParserNamespace<K, StmtContext<?, ? extends D, ?>> namespace, final K key) {
+        return requiresCtxImpl(context, namespace, key, FULL_DECLARATION).transform(StmtContext::declared);
     }
 
     @Override
     @Deprecated
-    public <K, D extends DeclaredStatement<?>, N extends StatementNamespace<K, ? extends D, ?>>
-            AbstractPrerequisite<StmtContext<?, D, ?>> requiresDeclaredCtx(final StmtContext<?, ?, ?> context,
-                    final Class<N> namespace, final K key) {
+    public <K, C extends StmtContext<?, ?, ?>> AbstractPrerequisite<C> requiresDeclaredCtx(
+            final StmtContext<?, ?, ?> context, final ParserNamespace<K, C> namespace, final K key) {
         return requiresCtxImpl(context, namespace, key, FULL_DECLARATION);
     }
 
@@ -212,50 +217,42 @@ final class ModifierImpl implements ModelActionBuilder {
 
     @Override
     @Deprecated
-    public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>> Prerequisite<E>
-            requiresEffective(final StmtContext<?, ?, ?> context, final Class<N> namespace, final K key) {
-        final AbstractPrerequisite<StmtContext<?, ?, E>> rawContext = requiresCtxImpl(context, namespace, key,
-            EFFECTIVE_MODEL);
-        return rawContext.transform(StmtContext::buildEffective);
+    public <K, E extends EffectiveStatement<?, ?>> Prerequisite<E> requiresEffective(final StmtContext<?, ?, ?> context,
+            final ParserNamespace<K, StmtContext<?, ?, ? extends E>> namespace, final K key) {
+        return requiresCtxImpl(context, namespace, key, EFFECTIVE_MODEL).transform(StmtContext::buildEffective);
     }
 
     @Override
     @Deprecated
-    public <K, E extends EffectiveStatement<?, ?>, N extends StatementNamespace<K, ?, ? extends E>>
-            AbstractPrerequisite<StmtContext<?, ?, E>> requiresEffectiveCtx(final StmtContext<?, ?, ?> context,
-                    final Class<N> namespace, final K key) {
+    public <K, C extends StmtContext<?, ?, ?>> AbstractPrerequisite<C> requiresEffectiveCtx(
+            final StmtContext<?, ?, ?> context, final ParserNamespace<K, C> namespace, final K key) {
         return requiresCtxImpl(contextImpl(context), namespace, key, EFFECTIVE_MODEL);
     }
 
     @Override
     @Deprecated
-    public <N extends ParserNamespace<?, ?>> Prerequisite<Mutable<?, ?, ?>> mutatesNs(final Mutable<?, ?, ?> context,
-            final Class<N> namespace) {
-        return addMutation(new NamespaceMutation<>(contextImpl(context), namespace));
+    public Prerequisite<Mutable<?, ?, ?>> mutatesNs(final Mutable<?, ?, ?> context,
+            final ParserNamespace<?, ?> namespace) {
+        return addMutation(new NamespaceMutation(this, contextImpl(context), namespace));
     }
 
     @Override
-    public <K, E extends EffectiveStatement<?, ?>, N extends ParserNamespace<K, ? extends StmtContext<?, ?, ?>>>
-            AbstractPrerequisite<Mutable<?, ?, E>> mutatesEffectiveCtx(final StmtContext<?, ?, ?> context,
-                    final Class<N> namespace, final K key) {
+    public <K, E extends EffectiveStatement<?, ?>> AbstractPrerequisite<Mutable<?, ?, E>> mutatesEffectiveCtx(
+            final StmtContext<?, ?, ?> context, final ParserNamespace<K, ? extends StmtContext<?, ?, ?>> namespace,
+            final K key) {
         return mutatesCtxImpl(context, namespace, key, EFFECTIVE_MODEL);
     }
 
     @Override
-    public <K, E extends EffectiveStatement<?, ?>, N extends ParserNamespace<K, ? extends StmtContext<?, ?, ?>>>
-            AbstractPrerequisite<Mutable<?, ?, E>> mutatesEffectiveCtxPath(final StmtContext<?, ?, ?> context,
-                    final Class<N> namespace, final Iterable<K> keys) {
+    public <K, E extends EffectiveStatement<?, ?>> AbstractPrerequisite<Mutable<?, ?, E>> mutatesEffectiveCtxPath(
+            final StmtContext<?, ?, ?> context, final ParserNamespace<K, ? extends StmtContext<?, ?, ?>> namespace,
+            final Iterable<K> keys) {
         checkNotRegistered();
 
-        final PhaseModificationInNamespacePath<Mutable<?, ?, E>, K, N> ret = new PhaseModificationInNamespacePath<>(
-                EFFECTIVE_MODEL, keys);
+        final var ret = new PhaseModificationInNamespacePath<Mutable<?, ?, E>, K>(this, EFFECTIVE_MODEL, keys);
         addReq(ret);
         addMutation(ret);
-
-        if (bootstraps == null) {
-            bootstraps = new ArrayList<>(1);
-        }
-        bootstraps.add(() -> ret.hookOnto(context, namespace));
+        addBootstrap(() -> ret.hookOnto(context, namespace));
         return ret;
     }
 
@@ -270,15 +267,28 @@ final class ModifierImpl implements ModelActionBuilder {
         }
     }
 
-    private abstract class AbstractPrerequisite<T> implements Prerequisite<T> {
+    private void addBootstrap(final Runnable bootstrap) {
+        if (bootstraps == null) {
+            bootstraps = new ArrayList<>(1);
+        }
+        bootstraps.add(bootstrap);
+    }
+
+    private abstract static class AbstractPrerequisite<T> implements Prerequisite<T> {
+        final @NonNull ModifierImpl modifier;
+
         private boolean done = false;
         private T value;
 
+        AbstractPrerequisite(final ModifierImpl modifier) {
+            this.modifier = requireNonNull(modifier);
+        }
+
         @Override
         @SuppressWarnings("checkstyle:hiddenField")
         public final T resolve(final InferenceContext ctx) {
             checkState(done);
-            checkArgument(ctx == ModifierImpl.this.ctx);
+            checkArgument(ctx == modifier.ctx);
             return verifyNotNull(value, "Attempted to access unavailable prerequisite %s", this);
         }
 
@@ -290,7 +300,7 @@ final class ModifierImpl implements ModelActionBuilder {
         final boolean resolvePrereq(final T value) {
             this.value = value;
             this.done = true;
-            return isApplied();
+            return modifier.isApplied();
         }
 
         final <O> @NonNull Prerequisite<O> transform(final Function<? super T, O> transformation) {
@@ -307,47 +317,116 @@ final class ModifierImpl implements ModelActionBuilder {
         }
     }
 
-    private final class PhaseMutation<C> extends AbstractPrerequisite<C> implements ContextMutation {
+    private abstract static class AbstractPathPrerequisite<C extends StmtContext<?, ?, ?>, K>
+            extends AbstractPrerequisite<C> implements OnNamespaceItemAdded {
+        private final ModelProcessingPhase modPhase;
+        private final Iterable<K> keys;
+        private final Iterator<K> it;
+
+        AbstractPathPrerequisite(final ModifierImpl modifier, final ModelProcessingPhase phase,
+                final Iterable<K> keys) {
+            super(modifier);
+            this.modPhase = requireNonNull(phase);
+            this.keys = requireNonNull(keys);
+            it = keys.iterator();
+        }
+
+        @Override
+        public final void namespaceItemAdded(final StatementContextBase<?, ?, ?> context,
+                final ParserNamespace<?, ?> namespace, final Object key, final Object value) {
+            LOG.debug("Action for {} got key {}", keys, key);
+
+            final StatementContextBase<?, ?, ?> target = contextImpl(value);
+            if (!target.isSupportedByFeatures()) {
+                LOG.debug("Key {} in {} is not supported", key, keys);
+                resolvePrereq(null);
+                modifier.action.prerequisiteUnavailable(this);
+                return;
+            }
+
+            nextStep(modPhase, context, target);
+
+            if (!it.hasNext()) {
+                // Last step: we are done
+                if (resolvePrereq((C) value)) {
+                    modifier.tryApply();
+                }
+                return;
+            }
+
+            // Make sure target's storage notifies us when the next step becomes available.
+            hookOnto(target, namespace, it.next());
+        }
+
+        abstract void nextStep(ModelProcessingPhase phase, StatementContextBase<?, ?, ?> current,
+            StatementContextBase<?, ?, ?> next);
+
+        @Override
+        final ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
+            return super.addToStringAttributes(toStringHelper).add("phase", modPhase).add("keys", keys);
+        }
+
+        final void hookOnto(final StmtContext<?, ?, ?> context, final ParserNamespace<?, ?> namespace) {
+            checkArgument(it.hasNext(), "Namespace %s keys may not be empty", namespace);
+            hookOnto(contextImpl(context), namespace, it.next());
+        }
+
+        @SuppressWarnings("unchecked")
+        private void hookOnto(final StatementContextBase<?, ?, ?> context, final ParserNamespace<?, ?> namespace,
+                final K key) {
+            context.onNamespaceItemAddedAction((ParserNamespace) namespace, requireNonNull(key), this);
+        }
+    }
+
+    private static final class PhaseMutation<C> extends AbstractPrerequisite<C> implements ContextMutation {
         @SuppressWarnings("unchecked")
-        PhaseMutation(final StatementContextBase<?, ?, ?> context, final ModelProcessingPhase phase) {
+        PhaseMutation(final ModifierImpl modifier, final StatementContextBase<?, ?, ?> context,
+                final ModelProcessingPhase phase) {
+            super(modifier);
             context.addMutation(phase, this);
             resolvePrereq((C) context);
         }
 
         @Override
         public boolean isFinished() {
-            return isApplied();
+            return modifier.isApplied();
         }
     }
 
-    private final class PhaseFinished<C extends StmtContext<?, ?, ?>> extends AbstractPrerequisite<C>
+    private static final class PhaseFinished<C extends StmtContext<?, ?, ?>> extends AbstractPrerequisite<C>
             implements OnPhaseFinished {
+        PhaseFinished(final ModifierImpl modifier) {
+            super(modifier);
+        }
+
         @SuppressWarnings("unchecked")
         @Override
         public boolean phaseFinished(final StatementContextBase<?, ?, ?> context,
                 final ModelProcessingPhase finishedPhase) {
-            return resolvePrereq((C) context) || tryApply();
+            return resolvePrereq((C) context) || modifier.tryApply();
         }
     }
 
-    private final class NamespaceMutation<N extends ParserNamespace<?, ?>>
-            extends AbstractPrerequisite<Mutable<?, ?, ?>>  {
-        NamespaceMutation(final StatementContextBase<?, ?, ?> ctx, final Class<N> namespace) {
+    private static final class NamespaceMutation extends AbstractPrerequisite<Mutable<?, ?, ?>> {
+        NamespaceMutation(final ModifierImpl modifier, final StatementContextBase<?, ?, ?> ctx,
+                final ParserNamespace<?, ?> namespace) {
+            super(modifier);
             resolvePrereq(ctx);
         }
     }
 
-    private final class AddedToNamespace<C extends StmtContext<?, ?, ?>> extends AbstractPrerequisite<C>
+    private static final class AddedToNamespace<C extends StmtContext<?, ?, ?>> extends AbstractPrerequisite<C>
             implements OnNamespaceItemAdded, OnPhaseFinished {
         private final ModelProcessingPhase phase;
 
-        AddedToNamespace(final ModelProcessingPhase phase) {
+        AddedToNamespace(final ModifierImpl modifier, final ModelProcessingPhase phase) {
+            super(modifier);
             this.phase = requireNonNull(phase);
         }
 
         @Override
-        public void namespaceItemAdded(final StatementContextBase<?, ?, ?> context, final Class<?> namespace,
-                final Object key, final Object value) {
+        public void namespaceItemAdded(final StatementContextBase<?, ?, ?> context,
+                final ParserNamespace<?, ?> namespace, final Object key, final Object value) {
             ((StatementContextBase<?, ?, ?>) value).addPhaseCompletedListener(phase, this);
         }
 
@@ -355,7 +434,7 @@ final class ModifierImpl implements ModelActionBuilder {
         @Override
         public boolean phaseFinished(final StatementContextBase<?, ?, ?> context,
                 final ModelProcessingPhase finishedPhase) {
-            return resolvePrereq((C) context) || tryApply();
+            return resolvePrereq((C) context) || modifier.tryApply();
         }
 
         @Override
@@ -364,19 +443,34 @@ final class ModifierImpl implements ModelActionBuilder {
         }
     }
 
-    private final class PhaseModificationInNamespace<C extends Mutable<?, ?, ?>> extends AbstractPrerequisite<C>
+    private static final class PhaseRequirementInNamespacePath<C extends StmtContext<?, ?, ?>, K>
+            extends AbstractPathPrerequisite<C, K> {
+        PhaseRequirementInNamespacePath(final ModifierImpl modifier, final ModelProcessingPhase phase,
+                final Iterable<K> keys) {
+            super(modifier, phase, keys);
+        }
+
+        @Override
+        void nextStep(final ModelProcessingPhase phase, final StatementContextBase<?, ?, ?> current,
+                final StatementContextBase<?, ?, ?> next) {
+            // No-op
+        }
+    }
+
+    private static final class PhaseModificationInNamespace<C extends Mutable<?, ?, ?>> extends AbstractPrerequisite<C>
             implements OnNamespaceItemAdded, ContextMutation {
         private final ModelProcessingPhase modPhase;
 
-        PhaseModificationInNamespace(final ModelProcessingPhase phase) {
+        PhaseModificationInNamespace(final ModifierImpl modifier, final ModelProcessingPhase phase) {
+            super(modifier);
             checkArgument(phase != null, "Model processing phase must not be null");
             this.modPhase = phase;
         }
 
         @SuppressWarnings("unchecked")
         @Override
-        public void namespaceItemAdded(final StatementContextBase<?, ?, ?> context, final Class<?> namespace,
-                final Object key, final Object value) {
+        public void namespaceItemAdded(final StatementContextBase<?, ?, ?> context,
+                final ParserNamespace<?, ?> namespace, final Object key, final Object value) {
             StatementContextBase<?, ?, ?> targetCtx = contextImpl(value);
             targetCtx.addMutation(modPhase, this);
             resolvePrereq((C) targetCtx);
@@ -384,7 +478,7 @@ final class ModifierImpl implements ModelActionBuilder {
 
         @Override
         public boolean isFinished() {
-            return isApplied();
+            return modifier.isApplied();
         }
     }
 
@@ -393,68 +487,26 @@ final class ModifierImpl implements ModelActionBuilder {
      * target. The mechanics is driven as a sequence of prerequisites along a path: first we hook onto namespace to
      * give us the first step. When it does, we hook onto the first item to provide us the second step and so on.
      */
-    private final class PhaseModificationInNamespacePath<C extends Mutable<?, ?, ?>, K,
-            N extends ParserNamespace<K, ? extends StmtContext<?, ?, ?>>> extends AbstractPrerequisite<C>
-            implements OnNamespaceItemAdded, ContextMutation {
-        private final ModelProcessingPhase modPhase;
-        private final Iterable<K> keys;
-        private final Iterator<K> it;
-
-        PhaseModificationInNamespacePath(final ModelProcessingPhase phase, final Iterable<K> keys) {
-            this.modPhase = requireNonNull(phase);
-            this.keys = requireNonNull(keys);
-            it = keys.iterator();
+    private static final class PhaseModificationInNamespacePath<C extends Mutable<?, ?, ?>, K>
+            extends AbstractPathPrerequisite<C, K> implements ContextMutation {
+        PhaseModificationInNamespacePath(final ModifierImpl modifier, final ModelProcessingPhase phase,
+                final Iterable<K> keys) {
+            super(modifier, phase, keys);
         }
 
         @Override
         public boolean isFinished() {
-            return isApplied();
+            return modifier.isApplied();
         }
 
         @Override
-        public void namespaceItemAdded(final StatementContextBase<?, ?, ?> context, final Class<?> namespace,
-                final Object key, final Object value) {
-            LOG.debug("Action for {} got key {}", keys, key);
-
-            final StatementContextBase<?, ?, ?> target = contextImpl(value);
-            if (!target.isSupportedByFeatures()) {
-                LOG.debug("Key {} in {} is not supported", key, keys);
-                resolvePrereq(null);
-                action.prerequisiteUnavailable(this);
-                return;
-            }
-
+        void nextStep(final ModelProcessingPhase phase, final StatementContextBase<?, ?, ?> current,
+                final StatementContextBase<?, ?, ?> next) {
             // Hook onto target: we either have a modification of the target itself or one of its children.
-            target.addMutation(modPhase, this);
+            next.addMutation(phase, this);
             // We have completed the context -> target step, hence we are no longer directly blocking context from
             // making forward progress.
-            context.removeMutation(modPhase, this);
-
-            if (!it.hasNext()) {
-                // Last step: we are done
-                if (resolvePrereq((C) value)) {
-                    tryApply();
-                }
-                return;
-            }
-
-            // Make sure target's storage notifies us when the next step becomes available.
-            hookOnto(target, namespace, it.next());
-        }
-
-        @Override
-        ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
-            return super.addToStringAttributes(toStringHelper).add("phase", modPhase).add("keys", keys);
-        }
-
-        void hookOnto(final StmtContext<?, ?, ?> context, final Class<?> namespace) {
-            checkArgument(it.hasNext(), "Namespace %s keys may not be empty", namespace);
-            hookOnto(contextImpl(context), namespace, it.next());
-        }
-
-        @SuppressWarnings("unchecked")
-        private void hookOnto(final StatementContextBase<?, ?, ?> context, final Class<?> namespace, final K key) {
-            context.onNamespaceItemAddedAction((Class) namespace, requireNonNull(key), this);
+            current.removeMutation(phase, this);
         }
     }
 }