+ final <K, V, N extends IdentifierNamespace<K, V>> void onNamespaceItemAddedAction(final Class<N> type,
+ final ModelProcessingPhase phase, final NamespaceKeyCriterion<K> criterion,
+ final OnNamespaceItemAdded listener) {
+ final Optional<Entry<K, V>> existing = getFromNamespace(type, criterion);
+ if (existing.isPresent()) {
+ final Entry<K, V> entry = existing.get();
+ LOG.debug("Listener on {} criterion {} found a pre-existing match: {}", type, criterion, entry);
+ waitForPhase(entry.getValue(), type, phase, criterion, listener);
+ return;
+ }
+
+ final NamespaceBehaviourWithListeners<K, V, N> behaviour = getBehaviour(type);
+ behaviour.addListener(new PredicateValueAddedListener<K, V>(this) {
+ @Override
+ boolean onValueAdded(final K key, final V value) {
+ if (criterion.match(key)) {
+ LOG.debug("Listener on {} criterion {} matched added key {}", type, criterion, key);
+ waitForPhase(value, type, phase, criterion, listener);
+ return true;
+ }
+
+ return false;
+ }
+ });
+ }
+
+ final <K, V, N extends IdentifierNamespace<K, V>> void selectMatch(final Class<N> type,
+ final NamespaceKeyCriterion<K> criterion, final OnNamespaceItemAdded listener) {
+ final Optional<Entry<K, V>> optMatch = getFromNamespace(type, criterion);
+ Preconditions.checkState(optMatch.isPresent(),
+ "Failed to find a match for criterion %s in namespace %s node %s", criterion, type, this);
+ final Entry<K, V> match = optMatch.get();
+ listener.namespaceItemAdded(StatementContextBase.this, type, match.getKey(), match.getValue());
+ }
+
+ final <K, V, N extends IdentifierNamespace<K, V>> void waitForPhase(final Object value, final Class<N> type,
+ final ModelProcessingPhase phase, final NamespaceKeyCriterion<K> criterion,
+ final OnNamespaceItemAdded listener) {
+ ((StatementContextBase<?, ? ,?>) value).addPhaseCompletedListener(phase,
+ (context, completedPhase) -> {
+ selectMatch(type, criterion, listener);
+ return true;
+ });
+ }
+
+ private <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviourWithListeners<K, V, N> getBehaviour(
+ final Class<N> type) {
+ final NamespaceBehaviour<K, V, N> behaviour = getBehaviourRegistry().getNamespaceBehaviour(type);
+ Preconditions.checkArgument(behaviour instanceof NamespaceBehaviourWithListeners,
+ "Namespace %s does not support listeners", type);
+
+ return (NamespaceBehaviourWithListeners<K, V, N>) behaviour;
+ }
+