Add SchemaPath->SchemaNodeIdentifier conversions
[yangtools.git] / yang / yang-model-api / src / main / java / org / opendaylight / yangtools / yang / model / api / SchemaPath.java
index 7d6ca30e48dbd808e49b8f1ba727a9121957faa3..267e9786e4cd515d221074e051293b3b01955908 100644 (file)
@@ -8,17 +8,14 @@
 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.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
@@ -26,6 +23,9 @@ import java.util.Objects;
 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.
@@ -35,7 +35,6 @@ public abstract class SchemaPath implements Immutable {
     /**
      * An absolute SchemaPath.
      */
-    // FIXME: 5.0.0: expose as a top-level construct (and use in APIs)
     private static final class AbsoluteSchemaPath extends SchemaPath {
         private AbsoluteSchemaPath(final SchemaPath parent, final QName qname) {
             super(parent, qname);
@@ -55,7 +54,6 @@ public abstract class SchemaPath implements Immutable {
     /**
      * A relative SchemaPath.
      */
-    // FIXME: 5.0.0: expose as a top-level construct (and use in APIs)
     private static final class RelativeSchemaPath extends SchemaPath {
         private RelativeSchemaPath(final SchemaPath parent, final QName qname) {
             super(parent, qname);
@@ -72,16 +70,6 @@ public abstract class SchemaPath implements Immutable {
         }
     }
 
-    private static final VarHandle LEGACY_PATH;
-
-    static {
-        try {
-            LEGACY_PATH = MethodHandles.lookup().findVarHandle(SchemaPath.class, "legacyPath", ImmutableList.class);
-        } catch (NoSuchFieldException | IllegalAccessException e) {
-            throw new ExceptionInInitializerError(e);
-        }
-    }
-
     /**
      * Shared instance of the conceptual root schema node.
      */
@@ -107,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.
-     */
-    @SuppressWarnings("unused")
-    private volatile ImmutableList<QName> legacyPath;
-
     SchemaPath(final SchemaPath parent, final QName qname) {
         this.parent = parent;
         this.qname = qname;
@@ -125,22 +107,6 @@ public abstract class SchemaPath implements Immutable {
         hash = tmp;
     }
 
-    private ImmutableList<QName> getLegacyPath() {
-        final ImmutableList<QName> local = (ImmutableList<QName>) LEGACY_PATH.getAcquire(this);
-        return local != null ? local : loadLegacyPath();
-    }
-
-    @SuppressWarnings("unchecked")
-    private ImmutableList<QName> loadLegacyPath() {
-        final List<QName> tmp = new ArrayList<>();
-        for (QName item : getPathTowardsRoot()) {
-            tmp.add(item);
-        }
-        final ImmutableList<QName> ret = ImmutableList.copyOf(Lists.reverse(tmp));
-        final Object witness = LEGACY_PATH.compareAndExchangeRelease(this, null, ret);
-        return witness == null ? ret : (ImmutableList<QName>) witness;
-    }
-
     /**
      * Constructs new instance of this class with the concrete path.
      *
@@ -246,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);
     }
 
     /**
@@ -305,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;