Remove unused constructor
[yangtools.git] / yang / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / StatementContextBase.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 com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkState;
12 import static com.google.common.base.Verify.verify;
13 import static com.google.common.base.Verify.verifyNotNull;
14 import static java.util.Objects.requireNonNull;
15
16 import com.google.common.annotations.Beta;
17 import com.google.common.base.VerifyException;
18 import com.google.common.collect.ImmutableCollection;
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.ImmutableMultimap;
21 import com.google.common.collect.Multimap;
22 import com.google.common.collect.Multimaps;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.EnumMap;
27 import java.util.EventListener;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map.Entry;
31 import java.util.Optional;
32 import java.util.stream.Stream;
33 import org.eclipse.jdt.annotation.NonNull;
34 import org.opendaylight.yangtools.yang.common.QNameModule;
35 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
36 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
37 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
38 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyHistory;
39 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
40 import org.opendaylight.yangtools.yang.parser.spi.meta.ImplicitParentAwareStatementSupport;
41 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
42 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
43 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.ExecutionOrder;
44 import org.opendaylight.yangtools.yang.parser.spi.meta.MutableStatement;
45 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour;
46 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion;
47 import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace;
48 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory;
49 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace;
50 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
51 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport.CopyPolicy;
52 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
53 import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement;
54 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
55 import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.KeyedValueAddedListener;
56 import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.PredicateValueAddedListener;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 /**
61  * Core reactor statement implementation of {@link Mutable}.
62  *
63  * @param <A> Argument type
64  * @param <D> Declared Statement representation
65  * @param <E> Effective Statement representation
66  */
67 public abstract class StatementContextBase<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
68         extends ReactorStmtCtx<A, D, E> implements CopyHistory {
69     /**
70      * Event listener when an item is added to model namespace.
71      */
72     interface OnNamespaceItemAdded extends EventListener {
73         /**
74          * Invoked whenever a new item is added to a namespace.
75          */
76         void namespaceItemAdded(StatementContextBase<?, ?, ?> context, Class<?> namespace, Object key, Object value);
77     }
78
79     /**
80      * Event listener when a parsing {@link ModelProcessingPhase} is completed.
81      */
82     interface OnPhaseFinished extends EventListener {
83         /**
84          * Invoked whenever a processing phase has finished.
85          */
86         boolean phaseFinished(StatementContextBase<?, ?, ?> context, ModelProcessingPhase finishedPhase);
87     }
88
89     /**
90      * Interface for all mutations within an {@link ModelActionBuilder.InferenceAction}.
91      */
92     interface ContextMutation {
93
94         boolean isFinished();
95     }
96
97     private static final Logger LOG = LoggerFactory.getLogger(StatementContextBase.class);
98
99     //
100     // {@link CopyHistory} encoded as a single byte. We still have 4 bits unused.
101     //
102     private static final byte COPY_LAST_TYPE_MASK        = 0x03;
103     private static final byte COPY_ADDED_BY_USES         = 0x04;
104     private static final byte COPY_ADDED_BY_AUGMENTATION = 0x08;
105     private static final byte COPY_ORIGINAL              = 0x00;
106
107     private final byte copyHistory;
108
109     static {
110         final int copyTypes = CopyType.values().length;
111         // This implies CopyType.ordinal() is <= COPY_TYPE_MASK
112         verify(copyTypes == COPY_LAST_TYPE_MASK + 1, "Unexpected %s CopyType values", copyTypes);
113     }
114
115     // Note: this field can strictly be derived in InferredStatementContext, but it forms the basis of many of our
116     //       operations, hence we want to keep it close by.
117     private final @NonNull StatementDefinitionContext<A, D, E> definition;
118
119     // TODO: consider keying by Byte equivalent of ExecutionOrder
120     private Multimap<ModelProcessingPhase, OnPhaseFinished> phaseListeners = ImmutableMultimap.of();
121     private Multimap<ModelProcessingPhase, ContextMutation> phaseMutation = ImmutableMultimap.of();
122
123     private List<StmtContext<?, ?, ?>> effectOfStatement = ImmutableList.of();
124
125     /**
126      * {@link ModelProcessingPhase.ExecutionOrder} value of current {@link ModelProcessingPhase} of this statement.
127      */
128     private byte executionOrder;
129
130     // Copy constructor used by subclasses to implement reparent()
131     StatementContextBase(final StatementContextBase<A, D, E> original) {
132         super(original);
133         this.copyHistory = original.copyHistory;
134         this.definition = original.definition;
135         this.executionOrder = original.executionOrder;
136     }
137
138     StatementContextBase(final StatementDefinitionContext<A, D, E> def) {
139         this.definition = requireNonNull(def);
140         this.copyHistory = COPY_ORIGINAL;
141     }
142
143     StatementContextBase(final StatementDefinitionContext<A, D, E> def, final CopyType copyType) {
144         this.definition = requireNonNull(def);
145         this.copyHistory = (byte) copyFlags(copyType);
146     }
147
148     StatementContextBase(final StatementContextBase<A, D, E> prototype, final CopyType copyType) {
149         this.definition = prototype.definition;
150         this.copyHistory = (byte) (copyFlags(copyType) | prototype.copyHistory & ~COPY_LAST_TYPE_MASK);
151     }
152
153     private static int copyFlags(final CopyType copyType) {
154         return historyFlags(copyType) | copyType.ordinal();
155     }
156
157     private static byte historyFlags(final CopyType copyType) {
158         switch (copyType) {
159             case ADDED_BY_AUGMENTATION:
160                 return COPY_ADDED_BY_AUGMENTATION;
161             case ADDED_BY_USES:
162                 return COPY_ADDED_BY_USES;
163             case ADDED_BY_USES_AUGMENTATION:
164                 return COPY_ADDED_BY_AUGMENTATION | COPY_ADDED_BY_USES;
165             case ORIGINAL:
166                 return COPY_ORIGINAL;
167             default:
168                 throw new VerifyException("Unhandled type " + copyType);
169         }
170     }
171
172     @Override
173     public Collection<? extends StmtContext<?, ?, ?>> getEffectOfStatement() {
174         return effectOfStatement;
175     }
176
177     @Override
178     public void addAsEffectOfStatement(final Collection<? extends StmtContext<?, ?, ?>> ctxs) {
179         if (ctxs.isEmpty()) {
180             return;
181         }
182
183         if (effectOfStatement.isEmpty()) {
184             effectOfStatement = new ArrayList<>(ctxs.size());
185         }
186         effectOfStatement.addAll(ctxs);
187     }
188
189     //
190     // CopyHistory integration
191     //
192
193     @Override
194     public final CopyHistory history() {
195         return this;
196     }
197
198     @Override
199     public final boolean isAddedByUses() {
200         return (copyHistory & COPY_ADDED_BY_USES) != 0;
201     }
202
203     @Override
204     public final boolean isAugmenting() {
205         return (copyHistory & COPY_ADDED_BY_AUGMENTATION) != 0;
206     }
207
208     @Override
209     public final CopyType getLastOperation() {
210         return CopyType.values()[copyHistory & COPY_LAST_TYPE_MASK];
211     }
212
213     //
214     // Inference completion tracking
215     //
216
217     @Override
218     final byte executionOrder() {
219         return executionOrder;
220     }
221
222     // FIXME: this should be propagated through a correct constructor
223     @Deprecated
224     final void setCompletedPhase(final ModelProcessingPhase completedPhase) {
225         this.executionOrder = completedPhase.executionOrder();
226     }
227
228     @Override
229     public final <K, V, T extends K, U extends V, N extends ParserNamespace<K, V>> void addToNs(
230             final Class<@NonNull N> type, final T key, final U value) {
231         addToNamespace(type, key, value);
232     }
233
234     static final Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements(
235             final List<ReactorStmtCtx<?, ?, ?>> effective) {
236         return effective instanceof ImmutableCollection ? effective : Collections.unmodifiableCollection(effective);
237     }
238
239     private static List<ReactorStmtCtx<?, ?, ?>> shrinkEffective(final List<ReactorStmtCtx<?, ?, ?>> effective) {
240         return effective.isEmpty() ? ImmutableList.of() : effective;
241     }
242
243     public abstract void removeStatementFromEffectiveSubstatements(StatementDefinition statementDef);
244
245     static final List<ReactorStmtCtx<?, ?, ?>> removeStatementFromEffectiveSubstatements(
246             final List<ReactorStmtCtx<?, ?, ?>> effective, final StatementDefinition statementDef) {
247         if (effective.isEmpty()) {
248             return effective;
249         }
250
251         final Iterator<? extends StmtContext<?, ?, ?>> iterator = effective.iterator();
252         while (iterator.hasNext()) {
253             final StmtContext<?, ?, ?> next = iterator.next();
254             if (statementDef.equals(next.publicDefinition())) {
255                 iterator.remove();
256             }
257         }
258
259         return shrinkEffective(effective);
260     }
261
262     /**
263      * Removes a statement context from the effective substatements based on its statement definition (i.e statement
264      * keyword) and raw (in String form) statement argument. The statement context is removed only if both statement
265      * definition and statement argument match with one of the effective substatements' statement definition
266      * and argument.
267      *
268      * <p>
269      * If the statementArg parameter is null, the statement context is removed based only on its statement definition.
270      *
271      * @param statementDef statement definition of the statement context to remove
272      * @param statementArg statement argument of the statement context to remove
273      */
274     public abstract void removeStatementFromEffectiveSubstatements(StatementDefinition statementDef,
275             String statementArg);
276
277     static final List<ReactorStmtCtx<?, ?, ?>> removeStatementFromEffectiveSubstatements(
278             final List<ReactorStmtCtx<?, ?, ?>> effective, final StatementDefinition statementDef,
279             final String statementArg) {
280         if (statementArg == null) {
281             return removeStatementFromEffectiveSubstatements(effective, statementDef);
282         }
283
284         if (effective.isEmpty()) {
285             return effective;
286         }
287
288         final Iterator<ReactorStmtCtx<?, ?, ?>> iterator = effective.iterator();
289         while (iterator.hasNext()) {
290             final Mutable<?, ?, ?> next = iterator.next();
291             if (statementDef.equals(next.publicDefinition()) && statementArg.equals(next.rawArgument())) {
292                 iterator.remove();
293             }
294         }
295
296         return shrinkEffective(effective);
297     }
298
299     // YANG example: RPC/action statements always have 'input' and 'output' defined
300     @Beta
301     public <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>> @NonNull Mutable<X, Y, Z>
302             appendImplicitSubstatement(final StatementSupport<X, Y, Z> support, final String rawArg) {
303         // FIXME: YANGTOOLS-652: This does not need to be a SubstatementContext, in can be a specialized
304         //                       StatementContextBase subclass.
305         final Mutable<X, Y, Z> ret = new SubstatementContext<>(this, new StatementDefinitionContext<>(support),
306                 ImplicitSubstatement.of(sourceReference()), rawArg);
307         support.onStatementAdded(ret);
308         addEffectiveSubstatement(ret);
309         return ret;
310     }
311
312     /**
313      * Adds an effective statement to collection of substatements.
314      *
315      * @param substatement substatement
316      * @throws IllegalStateException if added in declared phase
317      * @throws NullPointerException if statement parameter is null
318      */
319     public abstract void addEffectiveSubstatement(Mutable<?, ?, ?> substatement);
320
321     final List<ReactorStmtCtx<?, ?, ?>> addEffectiveSubstatement(final List<ReactorStmtCtx<?, ?, ?>> effective,
322             final Mutable<?, ?, ?> substatement) {
323         verifyStatement(substatement);
324
325         final List<ReactorStmtCtx<?, ?, ?>> resized = beforeAddEffectiveStatement(effective, 1);
326         final ReactorStmtCtx<?, ?, ?> stmt = (ReactorStmtCtx<?, ?, ?>) substatement;
327         ensureCompletedExecution(stmt);
328         resized.add(stmt);
329         return resized;
330     }
331
332     /**
333      * Adds an effective statement to collection of substatements.
334      *
335      * @param statements substatements
336      * @throws IllegalStateException
337      *             if added in declared phase
338      * @throws NullPointerException
339      *             if statement parameter is null
340      */
341     public final void addEffectiveSubstatements(final Collection<? extends Mutable<?, ?, ?>> statements) {
342         if (!statements.isEmpty()) {
343             statements.forEach(StatementContextBase::verifyStatement);
344             addEffectiveSubstatementsImpl(statements);
345         }
346     }
347
348     abstract void addEffectiveSubstatementsImpl(Collection<? extends Mutable<?, ?, ?>> statements);
349
350     final List<ReactorStmtCtx<?, ?, ?>> addEffectiveSubstatementsImpl(final List<ReactorStmtCtx<?, ?, ?>> effective,
351             final Collection<? extends Mutable<?, ?, ?>> statements) {
352         final List<ReactorStmtCtx<?, ?, ?>> resized = beforeAddEffectiveStatement(effective, statements.size());
353         final Collection<? extends ReactorStmtCtx<?, ?, ?>> casted =
354             (Collection<? extends ReactorStmtCtx<?, ?, ?>>) statements;
355         if (executionOrder != ExecutionOrder.NULL) {
356             for (ReactorStmtCtx<?, ?, ?> stmt : casted) {
357                 ensureCompletedExecution(stmt, executionOrder);
358             }
359         }
360
361         resized.addAll(casted);
362         return resized;
363     }
364
365     abstract Iterable<ReactorStmtCtx<?, ?, ?>> effectiveChildrenToComplete();
366
367     // exposed for InferredStatementContext only
368     final void ensureCompletedPhase(final Mutable<?, ?, ?> stmt) {
369         verifyStatement(stmt);
370         ensureCompletedExecution((ReactorStmtCtx<?, ?, ?>) stmt);
371     }
372
373     // Make sure target statement has transitioned at least to our phase (if we have one). This method is just before we
374     // take allow a statement to become our substatement. This is needed to ensure that every statement tree does not
375     // contain any statements which did not complete the same phase as the root statement.
376     private void ensureCompletedExecution(final ReactorStmtCtx<?, ?, ?> stmt) {
377         if (executionOrder != ExecutionOrder.NULL) {
378             ensureCompletedExecution(stmt, executionOrder);
379         }
380     }
381
382     private static void ensureCompletedExecution(final ReactorStmtCtx<?, ?, ?> stmt, final byte executionOrder) {
383         verify(stmt.tryToCompletePhase(executionOrder), "Statement %s cannot complete phase %s", stmt, executionOrder);
384     }
385
386     private static void verifyStatement(final Mutable<?, ?, ?> stmt) {
387         verify(stmt instanceof ReactorStmtCtx, "Unexpected statement %s", stmt);
388     }
389
390     private List<ReactorStmtCtx<?, ?, ?>> beforeAddEffectiveStatement(final List<ReactorStmtCtx<?, ?, ?>> effective,
391             final int toAdd) {
392         // We cannot allow statement to be further mutated.
393         // TODO: we really want to say 'not NULL and not at or after EFFECTIVE_MODEL here. This will matter if we have
394         //       a phase after EFFECTIVE_MODEL
395         verify(executionOrder != ExecutionOrder.EFFECTIVE_MODEL, "Cannot modify finished statement at %s",
396             sourceReference());
397         return beforeAddEffectiveStatementUnsafe(effective, toAdd);
398     }
399
400     final List<ReactorStmtCtx<?, ?, ?>> beforeAddEffectiveStatementUnsafe(final List<ReactorStmtCtx<?, ?, ?>> effective,
401             final int toAdd) {
402         final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
403         checkState(inProgressPhase == ModelProcessingPhase.FULL_DECLARATION
404                 || inProgressPhase == ModelProcessingPhase.EFFECTIVE_MODEL,
405                 "Effective statement cannot be added in declared phase at: %s", sourceReference());
406
407         return effective.isEmpty() ? new ArrayList<>(toAdd) : effective;
408     }
409
410     @Override
411     final E createEffective() {
412         final E result = createEffective(definition.getFactory());
413         if (result instanceof MutableStatement) {
414             getRoot().addMutableStmtToSeal((MutableStatement) result);
415         }
416         return result;
417     }
418
419     @NonNull E createEffective(final StatementFactory<A, D, E> factory) {
420         return createEffective(factory, this);
421     }
422
423     // Creates EffectiveStatement through full materialization
424     static <A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> @NonNull E createEffective(
425             final StatementFactory<A, D, E> factory, final StatementContextBase<A, D, E> ctx) {
426         return factory.createEffective(ctx, ctx.streamDeclared(), ctx.streamEffective());
427     }
428
429     /**
430      * Return a stream of declared statements which can be built into an {@link EffectiveStatement}, as per
431      * {@link StmtContext#buildEffective()} contract.
432      *
433      * @return Stream of supported declared statements.
434      */
435     // FIXME: we really want to unify this with streamEffective(), under its name
436     abstract Stream<? extends @NonNull StmtContext<?, ?, ?>> streamDeclared();
437
438     /**
439      * Return a stream of inferred statements which can be built into an {@link EffectiveStatement}, as per
440      * {@link StmtContext#buildEffective()} contract.
441      *
442      * @return Stream of supported effective statements.
443      */
444     // FIXME: this method is currently a misnomer, but unifying with streamDeclared() would make this accurate again
445     abstract Stream<? extends @NonNull StmtContext<?, ?, ?>> streamEffective();
446
447     @Override
448     final boolean doTryToCompletePhase(final byte targetOrder) {
449         final boolean finished = phaseMutation.isEmpty() ? true : runMutations(targetOrder);
450         if (completeChildren(targetOrder) && finished) {
451             onPhaseCompleted(targetOrder);
452             return true;
453         }
454         return false;
455     }
456
457     private boolean completeChildren(final byte targetOrder) {
458         boolean finished = true;
459         for (final StatementContextBase<?, ?, ?> child : mutableDeclaredSubstatements()) {
460             finished &= child.tryToCompletePhase(targetOrder);
461         }
462         for (final ReactorStmtCtx<?, ?, ?> child : effectiveChildrenToComplete()) {
463             finished &= child.tryToCompletePhase(targetOrder);
464         }
465         return finished;
466     }
467
468     private boolean runMutations(final byte targetOrder) {
469         final ModelProcessingPhase phase = verifyNotNull(ModelProcessingPhase.ofExecutionOrder(targetOrder));
470         final Collection<ContextMutation> openMutations = phaseMutation.get(phase);
471         return openMutations.isEmpty() ? true : runMutations(phase, openMutations);
472     }
473
474     private boolean runMutations(final ModelProcessingPhase phase, final Collection<ContextMutation> openMutations) {
475         boolean finished = true;
476         final Iterator<ContextMutation> it = openMutations.iterator();
477         while (it.hasNext()) {
478             final ContextMutation current = it.next();
479             if (current.isFinished()) {
480                 it.remove();
481             } else {
482                 finished = false;
483             }
484         }
485
486         if (openMutations.isEmpty()) {
487             phaseMutation.removeAll(phase);
488             cleanupPhaseMutation();
489         }
490         return finished;
491     }
492
493     private void cleanupPhaseMutation() {
494         if (phaseMutation.isEmpty()) {
495             phaseMutation = ImmutableMultimap.of();
496         }
497     }
498
499     /**
500      * Occurs on end of {@link ModelProcessingPhase} of source parsing. This method must not be called with
501      * {@code executionOrder} equal to {@link ExecutionOrder#NULL}.
502      *
503      * @param phase that was to be completed (finished)
504      * @throws SourceException when an error occurred in source parsing
505      */
506     private void onPhaseCompleted(final byte completedOrder) {
507         executionOrder = completedOrder;
508         if (completedOrder == ExecutionOrder.EFFECTIVE_MODEL) {
509             // We have completed effective model, substatements are guaranteed not to change
510             summarizeSubstatementPolicy();
511         }
512
513         final ModelProcessingPhase phase = verifyNotNull(ModelProcessingPhase.ofExecutionOrder(completedOrder));
514         final Collection<OnPhaseFinished> listeners = phaseListeners.get(phase);
515         if (!listeners.isEmpty()) {
516             runPhaseListeners(phase, listeners);
517         }
518     }
519
520     private void summarizeSubstatementPolicy() {
521         if (definition().support().copyPolicy() == CopyPolicy.EXACT_REPLICA || noSensitiveSubstatements()) {
522             setAllSubstatementsContextIndependent();
523         }
524     }
525
526     /**
527      * Determine whether any substatements are copy-sensitive as determined by {@link StatementSupport#copyPolicy()}.
528      * Only {@link CopyPolicy#CONTEXT_INDEPENDENT}, {@link CopyPolicy#EXACT_REPLICA} and {@link CopyPolicy#IGNORE} are
529      * copy-insensitive. Note that statements which are not {@link StmtContext#isSupportedToBuildEffective()} are all
530      * considered copy-insensitive.
531      *
532      * <p>
533      * Implementations are expected to call {@link #noSensitiveSubstatements()} to actually traverse substatement sets.
534      *
535      * @return True if no substatements require copy-sensitive handling
536      */
537     abstract boolean noSensitiveSubstatements();
538
539     /**
540      * Determine whether any of the provided substatements are context-sensitive for purposes of implementing
541      * {@link #noSensitiveSubstatements()}.
542      *
543      * @param substatements Substatements to check
544      * @return True if no substatements require context-sensitive handling
545      */
546     static boolean noSensitiveSubstatements(final Collection<? extends ReactorStmtCtx<?, ?, ?>> substatements) {
547         for (ReactorStmtCtx<?, ?, ?> stmt : substatements) {
548             if (stmt.isSupportedToBuildEffective()) {
549                 if (!stmt.allSubstatementsContextIndependent()) {
550                     // This is a recursive property
551                     return false;
552                 }
553
554                 switch (stmt.definition().support().copyPolicy()) {
555                     case CONTEXT_INDEPENDENT:
556                     case EXACT_REPLICA:
557                     case IGNORE:
558                         break;
559                     default:
560                         return false;
561                 }
562             }
563         }
564         return true;
565     }
566
567     private void runPhaseListeners(final ModelProcessingPhase phase, final Collection<OnPhaseFinished> listeners) {
568         final Iterator<OnPhaseFinished> listener = listeners.iterator();
569         while (listener.hasNext()) {
570             final OnPhaseFinished next = listener.next();
571             if (next.phaseFinished(this, phase)) {
572                 listener.remove();
573             }
574         }
575
576         if (listeners.isEmpty()) {
577             phaseListeners.removeAll(phase);
578             if (phaseListeners.isEmpty()) {
579                 phaseListeners = ImmutableMultimap.of();
580             }
581         }
582     }
583
584     /**
585      * Ends declared section of current node.
586      */
587     void endDeclared(final ModelProcessingPhase phase) {
588         definition.onDeclarationFinished(this, phase);
589     }
590
591     @Override
592     final StatementDefinitionContext<A, D, E> definition() {
593         return definition;
594     }
595
596     final <K, V, N extends ParserNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type, final K key,
597             final OnNamespaceItemAdded listener) {
598         final Object potential = getFromNamespace(type, key);
599         if (potential != null) {
600             LOG.trace("Listener on {} key {} satisfied immediately", type, key);
601             listener.namespaceItemAdded(this, type, key, potential);
602             return;
603         }
604
605         getBehaviour(type).addListener(new KeyedValueAddedListener<>(this, key) {
606             @Override
607             void onValueAdded(final Object value) {
608                 listener.namespaceItemAdded(StatementContextBase.this, type, key, value);
609             }
610         });
611     }
612
613     final <K, V, N extends ParserNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type,
614             final ModelProcessingPhase phase, final NamespaceKeyCriterion<K> criterion,
615             final OnNamespaceItemAdded listener) {
616         final Optional<Entry<K, V>> existing = getFromNamespace(type, criterion);
617         if (existing.isPresent()) {
618             final Entry<K, V> entry = existing.get();
619             LOG.debug("Listener on {} criterion {} found a pre-existing match: {}", type, criterion, entry);
620             waitForPhase(entry.getValue(), type, phase, criterion, listener);
621             return;
622         }
623
624         final NamespaceBehaviourWithListeners<K, V, N> behaviour = getBehaviour(type);
625         behaviour.addListener(new PredicateValueAddedListener<K, V>(this) {
626             @Override
627             boolean onValueAdded(final K key, final V value) {
628                 if (criterion.match(key)) {
629                     LOG.debug("Listener on {} criterion {} matched added key {}", type, criterion, key);
630                     waitForPhase(value, type, phase, criterion, listener);
631                     return true;
632                 }
633
634                 return false;
635             }
636         });
637     }
638
639     final <K, V, N extends ParserNamespace<K, V>> void selectMatch(final Class<N> type,
640             final NamespaceKeyCriterion<K> criterion, final OnNamespaceItemAdded listener) {
641         final Optional<Entry<K, V>> optMatch = getFromNamespace(type, criterion);
642         checkState(optMatch.isPresent(), "Failed to find a match for criterion %s in namespace %s node %s", criterion,
643             type, this);
644         final Entry<K, V> match = optMatch.get();
645         listener.namespaceItemAdded(StatementContextBase.this, type, match.getKey(), match.getValue());
646     }
647
648     final <K, V, N extends ParserNamespace<K, V>> void waitForPhase(final Object value, final Class<N> type,
649             final ModelProcessingPhase phase, final NamespaceKeyCriterion<K> criterion,
650             final OnNamespaceItemAdded listener) {
651         ((StatementContextBase<?, ? ,?>) value).addPhaseCompletedListener(phase,
652             (context, phaseCompleted) -> {
653                 selectMatch(type, criterion, listener);
654                 return true;
655             });
656     }
657
658     private <K, V, N extends ParserNamespace<K, V>> NamespaceBehaviourWithListeners<K, V, N> getBehaviour(
659             final Class<N> type) {
660         final NamespaceBehaviour<K, V, N> behaviour = getBehaviourRegistry().getNamespaceBehaviour(type);
661         checkArgument(behaviour instanceof NamespaceBehaviourWithListeners, "Namespace %s does not support listeners",
662             type);
663
664         return (NamespaceBehaviourWithListeners<K, V, N>) behaviour;
665     }
666
667     private static <T> Multimap<ModelProcessingPhase, T> newMultimap() {
668         return Multimaps.newListMultimap(new EnumMap<>(ModelProcessingPhase.class), () -> new ArrayList<>(1));
669     }
670
671     /**
672      * Adds {@link OnPhaseFinished} listener for a {@link ModelProcessingPhase} end. If the base has already completed
673      * the listener is notified immediately.
674      *
675      * @param phase requested completion phase
676      * @param listener listener to invoke
677      * @throws NullPointerException if any of the arguments is null
678      */
679     void addPhaseCompletedListener(final ModelProcessingPhase phase, final OnPhaseFinished listener) {
680         requireNonNull(phase, "Statement context processing phase cannot be null");
681         requireNonNull(listener, "Statement context phase listener cannot be null");
682
683         ModelProcessingPhase finishedPhase = ModelProcessingPhase.ofExecutionOrder(executionOrder);
684         while (finishedPhase != null) {
685             if (phase.equals(finishedPhase)) {
686                 listener.phaseFinished(this, finishedPhase);
687                 return;
688             }
689             finishedPhase = finishedPhase.getPreviousPhase();
690         }
691         if (phaseListeners.isEmpty()) {
692             phaseListeners = newMultimap();
693         }
694
695         phaseListeners.put(phase, listener);
696     }
697
698     /**
699      * Adds a {@link ContextMutation} to a {@link ModelProcessingPhase}.
700      *
701      * @throws IllegalStateException when the mutation was registered after phase was completed
702      */
703     final void addMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
704         checkState(executionOrder < phase.executionOrder(), "Mutation registered after phase was completed at: %s",
705             sourceReference());
706
707         if (phaseMutation.isEmpty()) {
708             phaseMutation = newMultimap();
709         }
710         phaseMutation.put(phase, mutation);
711     }
712
713     final void removeMutation(final ModelProcessingPhase phase, final ContextMutation mutation) {
714         if (!phaseMutation.isEmpty()) {
715             phaseMutation.remove(phase, mutation);
716             cleanupPhaseMutation();
717         }
718     }
719
720     @Override
721     public <K, KT extends K, N extends StatementNamespace<K, ?, ?>> void addContext(final Class<@NonNull N> namespace,
722             final KT key,final StmtContext<?, ?, ?> stmt) {
723         addContextToNamespace(namespace, key, stmt);
724     }
725
726     @Override
727     public Optional<? extends Mutable<?, ?, ?>> copyAsChildOf(final Mutable<?, ?, ?> parent, final CopyType type,
728             final QNameModule targetModule) {
729         checkEffectiveModelCompleted(this);
730         return Optional.ofNullable(copyAsChildOfImpl(parent, type, targetModule));
731     }
732
733     private ReactorStmtCtx<A, D, E> copyAsChildOfImpl(final Mutable<?, ?, ?> parent, final CopyType type,
734             final QNameModule targetModule) {
735         final StatementSupport<A, D, E> support = definition.support();
736         final CopyPolicy policy = support.copyPolicy();
737         switch (policy) {
738             case EXACT_REPLICA:
739                 return replicaAsChildOf(parent);
740             case CONTEXT_INDEPENDENT:
741                 if (allSubstatementsContextIndependent()) {
742                     return replicaAsChildOf(parent);
743                 }
744
745                 // fall through
746             case DECLARED_COPY:
747                 // FIXME: ugly cast
748                 return (ReactorStmtCtx<A, D, E>) parent.childCopyOf(this, type, targetModule);
749             case IGNORE:
750                 return null;
751             case REJECT:
752                 throw new IllegalStateException("Statement " + support.getPublicView() + " should never be copied");
753             default:
754                 throw new IllegalStateException("Unhandled policy " + policy);
755         }
756     }
757
758     @Override
759     final ReactorStmtCtx<?, ?, ?> asEffectiveChildOf(final StatementContextBase<?, ?, ?> parent, final CopyType type,
760             final QNameModule targetModule) {
761         final ReactorStmtCtx<A, D, E> copy = copyAsChildOfImpl(parent, type, targetModule);
762         if (copy == null) {
763             // The statement fizzled, this should never happen, perhaps a verify()?
764             return null;
765         }
766
767         parent.ensureCompletedPhase(copy);
768         return canReuseCurrent(copy) ? this : copy;
769     }
770
771     private boolean canReuseCurrent(final ReactorStmtCtx<A, D, E> copy) {
772         // Defer to statement factory to see if we can reuse this object. If we can and have only context-independent
773         // substatements we can reuse the object. More complex cases are handled indirectly via the copy.
774         return definition.getFactory().canReuseCurrent(copy, this, buildEffective().effectiveSubstatements())
775             && allSubstatementsContextIndependent();
776     }
777
778     @Override
779     public final Mutable<?, ?, ?> childCopyOf(final StmtContext<?, ?, ?> stmt, final CopyType type,
780             final QNameModule targetModule) {
781         checkEffectiveModelCompleted(stmt);
782         checkArgument(stmt instanceof StatementContextBase, "Unsupported statement %s", stmt);
783         return childCopyOf((StatementContextBase<?, ?, ?>) stmt, type, targetModule);
784     }
785
786     private <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>> Mutable<X, Y, Z> childCopyOf(
787             final StatementContextBase<X, Y, Z> original, final CopyType type, final QNameModule targetModule) {
788         final Optional<StatementSupport<?, ?, ?>> implicitParent = definition.getImplicitParentFor(
789             original.publicDefinition());
790
791         final StatementContextBase<X, Y, Z> result;
792         final InferredStatementContext<X, Y, Z> copy;
793
794         if (implicitParent.isPresent()) {
795             final StatementDefinitionContext<?, ?, ?> def = new StatementDefinitionContext<>(implicitParent.get());
796             result = new SubstatementContext(this, def, original.sourceReference(), original.rawArgument(),
797                 original.argument(), type);
798
799             final CopyType childCopyType;
800             switch (type) {
801                 case ADDED_BY_AUGMENTATION:
802                     childCopyType = CopyType.ORIGINAL;
803                     break;
804                 case ADDED_BY_USES_AUGMENTATION:
805                     childCopyType = CopyType.ADDED_BY_USES;
806                     break;
807                 case ADDED_BY_USES:
808                 case ORIGINAL:
809                 default:
810                     childCopyType = type;
811             }
812
813             copy = new InferredStatementContext<>(result, original, childCopyType, type, targetModule);
814             result.addEffectiveSubstatement(copy);
815         } else {
816             result = copy = new InferredStatementContext<>(this, original, type, type, targetModule);
817         }
818
819         original.definition.onStatementAdded(copy);
820         return result;
821     }
822
823     @Override
824     final ReplicaStatementContext<A, D, E> replicaAsChildOf(final StatementContextBase<?, ?, ?> parent) {
825         return new ReplicaStatementContext<>(parent, this);
826     }
827
828     private static void checkEffectiveModelCompleted(final StmtContext<?, ?, ?> stmt) {
829         final ModelProcessingPhase phase = stmt.getCompletedPhase();
830         checkState(phase == ModelProcessingPhase.EFFECTIVE_MODEL,
831                 "Attempted to copy statement %s which has completed phase %s", stmt, phase);
832     }
833
834     @Beta
835     // FIXME: this information should be exposed as a well-known Namespace
836     public final boolean hasImplicitParentSupport() {
837         return definition.getFactory() instanceof ImplicitParentAwareStatementSupport;
838     }
839
840     @Beta
841     public final StatementContextBase<?, ?, ?> wrapWithImplicit(final StatementContextBase<?, ?, ?> original) {
842         final Optional<StatementSupport<?, ?, ?>> optImplicit = definition.getImplicitParentFor(
843             original.publicDefinition());
844         if (optImplicit.isEmpty()) {
845             return original;
846         }
847
848         final StatementDefinitionContext<?, ?, ?> def = new StatementDefinitionContext<>(optImplicit.get());
849         final CopyType type = original.history().getLastOperation();
850         final SubstatementContext<?, ?, ?> result = new SubstatementContext(original.getParentContext(), def,
851             original.sourceReference(), original.rawArgument(), original.argument(), type);
852
853         result.addEffectiveSubstatement(original.reparent(result));
854         result.setCompletedPhase(original.getCompletedPhase());
855         return result;
856     }
857
858     abstract StatementContextBase<A, D, E> reparent(StatementContextBase<?, ?, ?> newParent);
859
860     /**
861      * Indicate that the set of substatements is empty. This is a preferred shortcut to substatement stream filtering.
862      *
863      * @return True if {@link #allSubstatements()} and {@link #allSubstatementsStream()} would return an empty stream.
864      */
865     abstract boolean hasEmptySubstatements();
866 }