Add SchemaPath->SchemaNodeIdentifier conversions
[yangtools.git] / yang / yang-model-api / src / main / java / org / opendaylight / yangtools / yang / model / api / SchemaPath.java
index fb335dbd3f18575ddb9e3baf7aef512f2bffd0f6..267e9786e4cd515d221074e051293b3b01955908 100644 (file)
@@ -8,22 +8,24 @@
 package org.opendaylight.yangtools.yang.model.api;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.base.MoreObjects;
 import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
 import com.google.common.collect.UnmodifiableIterator;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Descendant;
 
 /**
  * Represents unique path to the every node inside the module.
@@ -44,8 +46,8 @@ public abstract class SchemaPath implements Immutable {
         }
 
         @Override
-        public AbsoluteSchemaPath createChild(final QName qname) {
-            return new AbsoluteSchemaPath(this, requireNonNull(qname));
+        public AbsoluteSchemaPath createChild(final QName element) {
+            return new AbsoluteSchemaPath(this, requireNonNull(element));
         }
     }
 
@@ -63,24 +65,20 @@ public abstract class SchemaPath implements Immutable {
         }
 
         @Override
-        public RelativeSchemaPath createChild(final QName qname) {
-            return new RelativeSchemaPath(this, requireNonNull(qname));
+        public RelativeSchemaPath createChild(final QName element) {
+            return new RelativeSchemaPath(this, requireNonNull(element));
         }
     }
 
-    @SuppressWarnings("rawtypes")
-    private static final AtomicReferenceFieldUpdater<SchemaPath, ImmutableList> LEGACYPATH_UPDATER =
-            AtomicReferenceFieldUpdater.newUpdater(SchemaPath.class, ImmutableList.class, "legacyPath");
-
     /**
      * Shared instance of the conceptual root schema node.
      */
-    public static final SchemaPath ROOT = new AbsoluteSchemaPath(null, null);
+    public static final @NonNull SchemaPath ROOT = new AbsoluteSchemaPath(null, null);
 
     /**
      * Shared instance of the "same" relative schema node.
      */
-    public static final SchemaPath SAME = new RelativeSchemaPath(null, null);
+    public static final @NonNull SchemaPath SAME = new RelativeSchemaPath(null, null);
 
     /**
      * Parent path.
@@ -97,12 +95,6 @@ public abstract class SchemaPath implements Immutable {
      */
     private final int hash;
 
-    /**
-     * Cached legacy path, filled-in when {@link #getPath()} or {@link #getPathTowardsRoot()}
-     * is invoked.
-     */
-    private volatile ImmutableList<QName> legacyPath;
-
     SchemaPath(final SchemaPath parent, final QName qname) {
         this.parent = parent;
         this.qname = qname;
@@ -115,48 +107,36 @@ public abstract class SchemaPath implements Immutable {
         hash = tmp;
     }
 
-    private ImmutableList<QName> getLegacyPath() {
-        ImmutableList<QName> ret = legacyPath;
-        if (ret == null) {
-            final List<QName> tmp = new ArrayList<>();
-            for (QName qname : getPathTowardsRoot()) {
-                tmp.add(qname);
-            }
-            ret = ImmutableList.copyOf(Lists.reverse(tmp));
-            LEGACYPATH_UPDATER.lazySet(this, ret);
-        }
-
-        return ret;
-    }
-
     /**
-     * Returns the complete path to schema node.
+     * Constructs new instance of this class with the concrete path.
      *
-     * @return list of <code>QName</code> instances which represents complete
-     *         path to schema node
+     * @param path
+     *            list of QName instances which specifies exact path to the
+     *            module node
+     * @param absolute
+     *            boolean value which specifies if the path is absolute or
+     *            relative
      *
-     * @deprecated Use {@link #getPathFromRoot()} instead.
+     * @return A SchemaPath instance.
      */
-    @Deprecated
-    public List<QName> getPath() {
-        return getLegacyPath();
+    public static @NonNull SchemaPath create(final Iterable<QName> path, final boolean absolute) {
+        return (absolute ? ROOT : SAME).createChild(path);
     }
 
     /**
      * Constructs new instance of this class with the concrete path.
      *
-     * @param path
-     *            list of QName instances which specifies exact path to the
-     *            module node
      * @param absolute
      *            boolean value which specifies if the path is absolute or
      *            relative
+     * @param element
+     *            a single QName which specifies exact path to the
+     *            module node
      *
      * @return A SchemaPath instance.
      */
-    public static SchemaPath create(final Iterable<QName> path, final boolean absolute) {
-        final SchemaPath parent = absolute ? ROOT : SAME;
-        return parent.createChild(path);
+    public static @NonNull SchemaPath create(final boolean absolute, final QName element) {
+        return (absolute ? ROOT : SAME).createChild(element);
     }
 
     /**
@@ -171,7 +151,7 @@ public abstract class SchemaPath implements Immutable {
      *
      * @return A SchemaPath instance.
      */
-    public static SchemaPath create(final boolean absolute, final QName... path) {
+    public static @NonNull SchemaPath create(final boolean absolute, final QName... path) {
         return create(Arrays.asList(path), absolute);
     }
 
@@ -181,14 +161,14 @@ public abstract class SchemaPath implements Immutable {
      * @param relative Relative path
      * @return A new child path
      */
-    public SchemaPath createChild(final Iterable<QName> relative) {
+    public @NonNull SchemaPath createChild(final Iterable<QName> relative) {
         if (Iterables.isEmpty(relative)) {
             return this;
         }
 
         SchemaPath parentPath = this;
-        for (QName qname : relative) {
-            parentPath = parentPath.createChild(qname);
+        for (QName item : relative) {
+            parentPath = parentPath.createChild(item);
         }
 
         return parentPath;
@@ -200,7 +180,7 @@ public abstract class SchemaPath implements Immutable {
      * @param relative Relative SchemaPath
      * @return A new child path
      */
-    public SchemaPath createChild(final SchemaPath relative) {
+    public @NonNull SchemaPath createChild(final SchemaPath relative) {
         checkArgument(!relative.isAbsolute(), "Child creation requires relative path");
         return createChild(relative.getPathFromRoot());
     }
@@ -211,7 +191,7 @@ public abstract class SchemaPath implements Immutable {
      * @param element Relative SchemaPath elements
      * @return A new child path
      */
-    public abstract SchemaPath createChild(QName element);
+    public abstract @NonNull SchemaPath createChild(QName element);
 
     /**
      * Create a child path based on concatenation of this path and additional
@@ -220,7 +200,7 @@ public abstract class SchemaPath implements Immutable {
      * @param elements Relative SchemaPath elements
      * @return A new child path
      */
-    public SchemaPath createChild(final QName... elements) {
+    public @NonNull SchemaPath createChild(final QName... elements) {
         return createChild(Arrays.asList(elements));
     }
 
@@ -232,8 +212,11 @@ public abstract class SchemaPath implements Immutable {
      * @return list of <code>qname</code> instances which represents
      *         path from the root to the schema node.
      */
-    public Iterable<QName> getPathFromRoot() {
-        return getLegacyPath();
+    public List<QName> getPathFromRoot() {
+        if (qname == null) {
+            return ImmutableList.of();
+        }
+        return parent == null ? ImmutableList.of(qname) : new PathFromRoot(this);
     }
 
     /**
@@ -244,7 +227,7 @@ public abstract class SchemaPath implements Immutable {
      *         path from the schema node towards the root.
      */
     public Iterable<QName> getPathTowardsRoot() {
-        return () -> new UnmodifiableIterator<QName>() {
+        return () -> new UnmodifiableIterator<>() {
             private SchemaPath current = SchemaPath.this;
 
             @Override
@@ -258,9 +241,9 @@ public abstract class SchemaPath implements Immutable {
                     final QName ret = current.qname;
                     current = current.parent;
                     return ret;
-                } else {
-                    throw new NoSuchElementException("No more elements available");
                 }
+
+                throw new NoSuchElementException("No more elements available");
             }
         };
     }
@@ -291,6 +274,46 @@ public abstract class SchemaPath implements Immutable {
      */
     public abstract boolean isAbsolute();
 
+    /**
+     * Return this path as a {@link SchemaNodeIdentifier}.
+     *
+     * @return A SchemaNodeIdentifier.
+     * @throws IllegalStateException if this path is empty
+     */
+    public final SchemaNodeIdentifier asSchemaNodeIdentifier() {
+        checkState(qname != null, "Cannot convert empty %s", this);
+        final List<QName> path = getPathFromRoot();
+        return isAbsolute() ? Absolute.of(path) : Descendant.of(path);
+    }
+
+    /**
+     * Return this path as an {@link Absolute} SchemaNodeIdentifier.
+     *
+     * @return An SchemaNodeIdentifier.
+     * @throws IllegalStateException if this path is empty or is not absolute.
+     */
+    public final Absolute asAbsolute() {
+        final SchemaNodeIdentifier ret = asSchemaNodeIdentifier();
+        if (ret instanceof Absolute) {
+            return (Absolute) ret;
+        }
+        throw new IllegalStateException("Path " + this + " is relative");
+    }
+
+    /**
+     * Return this path as an {@link Descendant} SchemaNodeIdentifier.
+     *
+     * @return An SchemaNodeIdentifier.
+     * @throws IllegalStateException if this path is empty or is not relative.
+     */
+    public final Descendant asDescendant() {
+        final SchemaNodeIdentifier ret = asSchemaNodeIdentifier();
+        if (ret instanceof Descendant) {
+            return (Descendant) ret;
+        }
+        throw new IllegalStateException("Path " + this + " is absolute");
+    }
+
     @Override
     public final int hashCode() {
         return hash;