You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2006/07/10 09:08:39 UTC
svn commit: r420449 [2/2] - in /jackrabbit/trunk/jackrabbit/src:
main/java/org/apache/jackrabbit/core/
main/java/org/apache/jackrabbit/core/lock/
main/java/org/apache/jackrabbit/core/state/
main/java/org/apache/jackrabbit/core/xml/ main/java/org/apache...
Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/PathMap.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/PathMap.java?rev=420449&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/PathMap.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/PathMap.java Mon Jul 10 00:08:37 2006
@@ -0,0 +1,577 @@
+/*
+ * 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.util;
+
+import org.apache.jackrabbit.name.MalformedPathException;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.QName;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Generic path map that associates information with the individual path elements
+ * of a path.
+ */
+public class PathMap {
+
+ /**
+ * Root element
+ */
+ private final Element root = new Element(Path.ROOT.getNameElement());
+
+ /**
+ * Map a path to a child. If <code>exact</code> is <code>false</code>,
+ * returns the last available item along the path that is stored in the map.
+ * @param path path to map
+ * @param exact flag indicating whether an exact match is required
+ * @return child, maybe <code>null</code> if <code>exact</code> is
+ * <code>true</code>
+ */
+ public Element map(Path path, boolean exact) {
+ Path.PathElement[] elements = path.getElements();
+ Element current = root;
+
+ for (int i = 1; i < elements.length; i++) {
+ Element next = current.getChild(elements[i]);
+ if (next == null) {
+ if (exact) {
+ return null;
+ }
+ break;
+ }
+ current = next;
+ }
+ return current;
+ }
+
+ /**
+ * Create an element given by its path. The path map will create any necessary
+ * intermediate elements.
+ * @param path path to child
+ * @param obj object to store at destination
+ */
+ public Element put(Path path, Object obj) {
+ Element element = put(path);
+ element.obj = obj;
+ return element;
+ }
+
+ /**
+ * Put an element given by its path. The path map will create any necessary
+ * intermediate elements.
+ * @param path path to child
+ * @param element element to store at destination
+ */
+ public void put(Path path, Element element) {
+ Path.PathElement[] elements = path.getElements();
+ Element current = root;
+
+ for (int i = 1; i < elements.length - 1; i++) {
+ Element next = current.getChild(elements[i]);
+ if (next == null) {
+ next = current.createChild(elements[i]);
+ }
+ current = next;
+ }
+ current.put(path.getNameElement(), element);
+ }
+
+ /**
+ * Create an empty child given by its path.
+ * @param path path to child
+ */
+ public Element put(Path path) {
+ Path.PathElement[] elements = path.getElements();
+ Element current = root;
+
+ for (int i = 1; i < elements.length; i++) {
+ Element next = current.getChild(elements[i]);
+ if (next == null) {
+ next = current.createChild(elements[i]);
+ }
+ current = next;
+ }
+ return current;
+ }
+
+ /**
+ * Traverse the path map and call back requester.
+ * @param includeEmpty if <code>true</code> invoke call back on every child
+ * regardless, whether the associated object is empty
+ * or not; otherwise call back on non-empty children
+ * only
+ */
+ public void traverse(ElementVisitor visitor, boolean includeEmpty) {
+ root.traverse(visitor, includeEmpty);
+ }
+
+ /**
+ * Internal class holding the object associated with a certain
+ * path element.
+ */
+ public static class Element {
+
+ /**
+ * Parent element
+ */
+ private Element parent;
+
+ /**
+ * Map of immediate children
+ */
+ private Map children;
+
+ /**
+ * Number of non-empty children
+ */
+ private int childrenCount;
+
+ /**
+ * Object associated with this element
+ */
+ private Object obj;
+
+ /**
+ * QName associated with this element
+ */
+ private QName name;
+
+ /**
+ * 1-based index associated with this element where index=0 is
+ * equivalent to index=1.
+ */
+ private int index;
+
+ /**
+ * Create a new instance of this class with a path element.
+ * @param nameIndex path element of this child
+ */
+ private Element(Path.PathElement nameIndex) {
+ this.name = nameIndex.getName();
+ this.index = nameIndex.getIndex();
+ }
+
+ /**
+ * Create a child of this node inside the path map.
+ * @param nameIndex position where child is created
+ * @return child
+ */
+ private Element createChild(Path.PathElement nameIndex) {
+ Element element = new Element(nameIndex);
+ put(nameIndex, element);
+ return element;
+ }
+
+ /**
+ * Insert an empty child. Will shift all children having an index
+ * greater than or equal to the child inserted to the right.
+ * @param nameIndex position where child is inserted
+ */
+ public void insert(Path.PathElement nameIndex) {
+ // convert 1-based index value to 0-base value
+ int index = getZeroBasedIndex(nameIndex);
+ if (children != null) {
+ ArrayList list = (ArrayList) children.get(nameIndex.getName());
+ if (list != null && list.size() > index) {
+ for (int i = index; i < list.size(); i++) {
+ Element element = (Element) list.get(i);
+ if (element != null) {
+ element.index = element.getNormalizedIndex() + 1;
+ }
+ }
+ list.add(index, null);
+ }
+ }
+ }
+
+ /**
+ * Return an element matching a name and index.
+ * @param nameIndex position where child is located
+ * @return element matching <code>nameIndex</code> or <code>null</code> if
+ * none exists.
+ */
+ private Element getChild(Path.PathElement nameIndex) {
+ // convert 1-based index value to 0-base value
+ int index = getZeroBasedIndex(nameIndex);
+ Element element = null;
+
+ if (children != null) {
+ ArrayList list = (ArrayList) children.get(nameIndex.getName());
+ if (list != null && list.size() > index) {
+ element = (Element) list.get(index);
+ }
+ }
+ return element;
+ }
+
+ /**
+ * Link a child of this node. Position is given by <code>nameIndex</code>.
+ * @param nameIndex position where child should be located
+ * @param element element to add
+ */
+ public void put(Path.PathElement nameIndex, Element element) {
+ // convert 1-based index value to 0-base value
+ int index = getZeroBasedIndex(nameIndex);
+ if (children == null) {
+ children = new HashMap();
+ }
+ ArrayList list = (ArrayList) children.get(nameIndex.getName());
+ if (list == null) {
+ list = new ArrayList();
+ children.put(nameIndex.getName(), list);
+ }
+ while (list.size() < index) {
+ list.add(null);
+ }
+ if (list.size() == index) {
+ list.add(element);
+ } else {
+ list.set(index, element);
+ }
+
+ element.parent = this;
+ element.name = nameIndex.getName();
+ element.index = nameIndex.getIndex();
+
+ childrenCount++;
+ }
+
+ /**
+ * Remove a child. Will shift all children having an index greater than
+ * the child removed to the left. If there are no more children left in
+ * this element and no object is associated with this element, the
+ * element itself gets removed.
+ *
+ * @param nameIndex child's path element
+ * @return removed child, may be <code>null</code>
+ */
+ public Element remove(Path.PathElement nameIndex) {
+ return remove(nameIndex, true);
+ }
+
+ /**
+ * Remove a child. If <code>shift</code> is set to <code>true</code>,
+ * will shift all children having an index greater than the child
+ * removed to the left. If there are no more children left in
+ * this element and no object is associated with this element, the
+ * element itself gets removed.
+ *
+ * @param nameIndex child's path element
+ * @param shift whether to shift same name siblings having a greater
+ * index to the left
+ * @return removed child, may be <code>null</code>
+ */
+ private Element remove(Path.PathElement nameIndex, boolean shift) {
+ // convert 1-based index value to 0-base value
+ int index = getZeroBasedIndex(nameIndex);
+ if (children == null) {
+ return null;
+ }
+ ArrayList list = (ArrayList) children.get(nameIndex.getName());
+ if (list == null || list.size() <= index) {
+ return null;
+ }
+ Element element = (Element) list.set(index, null);
+ if (shift) {
+ for (int i = index + 1; i < list.size(); i++) {
+ Element sibling = (Element) list.get(i);
+ if (sibling != null) {
+ sibling.index--;
+ }
+ }
+ list.remove(index);
+ }
+ if (element != null) {
+ element.parent = null;
+ childrenCount--;
+ }
+ if (childrenCount == 0 && obj == null && parent != null) {
+ parent.remove(getPathElement(), shift);
+ }
+ return element;
+ }
+
+ /**
+ * Remove this element. Delegates the call to the parent item.
+ * Index of same name siblings will be shifted!
+ */
+ public void remove() {
+ remove(true);
+ }
+
+ /**
+ * Remove this element. Delegates the call to the parent item.
+ * @param shift if index of same name siblings will be shifted.
+ */
+ public void remove(boolean shift) {
+ if (parent != null) {
+ parent.remove(getPathElement(), shift);
+ }
+ }
+
+ /**
+ * Remove all children of this element. Removes this element itself
+ * if this element does not contain associated information.
+ */
+ public void removeAll() {
+ children = null;
+ childrenCount = 0;
+
+ if (obj == null && parent != null) {
+ parent.remove(getPathElement(), false);
+ }
+ }
+
+ /**
+ * Return the object associated with this element
+ * @return object associated with this element
+ */
+ public Object get() {
+ return obj;
+ }
+
+ /**
+ * Set the object associated with this element
+ * @param obj object associated with this element
+ */
+ public void set(Object obj) {
+ this.obj = obj;
+
+ if (obj == null && childrenCount == 0 && parent != null) {
+ parent.remove(getPathElement(), false);
+ }
+ }
+
+ /**
+ * Return the name of this element
+ * @return name
+ */
+ public QName getName() {
+ return name;
+ }
+
+ /**
+ * Return the non-normalized 1-based index of this element. Note that
+ * this method can return a value of 0 which should be treated as 1.
+ * @return index
+ * @see #getNormalizedIndex()
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * Return the 1-based index of this element.
+ * Same as {@link #getIndex()} except that an {@link Path#INDEX_UNDEFINED
+ * undefined index} value is automatically converted to the
+ * {@link Path#INDEX_DEFAULT default index} value.
+ * @return 1-based index
+ */
+ public int getNormalizedIndex() {
+ if (index == Path.INDEX_UNDEFINED) {
+ return Path.INDEX_DEFAULT;
+ } else {
+ return index;
+ }
+ }
+
+ /**
+ * Return a path element pointing to this element
+ * @return path element
+ */
+ public Path.PathElement getPathElement() {
+ return Path.create(name, index).getNameElement();
+ }
+
+ /**
+ * Return the path of this element.
+ * @return path
+ * @throws MalformedPathException if building the path fails
+ */
+ public Path getPath() throws MalformedPathException {
+ if (parent == null) {
+ return Path.ROOT;
+ }
+
+ Path.PathBuilder builder = new Path.PathBuilder();
+ getPath(builder);
+ return builder.getPath();
+ }
+
+ /**
+ * Internal implementation of {@link #getPath()} that populates entries
+ * in a builder. On exit, <code>builder</code> contains the path
+ * of this element
+ */
+ private void getPath(Path.PathBuilder builder) {
+ if (parent == null) {
+ builder.addRoot();
+ return;
+ }
+ parent.getPath(builder);
+ if (index == Path.INDEX_UNDEFINED || index == Path.INDEX_DEFAULT) {
+ builder.addLast(name);
+ } else {
+ builder.addLast(name, index);
+ }
+ }
+
+ /**
+ * Checks whether this element has the specified path. Introduced to
+ * avoid catching a <code>MalformedPathException</code> for simple
+ * path comparisons.
+ * @param path path to compare to
+ * @return <code>true</code> if this child has the path
+ * <code>path</code>, <code>false</code> otherwise
+ */
+ public boolean hasPath(Path path) {
+ return hasPath(path.getElements(), path.getLength());
+ }
+
+ /**
+ * Checks whether this element has the specified path, given by
+ * path elements.
+ * @param elements path elements to compare to
+ * @param len number of elements to compare to
+ * @return <code>true</code> if this element has the path given;
+ * otherwise <code>false</code>
+ */
+ private boolean hasPath(Path.PathElement[] elements, int len) {
+ if (getPathElement().equals(elements[len - 1])) {
+ if (parent != null) {
+ return parent.hasPath(elements, len - 1);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Return 0-based index of a path element.
+ */
+ private static int getZeroBasedIndex(Path.PathElement nameIndex) {
+ return nameIndex.getNormalizedIndex() - 1;
+ }
+
+ /**
+ * Recursively invoked traversal method.
+ * @param visitor visitor to invoke
+ * @param includeEmpty if <code>true</code> invoke call back on every
+ * element regardless, whether the associated object is empty
+ * or not; otherwise call back on non-empty children only
+ */
+ public void traverse(ElementVisitor visitor, boolean includeEmpty) {
+ if (children != null) {
+ Iterator iter = children.values().iterator();
+ while (iter.hasNext()) {
+ ArrayList list = (ArrayList) iter.next();
+ for (int i = 0; i < list.size(); i++) {
+ Element element = (Element) list.get(i);
+ if (element != null) {
+ element.traverse(visitor, includeEmpty);
+ }
+ }
+ }
+ }
+ if (includeEmpty || obj != null) {
+ visitor.elementVisited(this);
+ }
+ }
+
+ /**
+ * Return the depth of this element. Defined to be <code>0</code> for the
+ * root element and <code>n + 1</code> for some element if the depth of
+ * its parent is <code>n</code>.
+ */
+ public int getDepth() {
+ if (parent != null) {
+ return parent.getDepth() + 1;
+ }
+ // Root
+ return Path.ROOT_DEPTH;
+ }
+
+ /**
+ * Return a flag indicating whether the specified node is a
+ * child of this node.
+ * @param other node to check
+ */
+ public boolean isAncestorOf(Element other) {
+ Element parent = other.parent;
+ while (parent != null) {
+ if (parent == this) {
+ return true;
+ }
+ parent = parent.parent;
+ }
+ return false;
+ }
+
+ /**
+ * Return the parent of this element
+ * @return parent or <code>null</code> if this is the root element
+ */
+ public Element getParent() {
+ return parent;
+ }
+
+ /**
+ * Return the children count of this element
+ * @return children count
+ */
+ public int getChildrenCount() {
+ return childrenCount;
+ }
+
+ /**
+ * Return an iterator over all of this element's children. Every
+ * element returned by this iterator is of type {@link #Element}.
+ */
+ public Iterator getChildren() {
+ ArrayList result = new ArrayList();
+
+ if (children != null) {
+ Iterator iter = children.values().iterator();
+ while (iter.hasNext()) {
+ ArrayList list = (ArrayList) iter.next();
+ for (int i = 0; i < list.size(); i++) {
+ Element element = (Element) list.get(i);
+ if (element != null) {
+ result.add(element);
+ }
+ }
+ }
+ }
+ return result.iterator();
+ }
+ }
+
+ /**
+ * Element visitor used in {@link PathMap#traverse}
+ */
+ public interface ElementVisitor {
+
+ /**
+ * Invoked for every element visited on a tree traversal
+ * @param element element visited
+ */
+ void elementVisited(Element element);
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/PathMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/PathMap.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/Text.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/Text.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/Text.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/Text.java Mon Jul 10 00:08:37 2006
@@ -532,6 +532,19 @@
}
/**
+ * Same as {@link #getName(String)} but adding the possibility
+ * to pass paths that end with a trailing '/'
+ *
+ * @see #getName(String)
+ */
+ public static String getName(String path, boolean ignoreTrailingSlash) {
+ if (ignoreTrailingSlash && path.endsWith("/") && path.length() > 1) {
+ path = path.substring(0, path.length()-1);
+ }
+ return getName(path);
+ }
+
+ /**
* Returns the namespace prefix of the given <code>qname</code>. If the
* prefix is missing, an empty string is returned. Please note, that this
* method does not validate the name or prefix.
@@ -634,6 +647,19 @@
level--;
}
return (idx == 0) ? "/" : path.substring(0, idx);
+ }
+
+ /**
+ * Same as {@link #getRelativeParent(String, int)} but adding the possibility
+ * to pass paths that end with a trailing '/'
+ *
+ * @see #getRelativeParent(String, int)
+ */
+ public static String getRelativeParent(String path, int level, boolean ignoreTrailingSlash) {
+ if (ignoreTrailingSlash && path.endsWith("/") && path.length() > 1) {
+ path = path.substring(0, path.length()-1);
+ }
+ return getRelativeParent(path, level);
}
/**
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/NameValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/NameValue.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/NameValue.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/NameValue.java Mon Jul 10 00:08:37 2006
@@ -16,8 +16,8 @@
*/
package org.apache.jackrabbit.value;
+import org.apache.jackrabbit.name.NameFormat;
import org.apache.jackrabbit.name.IllegalNameException;
-import org.apache.jackrabbit.name.QName;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
@@ -50,7 +50,7 @@
public static NameValue valueOf(String s) throws ValueFormatException {
if (s != null) {
try {
- QName.checkFormat(s);
+ NameFormat.checkFormat(s);
} catch (IllegalNameException ine) {
throw new ValueFormatException(ine.getMessage());
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/PathValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/PathValue.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/PathValue.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/PathValue.java Mon Jul 10 00:08:37 2006
@@ -17,7 +17,7 @@
package org.apache.jackrabbit.value;
import org.apache.jackrabbit.name.MalformedPathException;
-import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.PathFormat;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
@@ -51,7 +51,7 @@
public static PathValue valueOf(String s) throws ValueFormatException {
if (s != null) {
try {
- Path.checkFormat(s);
+ PathFormat.checkFormat(s);
} catch (MalformedPathException mpe) {
throw new ValueFormatException(mpe.getMessage());
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java Mon Jul 10 00:08:37 2006
@@ -21,20 +21,32 @@
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.ValueFormatException;
+import javax.jcr.PropertyType;
import java.io.InputStream;
import java.util.Calendar;
/**
- * This class implements the <code>ValueFactory</code> interface.
+ * This class implements the <code>ValueFactory</code> interface.
*
* @see javax.jcr.Session#getValueFactory()
*/
public class ValueFactoryImpl implements ValueFactory {
+ private static final ValueFactory valueFactory = new ValueFactoryImpl();
+
/**
* Constructs a <code>ValueFactory</code> object.
*/
- public ValueFactoryImpl() {
+ private ValueFactoryImpl() {
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ *
+ * @return
+ */
+ public static ValueFactory getInstance() {
+ return valueFactory;
}
//---------------------------------------------------------< ValueFactory >
@@ -92,6 +104,38 @@
*/
public Value createValue(String value, int type)
throws ValueFormatException {
- return ValueHelper.convert(value, type);
+ Value val;
+ switch (type) {
+ case PropertyType.STRING:
+ val = new StringValue(value);
+ break;
+ case PropertyType.BOOLEAN:
+ val = BooleanValue.valueOf(value);
+ break;
+ case PropertyType.DOUBLE:
+ val = DoubleValue.valueOf(value);
+ break;
+ case PropertyType.LONG:
+ val = LongValue.valueOf(value);
+ break;
+ case PropertyType.DATE:
+ val = DateValue.valueOf(value);
+ break;
+ case PropertyType.NAME:
+ val = NameValue.valueOf(value);
+ break;
+ case PropertyType.PATH:
+ val = PathValue.valueOf(value);
+ break;
+ case PropertyType.REFERENCE:
+ val = ReferenceValue.valueOf(value);
+ break;
+ case PropertyType.BINARY:
+ val = new BinaryValue(value);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid type constant: " + type);
+ }
+ return val;
}
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueHelper.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueHelper.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueHelper.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueHelper.java Mon Jul 10 00:08:37 2006
@@ -24,6 +24,7 @@
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
+import javax.jcr.ValueFactory;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.Reader;
@@ -48,38 +49,109 @@
}
/**
+ * Same as {@link #convert(String, int, ValueFactory)} using
+ * <code>ValueFactoryImpl</code>.
+ *
* @param srcValue
* @param targetType
* @return
* @throws ValueFormatException
* @throws IllegalArgumentException
- * @see #convert(Value, int)
+ * @deprecated Use {@link #convert(String, int, ValueFactory)} instead.
+ * @see #convert(Value, int, ValueFactory)
*/
public static Value convert(String srcValue, int targetType)
throws ValueFormatException, IllegalArgumentException {
+ return convert(srcValue, targetType, ValueFactoryImpl.getInstance());
+ }
+
+ /**
+ * @param srcValue
+ * @param targetType
+ * @param factory
+ * @return
+ * @throws ValueFormatException
+ * @throws IllegalArgumentException
+ * @see #convert(Value, int, ValueFactory)
+ */
+ public static Value convert(String srcValue, int targetType, ValueFactory factory)
+ throws ValueFormatException, IllegalArgumentException {
if (srcValue == null) {
return null;
} else {
- return convert(new StringValue(srcValue), targetType);
+ return factory.createValue(srcValue, targetType);
}
}
/**
+ * Same as {@link #convert(InputStream, int, ValueFactory)} using
+ * <code>ValueFactoryImpl</code>.
+ *
+ * @param srcValue
+ * @param targetType
+ * @return
+ * @throws ValueFormatException
+ * @throws IllegalArgumentException
+ * @deprecated Use {@link #convert(InputStream, int, ValueFactory)} instead.
+ */
+ public static Value convert(InputStream srcValue, int targetType)
+ throws ValueFormatException, IllegalArgumentException {
+ return convert(srcValue, targetType, ValueFactoryImpl.getInstance());
+ }
+
+ /**
+ * @param srcValue
+ * @param targetType
+ * @param factory
+ * @return
+ * @throws ValueFormatException
+ * @throws IllegalArgumentException
+ */
+ public static Value convert(InputStream srcValue, int targetType, ValueFactory factory)
+ throws ValueFormatException, IllegalArgumentException {
+ if (srcValue == null) {
+ return null;
+ } else {
+ return convert(factory.createValue(srcValue), targetType, factory);
+ }
+ }
+
+ /**
+ * Same as {@link #convert(String[], int, ValueFactory)} using
+ * <code>ValueFactoryImpl</code>.
+ *
* @param srcValues
* @param targetType
* @return
* @throws ValueFormatException
* @throws IllegalArgumentException
- * @see #convert(Value, int)
+ * @deprecated Use {@link #convert(String[], int, ValueFactory)} instead.
+ * @see #convert(Value, int, ValueFactory)
*/
public static Value[] convert(String[] srcValues, int targetType)
throws ValueFormatException, IllegalArgumentException {
+ return convert(srcValues, targetType, ValueFactoryImpl.getInstance());
+ }
+
+ /**
+ * Same as {@link #convert(String[], int, ValueFactory)} using
+ * <code>ValueFactoryImpl</code>.
+ *
+ * @param srcValues
+ * @param targetType
+ * @return
+ * @throws ValueFormatException
+ * @throws IllegalArgumentException
+ * @see #convert(Value, int, ValueFactory)
+ */
+ public static Value[] convert(String[] srcValues, int targetType, ValueFactory factory)
+ throws ValueFormatException, IllegalArgumentException {
if (srcValues == null) {
return null;
}
Value[] newValues = new Value[srcValues.length];
for (int i = 0; i < srcValues.length; i++) {
- newValues[i] = convert(srcValues[i], targetType);
+ newValues[i] = convert(srcValues[i], targetType, factory);
}
return newValues;
}
@@ -90,9 +162,49 @@
* @return
* @throws ValueFormatException
* @throws IllegalArgumentException
- * @see #convert(Value, int)
+ * @see #convert(Value, int, ValueFactory)
+ */
+ public static Value[] convert(InputStream[] srcValues, int targetType,
+ ValueFactory factory)
+ throws ValueFormatException, IllegalArgumentException {
+ if (srcValues == null) {
+ return null;
+ }
+ Value[] newValues = new Value[srcValues.length];
+ for (int i = 0; i < srcValues.length; i++) {
+ newValues[i] = convert(srcValues[i], targetType, factory);
+ }
+ return newValues;
+ }
+
+ /**
+ * Same as {@link #convert(Value[], int, ValueFactory)} using
+ * <code>ValueFactoryImpl</code>.
+ *
+ * @param srcValues
+ * @param targetType
+ * @return
+ * @throws ValueFormatException
+ * @throws IllegalArgumentException
+ * @deprecated Use {@link #convert(Value[], int, ValueFactory)} instead.
+ * @see #convert(Value, int, ValueFactory)
*/
public static Value[] convert(Value[] srcValues, int targetType)
+ throws ValueFormatException, IllegalArgumentException {
+ return convert(srcValues, targetType, ValueFactoryImpl.getInstance());
+ }
+
+ /**
+ * @param srcValues
+ * @param targetType
+ * @param factory
+ * @return
+ * @throws ValueFormatException
+ * @throws IllegalArgumentException
+ * @see #convert(Value, int, ValueFactory)
+ */
+ public static Value[] convert(Value[] srcValues, int targetType,
+ ValueFactory factory)
throws ValueFormatException, IllegalArgumentException {
if (srcValues == null) {
return null;
@@ -114,24 +226,44 @@
throw new ValueFormatException(msg);
}
- newValues[i] = convert(srcValues[i], targetType);
+ newValues[i] = convert(srcValues[i], targetType, factory);
}
return newValues;
}
/**
+ * Same as {@link #convert(Value, int, ValueFactory)} using
+ * <code>ValueFactoryImpl</code>.
+
+ * @param srcValue
+ * @param targetType
+ * @return
+ * @throws ValueFormatException
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ * @deprecated Use {@link #convert(Value, int, ValueFactory)} instead.
+ * @see #convert(Value, int, ValueFactory)
+ */
+ public static Value convert(Value srcValue, int targetType)
+ throws ValueFormatException, IllegalStateException,
+ IllegalArgumentException {
+ return convert(srcValue, targetType, ValueFactoryImpl.getInstance());
+ }
+
+ /**
* Converts the given value to a value of the specified target type.
* The conversion is performed according to the rules described in
* "6.2.6 Property Type Conversion" in the JSR 170 specification.
*
* @param srcValue
* @param targetType
+ * @param factory
* @return
* @throws ValueFormatException
* @throws IllegalStateException
* @throws IllegalArgumentException
*/
- public static Value convert(Value srcValue, int targetType)
+ public static Value convert(Value srcValue, int targetType, ValueFactory factory)
throws ValueFormatException, IllegalStateException,
IllegalArgumentException {
if (srcValue == null) {
@@ -150,7 +282,7 @@
case PropertyType.STRING:
// convert to STRING
try {
- val = new StringValue(srcValue.getString());
+ val = factory.createValue(srcValue.getString());
} catch (RepositoryException re) {
throw new ValueFormatException("conversion failed: "
+ PropertyType.nameFromValue(srcType) + " to "
@@ -161,7 +293,7 @@
case PropertyType.BINARY:
// convert to BINARY
try {
- val = new BinaryValue(srcValue.getStream());
+ val = factory.createValue(srcValue.getStream());
} catch (RepositoryException re) {
throw new ValueFormatException("conversion failed: "
+ PropertyType.nameFromValue(srcType) + " to "
@@ -172,7 +304,7 @@
case PropertyType.BOOLEAN:
// convert to BOOLEAN
try {
- val = new BooleanValue(srcValue.getBoolean());
+ val = factory.createValue(srcValue.getBoolean());
} catch (RepositoryException re) {
throw new ValueFormatException("conversion failed: "
+ PropertyType.nameFromValue(srcType) + " to "
@@ -183,7 +315,7 @@
case PropertyType.DATE:
// convert to DATE
try {
- val = new DateValue(srcValue.getDate());
+ val = factory.createValue(srcValue.getDate());
} catch (RepositoryException re) {
throw new ValueFormatException("conversion failed: "
+ PropertyType.nameFromValue(srcType) + " to "
@@ -194,7 +326,7 @@
case PropertyType.DOUBLE:
// convert to DOUBLE
try {
- val = new DoubleValue(srcValue.getDouble());
+ val = factory.createValue(srcValue.getDouble());
} catch (RepositoryException re) {
throw new ValueFormatException("conversion failed: "
+ PropertyType.nameFromValue(srcType) + " to "
@@ -205,7 +337,7 @@
case PropertyType.LONG:
// convert to LONG
try {
- val = new LongValue(srcValue.getLong());
+ val = factory.createValue(srcValue.getLong());
} catch (RepositoryException re) {
throw new ValueFormatException("conversion failed: "
+ PropertyType.nameFromValue(srcType) + " to "
@@ -234,7 +366,7 @@
throw new ValueFormatException("failed to convert source value to PATH value",
re);
}
- val = PathValue.valueOf(path);
+ val = factory.createValue(path, targetType);
break;
case PropertyType.BOOLEAN:
@@ -272,7 +404,7 @@
throw new ValueFormatException("failed to convert source value to NAME value",
re);
}
- val = NameValue.valueOf(name);
+ val = factory.createValue(name, targetType);
break;
case PropertyType.BOOLEAN:
@@ -306,10 +438,9 @@
uuid = srcValue.getString();
} catch (RepositoryException re) {
// should never happen
- throw new ValueFormatException("failed to convert source value to REFERENCE value",
- re);
+ throw new ValueFormatException("failed to convert source value to REFERENCE value", re);
}
- val = ReferenceValue.valueOf(uuid);
+ val = factory.createValue(uuid, targetType);
break;
case PropertyType.BOOLEAN:
@@ -335,11 +466,26 @@
}
/**
+ * Same as {@link #copy(Value, ValueFactory)} using <code>ValueFactoryImpl</code>.
+ *
* @param srcValue
* @return
* @throws IllegalStateException
+ * @deprecated Use {@link #copy(Value, ValueFactory)} instead.
*/
public static Value copy(Value srcValue) throws IllegalStateException {
+ return copy(srcValue, ValueFactoryImpl.getInstance());
+ }
+
+ /**
+ *
+ * @param srcValue
+ * @param factory
+ * @return
+ * @throws IllegalStateException
+ */
+ public static Value copy(Value srcValue, ValueFactory factory)
+ throws IllegalStateException {
if (srcValue == null) {
return null;
}
@@ -348,39 +494,33 @@
try {
switch (srcValue.getType()) {
case PropertyType.BINARY:
- newVal = new BinaryValue(srcValue.getStream());
+ newVal = factory.createValue(srcValue.getStream());
break;
case PropertyType.BOOLEAN:
- newVal = new BooleanValue(srcValue.getBoolean());
+ newVal = factory.createValue(srcValue.getBoolean());
break;
case PropertyType.DATE:
- newVal = new DateValue(srcValue.getDate());
+ newVal = factory.createValue(srcValue.getDate());
break;
case PropertyType.DOUBLE:
- newVal = new DoubleValue(srcValue.getDouble());
+ newVal = factory.createValue(srcValue.getDouble());
break;
case PropertyType.LONG:
- newVal = new LongValue(srcValue.getLong());
+ newVal = factory.createValue(srcValue.getLong());
break;
case PropertyType.PATH:
- newVal = PathValue.valueOf(srcValue.getString());
- break;
-
case PropertyType.NAME:
- newVal = NameValue.valueOf(srcValue.getString());
- break;
-
case PropertyType.REFERENCE:
- newVal = ReferenceValue.valueOf(srcValue.getString());
+ newVal = factory.createValue(srcValue.getString(), srcValue.getType());
break;
case PropertyType.STRING:
- newVal = new StringValue(srcValue.getString());
+ newVal = factory.createValue(srcValue.getString());
break;
}
} catch (RepositoryException re) {
@@ -390,18 +530,32 @@
}
/**
+ * Same as {@link #copy(Value[], ValueFactory)} using <code>ValueFactoryImpl</code>.
+ *
* @param srcValues
* @return
* @throws IllegalStateException
+ * @deprecated Use {@link #copy(Value[], ValueFactory)} instead.
*/
public static Value[] copy(Value[] srcValues) throws IllegalStateException {
+ return copy(srcValues, ValueFactoryImpl.getInstance());
+ }
+
+ /**
+ * @param srcValues
+ * @param factory
+ * @return
+ * @throws IllegalStateException
+ */
+ public static Value[] copy(Value[] srcValues, ValueFactory factory)
+ throws IllegalStateException {
if (srcValues == null) {
return null;
}
Value[] newValues = new Value[srcValues.length];
for (int i = 0; i < srcValues.length; i++) {
- newValues[i] = copy(srcValues[i]);
+ newValues[i] = copy(srcValues[i], factory);
}
return newValues;
}
@@ -477,6 +631,8 @@
/**
* Deserializes the given string to a <code>Value</code> of the given type.
+ * Same as {@link #deserialize(String, int, boolean, ValueFactory)} using
+ * <code>ValueFactoryImpl</code>.
*
* @param value string to be deserialized
* @param type type of value
@@ -488,10 +644,33 @@
* format
* @throws RepositoryException if an error occured during the
* deserialization.
+ * @deprecated Use {@link #deserialize(String, int, boolean, ValueFactory)}
+ * instead.
*/
public static Value deserialize(String value, int type,
boolean decodeBlanks)
throws ValueFormatException, RepositoryException {
+ return deserialize(value, type, decodeBlanks, ValueFactoryImpl.getInstance());
+ }
+
+ /**
+ * Deserializes the given string to a <code>Value</code> of the given type.
+ *
+ * @param value string to be deserialized
+ * @param type type of value
+ * @param decodeBlanks if <code>true</code> <code>"_x0020_"</code>
+ * character sequences will be decoded to single space
+ * characters each.
+ * @param factory ValueFactory used to build the <code>Value</code> object.
+ * @return the deserialized <code>Value</code>
+ * @throws ValueFormatException if the string data is not of the required
+ * format
+ * @throws RepositoryException if an error occured during the
+ * deserialization.
+ */
+ public static Value deserialize(String value, int type, boolean decodeBlanks,
+ ValueFactory factory)
+ throws ValueFormatException, RepositoryException {
if (type == PropertyType.BINARY) {
// base64 encoded binary value;
// the encodeBlanks flag can be ignored since base64-encoded
@@ -505,19 +684,24 @@
throw new RepositoryException("failed to decode binary value",
ioe);
}
+ // NOTE: for performance reasons the BinaryValue is created directly
+ // from the byte-array. This is inconsistent with the other calls,
+ // that delegate the value creation to the ValueFactory.
return new BinaryValue(baos.toByteArray());
} else {
if (decodeBlanks) {
// decode encoded blanks in value
value = Text.replace(value, "_x0020_", " ");
}
- return convert(value, type);
+ return convert(value, type, factory);
}
}
/**
* Deserializes the string data read from the given reader to a
- * <code>Value</code> of the given type.
+ * <code>Value</code> of the given type. Same as
+ * {@link #deserialize(Reader, int, boolean, ValueFactory)} using
+ * <code>ValueFactoryImpl</code>.
*
* @param reader reader for the string data to be deserialized
* @param type type of value
@@ -531,10 +715,36 @@
* format
* @throws RepositoryException if an error occured during the
* deserialization.
+ * @deprecated Use {@link #deserialize(Reader, int, boolean, ValueFactory)}
+ * instead.
*/
public static Value deserialize(Reader reader, int type,
boolean decodeBlanks)
throws IOException, ValueFormatException, RepositoryException {
+ return deserialize(reader, type, decodeBlanks, ValueFactoryImpl.getInstance());
+ }
+
+ /**
+ * Deserializes the string data read from the given reader to a
+ * <code>Value</code> of the given type.
+ *
+ * @param reader reader for the string data to be deserialized
+ * @param type type of value
+ * @param decodeBlanks if <code>true</code> <code>"_x0020_"</code>
+ * character sequences will be decoded to single space
+ * characters each.
+ * @param factory ValueFactory used to build the <code>Value</code> object.
+ * @return the deserialized <code>Value</code>
+ * @throws IOException if an i/o error occured during the
+ * serialization
+ * @throws ValueFormatException if the string data is not of the required
+ * format
+ * @throws RepositoryException if an error occured during the
+ * deserialization.
+ */
+ public static Value deserialize(Reader reader, int type,
+ boolean decodeBlanks, ValueFactory factory)
+ throws IOException, ValueFormatException, RepositoryException {
if (type == PropertyType.BINARY) {
// base64 encoded binary value;
// the encodeBlanks flag can be ignored since base64-encoded
@@ -553,8 +763,8 @@
// create an InputStream that keeps a hard reference to the temp file
// in order to prevent its automatic deletion once the associated
// File object is reclaimed by the garbage collector;
- // pass InputStream wrapper to BinaryValue constructor
- return new BinaryValue(new FilterInputStream(new FileInputStream(tmpFile)) {
+ // pass InputStream wrapper to ValueFactory, that creates a BinaryValue.
+ return factory.createValue(new FilterInputStream(new FileInputStream(tmpFile)) {
public void close() throws IOException {
in.close();
@@ -581,7 +791,7 @@
// decode encoded blanks in value
value = Text.replace(value, "_x0020_", " ");
}
- return convert(value, type);
+ return convert(value, type, factory);
}
}
}
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=420449&r1=420448&r2=420449&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 Mon Jul 10 00:08:37 2006
@@ -19,6 +19,8 @@
import junit.framework.TestCase;
import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
import org.apache.jackrabbit.util.Text;
@@ -273,6 +275,110 @@
return normalize ? builder.getPath().getNormalizedPath() : builder.getPath();
}
+ public void testNormalizedPaths() throws Exception {
+ List paths = new ArrayList();
+
+ // normalized paths
+ paths.add(PathFormat.parse("/", resolver));
+ paths.add(PathFormat.parse("/foo", resolver));
+ paths.add(PathFormat.parse("/foo/bar", resolver));
+ paths.add(PathFormat.parse("foo/bar", resolver));
+ paths.add(PathFormat.parse("foo", resolver));
+ paths.add(PathFormat.parse("../../foo/bar", resolver));
+ paths.add(PathFormat.parse("..", resolver));
+
+ for (Iterator it = paths.iterator(); it.hasNext(); ) {
+ Path path = (Path) it.next();
+ assertTrue("path is not normalized: " + PathFormat.format(path, resolver), path.isNormalized());
+ }
+
+ paths.clear();
+
+ // not normalized paths
+ paths.add(PathFormat.parse("/foo/..", resolver));
+ paths.add(PathFormat.parse("/foo/.", resolver));
+ paths.add(PathFormat.parse("/foo/../bar", resolver));
+ paths.add(PathFormat.parse("/foo/./bar", resolver));
+ paths.add(PathFormat.parse("./foo", resolver));
+ paths.add(PathFormat.parse(".", resolver));
+ paths.add(PathFormat.parse("foo/..", resolver));
+ paths.add(PathFormat.parse("../foo/..", resolver));
+ paths.add(PathFormat.parse("../foo/.", resolver));
+
+ for (Iterator it = paths.iterator(); it.hasNext(); ) {
+ Path path = (Path) it.next();
+ assertFalse("path is normalized: " + PathFormat.format(path, resolver), path.isNormalized());
+ }
+ }
+
+ public void testAbsolutePaths() throws Exception {
+ List paths = new ArrayList();
+
+ // absolute paths
+ paths.add(PathFormat.parse("/", resolver));
+ paths.add(PathFormat.parse("/foo", resolver));
+ paths.add(PathFormat.parse("/foo/bar", resolver));
+ paths.add(PathFormat.parse("/foo/../bar", resolver));
+ paths.add(PathFormat.parse("/foo/..", resolver));
+ paths.add(PathFormat.parse("/foo/./bar", resolver));
+ paths.add(PathFormat.parse("/foo/.././bar/./foo", resolver));
+
+ for (Iterator it = paths.iterator(); it.hasNext(); ) {
+ Path path = (Path) it.next();
+ assertTrue("path is not absolute: " + PathFormat.format(path, resolver), path.isAbsolute());
+ }
+
+ paths.clear();
+
+ // not absoulute paths
+ paths.add(PathFormat.parse("foo/..", resolver));
+ paths.add(PathFormat.parse("foo/.", resolver));
+ paths.add(PathFormat.parse("foo/../bar", resolver));
+ paths.add(PathFormat.parse("foo/./bar", resolver));
+ paths.add(PathFormat.parse("./foo", resolver));
+ paths.add(PathFormat.parse(".", resolver));
+ paths.add(PathFormat.parse("foo/..", resolver));
+ paths.add(PathFormat.parse("../foo/..", resolver));
+ paths.add(PathFormat.parse("../foo/.", resolver));
+
+ for (Iterator it = paths.iterator(); it.hasNext(); ) {
+ Path path = (Path) it.next();
+ assertFalse("path is absolute: " + PathFormat.format(path, resolver), path.isAbsolute());
+ }
+ }
+
+ public void testCanonicalPaths() throws Exception {
+ List paths = new ArrayList();
+
+ // canonical paths
+ paths.add(PathFormat.parse("/", resolver));
+ paths.add(PathFormat.parse("/foo", resolver));
+ paths.add(PathFormat.parse("/foo/bar", resolver));
+
+ for (Iterator it = paths.iterator(); it.hasNext(); ) {
+ Path path = (Path) it.next();
+ assertTrue("path is not canonical: " + PathFormat.format(path, resolver), path.isCanonical());
+ }
+
+ paths.clear();
+
+ // not canonical paths
+ paths.add(PathFormat.parse("/foo/..", resolver));
+ paths.add(PathFormat.parse("/foo/.", resolver));
+ paths.add(PathFormat.parse("/foo/../bar", resolver));
+ paths.add(PathFormat.parse("/foo/./bar", resolver));
+ paths.add(PathFormat.parse("./foo", resolver));
+ paths.add(PathFormat.parse(".", resolver));
+ paths.add(PathFormat.parse("/foo/..", resolver));
+ paths.add(PathFormat.parse("/../foo/..", resolver));
+ paths.add(PathFormat.parse("/../foo/.", resolver));
+
+ for (Iterator it = paths.iterator(); it.hasNext(); ) {
+ Path path = (Path) it.next();
+ assertFalse("path is canonical: " + PathFormat.format(path, resolver), path.isCanonical());
+ }
+ }
+
private static class Test {
private final String path;