+ 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 {