From: Robert Varga Date: Fri, 20 Oct 2017 12:08:59 +0000 (+0200) Subject: BUG-4688: Add flexible match support to NamespaceStorageSupport X-Git-Tag: v2.0.0~164 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=ee2a8704ba51ccff4f8411689f4e55371aba71a0;p=yangtools.git BUG-4688: Add flexible match support to NamespaceStorageSupport This patch adds the support for flexible match of namespace keys based on filter/reduce mechanics -- which are required to consistently support revisionless and semantic imports without reliance on magic constants in public interfaces. In order to support required mechanics, we need to fix the ValueAddedListener implementation and their lifecycle and introduce a predicate-based match. Change-Id: Icb22850e44de05d59820e1974e204dc1541e1f76 Signed-off-by: Robert Varga --- diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ModifierImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ModifierImpl.java index 7818069762..bfa3aa1622 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ModifierImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/ModifierImpl.java @@ -24,6 +24,7 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase; +import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion; import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable; @@ -89,7 +90,6 @@ final class ModifierImpl implements ModelActionBuilder { actionApplied = true; } - @SuppressWarnings({ "unchecked", "rawtypes" }) private , N extends StatementNamespace> AbstractPrerequisite requiresCtxImpl(final StmtContext context, final Class namespace, final K key, final ModelProcessingPhase phase) { @@ -97,7 +97,18 @@ final class ModifierImpl implements ModelActionBuilder { AddedToNamespace addedToNs = new AddedToNamespace<>(phase); addReq(addedToNs); - contextImpl(context).onNamespaceItemAddedAction((Class) namespace, key, addedToNs); + contextImpl(context).onNamespaceItemAddedAction(namespace, key, addedToNs); + return addedToNs; + } + + private , N extends StatementNamespace> AbstractPrerequisite + requiresCtxImpl(final StmtContext context, final Class namespace, + final NamespaceKeyCriterion criterion, final ModelProcessingPhase phase) { + checkNotRegistered(); + + AddedToNamespace addedToNs = new AddedToNamespace<>(phase); + addReq(addedToNs); + contextImpl(context).onNamespaceItemAddedAction(namespace, phase, criterion, addedToNs); return addedToNs; } @@ -165,6 +176,14 @@ final class ModifierImpl implements ModelActionBuilder { return requiresCtxImpl(context, namespace, key, phase); } + @Nonnull + @Override + public > Prerequisite> requiresCtx( + final StmtContext context, final Class namespace, final NamespaceKeyCriterion criterion, + final ModelProcessingPhase phase) { + return requiresCtxImpl(context, namespace, criterion, phase); + } + @Nonnull @Override public > Prerequisite requiresDeclared( diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceBehaviourWithListeners.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceBehaviourWithListeners.java index adba2b6572..9aa6ecc41e 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceBehaviourWithListeners.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceBehaviourWithListeners.java @@ -7,10 +7,13 @@ */ package org.opendaylight.yangtools.yang.parser.stmt.reactor; +import static java.util.Objects.requireNonNull; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; +import javax.annotation.Nonnull; import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour; @@ -19,25 +22,45 @@ abstract class NamespaceBehaviourWithListeners { private final NamespaceStorageNode ctxNode; - private final K key; - ValueAddedListener(final NamespaceStorageNode contextNode, final K key) { - this.ctxNode = contextNode; - this.key = key; + ValueAddedListener(final NamespaceStorageNode contextNode) { + this.ctxNode = requireNonNull(contextNode); } - NamespaceStorageNode getCtxNode() { + final NamespaceStorageNode getCtxNode() { return ctxNode; } + } + + abstract static class KeyedValueAddedListener extends ValueAddedListener { + private final K key; + + KeyedValueAddedListener(final NamespaceStorageNode contextNode, final K key) { + super(contextNode); + this.key = requireNonNull(key); + } + + final K getKey() { + return key; + } + final boolean isRequestedValue(final NamespaceBehaviour behavior, final NamespaceStorageNode storage, final V value) { - return value == behavior.getFrom(ctxNode, key); + return value == behavior.getFrom(getCtxNode(), key); } abstract void onValueAdded(Object value); } + abstract static class PredicateValueAddedListener extends ValueAddedListener { + PredicateValueAddedListener(final NamespaceStorageNode contextNode) { + super(contextNode); + } + + abstract boolean onValueAdded(@Nonnull K key, @Nonnull V value); + } + protected final NamespaceBehaviour delegate; private final List> derivedNamespaces = new ArrayList<>(); @@ -46,22 +69,24 @@ abstract class NamespaceBehaviourWithListeners listener); + abstract void addListener(KeyedValueAddedListener listener); + + abstract void addListener(PredicateValueAddedListener listener); @Override public abstract void addTo(NamespaceStorageNode storage, K key, V value); protected void notifyListeners(final NamespaceStorageNode storage, - final Iterator> keyListeners, final V value) { - List> toNotify = new ArrayList<>(); + final Iterator> keyListeners, final V value) { + List> toNotify = new ArrayList<>(); while (keyListeners.hasNext()) { - final ValueAddedListener listener = keyListeners.next(); + final KeyedValueAddedListener listener = keyListeners.next(); if (listener.isRequestedValue(this, storage, value)) { keyListeners.remove(); toNotify.add(listener); } } - for (ValueAddedListener listener : toNotify) { + for (KeyedValueAddedListener listener : toNotify) { listener.onValueAdded(value); } } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceStorageSupport.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceStorageSupport.java index 0a97b80aad..889dcc6721 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceStorageSupport.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/NamespaceStorageSupport.java @@ -11,6 +11,7 @@ import com.google.common.collect.ImmutableMap; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import javax.annotation.Nonnull; import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; @@ -18,6 +19,7 @@ import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier; import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.NamespaceStorageNode; import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry; +import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion; import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceNotAvailableException; import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; @@ -52,11 +54,16 @@ abstract class NamespaceStorageSupport implements NamespaceStorageNode { } @Nonnull - public final > V getFromNamespace(final Class type, + public final > V getFromNamespace(final Class type, final KT key) throws NamespaceNotAvailableException { return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, key); } + public final > Optional> getFromNamespace( + final Class type, final NamespaceKeyCriterion criterion) { + return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, criterion); + } + public final > Map getAllFromNamespace(final Class type) { return getBehaviourRegistry().getNamespaceBehaviour(type).getAllFrom(this); } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SimpleNamespaceContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SimpleNamespaceContext.java index e59e5e606f..b335df09f6 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SimpleNamespaceContext.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SimpleNamespaceContext.java @@ -8,6 +8,7 @@ package org.opendaylight.yangtools.yang.parser.stmt.reactor; import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; @@ -17,25 +18,36 @@ final class SimpleNamespaceContext> extends NamespaceBehaviourWithListeners { // FIXME: Change this to Multimap, once issue with modules is resolved. - private final List> listeners = new ArrayList<>(); + private final List> listeners = new ArrayList<>(); + + private final Collection> predicateListeners = new ArrayList<>(); SimpleNamespaceContext(final NamespaceBehaviour delegate) { super(delegate); } @Override - void addListener(final K key, final ValueAddedListener listener) { + void addListener(final KeyedValueAddedListener listener) { listeners.add(listener); } - private Iterator> getMutableListeners(final K key) { - return listeners.iterator(); + @Override + void addListener(final PredicateValueAddedListener listener) { + predicateListeners.add(listener); } @Override public void addTo(final NamespaceStorageNode storage, final K key, final V value) { delegate.addTo(storage, key, value); - notifyListeners(storage, getMutableListeners(key), value); + notifyListeners(storage, listeners.iterator(), value); + + final Iterator> it = predicateListeners.iterator(); + while (it.hasNext()) { + if (it.next().onValueAdded(key, value)) { + it.remove(); + } + } + notifyDerivedNamespaces(storage, key, value); } } diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java index ff54ac473b..c02909a7a1 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/SourceSpecificContext.java @@ -46,8 +46,8 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils; import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToModuleContext; import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleCtx; -import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx; import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace; +import org.opendaylight.yangtools.yang.parser.spi.source.ImportPrefixToModuleCtx; import org.opendaylight.yangtools.yang.parser.spi.source.ImportedModuleContext; import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName; import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule; @@ -314,6 +314,7 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh private static boolean tryToProgress(final Collection currentPhaseModifiers) { boolean hasProgressed = false; + // Try making forward progress ... final Iterator modifier = currentPhaseModifiers.iterator(); while (modifier.hasNext()) { if (modifier.next().tryApply()) { diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java index 1807b101de..d009eb78db 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/StatementContextBase.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.EventListener; import java.util.Iterator; +import java.util.Map.Entry; import java.util.Optional; import java.util.Set; import javax.annotation.Nonnull; @@ -40,6 +41,7 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder; import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase; import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour; +import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceKeyCriterion; import org.opendaylight.yangtools.yang.parser.spi.meta.StatementNamespace; import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport; import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext; @@ -50,7 +52,8 @@ import org.opendaylight.yangtools.yang.parser.spi.source.SourceException; import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference; import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace; import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace.SupportedFeatures; -import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.ValueAddedListener; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.KeyedValueAddedListener; +import org.opendaylight.yangtools.yang.parser.stmt.reactor.NamespaceBehaviourWithListeners.PredicateValueAddedListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -567,8 +570,8 @@ public abstract class StatementContextBase, E // definition().onNamespaceElementAdded(this, type, key, value); } - > void onNamespaceItemAddedAction(final Class type, final K key, - final OnNamespaceItemAdded listener) throws SourceException { + final > void onNamespaceItemAddedAction(final Class type, final K key, + final OnNamespaceItemAdded listener) { final Object potential = getFromNamespace(type, key); if (potential != null) { LOG.trace("Listener on {} key {} satisfied immediately", type, key); @@ -576,12 +579,7 @@ public abstract class StatementContextBase, E return; } - final NamespaceBehaviour behaviour = getBehaviourRegistry().getNamespaceBehaviour(type); - Preconditions.checkArgument(behaviour instanceof NamespaceBehaviourWithListeners, - "Namespace %s does not support listeners", type); - - final NamespaceBehaviourWithListeners casted = (NamespaceBehaviourWithListeners) behaviour; - casted.addListener(key, new ValueAddedListener(this, key) { + getBehaviour(type).addListener(new KeyedValueAddedListener(this, key) { @Override void onValueAdded(final Object value) { listener.namespaceItemAdded(StatementContextBase.this, type, key, value); @@ -589,6 +587,60 @@ public abstract class StatementContextBase, E }); } + final > void onNamespaceItemAddedAction(final Class type, + final ModelProcessingPhase phase, final NamespaceKeyCriterion criterion, + final OnNamespaceItemAdded listener) { + final Optional> existing = getFromNamespace(type, criterion); + if (existing.isPresent()) { + final Entry 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 behaviour = getBehaviour(type); + behaviour.addListener(new PredicateValueAddedListener(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 > void selectMatch(final Class type, + final NamespaceKeyCriterion criterion, final OnNamespaceItemAdded listener) { + final Optional> 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 match = optMatch.get(); + listener.namespaceItemAdded(StatementContextBase.this, type, match.getKey(), match.getValue()); + } + + final > void waitForPhase(final Object value, final Class type, + final ModelProcessingPhase phase, final NamespaceKeyCriterion criterion, + final OnNamespaceItemAdded listener) { + ((StatementContextBase) value).addPhaseCompletedListener(phase, + (context, completedPhase) -> { + selectMatch(type, criterion, listener); + return true; + }); + } + + private > NamespaceBehaviourWithListeners getBehaviour( + final Class type) { + final NamespaceBehaviour behaviour = getBehaviourRegistry().getNamespaceBehaviour(type); + Preconditions.checkArgument(behaviour instanceof NamespaceBehaviourWithListeners, + "Namespace %s does not support listeners", type); + + return (NamespaceBehaviourWithListeners) behaviour; + } + /** * See {@link StatementSupport#getPublicView()}. */ diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/VirtualNamespaceContext.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/VirtualNamespaceContext.java index 77693e8dc5..2df2fe5d36 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/VirtualNamespaceContext.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/VirtualNamespaceContext.java @@ -15,7 +15,7 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.DerivedNamespaceBehaviour final class VirtualNamespaceContext, D> extends NamespaceBehaviourWithListeners { - private final Multimap> listeners = HashMultimap.create(); + private final Multimap> listeners = HashMultimap.create(); private final DerivedNamespaceBehaviour derivedDelegate; VirtualNamespaceContext(final DerivedNamespaceBehaviour delegate) { @@ -24,8 +24,13 @@ final class VirtualNamespaceContext, D } @Override - void addListener(final K key, final ValueAddedListener listener) { - listeners.put(derivedDelegate.getSignificantKey(key), listener); + void addListener(final KeyedValueAddedListener listener) { + listeners.put(derivedDelegate.getSignificantKey(listener.getKey()), listener); + } + + @Override + void addListener(final PredicateValueAddedListener listener) { + throw new UnsupportedOperationException("Virtual namespaces support only exact lookups"); } void addedToSourceNamespace(final NamespaceStorageNode storage, final D key, final V value) { diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ModelActionBuilder.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ModelActionBuilder.java index eb6337a839..465e7fd4e9 100644 --- a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ModelActionBuilder.java +++ b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ModelActionBuilder.java @@ -156,6 +156,10 @@ public interface ModelActionBuilder { @Nonnull > Prerequisite> requiresCtx( StmtContext context, Class namespace, K key, ModelProcessingPhase phase); + @Nonnull > Prerequisite> requiresCtx( + StmtContext context, Class namespace, NamespaceKeyCriterion criterion, + ModelProcessingPhase phase); + default @Nonnull > Prerequisite mutatesEffectiveCtx(final T stmt) { return mutatesCtx(stmt, EFFECTIVE_MODEL); } diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceBehaviour.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceBehaviour.java index 0d88c3ef3e..9fcba740e9 100644 --- a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceBehaviour.java +++ b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceBehaviour.java @@ -9,7 +9,10 @@ package org.opendaylight.yangtools.yang.parser.spi.meta; import static java.util.Objects.requireNonNull; +import com.google.common.base.Verify; import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.opendaylight.yangtools.concepts.Identifiable; @@ -152,6 +155,41 @@ public abstract class NamespaceBehaviour> getFrom(final NamespaceStorageNode storage, + final NamespaceKeyCriterion criterion) { + final Map mappings = getAllFrom(storage); + if (mappings == null) { + return Optional.empty(); + } + + Entry match = null; + for (Entry entry : mappings.entrySet()) { + final K key = entry.getKey(); + if (criterion.match(key)) { + if (match != null) { + final K selected = criterion.select(match.getKey(), key); + if (selected.equals(match.getKey())) { + continue; + } + + Verify.verify(selected == key, "Criterion %s selected invalid key %s from candidates [%s %s]", + selected, match.getKey(), key); + } + + match = entry; + } + } + + return Optional.ofNullable(match); + } + /** * Returns all values of a keys of param class from model namespace storage. * diff --git a/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceKeyCriterion.java b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceKeyCriterion.java new file mode 100644 index 0000000000..72760959c2 --- /dev/null +++ b/yang/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/NamespaceKeyCriterion.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.yangtools.yang.parser.spi.meta; + +import com.google.common.annotations.Beta; +import javax.annotation.Nonnull; + +/** + * Namespace key matching criterion. + * + * @param Key type + * + * @author Robert Varga + */ +@Beta +public abstract class NamespaceKeyCriterion { + /** + * Match a key against this criterion. + * + * @param key Key to be matched + * @return True if the key matches this criterion, false otherwise. + */ + public abstract boolean match(@Nonnull K key); + + /** + * Select the better match from two candidate keys. + * + * @param first First key + * @param second Second key + * @return Selected key, must be either first or second key, by identity. + */ + public abstract K select(@Nonnull K first, @Nonnull K second); + + @Override + public abstract String toString(); + + @Override + public final int hashCode() { + return super.hashCode(); + } + + @Override + public final boolean equals(final Object obj) { + return super.equals(obj); + } +}