Add NormalizedNode.contract()
[yangtools.git] / yang / yang-data-api / src / main / java / org / opendaylight / yangtools / yang / data / api / YangInstanceIdentifier.java
index 96e4860dd0f584a869f875a2f27870c10a9bf51a..a7539e9167f08cb0917ba2b532e12f22e925194e 100644 (file)
@@ -12,6 +12,7 @@ import static com.google.common.base.Verify.verify;
 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;
@@ -44,7 +45,6 @@ import org.opendaylight.yangtools.concepts.Immutable;
 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;
@@ -54,50 +54,32 @@ import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
  * 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;
@@ -140,7 +122,6 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
      *
      * @return A optimized equivalent instance.
      */
-    @Beta
     public abstract @NonNull YangInstanceIdentifier toOptimized();
 
     /**
@@ -151,6 +132,15 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
      */
     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.
      *
@@ -196,6 +186,11 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
         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));
@@ -502,7 +497,7 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
         }
 
         protected int hashCodeImpl() {
-            return 31 + getNodeType().hashCode();
+            return nodeType.hashCode();
         }
 
         @Override
@@ -583,7 +578,8 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
      * 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;
@@ -597,7 +593,7 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
 
             @Override
             public SingletonSet<Entry<QName, Object>> entrySet() {
-                return SingletonSet.of(new SimpleImmutableEntry<>(key, value));
+                return SingletonSet.of(singleEntry());
             }
 
             @Override
@@ -605,6 +601,11 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
                 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);
@@ -620,6 +621,16 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
                 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;
@@ -652,6 +663,11 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
                 return keyValues.keySet();
             }
 
+            @Override
+            public boolean containsKey(final QName qname) {
+                return keyValues.containsKey(requireNonNull(qname));
+            }
+
             @Override
             public Collection<Object> values() {
                 return keyValues.values();
@@ -723,12 +739,6 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
             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());
         }
@@ -738,7 +748,6 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
          *
          * @return Predicate set.
          */
-        @Beta
         public abstract @NonNull Set<Entry<QName, Object>> entrySet();
 
         /**
@@ -746,15 +755,22 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
          *
          * @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
@@ -772,22 +788,14 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
          *
          * @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
@@ -832,23 +840,20 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
     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
@@ -1075,7 +1080,6 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
          * @return this builder
          * @throws NullPointerException if any of the arguments is null
          */
-        @Beta
         @NonNull InstanceIdentifierBuilder append(Collection<? extends PathArgument> args);
 
         /**
@@ -1085,7 +1089,6 @@ public abstract class YangInstanceIdentifier implements Path<YangInstanceIdentif
          * @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));
         }