Optimize ModifierImpl.AbstractPrerequisite
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / ModifierImpl.java
index d8e74317d19cd00c14063da386625dfde24761aa..486ebf469dfa8ec8e0f81d6445b44871d7b15a75 100644 (file)
@@ -16,8 +16,10 @@ import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPha
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.MoreObjects.ToStringHelper;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Set;
 import java.util.function.Function;
 import org.eclipse.jdt.annotation.NonNull;
@@ -39,13 +41,13 @@ import org.slf4j.LoggerFactory;
 final class ModifierImpl implements ModelActionBuilder {
     private static final Logger LOG = LoggerFactory.getLogger(ModifierImpl.class);
 
-    private final InferenceContext ctx = new InferenceContext() { };
-
     private final Set<AbstractPrerequisite<?>> unsatisfied = new HashSet<>(1);
     private final Set<AbstractPrerequisite<?>> mutations = new HashSet<>(1);
+    private final InferenceContext ctx = new InferenceContext() { };
 
+    private List<Runnable> bootstraps;
     private InferenceAction action;
-    private boolean actionApplied = false;
+    private boolean actionApplied;
 
     private <D> AbstractPrerequisite<D> addReq(final AbstractPrerequisite<D> prereq) {
         LOG.trace("Modifier {} adding prerequisite {}", this, prereq);
@@ -91,7 +93,7 @@ final class ModifierImpl implements ModelActionBuilder {
                     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;
@@ -102,7 +104,7 @@ final class ModifierImpl implements ModelActionBuilder {
                     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;
@@ -112,9 +114,9 @@ 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;
     }
 
@@ -124,7 +126,7 @@ final class ModifierImpl implements ModelActionBuilder {
                     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);
@@ -153,7 +155,7 @@ 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
@@ -163,7 +165,6 @@ final class ModifierImpl implements ModelActionBuilder {
         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,
@@ -178,6 +179,18 @@ final class ModifierImpl implements ModelActionBuilder {
         return requiresCtxImpl(context, namespace, criterion, phase);
     }
 
+    @Override
+    public <K, E extends EffectiveStatement<?, ?>, N extends ParserNamespace<K, ? extends StmtContext<?, ?, ?>>>
+            Prerequisite<StmtContext<?, ?, E>> requiresCtxPath(final StmtContext<?, ?, ?> context,
+                final Class<N> namespace, final Iterable<K> keys, final ModelProcessingPhase phase) {
+        checkNotRegistered();
+
+        final var ret = new PhaseRequirementInNamespacePath<StmtContext<?, ?, E>, K, N>(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) {
@@ -229,7 +242,7 @@ final class ModifierImpl implements ModelActionBuilder {
     @Deprecated
     public <N extends ParserNamespace<?, ?>> Prerequisite<Mutable<?, ?, ?>> mutatesNs(final Mutable<?, ?, ?> context,
             final Class<N> namespace) {
-        return addMutation(new NamespaceMutation<>(contextImpl(context), namespace));
+        return addMutation(new NamespaceMutation<>(this, contextImpl(context), namespace));
     }
 
     @Override
@@ -245,12 +258,10 @@ final class ModifierImpl implements ModelActionBuilder {
                     final Class<N> 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, N>(this, EFFECTIVE_MODEL, keys);
         addReq(ret);
         addMutation(ret);
-
-        ret.hookOnto(context, namespace);
+        addBootstrap(() -> ret.hookOnto(context, namespace));
         return ret;
     }
 
@@ -259,17 +270,34 @@ final class ModifierImpl implements ModelActionBuilder {
     public void apply(final InferenceAction action) {
         checkState(this.action == null, "Action already defined to %s", this.action);
         this.action = requireNonNull(action);
+        if (bootstraps != null) {
+            bootstraps.forEach(Runnable::run);
+            bootstraps = null;
+        }
+    }
+
+    private void addBootstrap(final Runnable bootstrap) {
+        if (bootstraps == null) {
+            bootstraps = new ArrayList<>(1);
+        }
+        bootstraps.add(bootstrap);
     }
 
-    private abstract class AbstractPrerequisite<T> implements Prerequisite<T> {
+    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);
         }
 
@@ -281,7 +309,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) {
@@ -298,41 +326,111 @@ final class ModifierImpl implements ModelActionBuilder {
         }
     }
 
-    private final class PhaseMutation<C> extends AbstractPrerequisite<C> implements ContextMutation {
+    private abstract static class AbstractPathPrerequisite<C extends StmtContext<?, ?, ?>, K,
+            N extends ParserNamespace<K, ? extends StmtContext<?, ?, ?>>> 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 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);
+                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 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);
+        }
+    }
+
+    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<?, ?>>
+    private static final class NamespaceMutation<N extends ParserNamespace<?, ?>>
             extends AbstractPrerequisite<Mutable<?, ?, ?>>  {
-        NamespaceMutation(final StatementContextBase<?, ?, ?> ctx, final Class<N> namespace) {
+        NamespaceMutation(final ModifierImpl modifier, final StatementContextBase<?, ?, ?> ctx,
+                final Class<N> 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);
         }
 
@@ -346,7 +444,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
@@ -355,11 +453,26 @@ final class ModifierImpl implements ModelActionBuilder {
         }
     }
 
-    private final class PhaseModificationInNamespace<C extends Mutable<?, ?, ?>> extends AbstractPrerequisite<C>
+    private static final class PhaseRequirementInNamespacePath<C extends StmtContext<?, ?, ?>, K,
+            N extends ParserNamespace<K, ? extends StmtContext<?, ?, ?>>> extends AbstractPathPrerequisite<C, K, N> {
+        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;
         }
@@ -375,7 +488,7 @@ final class ModifierImpl implements ModelActionBuilder {
 
         @Override
         public boolean isFinished() {
-            return isApplied();
+            return modifier.isApplied();
         }
     }
 
@@ -384,68 +497,27 @@ 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,
+            N extends ParserNamespace<K, ? extends StmtContext<?, ?, ?>>> extends AbstractPathPrerequisite<C, K, N>
+            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);
         }
     }
 }