import static java.util.Objects.requireNonNull;
import com.google.common.annotations.Beta;
+import com.google.common.base.VerifyException;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.opendaylight.yangtools.concepts.Path;
import org.opendaylight.yangtools.util.HashCodeBuilder;
import org.opendaylight.yangtools.util.ImmutableOffsetMap;
-import org.opendaylight.yangtools.util.SharedSingletonMap;
import org.opendaylight.yangtools.util.SingletonSet;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
* Unique identifier of a particular node instance in the data tree.
*
* <p>
- * Java representation of YANG Built-in type <code>instance-identifier</code>,
- * which conceptually is XPath expression minimized to uniquely identify element
- * in data tree which conforms to constraints maintained by YANG Model,
+ * Java representation of YANG Built-in type {@code instance-identifier}, which conceptually is XPath expression
+ * minimized to uniquely identify element in data tree which conforms to constraints maintained by YANG Model,
* effectively this makes Instance Identifier a path to element in data tree.
*
* <p>
- * Constraints put in YANG specification on instance-identifier allowed it to be
- * effectively represented in Java and it's evaluation does not require
- * full-blown XPath processor.
+ * Constraints put in YANG specification on instance-identifier allowed it to be effectively represented in Java and its
+ * evaluation does not require a full-blown XPath processor.
*
- * <p>
- * <h3>Path Arguments</h3>
- * Path to the node represented in instance identifier consists of
- * {@link PathArgument} which carries necessary information to uniquely identify
- * node on particular level in the subtree.
+ * <h2>Path Arguments</h2>
+ * Path to the node represented in instance identifier consists of {@link PathArgument} which carries necessary
+ * information to uniquely identify node on particular level in the subtree.
*
* <ul>
- * <li>{@link NodeIdentifier} - Identifier of node, which has cardinality
- * <code>0..1</code> in particular subtree in data tree.</li>
- * <li>{@link NodeIdentifierWithPredicates} - Identifier of node (list item),
- * which has cardinality <code>0..n</code>.</li>
- * <li>{@link NodeWithValue} - Identifier of instance <code>leaf</code> node or
- * <code>leaf-list</code> node.</li>
- * <li>{@link AugmentationIdentifier} - Identifier of instance of
- * <code>augmentation</code> node.</li>
+ * <li>{@link NodeIdentifier} - Identifier of node, which has cardinality {@code 0..1} in particular subtree in data
+ * tree</li>
+ * <li>{@link NodeIdentifierWithPredicates} - Identifier of node (list item), which has cardinality {@code 0..n}</li>
+ * <li>{@link NodeWithValue} - Identifier of instance {@code leaf} node or {@code leaf-list} node</li>
+ * <li>{@link AugmentationIdentifier} - Identifier of instance of {@code augmentation} node</li>
* </ul>
*
* @see <a href="http://tools.ietf.org/html/rfc6020#section-9.13">RFC6020</a>
*/
-// FIXME: 4.0.0: this concept needs to be moved to yang-common, as parser components need the ability to refer
+// FIXME: 7.0.0: this concept needs to be moved to yang-common, as parser components need the ability to refer
// to data nodes -- most notably XPath expressions and {@code default} statement arguments need to be able
// to represent these.
-// FIXME: Remove this suppression when we remove EMPTY
-@SuppressFBWarnings(value = "IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION",
- justification = "Having EMPTY a constant is the trouble here")
public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentifier>, Immutable, Serializable {
- /**
- * An empty {@link YangInstanceIdentifier}. It corresponds to the path of the conceptual root of the YANG namespace.
- *
- * @deprecated Use {@link #empty()} instead.
- */
- @Deprecated(forRemoval = true)
- public static final @NonNull YangInstanceIdentifier EMPTY = FixedYangInstanceIdentifier.EMPTY_INSTANCE;
-
private static final AtomicReferenceFieldUpdater<YangInstanceIdentifier, String> TOSTRINGCACHE_UPDATER =
AtomicReferenceFieldUpdater.newUpdater(YangInstanceIdentifier.class, String.class, "toStringCache");
private static final long serialVersionUID = 4L;
*
* @return A optimized equivalent instance.
*/
- @Beta
public abstract @NonNull YangInstanceIdentifier toOptimized();
/**
*/
public abstract @Nullable YangInstanceIdentifier getParent();
+ /**
+ * Return the conceptual parent {@link YangInstanceIdentifier}, which has one item less in
+ * {@link #getPathArguments()}.
+ *
+ * @return Parent {@link YangInstanceIdentifier}
+ * @throws VerifyException if this object is {@link #empty()}.
+ */
+ public abstract @NonNull YangInstanceIdentifier coerceParent();
+
/**
* Return the ancestor {@link YangInstanceIdentifier} with a particular depth, e.g. number of path arguments.
*
return FixedYangInstanceIdentifier.create(path, hash.build());
}
+ public static @NonNull YangInstanceIdentifier create(final PathArgument pathArgument) {
+ return new FixedYangInstanceIdentifier(ImmutableList.of(pathArgument),
+ HashCodeBuilder.nextHashCode(1, pathArgument));
+ }
+
public static @NonNull YangInstanceIdentifier create(final PathArgument... path) {
// We are forcing a copy, since we cannot trust the user
return create(Arrays.asList(path));
}
protected int hashCodeImpl() {
- return 31 + getNodeType().hashCode();
+ return nodeType.hashCode();
}
@Override
* overall data tree.
*/
public abstract static class NodeIdentifierWithPredicates extends AbstractPathArgument {
- private static final class Singleton extends NodeIdentifierWithPredicates {
+ @Beta
+ public static final class Singleton extends NodeIdentifierWithPredicates {
private static final long serialVersionUID = 1L;
private final @NonNull QName key;
@Override
public SingletonSet<Entry<QName, Object>> entrySet() {
- return SingletonSet.of(new SimpleImmutableEntry<>(key, value));
+ return SingletonSet.of(singleEntry());
}
@Override
return SingletonSet.of(key);
}
+ @Override
+ public boolean containsKey(final QName qname) {
+ return key.equals(requireNonNull(qname));
+ }
+
@Override
public SingletonSet<Object> values() {
return SingletonSet.of(value);
return ImmutableMap.of(key, value);
}
+ /**
+ * Return the single entry contained in this object. This is equivalent to
+ * {@code entrySet().iterator().next()}.
+ *
+ * @return A single entry.
+ */
+ public @NonNull Entry<QName, Object> singleEntry() {
+ return new SimpleImmutableEntry<>(key, value);
+ }
+
@Override
boolean equalMapping(final NodeIdentifierWithPredicates other) {
final Singleton single = (Singleton) other;
return keyValues.keySet();
}
+ @Override
+ public boolean containsKey(final QName qname) {
+ return keyValues.containsKey(requireNonNull(qname));
+ }
+
@Override
public Collection<Object> values() {
return keyValues.values();
return keyValues.size() == 1 ? of(keyValues, node) : new Regular(node, keyValues);
}
- @Deprecated
- public static @NonNull NodeIdentifierWithPredicates of(final QName node,
- final SharedSingletonMap<QName, Object> keyValues) {
- return of(node, keyValues.getEntry());
- }
-
private static @NonNull NodeIdentifierWithPredicates of(final Map<QName, Object> keyValues, final QName node) {
return of(node, keyValues.entrySet().iterator().next());
}
*
* @return Predicate set.
*/
- @Beta
public abstract @NonNull Set<Entry<QName, Object>> entrySet();
/**
*
* @return Predicate values.
*/
- @Beta
public abstract @NonNull Set<QName> keySet();
+ /**
+ * Determine whether a particular predicate key is present.
+ *
+ * @param key Predicate key
+ * @return True if the predicate is present, false otherwise
+ * @throws NullPointerException if {@code key} is null
+ */
+ public abstract boolean containsKey(QName key);
+
/**
* Return the predicate values in the iteration order of {@link #entrySet()}.
*
* @return Predicate values.
*/
- @Beta
public abstract @NonNull Collection<Object> values();
@Beta
*
* @return The number of predicates present.
*/
- @Beta
public abstract int size();
/**
* A Map-like view of this identifier's predicates. The view is expected to be stable and effectively-immutable.
*
* @return Map of predicates.
- * @deprecated This method in a provisional one. It can be used in the code base, but users requiring it should
- * contact <a href="mailto:yangtools-dev@lists.opendaylight.org">yangtools-dev</a> for migration
- * guidelines. Callers are strongly encouraged to explore {@link #entrySet()}, {@link #size()},
- * {@link #values()} and {@link #keySet()} as an alternative.
*/
@Beta
- @Deprecated
- // FIXME: 4.0.0: evaluate the real usefulness of this. The problem here is Map.hashCode() and Map.equals(),
- // which limits our options.
public abstract @NonNull Map<QName, Object> asMap();
@Override
public static final class NodeWithValue<T> extends AbstractPathArgument {
private static final long serialVersionUID = -3637456085341738431L;
- private final T value;
+ private final @NonNull T value;
public NodeWithValue(final QName node, final T value) {
super(node);
- this.value = value;
+ this.value = requireNonNull(value);
}
- public T getValue() {
+ public @NonNull T getValue() {
return value;
}
@Override
protected int hashCodeImpl() {
- final int prime = 31;
- int result = super.hashCodeImpl();
- result = prime * result + YangInstanceIdentifier.hashCode(value);
- return result;
+ return 31 * super.hashCodeImpl() + YangInstanceIdentifier.hashCode(value);
}
@Override
* @return this builder
* @throws NullPointerException if any of the arguments is null
*/
- @Beta
@NonNull InstanceIdentifierBuilder append(Collection<? extends PathArgument> args);
/**
* @return this builder
* @throws NullPointerException if any of the arguments is null
*/
- @Beta
default @NonNull InstanceIdentifierBuilder append(final PathArgument... args) {
return append(Arrays.asList(args));
}