org.apache.jackrabbit.spi.Path Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.spi;
import java.io.Serializable;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
/**
* The Path
interface defines the SPI level representation of
* a JCR path. It consists of an ordered list of {@link Path.Element} objects
* and is immutable.
*
* A {@link Path.Element} is either {@link Path.Element#denotesName() named}
* or one of the following special elements:
*
* - the {@link Element#denotesCurrent() current} element (Notation: "."),
* - the {@link Element#denotesParent() parent} element (Notation: ".."),
* - the {@link Element#denotesRoot() root} element (Notation: {}), which can
* only occur as the first element in a path, or
* - an {@link Element#denotesIdentifier() identifier} element, which can
* only occur as the first element in a path.
*
*
* A Path
is defined to have the following characteristics:
*
* Equality:
* Two paths are equal if they consist of the same elements.
*
* Length:
* The {@link Path#getLength() length} of a path is the number of its elements.
*
* Depth:
* The {@link Path#getDepth() depth} of a path is
*
* - 0 for the root path,
* - 0 for a path consisting of an identifier element only,
* - 0 for the path consisting of the current element only,
* - -1 for the path consisting of the parent element only,
* - 1 for the path consisting of a single named element,
* - depth(P) + depth(Q) for the path P/Q.
*
*
* The depth of a normalized absolute path equals its length minus 1.
*
* Absolute vs. Relative
* A path can be absolute or relative:
* A path {@link #isAbsolute() is absolute} if its first element is the root
* or an identifier element. A path is relative if it is not absolute.
*
* - An absolute path is valid if its depth is greater or equals 0. A relative
* path is always valid.
* - Two absolute paths are equivalent if "they refer to the same item in the
* hierarchy".
* - Two relative paths P and Q are equivalent if for every absolute path R such
* that R/P and R/Q are valid, R/P and R/Q are equivalent.
*
*
* Normalization:
* A path P {@link Path#isNormalized() is normalized} if P has minimal length
* amongst the set of all paths Q which are equivalent to P.
* This means that '.' and '..' elements are resolved as much as possible.
* An absolute path it is normalized if it is not identifier-based and
* contains no current or parent elements. The normalization of a path
* is unique.
*
* Equivalence:
* Path P is {@link Path#isEquivalentTo(Path) equivalent} to path Q (in the above sense)
* if the normalization of P is equal to the normalization of Q. This is
* an equivalence relation (i.e. reflexive, transitive,
* and symmetric).
*
* Canonical Paths:
* A path {@link Path#isCanonical() is canonical} if its absolute and normalized.
*
* Hierarchical Relationship:
* The ancestor relationship is a strict partial order (i.e. irreflexive, transitive,
* and asymmetric). Path P is a direct ancestor of path Q if P is equivalent to Q/..
*
* Path P is an {@link Path#isAncestorOf(Path) ancestor} of path Q if
*
* - P is a direct ancestor of Q or
* - P is a direct ancestor of some path S which is an ancestor of Q.
*
*
* Path P is an {@link Path#isDescendantOf(Path) descendant} of path Q if
*
* - Path P is a descendant of path Q if Q is an ancestor of P.
*
*/
public interface Path extends Serializable {
/**
* Constant representing an undefined index value
*/
public static final int INDEX_UNDEFINED = 0;
/**
* Constant representing the default (initial) index value.
*/
public static final int INDEX_DEFAULT = 1;
/**
* Constant defining the depth of the root path
*/
public static final int ROOT_DEPTH = 0;
/**
* Delimiter used in order to concatenate the Path.Element objects
* upon {@link Path#getString()}.
*/
public static final char DELIMITER = '\t';
/**
* Returns the name of the last path element, or null
* for an identifier. The names of the special root, current and parent
* elements are "", "." and ".." in the default namespace.
*
* @return name of the last path element, or null
*/
Name getName();
/**
* Returns the index of the last path element, or {@link #INDEX_UNDEFINED}
* if the index is not defined or not applicable. The index of an
* identifier or the special root, current or parent element is always
* undefined.
*
* @return index of the last path element, or {@link #INDEX_UNDEFINED}
*/
int getIndex();
/**
* Returns the normalized index of the last path element. The normalized
* index of an element with an undefined index is {@link #INDEX_DEFAULT}.
*
* @return normalized index of the last path element
*/
int getNormalizedIndex();
/**
* Returns the identifier of a single identifier element. Returns null
* for non-identifier paths or identifier paths with other relative path
* elements.
*
* @return identifier, or null
*/
String getIdentifier();
/**
* Tests whether this is the root path, i.e. "/".
*
* @return true
if this is the root path,
* false
otherwise.
*/
boolean denotesRoot();
/**
* Test if this path consists of a single identifier element.
*
* @return true
if this path is an identifier
*/
boolean denotesIdentifier();
/**
* Checks if the last path element is the parent element ("..").
*
* @return true
if the last path element is the parent element,
* false
otherwise
*/
boolean denotesParent();
/**
* Checks if the last path element is the current element (".").
*
* @return true
if the last path element is the current element,
* false
otherwise
*/
boolean denotesCurrent();
/**
* Checks if the last path element is a named and optionally indexed
* element.
*
* @return true
if the last path element is a named element,
* false
otherwise
*/
boolean denotesName();
/**
* Test if this path represents an unresolved identifier-based path.
*
* @return true
if this path represents an unresolved
* identifier-based path.
*/
boolean isIdentifierBased();
/**
* Tests whether this path is absolute, i.e. whether it starts with "/" or
* is an identifier based path.
*
* @return true if this path is absolute; false otherwise.
*/
public boolean isAbsolute();
/**
* Tests whether this path is canonical, i.e. whether it is absolute and
* does not contain redundant elements such as "." and "..".
*
* @return true if this path is canonical; false otherwise.
* @see #isAbsolute()
*/
public boolean isCanonical();
/**
* Tests whether this path is normalized, i.e. whether it does not
* contain redundant elements such as "." and "..".
*
* Note that a normalized path can still contain ".." elements if they are
* not redundant, e.g. "../../a/b/c" would be a normalized relative path,
* whereas "../a/../../a/b/c" wouldn't (although they're semantically
* equivalent).
*
* @return true if this path is normalized; false otherwise.
* @see #getNormalizedPath()
*/
public boolean isNormalized();
/**
* Returns the normalized path representation of this path.
*
* If the path cannot be normalized (e.g. if an absolute path is normalized
* that would result in a 'negative' path) a RepositoryException is thrown.
*
* @return a normalized path representation of this path.
* @throws RepositoryException if the path cannot be normalized.
* @see #isNormalized()
*/
public Path getNormalizedPath() throws RepositoryException;
/**
* Returns the canonical path representation of this path.
*
* If the path is relative or cannot be normalized a RepositoryException
* is thrown.
*
* @return a canonical path representation of this path.
* @throws RepositoryException if this path can not be canonicalized
* (e.g. if it is relative).
*/
public Path getCanonicalPath() throws RepositoryException;
/**
* Resolves the given path element against this path. If the given
* element is absolute (i.e. the root or an identifier element), then
* a path containing just that element is returned. Otherwise the
* returned path consists of this path followed by the given element.
*
* @param element path element
* @return resolved path
*/
Path resolve(Element element);
/**
* Resolves the given path against this path. If the given path is
* absolute, then it is returned as-is. Otherwise the path is resolved
* relative to this path and the resulting resolved path is returned.
*
* @param relative the path to be resolved
* @return resolved path
*/
Path resolve(Path relative);
/**
* Computes the relative path from this
absolute path to
* other
.
*
* @param other an absolute path.
* @return the relative path from this
path to other
* path.
* @throws RepositoryException if either this
or
* other
path is not absolute.
*/
public Path computeRelativePath(Path other) throws RepositoryException;
/**
* Normalizes this path and returns the ancestor path of the specified
* relative degree.
*
* An ancestor of relative degree x is the path that is x
* levels up along the path.
*
* - degree = 0 returns this path.
*
- degree = 1 returns the parent of this path.
*
- degree = 2 returns the grandparent of this path.
*
- And so on to degree = n, where n is the depth
* of this path, which returns the root path.
*
*
* If this path is relative the implementation may not be able to determine
* if the ancestor at degree
exists. Such an implementation
* should properly build the ancestor (i.e. parent of .. is ../..) and
* leave if it the caller to throw PathNotFoundException
.
*
* @param degree the relative degree of the requested ancestor.
* @return the normalized ancestor path of the specified degree.
* @throws IllegalArgumentException if degree
is negative.
* @throws PathNotFoundException if the implementation is able to determine
* that there is no ancestor of the specified degree. In case of this
* being an absolute path, this would be the case if degree
is
* greater that the {@link #getDepth() depth} of this path.
* @throws RepositoryException If the implementation is not able to determine
* the ancestor of the specified degree for some other reason.
*/
public Path getAncestor(int degree) throws IllegalArgumentException, PathNotFoundException, RepositoryException;
/**
* Returns the number of ancestors of this path. This is the equivalent
* of {@link #getDepth()}
in case of a absolute path.
* For relative path the number of ancestors cannot be determined and
* -1 should be returned.
*
* @return the number of ancestors of this path or -1 if the number of
* ancestors cannot be determined.
* @see #getDepth()
* @see #getLength()
* @see #isCanonical()
*/
public int getAncestorCount();
/**
* Returns the length of this path, i.e. the number of its elements.
* Note that the root element "/" counts as a separate element, e.g.
* the length of "/a/b/c" is 4 whereas the length of "a/b/c" is 3.
*
* Also note that the special elements "." and ".." are not treated
* specially, e.g. both "/a/./.." and "/a/b/c" have a length of 4
* but this value does not necessarily reflect the true hierarchy level as
* returned by {@link #getDepth()}
.
*
* @return the length of this path
* @see #getDepth()
* @see #getAncestorCount()
*/
public int getLength();
/**
* Returns the depth of this path. The depth reflects the absolute or
* relative hierarchy level this path is representing, depending on whether
* this path is an absolute or a relative path. The depth also takes '.'
* and '..' elements into account. The depth of the root path, an
* identifier and the current path must be 0.
*
* Note that the returned value might be negative if this path is not
* canonical, e.g. the depth of "../../a" is -1.
*
* @return the depth this path
* @see #getLength()
* @see #getAncestorCount()
*/
public int getDepth();
/**
* Determines if the the other
path would be equal to this
* path if both of them are normalized.
*
* @param other Another path.
* @return true if the given other path is equivalent to this path.
* @throws IllegalArgumentException if the given path is null
* or if not both paths are either absolute or relative.
* @throws RepositoryException if any of the path cannot be normalized.
*/
public boolean isEquivalentTo(Path other) throws IllegalArgumentException, RepositoryException;
/**
* Determines if this path is an ancestor of the specified path,
* based on their (absolute or relative) hierarchy level as returned by
* {@link #getDepth()}
. In case of undefined ancestor/descendant
* relationship that might occur with relative paths, the return value
* should be false
.
*
* @return true
if other
is a descendant;
* otherwise false
.
* @throws IllegalArgumentException if the given path is null
* or if not both paths are either absolute or relative.
* @throws RepositoryException if any of the path cannot be normalized.
* @see #getDepth()
*/
public boolean isAncestorOf(Path other) throws IllegalArgumentException, RepositoryException;
/**
* Determines if this path is a descendant of the specified path,
* based on their (absolute or relative) hierarchy level as returned by
* {@link #getDepth()}
. In case of undefined ancestor/descendant
* relationship that might occur with relative paths, the return value
* should be false
.
*
* @return true
if other
is an ancestor;
* otherwise false
.
* @throws IllegalArgumentException if the given path is null
* or if not both paths are either absolute or relative.
* @throws RepositoryException if any of the path cannot be normalized.
* @see #isAncestorOf(Path)
*/
public boolean isDescendantOf(Path other) throws IllegalArgumentException, RepositoryException;
/**
* Returns a new Path
consisting of those Path.Element objects
* between the given from
, inclusive, and the given to
,
* exclusive. An IllegalArgumentException
is thrown if from
* is greater or equal than to
or if any of both params is
* out of the possible range.
*
* @param from index of the element to start with and low endpoint
* (inclusive) within the list of elements to use for the sub-path.
* @param to index of the element outside of the range i.e. high endpoint
* (exclusive) within the list of elements to use for the sub-path.
* @return a new Path
consisting of those Path.Element objects
* between the given from
, inclusive, and the given
* to
, exclusive.
* @throws IllegalArgumentException if from
* is greater or equal than to
or if any of both params is
* out of the possible range.
*/
public Path subPath(int from, int to) throws IllegalArgumentException;
/**
* Returns the elements of this path.
*
* @return the elements of this path.
*/
public Element[] getElements();
/**
* Returns the name element (i.e. the last element) of this path.
*
* @return the name element of this path
*/
public Element getNameElement();
/**
* Returns a path that consists of only the last element of this path.
*
* @see #getFirstElements()
* @return last element of this path
*/
Path getLastElement();
/**
* Returns a path that consists of all but the last element of this path.
* Returns null
if this path contains just a single element.
*
* @see #getLastElement()
* @return first elements of this path, or null
*/
Path getFirstElements();
/**
* Returns the String representation of this Path as it is used
* by {@link PathFactory#create(String)}.
*
* The String representation must consist of the String representation of
* its elements separated by {@link Path#DELIMITER}.
*
* @see Path.Element#getString()
* @return Returns the String representation of this Path.
*/
public String getString();
//----------------------------------------------------< inner interface >---
/**
* Object representation of a single JCR path element. An Element
* object contains the Name
and optional index of a single
* JCR path element.
*
* Once created, a Element
object must be immutable.
*
* The String presentation of an Element
must be in the format
* "{namespaceURI}localPart
" or
* "{namespaceURI}localPart[index]
" case of an index greater
* than {@link Path#INDEX_DEFAULT}.
*
* Note, that the implementation must implement the equals method such, that
* two Element
objects having equals Name
s and the
* same normalized index must be equal.
*/
public interface Element extends Serializable {
/**
* Returns the name of this path element.
*
* @return The name of this path element.
*/
public Name getName();
/**
* Returns the index of the element as it has been assigned upon creation.
*
* @return index of the element as it has been assigned upon creation.
*/
public int getIndex();
/**
* Returns the normalized index of this path element, i.e. the index
* is always equals or greater that {@link Path#INDEX_DEFAULT}.
*
* @return the normalized index.
*/
public int getNormalizedIndex();
/**
* Returns the identifier of an identifier element, or
* null
for other kinds of elements.
*
* @return identifier, or null
*/
String getIdentifier();
/**
* Returns true
if this element denotes the root element,
* otherwise returns false
.
*
* @return true
if this element denotes the root
* element; otherwise false
*/
public boolean denotesRoot();
/**
* Returns true
if this element denotes the parent
* ('..') element, otherwise returns false
.
*
* @return true
if this element denotes the parent
* element; otherwise false
*/
public boolean denotesParent();
/**
* Returns true
if this element denotes the current
* ('.') element, otherwise returns false
.
*
* @return true
if this element denotes the current
* element; otherwise false
*/
public boolean denotesCurrent();
/**
* Returns true
if this element represents a regular name
* (i.e. neither root, '.' nor '..'), otherwise returns false
.
*
* @return true
if this element represents a regular name;
* otherwise false
*/
public boolean denotesName();
/**
* Returns true
if this element represents an identifier element.
*
* @return true
if this element represents an identifier element.
* @since JCR 2.0
*/
public boolean denotesIdentifier();
/**
* Return the String presentation of a {@link Path.Element}. It must be
* in the format "{namespaceURI}localPart
" or
* "{namespaceURI}localPart[index]
" in case of an index
* greater than {@link Path#INDEX_DEFAULT}.
*
* @return String representation of a {@link Path.Element}.
*/
public String getString();
}
}