Reformulate StatementContextFactory.createEffective()
[yangtools.git] / yang / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / StatementContextBase.java
index 02fb8d222e5f01c48c967bfd1d8b25fc280f421f..6f6119c1ff6b18492a6614f0a226af9c78fd49cc 100644 (file)
@@ -32,6 +32,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -140,7 +141,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
 
     private Multimap<ModelProcessingPhase, OnPhaseFinished> phaseListeners = ImmutableMultimap.of();
     private Multimap<ModelProcessingPhase, ContextMutation> phaseMutation = ImmutableMultimap.of();
-    private List<StatementContextBase<?, ?, ?>> effective = ImmutableList.of();
+
     private List<StmtContext<?, ?, ?>> effectOfStatement = ImmutableList.of();
 
     private @Nullable ModelProcessingPhase completedPhase;
@@ -154,9 +155,6 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     // Flag for use with AbstractResumedStatement. This is hiding in the alignment shadow created by above boolean
     private boolean fullyDefined;
 
-    // Flag for InferredStatementContext. This is hiding in the alignment shadow created by above boolean.
-    private boolean substatementsInitialized;
-
     // Flags for use with SubstatementContext. These are hiding in the alignment shadow created by above boolean and
     // hence improve memory layout.
     private byte flags;
@@ -370,24 +368,22 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, key);
     }
 
-    @Override
-    public Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements() {
-        if (effective instanceof ImmutableCollection) {
-            return effective;
-        }
-
-        return Collections.unmodifiableCollection(effective);
+    static final Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements(
+            final List<StatementContextBase<?, ?, ?>> effective) {
+        return effective instanceof ImmutableCollection ? effective : Collections.unmodifiableCollection(effective);
     }
 
-    private void shrinkEffective() {
-        if (effective.isEmpty()) {
-            effective = ImmutableList.of();
-        }
+    private static List<StatementContextBase<?, ?, ?>> shrinkEffective(
+            final List<StatementContextBase<?, ?, ?>> effective) {
+        return effective.isEmpty() ? ImmutableList.of() : effective;
     }
 
-    public void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef) {
+    public abstract void removeStatementFromEffectiveSubstatements(StatementDefinition statementDef);
+
+    static final List<StatementContextBase<?, ?, ?>> removeStatementFromEffectiveSubstatements(
+            final List<StatementContextBase<?, ?, ?>> effective, final StatementDefinition statementDef) {
         if (effective.isEmpty()) {
-            return;
+            return effective;
         }
 
         final Iterator<? extends StmtContext<?, ?, ?>> iterator = effective.iterator();
@@ -398,7 +394,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
             }
         }
 
-        shrinkEffective();
+        return shrinkEffective(effective);
     }
 
     /**
@@ -413,14 +409,18 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
      * @param statementDef statement definition of the statement context to remove
      * @param statementArg statement argument of the statement context to remove
      */
-    public void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef,
+    public abstract void removeStatementFromEffectiveSubstatements(StatementDefinition statementDef,
+            String statementArg);
+
+    static final List<StatementContextBase<?, ?, ?>> removeStatementFromEffectiveSubstatements(
+            final List<StatementContextBase<?, ?, ?>> effective, final StatementDefinition statementDef,
             final String statementArg) {
         if (statementArg == null) {
-            removeStatementFromEffectiveSubstatements(statementDef);
+            return removeStatementFromEffectiveSubstatements(effective, statementDef);
         }
 
         if (effective.isEmpty()) {
-            return;
+            return effective;
         }
 
         final Iterator<StatementContextBase<?, ?, ?>> iterator = effective.iterator();
@@ -431,7 +431,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
             }
         }
 
-        shrinkEffective();
+        return shrinkEffective(effective);
     }
 
     // YANG example: RPC/action statements always have 'input' and 'output' defined
@@ -451,21 +451,23 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
      * Adds an effective statement to collection of substatements.
      *
      * @param substatement substatement
-     * @throws IllegalStateException
-     *             if added in declared phase
-     * @throws NullPointerException
-     *             if statement parameter is null
+     * @throws IllegalStateException if added in declared phase
+     * @throws NullPointerException if statement parameter is null
      */
-    public void addEffectiveSubstatement(final Mutable<?, ?, ?> substatement) {
+    public abstract void addEffectiveSubstatement(Mutable<?, ?, ?> substatement);
+
+    final List<StatementContextBase<?, ?, ?>> addEffectiveSubstatement(
+            final List<StatementContextBase<?, ?, ?>> effective, final Mutable<?, ?, ?> substatement) {
         verifyStatement(substatement);
-        beforeAddEffectiveStatement(1);
 
+        final List<StatementContextBase<?, ?, ?>> resized = beforeAddEffectiveStatement(effective, 1);
         final StatementContextBase<?, ?, ?> stmt = (StatementContextBase<?, ?, ?>) substatement;
         final ModelProcessingPhase phase = completedPhase;
         if (phase != null) {
             ensureCompletedPhase(stmt, phase);
         }
-        effective.add(stmt);
+        resized.add(stmt);
+        return resized;
     }
 
     /**
@@ -477,27 +479,19 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
      * @throws NullPointerException
      *             if statement parameter is null
      */
-    public void addEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> statements) {
+    public final void addEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> statements) {
         if (!statements.isEmpty()) {
             statements.forEach(StatementContextBase::verifyStatement);
-            beforeAddEffectiveStatement(statements.size());
-            doAddEffectiveSubstatements(statements);
+            addEffectiveSubstatementsImpl(statements);
         }
     }
 
-    // exposed for InferredStatementContext only
-    final void addInitialEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> statements) {
-        verify(!substatementsInitialized, "Attempted to re-initialized statement {} with {}", this, statements);
-        substatementsInitialized = true;
+    abstract void addEffectiveSubstatementsImpl(Collection<? extends Mutable<?, ?, ?>> statements);
 
-        if (!statements.isEmpty()) {
-            statements.forEach(StatementContextBase::verifyStatement);
-            beforeAddEffectiveStatementUnsafe(statements.size());
-            doAddEffectiveSubstatements(statements);
-        }
-    }
-
-    private void doAddEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> statements) {
+    final List<StatementContextBase<?, ?, ?>> addEffectiveSubstatementsImpl(
+            final List<StatementContextBase<?, ?, ?>> effective,
+            final Collection<? extends Mutable<?, ?, ?>> statements) {
+        final List<StatementContextBase<?, ?, ?>> resized = beforeAddEffectiveStatement(effective, statements.size());
         final Collection<? extends StatementContextBase<?, ?, ?>> casted =
             (Collection<? extends StatementContextBase<?, ?, ?>>) statements;
         final ModelProcessingPhase phase = completedPhase;
@@ -507,7 +501,19 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
             }
         }
 
-        effective.addAll(casted);
+        resized.addAll(casted);
+        return resized;
+    }
+
+    abstract Iterable<StatementContextBase<?, ?, ?>> effectiveChildrenToComplete();
+
+    // exposed for InferredStatementContext only
+    final void ensureCompletedPhase(final Mutable<?, ?, ?> stmt) {
+        verifyStatement(stmt);
+        final ModelProcessingPhase phase = completedPhase;
+        if (phase != null) {
+            ensureCompletedPhase((StatementContextBase<?, ?, ?>) stmt, phase);
+        }
     }
 
     // Make sure target statement has transitioned at least to specified phase. This method is just before we take
@@ -522,22 +528,22 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         verify(stmt instanceof StatementContextBase, "Unexpected statement %s", stmt);
     }
 
-    private void beforeAddEffectiveStatement(final int toAdd) {
+    private List<StatementContextBase<?, ?, ?>> beforeAddEffectiveStatement(
+            final List<StatementContextBase<?, ?, ?>> effective, final int toAdd) {
         // We cannot allow statement to be further mutated
         verify(completedPhase != ModelProcessingPhase.EFFECTIVE_MODEL, "Cannot modify finished statement at %s",
             getStatementSourceReference());
-        beforeAddEffectiveStatementUnsafe(toAdd);
+        return beforeAddEffectiveStatementUnsafe(effective, toAdd);
     }
 
-    private void beforeAddEffectiveStatementUnsafe(final int toAdd) {
+    final List<StatementContextBase<?, ?, ?>> beforeAddEffectiveStatementUnsafe(
+            final List<StatementContextBase<?, ?, ?>> effective, final int toAdd) {
         final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
         checkState(inProgressPhase == ModelProcessingPhase.FULL_DECLARATION
                 || inProgressPhase == ModelProcessingPhase.EFFECTIVE_MODEL,
                 "Effective statement cannot be added in declared phase at: %s", getStatementSourceReference());
 
-        if (effective.isEmpty()) {
-            effective = new ArrayList<>(toAdd);
-        }
+        return effective.isEmpty() ? new ArrayList<>(toAdd) : effective;
     }
 
     // These two exists only due to memory optimization, should live in AbstractResumedStatement
@@ -549,15 +555,6 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         fullyDefined = true;
     }
 
-    // These two exist only due to memory optimization, should live in InferredStatementContext
-    final boolean substatementsInitialized() {
-        return substatementsInitialized;
-    }
-
-    final void setSubstatementsInitialized() {
-        substatementsInitialized = true;
-    }
-
     @Override
     public E buildEffective() {
         final E existing;
@@ -565,9 +562,14 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     }
 
     private E loadEffective() {
-        return effectiveInstance = definition.getFactory().createEffective(this);
+        return effectiveInstance = definition.getFactory().createEffective(new BaseCurrentEffectiveStmtCtx<>(this),
+            streamDeclared(), streamEffective());
     }
 
+    abstract Stream<? extends StmtContext<?, ?, ?>> streamDeclared();
+
+    abstract Stream<? extends StmtContext<?, ?, ?>> streamEffective();
+
     /**
      * Try to execute current {@link ModelProcessingPhase} of source parsing. If the phase has already been executed,
      * this method does nothing.
@@ -594,7 +596,7 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         for (final StatementContextBase<?, ?, ?> child : mutableDeclaredSubstatements()) {
             finished &= child.tryToCompletePhase(phase);
         }
-        for (final StatementContextBase<?, ?, ?> child : effective) {
+        for (final StatementContextBase<?, ?, ?> child : effectiveChildrenToComplete()) {
             finished &= child.tryToCompletePhase(phase);
         }
         return finished;
@@ -619,13 +621,17 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
 
         if (openMutations.isEmpty()) {
             phaseMutation.removeAll(phase);
-            if (phaseMutation.isEmpty()) {
-                phaseMutation = ImmutableMultimap.of();
-            }
+            cleanupPhaseMutation();
         }
         return finished;
     }
 
+    private void cleanupPhaseMutation() {
+        if (phaseMutation.isEmpty()) {
+            phaseMutation = ImmutableMultimap.of();
+        }
+    }
+
     /**
      * Occurs on end of {@link ModelProcessingPhase} of source parsing.
      *
@@ -802,10 +808,9 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
     /**
      * Adds a {@link ContextMutation} to a {@link ModelProcessingPhase}.
      *
-     * @throws IllegalStateException
-     *             when the mutation was registered after phase was completed
+     * @throws IllegalStateException when the mutation was registered after phase was completed
      */
-    void addMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
+    final void addMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
         ModelProcessingPhase finishedPhase = completedPhase;
         while (finishedPhase != null) {
             checkState(!phase.equals(finishedPhase), "Mutation registered after phase was completed at: %s",
@@ -819,6 +824,13 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
         phaseMutation.put(phase, mutation);
     }
 
+    final void removeMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
+        if (!phaseMutation.isEmpty()) {
+            phaseMutation.remove(phase, mutation);
+            cleanupPhaseMutation();
+        }
+    }
+
     @Override
     public <K, KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(final Class<@NonNull N> namespace,
             final KT key,final StmtContext<?, ?, ?> stmt) {
@@ -941,10 +953,6 @@ public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E
      */
     abstract boolean hasEmptySubstatements();
 
-    final boolean hasEmptyEffectiveSubstatements() {
-        return effective.isEmpty();
-    }
-
     /**
      * Config statements are not all that common which means we are performing a recursive search towards the root
      * every time {@link #isConfiguration()} is invoked. This is quite expensive because it causes a linear search