You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2006/07/21 12:43:06 UTC
svn commit: r424258 - in /jackrabbit/trunk/jackrabbit/src:
main/java/org/apache/jackrabbit/name/ test/java/org/apache/jackrabbit/name/
Author: tripod
Date: Fri Jul 21 03:43:04 2006
New Revision: 424258
URL: http://svn.apache.org/viewvc?rev=424258&view=rev
Log:
- improve Path and QName classes
- improve PathElement handling
- add convenience methods to NameFormat
Modified:
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/Path.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/QName.java
jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/name/PathTest.java
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java?rev=424258&r1=424257&r2=424258&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java Fri Jul 21 03:43:04 2006
@@ -80,6 +80,39 @@
}
/**
+ * Parses an array of <code>jcrName</code> and returns the respective
+ * array of <code>QName</code>. If the passed <code>resolver</code> also an
+ * instance of {@link NameCache} then the parsing is first read from the cache.
+ *
+ * @param jcrNames the array of names to be parsed
+ * @param resolver <code>NamespaceResolver</code> use to retrieve the
+ * namespace URI from the prefix contained in the given JCR name.
+ * @return the new array of <code>QName</code>
+ * @throws IllegalNameException If <code>jcrName</code> is not a valid
+ * JCR-style name.
+ */
+ public static QName[] parse(String jcrNames[], NamespaceResolver resolver)
+ throws IllegalNameException, UnknownPrefixException {
+
+ QName[] ret = new QName[jcrNames.length];
+ if (resolver instanceof NameCache) {
+ for (int i=0; i<ret.length; i++) {
+ QName name = ((NameCache) resolver).retrieveName(jcrNames[i]);
+ if (name == null) {
+ name = parseNoCache(jcrNames[i], resolver);
+ ((NameCache) resolver).cacheName(jcrNames[i], name);
+ }
+ ret[i] = name;
+ }
+ } else {
+ for (int i=0; i<ret.length; i++) {
+ ret[i] = parseNoCache(jcrNames[i], resolver);
+ }
+ }
+ return ret;
+ }
+
+ /**
* Parses the <code>jcrName</code> and returns a new <code>QName</code>,
* but does not respect possible caches.
*
@@ -195,6 +228,42 @@
formatNoCache(qName, resolver, buf);
return buf.toString();
}
+ }
+
+ /**
+ * Optimized convenience method that returns an array of string
+ * representations of the given qualified <code>name</code> in the JCR name
+ * format. If the passed <code>resolver</code> also an instance of
+ * {@link NameCache} then the formatting is first read from the cache.
+ *
+ * @param qNames the array of qualified name to resolve.
+ * @param resolver the namespace resolver.
+ * @return the array of jcr names
+ * @throws NoPrefixDeclaredException if a namespace can not be resolved
+ * @see #format(QName, NamespaceResolver, StringBuffer)
+ */
+ public static String[] format(QName[] qNames, NamespaceResolver resolver)
+ throws NoPrefixDeclaredException {
+ String[] ret = new String[qNames.length];
+ if (resolver instanceof NameCache) {
+ for (int i=0; i<ret.length; i++) {
+ String jcrName = ((NameCache) resolver).retrieveName(qNames[i]);
+ if (jcrName == null) {
+ StringBuffer buf = new StringBuffer();
+ formatNoCache(qNames[i], resolver, buf);
+ jcrName = buf.toString();
+ ((NameCache) resolver).cacheName(jcrName, qNames[i]);
+ }
+ ret[i] = jcrName;
+ }
+ } else {
+ for (int i=0; i<ret.length; i++) {
+ StringBuffer buf = new StringBuffer();
+ formatNoCache(qNames[i], resolver, buf);
+ ret[i] = buf.toString();
+ }
+ }
+ return ret;
}
/**
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/Path.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/Path.java?rev=424258&r1=424257&r2=424258&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/Path.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/Path.java Fri Jul 21 03:43:04 2006
@@ -16,8 +16,6 @@
*/
package org.apache.jackrabbit.name;
-import org.apache.jackrabbit.util.Text;
-
import javax.jcr.PathNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -43,7 +41,7 @@
* <p/>
* <code>isCanonical()</code>:<br>
* A path is canonical if its absolute and normalized.
- *
+ * <p/>
* <h2>String representations</h2>
* <p/>
* The JCR path format is specified by JSR 170 as follows:
@@ -159,6 +157,43 @@
}
//------------------------------------------------------< factory methods >
+
+ /**
+ * Creates a new <code>Path</code> from the given path elements.
+ *
+ * @param elements the path elements that will form the path
+ * @return a new <code>Path</code>
+ */
+ public static Path create(PathElement[] elements) {
+ PathElement[] tmp = new PathElement[elements.length];
+ boolean isNormalized = true;
+ boolean leadingParent = true;
+ for (int i = 0; i < elements.length; i++) {
+ PathElement elem = tmp[i] = elements[i];
+ if (elem.denotesCurrent() || elem.denotesParent()) {
+ leadingParent &= elem.denotesParent();
+ isNormalized &= !elem.denotesCurrent() && (leadingParent || !elem.denotesParent());
+ }
+ }
+ return new Path(tmp, isNormalized);
+ }
+
+ /**
+ * Creates a new <code>Path</code> from the given path elements but does
+ * not check if the path is normalized or not.
+ * <p/>
+ * Please note that this method should only be called, if the normalized
+ * state is known. Further is the element array not duplicated. Basically
+ * this method should only be called from {@link PathFormat}.
+ *
+ * @param elements the path elements that will form the path
+ * @param isNormalized flag
+ * @return a new <code>Path</code>
+ */
+ protected static Path create(PathElement[] elements, boolean isNormalized) {
+ return new Path(elements, isNormalized);
+ }
+
/**
* Creates a new <code>Path</code> from the given <code>jcrPath</code>
* string. If <code>normalize</code> is <code>true</code>, the returned
@@ -174,12 +209,9 @@
public static Path create(String jcrPath, NamespaceResolver resolver,
boolean normalize)
throws MalformedPathException {
- Path path = PathFormat.parse(jcrPath, resolver);
- if (normalize) {
- return path.getNormalizedPath();
- } else {
- return path;
- }
+ return normalize
+ ? PathFormat.parse(null, jcrPath, resolver).getNormalizedPath()
+ : PathFormat.parse(null, jcrPath, resolver);
}
/**
@@ -198,12 +230,9 @@
public static Path create(Path parent, String relJCRPath,
NamespaceResolver resolver, boolean canonicalize)
throws MalformedPathException {
- Path path = PathFormat.parse(parent, relJCRPath, resolver);
- if (canonicalize) {
- return path.getCanonicalPath();
- } else {
- return path;
- }
+ return canonicalize
+ ? PathFormat.parse(parent, relJCRPath, resolver).getCanonicalPath()
+ : PathFormat.parse(parent, relJCRPath, resolver);
}
/**
@@ -223,16 +252,11 @@
if (relPath.isAbsolute()) {
throw new MalformedPathException("relPath is not a relative path");
}
-
PathBuilder pb = new PathBuilder(parent);
pb.addAll(relPath.getElements());
-
- Path path = pb.getPath();
- if (normalize) {
- return path.getNormalizedPath();
- } else {
- return path;
- }
+ return normalize
+ ? pb.getPath().getNormalizedPath()
+ : pb.getPath();
}
/**
@@ -241,30 +265,26 @@
* the returned path will be normalized (or canonicalized, if the parent
* path is absolute).
*
- * @param parent the parent path
- * @param name the name of the new path element.
+ * @param parent the parent path
+ * @param name the name of the new path element.
* @param normalize
* @return the new path.
*/
public static Path create(Path parent, QName name, boolean normalize) throws MalformedPathException {
PathBuilder pb = new PathBuilder(parent);
pb.addLast(name);
-
- Path path = pb.getPath();
- if (normalize) {
- return path.getNormalizedPath();
- } else {
- return path;
- }
+ return normalize
+ ? pb.getPath().getNormalizedPath()
+ : pb.getPath();
}
/**
* Creates a new <code>Path</code> out of the given <code>parent<code> path
* and the give name and index.
*
- * @param parent the paren tpath.
- * @param name the name of the new path element.
- * @param index the index of the new path element.
+ * @param parent the paren tpath.
+ * @param name the name of the new path element.
+ * @param index the index of the new path element.
* @param normalize
* @return the new path.
*/
@@ -272,13 +292,9 @@
throws MalformedPathException {
PathBuilder pb = new PathBuilder(parent);
pb.addLast(name, index);
-
- Path path = pb.getPath();
- if (normalize) {
- return path.getNormalizedPath();
- } else {
- return path;
- }
+ return normalize
+ ? pb.getPath().getNormalizedPath()
+ : pb.getPath();
}
/**
@@ -291,19 +307,31 @@
*/
public static Path create(QName name, int index)
throws IllegalArgumentException {
- if (index < INDEX_UNDEFINED) {
+ PathElement elem = createPathElement(name, index);
+ return new Path(new PathElement[]{elem}, !elem.denotesCurrent());
+ }
+
+ /**
+ * Create a PathElement from the given QName and index.
+ *
+ * @param qName
+ * @param index
+ * @return new path element
+ * @throws IllegalArgumentException if the index is less than {@link Path#INDEX_UNDEFINED}.
+ */
+ public static PathElement createPathElement(QName qName, int index) {
+ if (index < Path.INDEX_UNDEFINED) {
throw new IllegalArgumentException("index must not be negative: " + index);
}
- PathElement elem;
- if (index < INDEX_DEFAULT) {
- elem = new PathElement(name);
+ if (index < Path.INDEX_DEFAULT) {
+ return PathElement.create(qName);
} else {
- elem = new PathElement(name, index);
+ return PathElement.create(qName, index);
}
- return new Path(new PathElement[]{elem}, !elem.equals(CURRENT_ELEMENT));
}
//------------------------------------------------------< utility methods >
+
/**
* Checks if <code>jcrPath</code> is a valid JCR-style absolute or relative
* path.
@@ -318,6 +346,7 @@
}
//-------------------------------------------------------< public methods >
+
/**
* Tests whether this path represents the root path, i.e. "/".
*
@@ -382,26 +411,19 @@
return this;
}
LinkedList queue = new LinkedList();
- PathElement last = null;
+ PathElement last = PARENT_ELEMENT;
for (int i = 0; i < elements.length; i++) {
PathElement elem = elements[i];
- if (elem.denotesCurrent()) {
- continue;
- } else if (elem.denotesParent() && last != null && !last.denotesParent()) {
+ if (elem.denotesParent() && !last.denotesParent()) {
if (last.denotesRoot()) {
// the first element is the root element;
// ".." would refer to the parent of root
throw new MalformedPathException("Path can not be canonicalized: unresolvable '..' element");
}
queue.removeLast();
- if (queue.isEmpty()) {
- last = null;
- } else {
- last = (PathElement) queue.getLast();
- }
- } else {
- last = elem;
- queue.add(elem);
+ last = queue.isEmpty() ? PARENT_ELEMENT : (PathElement) queue.getLast();
+ } else if (!elem.denotesCurrent()) {
+ queue.add(last = elem);
}
}
if (queue.isEmpty()) {
@@ -462,7 +484,8 @@
// determine length of common path fragment
int lengthCommon = 0;
- for (int i = 0; i < p0.getElements().length && i < p1.getElements().length; i++) {
+ for (int i = 0; i < p0.getElements().length && i < p1.getElements().length; i++)
+ {
if (!p0.getElement(i).equals(p1.getElement(i))) {
break;
}
@@ -508,7 +531,8 @@
*
* @param degree the relative degree of the requested ancestor.
* @return the ancestor path of the specified degree.
- * @throws javax.jcr.PathNotFoundException if there is no ancestor of the specified
+ * @throws PathNotFoundException
+ * if there is no ancestor of the specified
* degree
* @throws IllegalArgumentException if <code>degree</code> is negative
*/
@@ -668,7 +692,7 @@
* @param i element index.
* @return the <code>i</code><sup>th</sup> element of this path.
* @throws ArrayIndexOutOfBoundsException if this path does not have an
- * element at index <code>i</code>.
+ * element at index <code>i</code>.
*/
public PathElement getElement(int i) {
return elements[i];
@@ -688,6 +712,7 @@
}
//---------------------------------------------------------------< Object >
+
/**
* Returns the internal string representation of this <code>Path</code>.
* <p/>
@@ -737,12 +762,22 @@
// split into path elements
// @todo find safe path separator char that does not conflict with chars in serialized QName
- String[] elements = Text.explode(s, '\t', true);
+ final char delim = '\t';
+ int lastPos = 0;
+ int pos = s.indexOf(delim);
ArrayList list = new ArrayList();
boolean isNormalized = true;
boolean leadingParent = true;
- for (int i = 0; i < elements.length; i++) {
- PathElement elem = PathElement.fromString(elements[i]);
+ while (lastPos >= 0) {
+ PathElement elem;
+ if (pos >= 0) {
+ elem = PathElement.fromString(s.substring(lastPos, pos));
+ lastPos = pos + 1;
+ pos = s.indexOf(delim, lastPos);
+ } else {
+ elem = PathElement.fromString(s.substring(lastPos));
+ lastPos = -1;
+ }
list.add(elem);
leadingParent &= elem.denotesParent();
isNormalized &= !elem.denotesCurrent() && (leadingParent || !elem.denotesParent());
@@ -788,6 +823,7 @@
}
//--------------------------------------------------------< inner classes >
+
/**
* Internal helper class used to build a path from pre-parsed path elements.
* <p/>
@@ -883,7 +919,7 @@
* @param name
*/
public void addFirst(QName name) {
- addFirst(new PathElement(name));
+ addFirst(PathElement.create(name));
}
/**
@@ -893,7 +929,7 @@
* @param index
*/
public void addFirst(QName name, int index) {
- addFirst(new PathElement(name, index));
+ addFirst(PathElement.create(name, index));
}
/**
@@ -913,7 +949,7 @@
* @param name
*/
public void addLast(QName name) {
- addLast(new PathElement(name));
+ addLast(PathElement.create(name));
}
/**
@@ -923,7 +959,7 @@
* @param index
*/
public void addLast(QName name, int index) {
- addLast(new PathElement(name, index));
+ addLast(PathElement.create(name, index));
}
/**
@@ -943,198 +979,27 @@
return new Path(elements, isNormalized);
}
- public Object clone() {
+ /**
+ * {@inheritDoc}
+ */
+ public Object clone() throws CloneNotSupportedException {
+ super.clone();
PathBuilder clone = new PathBuilder();
clone.queue.addAll(queue);
return clone;
}
}
- public static final class RootElement extends PathElement {
- // use a literal that is an illegal name character to avoid collisions
- static final String LITERAL = "*";
-
- private RootElement() {
- super(QName.ROOT);
- }
-
- /**
- * Returns true.
- * @return true
- * @see PathElement#denotesRoot()
- */
- public boolean denotesRoot() {
- return true;
- }
-
- /**
- * Returns false.
- * @return false
- * @see PathElement#denotesCurrent()
- */
- public boolean denotesCurrent() {
- return false;
- }
-
- /**
- * Returns false.
- * @return false
- * @see PathElement#denotesParent()
- */
- public boolean denotesParent() {
- return false;
- }
-
- /**
- * Returns false.
- * @return false
- * @see PathElement#denotesName()
- */
- public boolean denotesName() {
- return false;
- }
-
- /**
- * @return {@link #LITERAL}
- * @see Object#toString()
- */
- public String toString() {
- return LITERAL;
- }
- }
-
- public static final class CurrentElement extends PathElement {
- static final String LITERAL = ".";
-
- private CurrentElement() {
- super(QName.NS_DEFAULT_URI, LITERAL);
- }
-
- /**
- * Returns false.
- * @return false
- * @see PathElement#denotesRoot()
- */
- public boolean denotesRoot() {
- return false;
- }
-
- /**
- * Returns true.
- * @return true
- */
- public boolean denotesCurrent() {
- return true;
- }
-
- /**
- * Returns false.
- * @return false
- * @see PathElement#denotesParent()
- */
- public boolean denotesParent() {
- return false;
- }
-
- /**
- * Returns false.
- * @return false
- * @see PathElement#denotesName()
- */
- public boolean denotesName() {
- return false;
- }
-
- /**
- * Returns the JCR name of this path element.
- *
- * @param resolver
- * @return {@link #LITERAL}
- */
- public String toJCRName(NamespaceResolver resolver) {
- return LITERAL;
- }
-
-
- /**
- * @return {@link #LITERAL}
- * @see Object#toString()
- */
- public String toString() {
- return LITERAL;
- }
- }
-
- private static final class ParentElement extends PathElement {
- static final String LITERAL = "..";
-
- private ParentElement() {
- super(QName.NS_DEFAULT_URI, LITERAL);
- }
-
- /**
- * Returns false.
- * @return false
- * @see PathElement#denotesRoot()
- */
- public boolean denotesRoot() {
- return false;
- }
-
- /**
- * Returns false.
- * @return false
- * @see PathElement#denotesCurrent()
- */
- public boolean denotesCurrent() {
- return false;
- }
-
- /**
- * Returns true.
- * @return true
- * @see PathElement#denotesParent()
- */
- public boolean denotesParent() {
- return true;
- }
-
- /**
- * Returns false.
- * @return false
- * @see PathElement#denotesName()
- */
- public boolean denotesName() {
- return false;
- }
-
- /**
- * Returns the JCR name of this path element.
- *
- * @param resolver
- * @return {@link #LITERAL}
- */
- public String toJCRName(NamespaceResolver resolver) {
- return LITERAL;
- }
-
- /**
- * @return {@link #LITERAL}
- * @see Object#toString()
- */
- public String toString() {
- return LITERAL;
- }
- }
+ //---------------------------------------------------------< Path Elements >
/**
* Object representation of a single JCR path element. A PathElement
* object contains the qualified name and optional index of a single
* JCR path element.
* <p/>
- * Once created, a PathElement object is immutable.
+ * Once created, a NameElement object is immutable.
*/
- public static class PathElement {
+ public abstract static class PathElement {
/**
* Qualified name of the path element.
@@ -1147,59 +1012,72 @@
*/
private final int index;
- /**
- * Creates a path element with the given qualified name.
- * The created path element does not contain an explicit index.
- *
- * @param namespaceURI namespace URI
- * @param localName local name
- */
- private PathElement(String namespaceURI, String localName) {
- this(new QName(namespaceURI, localName));
- }
/**
* Creates a path element with the given qualified name and index.
*
- * @param namespaceURI namespace URI
- * @param localName local name
- * @param index index
+ * @param name qualified name
+ * @param index index
*/
- private PathElement(String namespaceURI, String localName, int index) {
- this(new QName(namespaceURI, localName), index);
+ private PathElement(QName name, int index) {
+ this.index = index;
+ this.name = name;
}
/**
- * Creates a path element with the given qualified name.
- * The created path element does not contain an explicit index.
+ * Creates a new path element with the given qualified name and index.
+ * If the name is equals to the name of a special element, like the
+ * {@link PARENT_ELEMENT},{@link CURRENT_ELEMENT} or the
+ * {@link ROOT_ELEMENT}, then it's instance is returned.
+ * <p/>
+ * the private constructor must never be called but from these 2 methods.
*
- * @param name qualified name
+ * @param name the name of the element
+ * @return a path element
* @throws IllegalArgumentException if the name is <code>null</code>
*/
- private PathElement(QName name) throws IllegalArgumentException {
+ public static PathElement create(QName name) {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
+ } else if (name.equals(PARENT_ELEMENT.getName())) {
+ return PARENT_ELEMENT;
+ } else if (name.equals(CURRENT_ELEMENT.getName())) {
+ return CURRENT_ELEMENT;
+ } else if (name.equals(ROOT_ELEMENT.getName())) {
+ return ROOT_ELEMENT;
+ } else {
+ return new NameElement(name, INDEX_UNDEFINED);
}
- this.name = name;
- this.index = INDEX_UNDEFINED;
}
/**
- * Creates a path element with the given qualified name and index.
+ * Creates a new path element with the given qualified name and index.
+ * If the name is equals to the name of a special element, like the
+ * {@link PARENT_ELEMENT},{@link CURRENT_ELEMENT} or the
+ * {@link ROOT_ELEMENT}, then it's instance is returned.
+ * <p/>
+ * the private constructor must never be called but from these 2 methods.
*
- * @param name qualified name
- * @param index index
- * @throws IllegalArgumentException if the name is <code>null</code>
+ * @param name the name of the element
+ * @param index the 1-based index.
+ * @return a path element
+ * @throws IllegalArgumentException if the name is <code>null</code> or
+ * if the given index is less than 1.
*/
- private PathElement(QName name, int index) throws IllegalArgumentException {
- if (name == null) {
- throw new IllegalArgumentException("name must not be null");
- }
+ public static PathElement create(QName name, int index) {
if (index < INDEX_DEFAULT) {
- throw new IllegalArgumentException("index is 1-based");
+ throw new IllegalArgumentException("index is 1-based.");
+ } else if (name == null) {
+ throw new IllegalArgumentException("name must not be null");
+ } else if (name.equals(PARENT_ELEMENT.getName())) {
+ return PARENT_ELEMENT;
+ } else if (name.equals(CURRENT_ELEMENT.getName())) {
+ return CURRENT_ELEMENT;
+ } else if (name.equals(ROOT_ELEMENT.getName())) {
+ return ROOT_ELEMENT;
+ } else {
+ return new NameElement(name, index);
}
- this.index = index;
- this.name = name;
}
/**
@@ -1234,54 +1112,10 @@
}
/**
- * Returns <code>true</code> if this element denotes the <i>root</i> element,
- * otherwise returns <code>false</code>.
- *
- * @return <code>true</code> if this element denotes the <i>root</i>
- * element; otherwise <code>false</code>
- */
- public boolean denotesRoot() {
- return equals(ROOT_ELEMENT);
- }
-
- /**
- * Returns <code>true</code> if this element denotes the <i>parent</i>
- * ('..') element, otherwise returns <code>false</code>.
- *
- * @return <code>true</code> if this element denotes the <i>parent</i>
- * element; otherwise <code>false</code>
- */
- public boolean denotesParent() {
- return equals(PARENT_ELEMENT);
- }
-
- /**
- * Returns <code>true</code> if this element denotes the <i>current</i>
- * ('.') element, otherwise returns <code>false</code>.
- *
- * @return <code>true</code> if this element denotes the <i>current</i>
- * element; otherwise <code>false</code>
- */
- public boolean denotesCurrent() {
- return equals(CURRENT_ELEMENT);
- }
-
- /**
- * Returns <code>true</code> if this element represents a regular name
- * (i.e. neither root, '.' nor '..'), otherwise returns <code>false</code>.
- *
- * @return <code>true</code> if this element represents a regular name;
- * otherwise <code>false</code>
- */
- public boolean denotesName() {
- return !denotesRoot() && !denotesParent() && !denotesCurrent();
- }
-
- /**
- * Returns the JCR name representation of this path element.
- * Note that strictly speaking the returned value is in fact
- * a JCR relative path instead of a JCR name, as it contains
- * the index value if the index is greater than one.
+ * Returns the JCR name representation of this path element.
+ * Note that strictly speaking the returned value is in fact
+ * a JCR relative path instead of a JCR name, as it contains
+ * the index value if the index is greater than one.
*
* @param resolver namespace resolver
* @return JCR name representation of the path element
@@ -1371,7 +1205,7 @@
int pos = s.indexOf('[');
if (pos == -1) {
QName name = QName.valueOf(s);
- return new PathElement(name.getNamespaceURI(), name.getLocalName());
+ return new NameElement(name, INDEX_UNDEFINED);
}
QName name = QName.valueOf(s.substring(0, pos));
int pos1 = s.indexOf(']');
@@ -1383,7 +1217,7 @@
if (index < 1) {
throw new IllegalArgumentException("invalid PathElement literal: " + s + " (index is 1-based)");
}
- return new PathElement(name.getNamespaceURI(), name.getLocalName(), index);
+ return new NameElement(name, index);
} catch (Throwable t) {
throw new IllegalArgumentException("invalid PathElement literal: " + s + " (" + t.getMessage() + ")");
}
@@ -1420,6 +1254,311 @@
// @todo treat index==0 as index==1?
&& index == other.index;
}
+ return false;
+ }
+
+ /**
+ * Returns <code>true</code> if this element denotes the <i>root</i> element,
+ * otherwise returns <code>false</code>.
+ *
+ * @return <code>true</code> if this element denotes the <i>root</i>
+ * element; otherwise <code>false</code>
+ */
+ abstract public boolean denotesRoot();
+
+ /**
+ * Returns <code>true</code> if this element denotes the <i>parent</i>
+ * ('..') element, otherwise returns <code>false</code>.
+ *
+ * @return <code>true</code> if this element denotes the <i>parent</i>
+ * element; otherwise <code>false</code>
+ */
+ abstract public boolean denotesParent();
+
+ /**
+ * Returns <code>true</code> if this element denotes the <i>current</i>
+ * ('.') element, otherwise returns <code>false</code>.
+ *
+ * @return <code>true</code> if this element denotes the <i>current</i>
+ * element; otherwise <code>false</code>
+ */
+ abstract public boolean denotesCurrent();
+
+ /**
+ * Returns <code>true</code> if this element represents a regular name
+ * (i.e. neither root, '.' nor '..'), otherwise returns <code>false</code>.
+ *
+ * @return <code>true</code> if this element represents a regular name;
+ * otherwise <code>false</code>
+ */
+ abstract public boolean denotesName();
+
+ }
+
+ public static final class RootElement extends PathElement {
+ // use a literal that is an illegal name character to avoid collisions
+ static final String LITERAL = "*";
+
+ private RootElement() {
+ super(QName.ROOT, Path.INDEX_UNDEFINED);
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesName()
+ */
+ public boolean denotesName() {
+ return false;
+ }
+
+ /**
+ * Returns true.
+ *
+ * @return true
+ * @see PathElement#denotesRoot()
+ */
+ public boolean denotesRoot() {
+ return true;
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesParent()
+ */
+ public boolean denotesParent() {
+ return false;
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesCurrent()
+ */
+ public boolean denotesCurrent() {
+ return false;
+ }
+
+ /**
+ * Returns the JCR name of this path element.
+ *
+ * @param resolver
+ * @return ""
+ */
+ public String toJCRName(NamespaceResolver resolver) {
+ return "";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void toJCRName(NamespaceResolver resolver, StringBuffer buf) {
+ // append empty string, i.e. nothing.
+ }
+
+ /**
+ * @return {@link #LITERAL}
+ * @see Object#toString()
+ */
+ public String toString() {
+ return LITERAL;
+ }
+ }
+
+
+ public static final class CurrentElement extends PathElement {
+ static final String LITERAL = ".";
+
+ private CurrentElement() {
+ super(new QName(QName.NS_DEFAULT_URI, LITERAL), Path.INDEX_UNDEFINED);
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesName()
+ */
+ public boolean denotesName() {
+ return false;
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesRoot()
+ */
+ public boolean denotesRoot() {
+ return false;
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesParent()
+ */
+ public boolean denotesParent() {
+ return false;
+ }
+
+ /**
+ * Returns true.
+ *
+ * @return true
+ * @see PathElement#denotesCurrent()
+ */
+ public boolean denotesCurrent() {
+ return true;
+ }
+
+ /**
+ * Returns the JCR name of this path element.
+ *
+ * @param resolver
+ * @return {@link #LITERAL}
+ */
+ public String toJCRName(NamespaceResolver resolver) {
+ return LITERAL;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void toJCRName(NamespaceResolver resolver, StringBuffer buf) {
+ buf.append(LITERAL);
+ }
+
+ /**
+ * @return {@link #LITERAL}
+ * @see Object#toString()
+ */
+ public String toString() {
+ return LITERAL;
+ }
+ }
+
+ public static final class ParentElement extends PathElement {
+ static final String LITERAL = "..";
+
+ private ParentElement() {
+ super(new QName(QName.NS_DEFAULT_URI, LITERAL), Path.INDEX_UNDEFINED);
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesName()
+ */
+ public boolean denotesName() {
+ return false;
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesRoot()
+ */
+ public boolean denotesRoot() {
+ return false;
+ }
+
+ /**
+ * Returns true.
+ *
+ * @return true
+ * @see PathElement#denotesParent()
+ */
+ public boolean denotesParent() {
+ return true;
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesCurrent()
+ */
+ public boolean denotesCurrent() {
+ return false;
+ }
+
+ /**
+ * Returns the JCR name of this path element.
+ *
+ * @param resolver
+ * @return {@link #LITERAL}
+ */
+ public String toJCRName(NamespaceResolver resolver) {
+ return LITERAL;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void toJCRName(NamespaceResolver resolver, StringBuffer buf) {
+ buf.append(LITERAL);
+ }
+
+ /**
+ * @return {@link #LITERAL}
+ * @see Object#toString()
+ */
+ public String toString() {
+ return LITERAL;
+ }
+ }
+
+ public static final class NameElement extends PathElement {
+
+ private NameElement(QName name, int index) {
+ super(name, index);
+ }
+
+ /**
+ * Returns true.
+ *
+ * @return true
+ * @see PathElement#denotesName()
+ */
+ public boolean denotesName() {
+ return true;
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesRoot()
+ */
+ public boolean denotesRoot() {
+ return false;
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesParent()
+ */
+ public boolean denotesParent() {
+ return false;
+ }
+
+ /**
+ * Returns false.
+ *
+ * @return false
+ * @see PathElement#denotesCurrent()
+ */
+ public boolean denotesCurrent() {
return false;
}
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/QName.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/QName.java?rev=424258&r1=424257&r2=424258&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/QName.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/QName.java Fri Jul 21 03:43:04 2006
@@ -534,13 +534,25 @@
if (localName == null) {
throw new IllegalArgumentException("invalid localName specified");
}
- // internalize both namespaceURI and localName to improve performance
- // of QName comparisons
+ // internalize only namespaceURI to improve performance of QName
+ // comparisons. Please note that we do not internalize the localname
+ // since this could blow perm space for big repositories.
this.namespaceURI = namespaceURI.intern();
- this.localName = localName.intern();
+ this.localName = localName;
hash = 0;
}
+ /**
+ * Returns a new instance of this class with the same namespace URI and
+ * local name as has been deserialized.
+ * <p>
+ * If just sing plain serialization, the strings are just created but not
+ * internalized.
+ */
+ private Object readResolve() {
+ return new QName(namespaceURI, localName);
+ }
+
//------------------------------------------------------< factory methods >
/**
@@ -712,10 +724,10 @@
}
if (obj instanceof QName) {
QName other = (QName) obj;
- // localName & namespaceURI are internalized,
- // we only have to compare their references
- return localName == other.localName
- && namespaceURI == other.namespaceURI;
+ // namespaceURI is internalized, we only have to compare their
+ // references
+ return namespaceURI == other.namespaceURI
+ && localName.equals(other.localName);
}
return false;
}
@@ -763,9 +775,16 @@
* @throws ClassCastException if the given object is not a qualified name
* @see Comparable#compareTo(Object)
*/
- public int compareTo(Object o) throws ClassCastException {
+ public int compareTo(Object o) {
+ if (this == o) {
+ return 0;
+ }
QName other = (QName) o;
- int result = namespaceURI.compareTo(other.namespaceURI);
- return (result != 0) ? result : localName.compareTo(other.localName);
+ // == comparison ok, because of .intern() strings
+ if (namespaceURI == other.namespaceURI) {
+ return localName.compareTo(other.localName);
+ } else {
+ return namespaceURI.compareTo(other.namespaceURI);
+ }
}
}
Modified: jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/name/PathTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/name/PathTest.java?rev=424258&r1=424257&r2=424258&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/name/PathTest.java (original)
+++ jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/name/PathTest.java Fri Jul 21 03:43:04 2006
@@ -90,6 +90,7 @@
// not normalized paths
list.add(new Test("/a/../b", "/b", VAL));
+ list.add(new Test("./../.", "..", VAL));
list.add(new Test("/a/./b", "/a/b", VAL));
list.add(new Test("/a/b/../..", "/", VAL));
list.add(new Test("/a/b/c/../d/..././f", "/a/b/d/.../f", VAL));