Refactor rpc/action statements
[yangtools.git] / yang / yang-model-api / src / main / java / org / opendaylight / yangtools / yang / model / api / PathExpression.java
index f3a251ae6c2674879e55fb363e9f1beca8e1a2c2..5673a241172bbb3b24a551a5d1fbaa3804306dad 100644 (file)
@@ -7,13 +7,20 @@
  */
 package org.opendaylight.yangtools.yang.model.api;
 
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
-import org.eclipse.jdt.annotation.NonNull;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.concepts.Immutable;
 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
 import org.opendaylight.yangtools.yang.xpath.api.YangFunction;
 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.QNameStep;
+import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Relative;
+import org.opendaylight.yangtools.yang.xpath.api.YangPathExpr;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
 import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression;
 
@@ -26,21 +33,141 @@ import org.opendaylight.yangtools.yang.xpath.api.YangXPathExpression;
  * subexpressions it can contain:
  * <ul>
  * <li>the root expression must be a {@link YangLocationPath}</li>
- * <li>it can contain steps only along {@link YangXPathAxis#DESCENDANT} and {@link YangXPathAxis#PARENT} axis</li>
- * <li>all steps along {@link YangXPathAxis#DESCENDANT} axis are {@link QNameStep}</li>
+ * <li>it can contain steps only along {@link YangXPathAxis#CHILD} and {@link YangXPathAxis#PARENT} axis</li>
+ * <li>all steps along {@link YangXPathAxis#CHILD} axis are {@link QNameStep}</li>
  * <li>the only function invocation is {@link YangFunction#CURRENT}</li>
  * <li>only {@link YangBinaryOperator#EQUALS} is allowed</li>
  * <li>no literals nor numbers are allowed</li>
+ * <li>all qualified node identifiers must me resolved</li>
  * </ul>
  *
  * @author Robert Varga
  */
 @Beta
+@NonNullByDefault
 public interface PathExpression extends Immutable {
     /**
-     * Return the {@link YangLocationPath} of this expression.
+     * Abstract base class for expressing steps of a PathExpression.
+     */
+    abstract class Steps {
+        Steps() {
+            // Prevent external subclassing
+        }
+
+        @Override
+        public abstract int hashCode();
+
+        @Override
+        public abstract boolean equals(@Nullable Object obj);
+
+        @Override
+        public final String toString() {
+            return addToStringAttributes(MoreObjects.toStringHelper(this)).toString();
+        }
+
+        abstract ToStringHelper addToStringAttributes(ToStringHelper helper);
+    }
+
+    /**
+     * Steps of a PathExpression which is a LocationPath, corresponding to RFC7950 base specification.
+     */
+    final class LocationPathSteps extends Steps {
+        private final YangLocationPath locationPath;
+
+        public LocationPathSteps(final YangLocationPath locationPath) {
+            this.locationPath = requireNonNull(locationPath);
+        }
+
+        public YangLocationPath getLocationPath() {
+            return locationPath;
+        }
+
+        @Override
+        public int hashCode() {
+            return locationPath.hashCode();
+        }
+
+        @Override
+        public boolean equals(final @Nullable Object obj) {
+            return this == obj
+                    || obj instanceof LocationPathSteps && locationPath.equals(((LocationPathSteps) obj).locationPath);
+        }
+
+        @Override
+        ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+            return helper.add("locationPath", locationPath);
+        }
+    }
+
+    /**
+     * Steps of a PathExpression which is a combination of {@code deref()} function call and a relative path,
+     * corresponding to Errata 5617.
+     */
+    final class DerefSteps extends Steps {
+        private final Relative derefArgument;
+        private final Relative relativePath;
+
+        public DerefSteps(final Relative derefArgument, final Relative relativePath) {
+            this.derefArgument = requireNonNull(derefArgument);
+            this.relativePath = requireNonNull(relativePath);
+        }
+
+        public Relative getDerefArgument() {
+            return derefArgument;
+        }
+
+        public Relative getRelativePath() {
+            return relativePath;
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 * derefArgument.hashCode() + relativePath.hashCode();
+        }
+
+        @Override
+        public boolean equals(@Nullable final Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof DerefSteps)) {
+                return false;
+            }
+            final DerefSteps other = (DerefSteps) obj;
+            return derefArgument.equals(other.derefArgument) && relativePath.equals(other.relativePath);
+        }
+
+        @Override
+        ToStringHelper addToStringAttributes(final ToStringHelper helper) {
+            return helper.add("derefArgument", derefArgument).add("relativePath", relativePath);
+        }
+    }
+
+    /**
+     * Returns the path expression formatted string as is defined in model. For example:
+     * {@code /prefix:container/prefix:container::cond[when()=foo]/prefix:leaf}
+     *
+     * @return the path expression formatted string as is defined in model.
+     */
+    String getOriginalString();
+
+    /**
+     * Return the path of this expression, which can either be a {@link YangLocationPath} (compliant to RFC7950) or
+     * a {@link YangPathExpr} with filter being an invocation of {@link YangFunction#DEREF}.
+     *
+     * @return The path's steps
+     * @throws UnsupportedOperationException if the implementation has not parsed the string. Implementations are
+     *         strongly encouraged to perform proper parsing.
+     */
+    Steps getSteps();
+
+    /**
+     * Returns <code>true</code> if the XPapth starts in root of YANG model, otherwise returns <code>false</code>.
      *
-     * @return The location path
+     * @return <code>true</code> if the XPapth starts in root of YANG model, otherwise returns <code>false</code>
      */
-    @NonNull YangLocationPath getLocation();
+    default boolean isAbsolute() {
+        final Steps steps = getSteps();
+        return steps instanceof LocationPathSteps && ((LocationPathSteps) steps).getLocationPath().isAbsolute();
+    }
 }