action = null;
}
- private void applyAction() {
- checkState(!actionApplied);
- action.apply(ctx);
- actionApplied = true;
- }
-
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) {
checkState(action != null, "Action was not defined yet.");
if (removeSatisfied()) {
- applyAction();
+ if (!actionApplied) {
+ action.apply(ctx);
+ actionApplied = true;
+ }
return true;
}
return false;
@Override
public boolean phaseFinished(final StatementContextBase<?, ?, ?> context,
final ModelProcessingPhase finishedPhase) {
- return resolvePrereq((C) context);
+ return resolvePrereq((C) context) || tryApply();
}
}
@Override
public boolean phaseFinished(final StatementContextBase<?, ?, ?> context,
final ModelProcessingPhase finishedPhase) {
- return resolvePrereq((C) context);
+ return resolvePrereq((C) context) || tryApply();
}
@Override
}
}
+ /**
+ * This similar to {@link PhaseModificationInNamespace}, but allows recursive descent until it finds the real
+ * 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 IdentifierNamespace<K, ? extends StmtContext<?, ?, ?>>> extends AbstractPrerequisite<C>
implements OnNamespaceItemAdded, ContextMutation {
return;
}
+ // Hook onto target: we either have a modification of the target itself or one of its children.
+ target.addMutation(modPhase, 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()) {
- target.addMutation(modPhase, this);
- resolvePrereq((C) value);
+ // 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());