Index: src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java (working copy)
@@ -26,6 +26,7 @@
import org.apache.jackrabbit.name.NamespaceResolver;
import org.apache.jackrabbit.name.Path;
import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.util.PathMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Index: src/main/java/org/apache/jackrabbit/core/CachingNamespaceResolver.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/CachingNamespaceResolver.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/CachingNamespaceResolver.java (working copy)
@@ -23,6 +23,9 @@
import org.apache.jackrabbit.name.NamespaceResolver;
import org.apache.jackrabbit.name.NamespaceListener;
import org.apache.jackrabbit.name.AbstractNamespaceResolver;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.MalformedPathException;
+import org.apache.jackrabbit.name.PathFormat;
import org.apache.commons.collections.map.LRUMap;
import javax.jcr.NamespaceException;
@@ -106,6 +109,24 @@
}
/**
+ * @inheritDoc
+ * As currently paths are not cached, the call is delegated to
+ * {@link PathFormat#parse(String, NamespaceResolver)}.
+ */
+ public Path getQPath(String jcrPath) throws MalformedPathException {
+ return PathFormat.parse(jcrPath, this);
+ }
+
+ /**
+ * @inheritDoc
+ * As currently paths are not cached, the call is delegated to
+ * {@link PathFormat#format(Path, NamespaceResolver)}.
+ */
+ public String getJCRPath(Path qPath) throws NoPrefixDeclaredException {
+ return PathFormat.format(qPath, this);
+ }
+
+ /**
* Disposes this CachingNamespaceResolver.
*/
public void dispose() {
@@ -129,4 +150,13 @@
qnameToJCRName.clear();
jcrNameToQName.clear();
}
+
+ /**
+ * @inheritDoc
+ * Invalidates all cached mappings.
+ */
+ public void namespaceRemoved(String uri) {
+ qnameToJCRName.clear();
+ jcrNameToQName.clear();
+ }
}
Index: src/main/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java (working copy)
@@ -296,4 +296,17 @@
uriToPrefix.put(uri, uniquePrefix);
}
}
+
+ /**
+ * @inheritDoc
+ * This method gets called when an existing namespace is removed
+ * in the global NamespaceRegistry. Overridden in order to check
+ * for/resolve collision of new global prefix with existing local prefix.
+ */
+ public void namespaceRemoved(String uri) {
+ if (uriToPrefix.containsKey(uri)) {
+ String prefix = (String)uriToPrefix.remove(uri);
+ prefixToURI.remove(prefix);
+ }
+ }
}
Index: src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java (working copy)
@@ -21,7 +21,7 @@
import org.apache.jackrabbit.core.ItemId;
import org.apache.jackrabbit.core.NodeId;
import org.apache.jackrabbit.core.NodeImpl;
-import org.apache.jackrabbit.core.PathMap;
+import org.apache.jackrabbit.util.PathMap;
import org.apache.jackrabbit.core.SessionImpl;
import org.apache.jackrabbit.core.SessionListener;
import org.apache.jackrabbit.core.fs.FileSystem;
@@ -852,7 +852,7 @@
/**
* Contains information about a lock and gets placed inside the child
- * information of a {@link org.apache.jackrabbit.core.PathMap}.
+ * information of a {@link org.apache.jackrabbit.util.PathMap}.
*/
class LockInfo extends AbstractLockInfo implements SessionListener {
Index: src/main/java/org/apache/jackrabbit/core/NodeImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/NodeImpl.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/NodeImpl.java (working copy)
@@ -1635,7 +1635,7 @@
try {
if (prop.getDefinition().getRequiredType() == PropertyType.UNDEFINED
&& type != PropertyType.UNDEFINED) {
- prop.setValue(ValueHelper.convert(values, type));
+ prop.setValue(ValueHelper.convert(values, type, session.getValueFactory()));
} else {
prop.setValue(values);
}
@@ -1998,7 +1998,7 @@
try {
if (prop.getDefinition().getRequiredType() == PropertyType.UNDEFINED
&& type != PropertyType.UNDEFINED) {
- prop.setValue(ValueHelper.convert(values, type));
+ prop.setValue(ValueHelper.convert(values, type, session.getValueFactory()));
} else {
prop.setValue(values);
}
@@ -2030,7 +2030,7 @@
try {
if (prop.getDefinition().getRequiredType() == PropertyType.UNDEFINED
&& type != PropertyType.UNDEFINED) {
- prop.setValue(ValueHelper.convert(values, type));
+ prop.setValue(ValueHelper.convert(values, type, session.getValueFactory()));
} else {
prop.setValue(values);
}
@@ -2094,7 +2094,7 @@
try {
if (prop.getDefinition().getRequiredType() == PropertyType.UNDEFINED
&& type != PropertyType.UNDEFINED) {
- prop.setValue(ValueHelper.convert(values, type));
+ prop.setValue(ValueHelper.convert(values, type, session.getValueFactory()));
} else {
prop.setValue(values);
}
@@ -2154,7 +2154,7 @@
try {
if (prop.getDefinition().getRequiredType() == PropertyType.UNDEFINED
&& type != PropertyType.UNDEFINED) {
- prop.setValue(ValueHelper.convert(value, type));
+ prop.setValue(ValueHelper.convert(value, type, session.getValueFactory()));
} else {
prop.setValue(value);
}
@@ -2186,7 +2186,7 @@
try {
if (prop.getDefinition().getRequiredType() == PropertyType.UNDEFINED
&& type != PropertyType.UNDEFINED) {
- prop.setValue(ValueHelper.convert(value, type));
+ prop.setValue(ValueHelper.convert(value, type, session.getValueFactory()));
} else {
prop.setValue(value);
}
@@ -2223,7 +2223,7 @@
try {
if (prop.getDefinition().getRequiredType() == PropertyType.UNDEFINED
&& type != PropertyType.UNDEFINED) {
- prop.setValue(ValueHelper.convert(value, type));
+ prop.setValue(ValueHelper.convert(value, type, session.getValueFactory()));
} else {
prop.setValue(value);
}
Index: src/main/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefReader.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefReader.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefReader.java (working copy)
@@ -35,6 +35,7 @@
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.ValueFormatException;
+import javax.jcr.ValueFactory;
import javax.jcr.version.OnParentVersionAction;
import java.io.Reader;
import java.util.ArrayList;
@@ -132,6 +133,12 @@
private NamespaceMapping nsMapping;
/**
+ * the ValueFactory used to create qualified values from
+ * JCR values.
+ */
+ private ValueFactory valueFactory;
+
+ /**
* the underlying lexer
*/
private Lexer lexer;
@@ -145,10 +152,11 @@
* Creates a new CND reader.
*
* @param r
+ * @param valueFactory
* @throws ParseException
*/
- public CompactNodeTypeDefReader(Reader r, String systemId) throws ParseException {
- this(r, systemId, new NamespaceMapping());
+ public CompactNodeTypeDefReader(Reader r, String systemId, ValueFactory valueFactory) throws ParseException {
+ this(r, systemId, new NamespaceMapping(), valueFactory);
}
@@ -156,12 +164,16 @@
* Creates a new CND reader.
*
* @param r
+ * @param valueFactory
* @throws ParseException
*/
- public CompactNodeTypeDefReader(Reader r, String systemId, NamespaceMapping mapping)
+ public CompactNodeTypeDefReader(Reader r, String systemId,
+ NamespaceMapping mapping,
+ ValueFactory valueFactory)
throws ParseException {
lexer = new Lexer(r, systemId);
this.nsMapping = mapping;
+ this.valueFactory = valueFactory;
nextToken();
parse();
}
@@ -484,7 +496,7 @@
nextToken();
InternalValue value = null;
try {
- value = InternalValue.create(currentToken, pdi.getRequiredType(), nsMapping);
+ value = InternalValue.create(currentToken, pdi.getRequiredType(), nsMapping, valueFactory);
} catch (ValueFormatException e) {
lexer.fail("'" + currentToken + "' is not a valid string representation of a value of type " + pdi.getRequiredType());
} catch (RepositoryException e) {
Index: src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeDefStore.java (working copy)
@@ -19,6 +19,7 @@
import org.apache.jackrabbit.core.nodetype.xml.NodeTypeReader;
import org.apache.jackrabbit.core.nodetype.xml.NodeTypeWriter;
import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
import javax.jcr.NamespaceRegistry;
import javax.jcr.RepositoryException;
@@ -52,7 +53,13 @@
public void load(InputStream in)
throws IOException, InvalidNodeTypeDefException,
RepositoryException {
- NodeTypeDef[] types = NodeTypeReader.read(in);
+ /* TODO: improve. instead of accessing a specific ValueFactory instance
+ the factory should be provided by the NodeTypeRegistry (and thus
+ by the Repository). this has been avoided in order not to modify
+ the RepositoryImpl. the result obtained with the given solution is
+ identical to the original code, where Value instances were created
+ by the ValueHelper (which in turn is used by InternalValue). */
+ NodeTypeDef[] types = NodeTypeReader.read(in, ValueFactoryImpl.getInstance());
for (int i = 0; i < types.length; i++) {
add(types[i]);
}
Index: src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeImpl.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeImpl.java (working copy)
@@ -29,6 +29,7 @@
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
+import javax.jcr.ValueFactory;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeDefinition;
@@ -49,6 +50,8 @@
private final NodeTypeManagerImpl ntMgr;
// namespace resolver used to translate qualified names to JCR names
private final NamespaceResolver nsResolver;
+ // value factory used to to translate qualified names to JCR names
+ private final ValueFactory valueFactory;
/**
* Package private constructor
@@ -63,11 +66,13 @@
* @param nsResolver namespace resolver
*/
NodeTypeImpl(EffectiveNodeType ent, NodeTypeDef ntd,
- NodeTypeManagerImpl ntMgr, NamespaceResolver nsResolver) {
+ NodeTypeManagerImpl ntMgr, NamespaceResolver nsResolver,
+ ValueFactory valueFactory) {
this.ent = ent;
this.ntMgr = ntMgr;
this.nsResolver = nsResolver;
this.ntd = ntd;
+ this.valueFactory = valueFactory;
}
/**
@@ -378,7 +383,7 @@
// create InternalValue from Value and perform
// type conversion as necessary
InternalValue internalValue = InternalValue.create(value, targetType,
- nsResolver);
+ nsResolver, valueFactory);
EffectiveNodeType.checkSetPropertyValueConstraints(
def, new InternalValue[]{internalValue});
return true;
@@ -448,7 +453,7 @@
// type conversion as necessary
InternalValue internalValue =
InternalValue.create(values[i], targetType,
- nsResolver);
+ nsResolver, valueFactory);
list.add(internalValue);
}
}
Index: src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/nodetype/NodeTypeManagerImpl.java (working copy)
@@ -36,6 +36,7 @@
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.ValueFactory;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeIterator;
@@ -90,6 +91,12 @@
private final NamespaceResolver nsResolver;
/**
+ * The ValueFactory used to parse JCR values of a given type
+ * into qualified values.
+ */
+ private final ValueFactory valueFactory;
+
+ /**
* A cache for NodeType instances created by this
* NodeTypeManager
*/
@@ -115,11 +122,12 @@
*/
public NodeTypeManagerImpl(
NodeTypeRegistry ntReg, NamespaceRegistryImpl nsReg,
- NamespaceResolver nsResolver) {
+ NamespaceResolver nsResolver, ValueFactory valueFactory) {
this.nsResolver = nsResolver;
this.ntReg = ntReg;
this.nsReg = nsReg;
this.ntReg.addListener(this);
+ this.valueFactory = valueFactory;
// setup caches with soft references to node type
// & item definition instances
@@ -186,7 +194,7 @@
if (nt == null) {
EffectiveNodeType ent = ntReg.getEffectiveNodeType(name);
NodeTypeDef def = ntReg.getNodeTypeDef(name);
- nt = new NodeTypeImpl(ent, def, this, nsResolver);
+ nt = new NodeTypeImpl(ent, def, this, nsResolver, valueFactory);
ntCache.put(name, nt);
}
return nt;
@@ -353,7 +361,7 @@
public NodeType[] registerNodeTypes(InputSource in)
throws SAXException, RepositoryException {
try {
- NodeTypeReader ntr = new NodeTypeReader(in.getByteStream());
+ NodeTypeReader ntr = new NodeTypeReader(in.getByteStream(), valueFactory);
Properties namespaces = ntr.getNamespaces();
if (namespaces != null) {
@@ -397,7 +405,7 @@
} else if (contentType.equalsIgnoreCase(TEXT_X_JCR_CND)) {
NamespaceMapping mapping = new NamespaceMapping(nsResolver);
CompactNodeTypeDefReader reader = new CompactNodeTypeDefReader(
- new InputStreamReader(in), "cnd input stream", mapping);
+ new InputStreamReader(in), "cnd input stream", mapping, valueFactory);
Map nsMap = mapping.getPrefixToURIMapping();
Iterator iterator = nsMap.entrySet().iterator();
Index: src/main/java/org/apache/jackrabbit/core/nodetype/xml/NodeTypeReader.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/nodetype/xml/NodeTypeReader.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/nodetype/xml/NodeTypeReader.java (working copy)
@@ -34,6 +34,7 @@
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
+import javax.jcr.ValueFactory;
import javax.jcr.version.OnParentVersionAction;
import java.io.IOException;
import java.io.InputStream;
@@ -52,16 +53,18 @@
* returned.
*
* @param xml XML input stream
+ * @param valueFactory used for conversion of JCR values read from the
+ * definition.
* @return node type definitions
* @throws IOException if the node type definitions
* cannot be read
* @throws InvalidNodeTypeDefException if the node type definition
* format is invalid
*/
- public static NodeTypeDef[] read(InputStream xml)
+ public static NodeTypeDef[] read(InputStream xml, ValueFactory valueFactory)
throws IOException, InvalidNodeTypeDefException {
try {
- NodeTypeReader reader = new NodeTypeReader(xml);
+ NodeTypeReader reader = new NodeTypeReader(xml, valueFactory);
return reader.getNodeTypeDefs();
} catch (IllegalNameException e) {
throw new InvalidNodeTypeDefException(
@@ -81,16 +84,22 @@
/** The namespace resolver. */
private final NamespaceResolver resolver;
+ /** The ValueFactory for value conversion (between types) */
+ private final ValueFactory valueFactory;
+
/**
* Creates a node type definition file reader.
*
* @param xml node type definition file
+ * @param valueFactory used for conversion of JCR values read from the
+ * definition.
* @throws IOException if the node type definition file cannot be read
*/
- public NodeTypeReader(InputStream xml) throws IOException {
+ public NodeTypeReader(InputStream xml, ValueFactory valueFactory) throws IOException {
walker = new DOMWalker(xml);
namespaces = walker.getNamespaces();
resolver = new AdditionalNamespaceResolver(namespaces);
+ this.valueFactory = valueFactory;
}
/**
@@ -255,7 +264,7 @@
while (walker.iterateElements(Constants.DEFAULTVALUE_ELEMENT)) {
String value = walker.getContent();
try {
- values.add(InternalValue.create(value, type, resolver));
+ values.add(InternalValue.create(value, type, resolver, valueFactory));
} catch (RepositoryException e) {
throw new InvalidNodeTypeDefException(
"Unable to create default value: " + value, e);
Index: src/main/java/org/apache/jackrabbit/core/PropertyImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/PropertyImpl.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/PropertyImpl.java (working copy)
@@ -349,7 +349,7 @@
// type conversion required
internalValue =
InternalValue.create(InternalValue.create(name).toJCRValue(session.getNamespaceResolver()),
- reqType, session.getNamespaceResolver());
+ reqType, session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
internalValue = InternalValue.create(name);
@@ -398,7 +398,7 @@
// type conversion required
internalValue =
InternalValue.create(InternalValue.create(name).toJCRValue(session.getNamespaceResolver()),
- reqType, session.getNamespaceResolver());
+ reqType, session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
internalValue = InternalValue.create(name);
@@ -686,7 +686,8 @@
InternalValue value;
if (reqType != PropertyType.DATE) {
// type conversion required
- value = InternalValue.create(new DateValue(date), reqType, session.getNamespaceResolver());
+ value = InternalValue.create(new DateValue(date), reqType,
+ session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
value = InternalValue.create(date);
@@ -717,7 +718,8 @@
InternalValue value;
if (reqType != PropertyType.DOUBLE) {
// type conversion required
- value = InternalValue.create(new DoubleValue(number), reqType, session.getNamespaceResolver());
+ value = InternalValue.create(new DoubleValue(number), reqType,
+ session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
value = InternalValue.create(number);
@@ -754,7 +756,8 @@
try {
if (reqType != PropertyType.BINARY) {
// type conversion required
- value = InternalValue.create(new BLOBFileValue(stream), reqType, session.getNamespaceResolver());
+ value = InternalValue.create(new BLOBFileValue(stream), reqType,
+ session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
value = InternalValue.create(stream);
@@ -795,7 +798,8 @@
InternalValue internalValue;
if (reqType != PropertyType.STRING) {
// type conversion required
- internalValue = InternalValue.create(string, reqType, session.getNamespaceResolver());
+ internalValue = InternalValue.create(string, reqType,
+ session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
internalValue = InternalValue.create(string);
@@ -832,7 +836,8 @@
if (string != null) {
if (reqType != PropertyType.STRING) {
// type conversion required
- internalValue = InternalValue.create(string, reqType, session.getNamespaceResolver());
+ internalValue = InternalValue.create(string, reqType,
+ session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
internalValue = InternalValue.create(string);
@@ -867,7 +872,8 @@
InternalValue value;
if (reqType != PropertyType.BOOLEAN) {
// type conversion required
- value = InternalValue.create(new BooleanValue(b), reqType, session.getNamespaceResolver());
+ value = InternalValue.create(new BooleanValue(b), reqType,
+ session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
value = InternalValue.create(b);
@@ -940,7 +946,8 @@
InternalValue value;
if (reqType != PropertyType.LONG) {
// type conversion required
- value = InternalValue.create(new LongValue(number), reqType, session.getNamespaceResolver());
+ value = InternalValue.create(new LongValue(number), reqType,
+ session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
value = InternalValue.create(number);
@@ -980,7 +987,8 @@
InternalValue internalValue;
if (reqType != value.getType()) {
// type conversion required
- internalValue = InternalValue.create(value, reqType, session.getNamespaceResolver());
+ internalValue = InternalValue.create(value, reqType,
+ session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
internalValue = InternalValue.create(value, session.getNamespaceResolver());
@@ -1038,7 +1046,8 @@
if (reqType != PropertyType.UNDEFINED
&& reqType != value.getType()) {
// type conversion required
- internalValue = InternalValue.create(value, reqType, session.getNamespaceResolver());
+ internalValue = InternalValue.create(value, reqType,
+ session.getNamespaceResolver(), session.getValueFactory());
} else {
// no type conversion required
internalValue = InternalValue.create(value, session.getNamespaceResolver());
Index: src/main/java/org/apache/jackrabbit/core/SessionImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/SessionImpl.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/SessionImpl.java (working copy)
@@ -237,7 +237,7 @@
}
this.subject = subject;
nsMappings = new LocalNamespaceMappings(rep.getNamespaceRegistry());
- ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), rep.getNamespaceRegistry(), getNamespaceResolver());
+ ntMgr = new NodeTypeManagerImpl(rep.getNodeTypeRegistry(), rep.getNamespaceRegistry(), getNamespaceResolver(), getValueFactory());
String wspName = wspConfig.getName();
wsp = createWorkspaceInstance(wspConfig,
rep.getWorkspaceStateManager(wspName), rep, this);
@@ -1225,7 +1225,7 @@
public ValueFactory getValueFactory()
throws UnsupportedRepositoryOperationException, RepositoryException {
if (valueFactory == null) {
- valueFactory = new ValueFactoryImpl();
+ valueFactory = ValueFactoryImpl.getInstance();
}
return valueFactory;
}
Index: src/main/java/org/apache/jackrabbit/core/state/NodeReferences.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/state/NodeReferences.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/state/NodeReferences.java (working copy)
@@ -18,7 +18,6 @@
import org.apache.jackrabbit.core.PropertyId;
import org.apache.jackrabbit.core.NodeId;
-import org.apache.jackrabbit.uuid.UUID;
import java.io.Serializable;
import java.util.ArrayList;
Index: src/main/java/org/apache/jackrabbit/core/value/InternalValue.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/value/InternalValue.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/value/InternalValue.java (working copy)
@@ -41,6 +41,7 @@
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
+import javax.jcr.ValueFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -151,12 +152,14 @@
* @throws RepositoryException
*/
public static InternalValue create(Value value, int targetType,
- NamespaceResolver nsResolver)
+ NamespaceResolver nsResolver,
+ ValueFactory valueFactory)
throws ValueFormatException, RepositoryException {
if (value == null) {
throw new IllegalArgumentException("null value");
}
- return create(ValueHelper.convert(value, targetType), nsResolver);
+ Value targetValue = ValueHelper.convert(value, targetType, valueFactory);
+ return create(targetValue, nsResolver);
}
/**
@@ -168,12 +171,14 @@
* @throws RepositoryException
*/
public static InternalValue create(String value, int targetType,
- NamespaceResolver nsResolver)
+ NamespaceResolver nsResolver,
+ ValueFactory valueFactory)
throws ValueFormatException, RepositoryException {
if (value == null) {
throw new IllegalArgumentException("null value");
}
- return create(ValueHelper.convert(value, targetType), nsResolver);
+ Value targetValue = ValueHelper.convert(value, targetType, valueFactory);
+ return create(targetValue, nsResolver);
}
/**
Index: src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/xml/BufferedStringValue.java (working copy)
@@ -30,6 +30,7 @@
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
+import javax.jcr.ValueFactory;
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.name.NamespaceResolver;
@@ -226,7 +227,8 @@
//--------------------------------------------------------< TextValue >
- public Value getValue(int targetType, NamespaceResolver resolver)
+ public Value getValue(int targetType, NamespaceResolver resolver,
+ ValueFactory valueFactory)
throws ValueFormatException, RepositoryException {
try {
if (targetType == PropertyType.NAME
@@ -238,26 +240,26 @@
// convert serialized value to InternalValue using
// current namespace context of xml document
InternalValue ival =
- InternalValue.create(retrieve(), targetType, nsContext);
+ InternalValue.create(retrieve(), targetType, nsContext, valueFactory);
// convert InternalValue to Value using this
// session's namespace mappings
return ival.toJCRValue(resolver);
} else if (targetType == PropertyType.BINARY) {
if (length() < 0x10000) {
// < 65kb: deserialize BINARY type using String
- return ValueHelper.deserialize(retrieve(), targetType, false);
+ return ValueHelper.deserialize(retrieve(), targetType, false, valueFactory);
} else {
// >= 65kb: deserialize BINARY type using Reader
Reader reader = reader();
try {
- return ValueHelper.deserialize(reader, targetType, false);
+ return ValueHelper.deserialize(reader, targetType, false, valueFactory);
} finally {
reader.close();
}
}
} else {
// all other types
- return ValueHelper.deserialize(retrieve(), targetType, true);
+ return ValueHelper.deserialize(retrieve(), targetType, true, valueFactory);
}
} catch (IOException e) {
String msg = "failed to retrieve serialized value";
@@ -266,7 +268,7 @@
}
}
- public InternalValue getInternalValue(int type)
+ public InternalValue getInternalValue(int type, ValueFactory valueFactory)
throws ValueFormatException, RepositoryException {
try {
if (type == PropertyType.BINARY) {
@@ -297,7 +299,7 @@
} else {
// convert serialized value to InternalValue using
// current namespace context of xml document
- return InternalValue.create(retrieve(), type, nsContext);
+ return InternalValue.create(retrieve(), type, nsContext, valueFactory);
}
} catch (IOException e) {
throw new RepositoryException("Error accessing property value", e);
Index: src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/xml/DocViewImportHandler.java (working copy)
@@ -27,7 +27,6 @@
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
-import javax.jcr.Value;
import java.io.IOException;
import java.io.Reader;
Index: src/main/java/org/apache/jackrabbit/core/xml/Importer.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/xml/Importer.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/xml/Importer.java (working copy)
@@ -16,8 +16,6 @@
*/
package org.apache.jackrabbit.core.xml;
-import org.apache.jackrabbit.name.NamespaceResolver;
-
import javax.jcr.RepositoryException;
import java.util.List;
Index: src/main/java/org/apache/jackrabbit/core/xml/ImportHandler.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/xml/ImportHandler.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/xml/ImportHandler.java (working copy)
@@ -17,7 +17,6 @@
package org.apache.jackrabbit.core.xml;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.Map;
import org.apache.jackrabbit.core.NamespaceRegistryImpl;
@@ -26,13 +25,11 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
-import javax.jcr.NamespaceException;
import javax.jcr.RepositoryException;
/**
Index: src/main/java/org/apache/jackrabbit/core/xml/NamespaceContext.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/xml/NamespaceContext.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/xml/NamespaceContext.java (working copy)
@@ -27,6 +27,9 @@
import org.apache.jackrabbit.name.NoPrefixDeclaredException;
import org.apache.jackrabbit.name.QName;
import org.apache.jackrabbit.name.UnknownPrefixException;
+import org.apache.jackrabbit.name.Path;
+import org.apache.jackrabbit.name.MalformedPathException;
+import org.apache.jackrabbit.name.PathFormat;
/**
* Hierarchically scoped namespace resolver. Each NamespaceContext instance
@@ -128,6 +131,14 @@
return name.toJCRName(this);
}
+ public Path getQPath(String jcrPath) throws MalformedPathException {
+ return PathFormat.parse(jcrPath, this);
+ }
+
+ public String getJCRPath(Path qPath) throws NoPrefixDeclaredException {
+ return PathFormat.format(qPath, this);
+ }
+
/** {@inheritDoc} */
public QName getQName(String name)
throws IllegalNameException, UnknownPrefixException {
Index: src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/xml/PropInfo.java (working copy)
@@ -22,6 +22,7 @@
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
+import javax.jcr.ValueFactory;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.version.VersionException;
@@ -88,7 +89,9 @@
}
}
- public void apply(NodeImpl node, NamespaceResolver resolver, ReferenceChangeTracker refTracker) throws RepositoryException, ConstraintViolationException, ValueFormatException, VersionException, LockException, ItemNotFoundException {
+ public void apply(NodeImpl node, NamespaceResolver resolver,
+ ReferenceChangeTracker refTracker, ValueFactory valueFactory)
+ throws RepositoryException, ConstraintViolationException, ValueFormatException, VersionException, LockException, ItemNotFoundException {
// find applicable definition
PropDef def = getApplicablePropertyDef(node.getEffectiveNodeType());
if (def.isProtected()) {
@@ -101,7 +104,7 @@
Value[] va = new Value[values.length];
int targetType = getTargetType(def);
for (int i = 0; i < values.length; i++) {
- va[i] = values[i].getValue(targetType, resolver);
+ va[i] = values[i].getValue(targetType, resolver, valueFactory);
}
// multi- or single-valued property?
@@ -127,7 +130,9 @@
}
}
- public void apply(NodeState node, BatchedItemOperations itemOps, NodeTypeRegistry ntReg, ReferenceChangeTracker refTracker) throws ItemNotFoundException, RepositoryException, ItemExistsException, ConstraintViolationException, ValueFormatException {
+ public void apply(NodeState node, BatchedItemOperations itemOps,
+ NodeTypeRegistry ntReg, ReferenceChangeTracker refTracker,
+ ValueFactory valueFactory) throws ItemNotFoundException, RepositoryException, ItemExistsException, ConstraintViolationException, ValueFormatException {
PropertyState prop = null;
PropDef def = null;
@@ -171,7 +176,7 @@
int targetType = getTargetType(def);
InternalValue[] iva = new InternalValue[values.length];
for (int i = 0; i < values.length; i++) {
- iva[i] = values[i].getInternalValue(targetType);
+ iva[i] = values[i].getInternalValue(targetType, valueFactory);
}
// set values
Index: src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/xml/SessionImporter.java (working copy)
@@ -259,7 +259,7 @@
Iterator iter = propInfos.iterator();
while (iter.hasNext()) {
PropInfo pi = (PropInfo) iter.next();
- pi.apply(node, session.getNamespaceResolver(), refTracker);
+ pi.apply(node, session.getNamespaceResolver(), refTracker, session.getValueFactory());
}
parents.push(node);
Index: src/main/java/org/apache/jackrabbit/core/xml/StringValue.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/xml/StringValue.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/xml/StringValue.java (working copy)
@@ -18,13 +18,12 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
+import javax.jcr.ValueFactory;
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.name.NamespaceResolver;
@@ -53,7 +52,7 @@
//--------------------------------------------------------< TextValue >
- public Value getValue(int type, NamespaceResolver resolver)
+ public Value getValue(int type, NamespaceResolver resolver, ValueFactory valueFactory)
throws ValueFormatException, RepositoryException {
if (type == PropertyType.NAME || type == PropertyType.PATH) {
// NAME and PATH require special treatment because
@@ -62,19 +61,19 @@
// convert serialized value to InternalValue using
// current namespace context of xml document
- InternalValue ival = InternalValue.create(value, type, nsContext);
+ InternalValue ival = InternalValue.create(value, type, nsContext, valueFactory);
// convert InternalValue to Value using this
// session's namespace mappings
return ival.toJCRValue(resolver);
} else if (type == PropertyType.BINARY) {
- return ValueHelper.deserialize(value, type, false);
+ return ValueHelper.deserialize(value, type, false, valueFactory);
} else {
// all other types
- return ValueHelper.deserialize(value, type, true);
+ return ValueHelper.deserialize(value, type, true, valueFactory);
}
}
- public InternalValue getInternalValue(int targetType)
+ public InternalValue getInternalValue(int targetType, ValueFactory valueFactory)
throws ValueFormatException, RepositoryException {
try {
if (targetType == PropertyType.BINARY) {
@@ -86,7 +85,7 @@
} else {
// convert serialized value to InternalValue using
// current namespace context of xml document
- return InternalValue.create(value, targetType, nsContext);
+ return InternalValue.create(value, targetType, nsContext, valueFactory);
}
} catch (IOException e) {
throw new RepositoryException("Error decoding Base64 content", e);
Index: src/main/java/org/apache/jackrabbit/core/xml/TextValue.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/xml/TextValue.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/xml/TextValue.java (working copy)
@@ -19,6 +19,7 @@
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
+import javax.jcr.ValueFactory;
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.name.NamespaceResolver;
@@ -29,10 +30,10 @@
*/
public interface TextValue {
- Value getValue(int type, NamespaceResolver resolver)
+ Value getValue(int type, NamespaceResolver resolver, ValueFactory valueFactory)
throws ValueFormatException, RepositoryException;
- InternalValue getInternalValue(int type)
+ InternalValue getInternalValue(int type, ValueFactory valueFactory)
throws ValueFormatException, RepositoryException;
/**
Index: src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java
===================================================================
--- src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/core/xml/WorkspaceImporter.java (working copy)
@@ -493,7 +493,7 @@
Iterator iter = propInfos.iterator();
while (iter.hasNext()) {
PropInfo pi = (PropInfo) iter.next();
- pi.apply(node, itemOps, ntReg, refTracker);
+ pi.apply(node, itemOps, ntReg, refTracker, wsp.getSession().getValueFactory());
}
// store affected nodes
Index: src/main/java/org/apache/jackrabbit/name/AbstractNamespaceResolver.java
===================================================================
--- src/main/java/org/apache/jackrabbit/name/AbstractNamespaceResolver.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/name/AbstractNamespaceResolver.java (working copy)
@@ -40,19 +40,33 @@
/**
* @inheritDoc
*/
- public QName getQName(String name)
+ public QName getQName(String jcrName)
throws IllegalNameException, UnknownPrefixException {
- return QName.fromJCRName(name, this);
+ return NameFormat.parse(jcrName, this);
}
/**
* @inheritDoc
*/
- public String getJCRName(QName name) throws NoPrefixDeclaredException {
- return name.toJCRName(this);
+ public String getJCRName(QName qName) throws NoPrefixDeclaredException {
+ return NameFormat.format(qName, this);
}
/**
+ * @inheritDoc
+ */
+ public Path getQPath(String jcrPath) throws MalformedPathException {
+ return PathFormat.parse(jcrPath, this);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public String getJCRPath(Path qPath) throws NoPrefixDeclaredException {
+ return PathFormat.format(qPath, this);
+ }
+
+ /**
* Creates a AbstractNamespaceResolver without listener
* support.
*/
@@ -164,4 +178,30 @@
currentListeners[i].namespaceRemapped(oldPrefix, newPrefix, uri);
}
}
+
+ /**
+ * Notifies the listeners that the namespace with the given uri
+ * has been removed from the mapping.
+ *
+ * @param uri the namespace uri.
+ * @see NamespaceListener#namespaceRemoved(String)
+ */
+ protected void notifyNamespaceRemoved(String uri) {
+ if (listeners == null) {
+ throw new UnsupportedOperationException("notifyNamespaceRemapped");
+ }
+ // removal is infrequent compared to listener registration
+ // -> use copy-on-read
+ NamespaceListener[] currentListeners;
+ synchronized (listeners) {
+ int i = 0;
+ currentListeners = new NamespaceListener[listeners.size()];
+ for (Iterator it = listeners.iterator(); it.hasNext();) {
+ currentListeners[i++] = (NamespaceListener) it.next();
+ }
+ }
+ for (int i = 0; i < currentListeners.length; i++) {
+ currentListeners[i].namespaceRemoved(uri);
+ }
+ }
}
Index: src/main/java/org/apache/jackrabbit/name/NameFormat.java
===================================================================
--- src/main/java/org/apache/jackrabbit/name/NameFormat.java (revision 0)
+++ src/main/java/org/apache/jackrabbit/name/NameFormat.java (revision 0)
@@ -0,0 +1,188 @@
+/*
+ * 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.name;
+
+import org.apache.xerces.util.XMLChar;
+
+import javax.jcr.NamespaceException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * NameFormat formats a {@link QName} using a
+ * {@link NamespaceResolver}.
+ */
+public class NameFormat {
+
+ /**
+ * The reqular expression pattern used to validate and parse
+ * qualified names.
+ *
+ * The pattern contains the following groups: + *
jcrName and returns an array of two strings:
+ * the first array element contains the prefix (or empty string),
+ * the second the local name.
+ *
+ * @param jcrName the name to be parsed
+ * @return An array holding two strings: the first array element contains
+ * the prefix (or empty string), the second the local name.
+ * @throws IllegalNameException If jcrName is not a valid
+ * JCR-style name.
+ */
+ public static QName parse(String jcrName, NamespaceResolver nsResolver) throws IllegalNameException, UnknownPrefixException {
+ String[] parts = parse(jcrName);
+ String uri;
+ try {
+ uri = nsResolver.getURI(parts[0]);
+ } catch (NamespaceException nse) {
+ throw new UnknownPrefixException(parts[0]);
+ }
+
+ return new QName(uri, parts[1]);
+ }
+
+ /**
+ * Parses the jcrName and returns an array of two strings:
+ * the first array element contains the prefix (or empty string),
+ * the second the local name.
+ *
+ * @param jcrName the name to be parsed
+ * @return qName
+ * @throws IllegalNameException If jcrName is not a valid
+ * JCR-style name.
+ */
+ public static String[] parse(String jcrName) throws IllegalNameException {
+ if (jcrName == null || jcrName.length() == 0) {
+ throw new IllegalNameException("empty name");
+ }
+
+ if (".".equals(jcrName) || "..".equals(jcrName)) {
+ // illegal syntax for name
+ throw new IllegalNameException("'" + jcrName + "' is not a valid name");
+ }
+
+ String prefix;
+ String localName;
+
+ Matcher matcher = (Matcher) NAME_MATCHER.get();
+ matcher.reset(jcrName);
+ if (matcher.matches()) {
+ // check for prefix (group 1)
+ if (matcher.group(1) != null) {
+ // prefix specified
+ // group 2 is namespace prefix excl. delimiter (colon)
+ prefix = matcher.group(2);
+ // check if the prefix is a valid XML prefix
+ if (!XMLChar.isValidNCName(prefix)) {
+ // illegal syntax for prefix
+ throw new IllegalNameException("'" + jcrName
+ + "' is not a valid name: illegal prefix");
+ }
+ } else {
+ // no prefix specified
+ prefix = "";
+ }
+
+ // group 3 is localName
+ localName = matcher.group(3);
+ } else {
+ // illegal syntax for name
+ throw new IllegalNameException("'" + jcrName + "' is not a valid name");
+ }
+
+ return new String[] {prefix, localName};
+
+ }
+ /**
+ * Checks if jcrName is a valid JCR-style name.
+ *
+ * @param jcrName the name to be checked
+ * @throws IllegalNameException If jcrName is not a valid
+ * JCR-style name.
+ */
+ public static void checkFormat(String jcrName) throws IllegalNameException {
+ parse(jcrName);
+ }
+
+ /**
+ * Returns a string representation of the qualified name in the
+ * JCR name format.
+ *
+ * @param qName the qualified name to resolve.
+ * @param resolver the namespace resolver.
+ * @return JCR the formatted path.
+ * @throws NoPrefixDeclaredException if a namespace can not be resolved
+ * @see #format(QName, NamespaceResolver, StringBuffer)
+ */
+ public static String format(QName qName, NamespaceResolver resolver)
+ throws NoPrefixDeclaredException {
+ StringBuffer buf = new StringBuffer();
+ format(qName, resolver, buf);
+ return buf.toString();
+ }
+
+ /**
+ * Returns a string representation of the qualified name in the
+ * JCR name format.
+ *
+ * @param qName the qualified name to resolve.
+ * @param resolver the namespace resolver.
+ * @param buffer StringBuffer where the prefixed JCR name should be appended to.
+ * @return JCR the formatted path.
+ * @throws NoPrefixDeclaredException if a namespace can not be resolved
+ * @see #format(QName, NamespaceResolver)
+ */
+ public static void format(QName qName, NamespaceResolver resolver, StringBuffer buffer)
+ throws NoPrefixDeclaredException {
+ // prefix
+ String prefix;
+ try {
+ prefix = resolver.getPrefix(qName.getNamespaceURI());
+ } catch (NamespaceException nse) {
+ throw new NoPrefixDeclaredException("no prefix declared for URI: "
+ + qName.getNamespaceURI());
+ }
+ if (prefix.length() == 0) {
+ // default prefix (empty string)
+ } else {
+ buffer.append(prefix);
+ buffer.append(':');
+ }
+ // name
+ buffer.append(qName.getLocalName());
+ }
+}
Property changes on: src\main\java\org\apache\jackrabbit\name\NameFormat.java
___________________________________________________________________
Name: svn:keywords
+ author date id revision url
Name: svn:eol-style
+ native
Index: src/main/java/org/apache/jackrabbit/name/NamespaceListener.java
===================================================================
--- src/main/java/org/apache/jackrabbit/name/NamespaceListener.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/name/NamespaceListener.java (working copy)
@@ -39,4 +39,12 @@
* @param uri the namespace uri.
*/
public void namespaceAdded(String prefix, String uri);
+
+ /**
+ * Notifies the listeners that the namespace with the given uri has been
+ * unregistered.
+ *
+ * @param uri the namespace uri.
+ */
+ public void namespaceRemoved(String uri);
}
Index: src/main/java/org/apache/jackrabbit/name/NamespaceResolver.java
===================================================================
--- src/main/java/org/apache/jackrabbit/name/NamespaceResolver.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/name/NamespaceResolver.java (working copy)
@@ -49,20 +49,37 @@
/**
* Parses the given prefixed JCR name into a qualified name.
*
- * @param name the raw name, potentially prefixed.
+ * @param jcrName the raw name, potentially prefixed.
* @return the QName instance for the raw name.
* @throws IllegalNameException if the given name is not a valid JCR name
* @throws UnknownPrefixException if the JCR name prefix does not resolve
*/
- public QName getQName(String name)
+ public QName getQName(String jcrName)
throws IllegalNameException, UnknownPrefixException;
/**
* Returns the qualified name in the prefixed JCR name format.
*
- * @param name a qualified name
+ * @param qName a qualified name
* @return the raw JCR name
* @throws NoPrefixDeclaredException if the namespace can not be resolved
*/
- public String getJCRName(QName name) throws NoPrefixDeclaredException;
+ public String getJCRName(QName qName) throws NoPrefixDeclaredException;
+
+ /**
+ * Parses the given prefixed JCR Path into a qualified path.
+ *
+ * @param jcrPath the raw path, with potentially prefixed path elements.
+ * @return the Path instance for the raw path.
+ */
+ public Path getQPath(String jcrPath) throws MalformedPathException;
+
+ /**
+ * Returns the qualified path in the prefixed JCR path format.
+ *
+ * @param qPath a qualified path
+ * @return the corresponding JCR path, eventually containing prefixed elements.
+ * @throws NoPrefixDeclaredException if a namespace can not be resolved
+ */
+ public String getJCRPath(Path qPath) throws NoPrefixDeclaredException;
}
Index: src/main/java/org/apache/jackrabbit/name/Path.java
===================================================================
--- src/main/java/org/apache/jackrabbit/name/Path.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/name/Path.java (working copy)
@@ -17,15 +17,11 @@
package org.apache.jackrabbit.name;
import org.apache.jackrabbit.util.Text;
-import org.apache.xerces.util.XMLChar;
-import javax.jcr.NamespaceException;
-import javax.jcr.PathNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import javax.jcr.PathNotFoundException;
/**
* The Path utility class provides misc. methods to resolve and
@@ -90,17 +86,17 @@
/**
* the 'root' element. i.e. '/'
*/
- private static final PathElement ROOT_ELEMENT = new RootElement();
+ public static final PathElement ROOT_ELEMENT = new RootElement();
/**
* the 'current' element. i.e. '.'
*/
- private static final PathElement CURRENT_ELEMENT = new CurrentElement();
+ public static final PathElement CURRENT_ELEMENT = new CurrentElement();
/**
* the 'parent' element. i.e. '..'
*/
- private static final PathElement PARENT_ELEMENT = new ParentElement();
+ public static final PathElement PARENT_ELEMENT = new ParentElement();
/**
* the root path
@@ -108,34 +104,21 @@
public static final Path ROOT = new Path(new PathElement[]{ROOT_ELEMENT}, true);
/**
- * Pattern used to validate and parse path elements:- *
Path from the given jcrPath
* string. If normalize is true, the returned
* path will be normalized (or canonicalized if absolute).
@@ -186,11 +181,12 @@
* @param normalize
* @return
* @throws MalformedPathException
+ * @deprecated Use PathFormat#parse(String, NamespaceResolver)} instead.
*/
public static Path create(String jcrPath, NamespaceResolver resolver,
boolean normalize)
throws MalformedPathException {
- Path path = parse(jcrPath, null, resolver);
+ Path path = PathFormat.parse(jcrPath, resolver);
if (normalize) {
return path.getNormalizedPath();
} else {
@@ -209,11 +205,12 @@
* @param canonicalize
* @return
* @throws MalformedPathException
+ * @deprecated Use {@link PathFormat#create(Path, String, NamespaceResolver)} instead.
*/
public static Path create(Path parent, String relJCRPath,
NamespaceResolver resolver, boolean canonicalize)
throws MalformedPathException {
- Path path = parse(relJCRPath, parent, resolver);
+ Path path = PathFormat.parse(parent, relJCRPath, resolver);
if (canonicalize) {
return path.getCanonicalPath();
} else {
@@ -231,7 +228,7 @@
* @param relPath
* @param normalize
* @return
- * @throws MalformedPathException
+ * @throws MalformedPathException if relPath is absolute
*/
public static Path create(Path parent, Path relPath, boolean normalize)
throws MalformedPathException {
@@ -239,7 +236,7 @@
throw new MalformedPathException("relPath is not a relative path");
}
- PathBuilder pb = new PathBuilder(parent.getElements());
+ PathBuilder pb = new PathBuilder(parent);
pb.addAll(relPath.getElements());
Path path = pb.getPath();
@@ -256,15 +253,13 @@
* the returned path will be normalized (or canonicalized, if the parent
* path is absolute).
*
- * @param parent
- * @param name
+ * @param parent the parent path
+ * @param name the name of the new path element.
* @param normalize
- * @return
- * @throws MalformedPathException
+ * @return the new path.
*/
- public static Path create(Path parent, QName name, boolean normalize)
- throws MalformedPathException {
- PathBuilder pb = new PathBuilder(parent.getElements());
+ public static Path create(Path parent, QName name, boolean normalize) throws MalformedPathException {
+ PathBuilder pb = new PathBuilder(parent);
pb.addLast(name);
Path path = pb.getPath();
@@ -277,21 +272,17 @@
/**
* Creates a new Path out of the given parent path
- * and the give name and index. If normalize is
- * true, the returned path will be normalized
- * (or canonicalized, if the parent path is absolute).
+ * and the give name and index.
*
- * @param parent
- * @param name
- * @param 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 normalize
- * @return
- * @throws MalformedPathException
+ * @return the new path.
*/
- public static Path create(Path parent, QName name, int index,
- boolean normalize)
+ public static Path create(Path parent, QName name, int index, boolean normalize)
throws MalformedPathException {
- PathBuilder pb = new PathBuilder(parent.getElements());
+ PathBuilder pb = new PathBuilder(parent);
pb.addLast(name, index);
Path path = pb.getPath();
@@ -312,11 +303,11 @@
*/
public static Path create(QName name, int index)
throws IllegalArgumentException {
- if (index < 0) {
+ if (index < INDEX_UNDEFINED) {
throw new IllegalArgumentException("index must not be negative: " + index);
}
PathElement elem;
- if (index < 1) {
+ if (index < INDEX_DEFAULT) {
elem = new PathElement(name);
} else {
elem = new PathElement(name, index);
@@ -336,132 +327,11 @@
* @param resolver
* @return
* @throws MalformedPathException
+ * @deprecated use {@link PathFormat#parse(Path, String, NamespaceResolver)} instead.
*/
private static Path parse(String jcrPath, Path master, NamespaceResolver resolver)
throws MalformedPathException {
- // shortcut
- if ("/".equals(jcrPath)) {
- return ROOT;
- }
-
- // split path into path elements
- String[] elems = Text.explode(jcrPath, '/', true);
- if (elems.length == 0) {
- throw new MalformedPathException("empty path");
- }
-
- ArrayList list = new ArrayList();
- boolean isNormalized = true;
- boolean leadingParent = true;
- if (master != null) {
- isNormalized = master.normalized;
- // a master path was specified; the 'path' argument is assumed
- // to be a relative path
- for (int i = 0; i < master.elements.length; i++) {
- list.add(master.elements[i]);
- leadingParent &= master.elements[i].denotesParent();
- }
- }
-
- for (int i = 0; i < elems.length; i++) {
- // validate & parse path element
- String prefix;
- String localName;
- int index;
-
- String elem = elems[i];
- if (i == 0 && elem.length() == 0) {
- // path is absolute, i.e. the first element is the root element
- if (!list.isEmpty()) {
- throw new MalformedPathException("'" + jcrPath + "' is not a relative path");
- }
- list.add(ROOT_ELEMENT);
- leadingParent = false;
- continue;
- }
- if (elem.length() == 0 && i == elems.length - 1) {
- // ignore trailing '/'
- break;
- }
- Matcher matcher = (Matcher) PATH_ELEMENT_MATCHER.get();
- matcher.reset(elem);
- if (matcher.matches()) {
- if (resolver == null) {
- // check only
- continue;
- }
-
- if (matcher.group(1) != null) {
- // group 1 is .
- list.add(CURRENT_ELEMENT);
- leadingParent = false;
- isNormalized = false;
- } else if (matcher.group(2) != null) {
- // group 2 is ..
- list.add(PARENT_ELEMENT);
- isNormalized &= leadingParent;
- } else {
- // element is a name
-
- // check for prefix (group 3)
- if (matcher.group(3) != null) {
- // prefix specified
- // group 4 is namespace prefix excl. delimiter (colon)
- prefix = matcher.group(4);
- // check if the prefix is a valid XML prefix
- if (!XMLChar.isValidNCName(prefix)) {
- // illegal syntax for prefix
- throw new MalformedPathException("'" + jcrPath + "' is not a valid path: '"
- + elem + "' specifies an illegal namespace prefix");
- }
- } else {
- // no prefix specified
- prefix = "";
- }
-
- // group 5 is localName
- localName = matcher.group(5);
-
- // check for index (group 6)
- if (matcher.group(6) != null) {
- // index specified
- // group 7 is index excl. brackets
- index = Integer.parseInt(matcher.group(7));
- } else {
- // no index specified
- index = 0;
- }
-
- String nsURI;
- try {
- nsURI = resolver.getURI(prefix);
- } catch (NamespaceException nse) {
- // unknown prefix
- throw new MalformedPathException("'" + jcrPath + "' is not a valid path: '"
- + elem + "' specifies an unmapped namespace prefix");
- }
-
- PathElement element;
- if (index == 0) {
- element = new PathElement(nsURI, localName);
- } else {
- element = new PathElement(nsURI, localName, index);
- }
- list.add(element);
- leadingParent = false;
- }
- } else {
- // illegal syntax for path element
- throw new MalformedPathException("'" + jcrPath + "' is not a valid path: '"
- + elem + "' is not a legal path element");
- }
- }
- if (resolver != null) {
- return new Path((PathElement[]) list.toArray(new PathElement[list.size()]),
- isNormalized);
- } else {
- return null;
- }
+ return PathFormat.parse(master, jcrPath, resolver);
}
//------------------------------------------------------< utility methods >
@@ -472,9 +342,10 @@
* @param jcrPath the path to be checked
* @throws MalformedPathException If jcrPath is not a valid
* JCR-style path.
+ * @deprecated Use {@link PathFormat#checkFormat(String)} instead.
*/
public static void checkFormat(String jcrPath) throws MalformedPathException {
- parse(jcrPath, null, null);
+ PathFormat.checkFormat(jcrPath);
}
//-------------------------------------------------------< public methods >
@@ -622,28 +493,28 @@
// determine length of common path fragment
int lengthCommon = 0;
- for (int i = 0; i < p0.elements.length && i < p1.elements.length; i++) {
- if (!p0.elements[i].equals(p1.elements[i])) {
+ for (int i = 0; i < p0.getElements().length && i < p1.getElements().length; i++) {
+ if (!p0.getElement(i).equals(p1.getElement(i))) {
break;
}
lengthCommon++;
}
PathBuilder pb = new PathBuilder();
- if (lengthCommon < p0.elements.length) {
+ if (lengthCommon < p0.getElements().length) {
/**
* the common path fragment is an ancestor of this path;
* this has to be accounted for by prepending '..' elements
* to the relative path
*/
- int tmp = p0.elements.length - lengthCommon;
+ int tmp = p0.getElements().length - lengthCommon;
while (tmp-- > 0) {
pb.addFirst(PARENT_ELEMENT);
}
}
// add remainder of other path
- for (int i = lengthCommon; i < p1.elements.length; i++) {
- pb.addLast(p1.elements[i]);
+ for (int i = lengthCommon; i < p1.getElements().length; i++) {
+ pb.addLast(p1.getElement(i));
}
// we're done
return pb.getPath();
@@ -739,7 +610,7 @@
* @see #getAncestorCount()
*/
public int getDepth() {
- int depth = 0;
+ int depth = ROOT_DEPTH;
for (int i = 0; i < elements.length; i++) {
if (elements[i].denotesParent()) {
depth--;
@@ -780,8 +651,8 @@
if (p0.getDepth() >= p1.getDepth()) {
return false;
}
- for (int i = 0; i < p0.elements.length; i++) {
- if (!p0.elements[i].equals(p1.elements[i])) {
+ for (int i = 0; i < p0.getElements().length; i++) {
+ if (!p0.getElement(i).equals(p1.getElement(i))) {
return false;
}
}
@@ -825,31 +696,31 @@
}
/**
+ * Returns the ith element of this path.
+ *
+ * @param i element index.
+ * @return the ith element of this path.
+ * @throws ArrayIndexOutOfBoundsException if this path does not have an
+ * element at index i.
+ */
+ public PathElement getElement(int i) {
+ return elements[i];
+ }
+
+ /**
* Returns a string representation of this Path in the
* JCR path format.
*
* @param resolver namespace resolver
* @return JCR path
* @throws NoPrefixDeclaredException if a namespace can not be resolved
+ * @deprecated Use {@link PathFormat#format(Path, NamespaceResolver} instead.
*/
- public String toJCRPath(NamespaceResolver resolver)
- throws NoPrefixDeclaredException {
- if (denotesRoot()) {
- // shortcut
- return "/";
- }
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < elements.length; i++) {
- if (i > 0) {
- sb.append('/');
- }
- PathElement element = elements[i];
- // name
- element.toJCRName(resolver, sb);
- }
- return sb.toString();
+ public String toJCRPath(NamespaceResolver resolver) throws NoPrefixDeclaredException {
+ return PathFormat.format(this, resolver);
}
+ //---------------------------------------------------------------< Object >
/**
* Returns the internal string representation of this Path.
*
@@ -944,7 +815,7 @@
}
if (obj instanceof Path) {
Path other = (Path) obj;
- return Arrays.equals(elements, other.elements);
+ return Arrays.equals(elements, other.getElements());
}
return false;
}
@@ -995,6 +866,17 @@
}
/**
+ * Creates a new PathBuilder and initialized it with elements of the
+ * given path.
+ *
+ * @param parent
+ */
+ public PathBuilder(Path parent) {
+ this();
+ addAll(parent.getElements());
+ }
+
+ /**
* Adds the {@link Path#ROOT_ELEMENT}.
*/
public void addRoot() {
@@ -1106,36 +988,49 @@
static final String LITERAL = "*";
private RootElement() {
- super(QName.NS_DEFAULT_URI, "");
+ super(QName.ROOT);
}
- // PathElement override
+ /**
+ * Returns true.
+ * @return true
+ * @see PathElement#denotesRoot()
+ */
public boolean denotesRoot() {
return true;
}
- // PathElement override
+ /**
+ * Returns false.
+ * @return false
+ * @see PathElement#denotesCurrent()
+ */
public boolean denotesCurrent() {
return false;
}
- // PathElement override
+ /**
+ * Returns false.
+ * @return false
+ * @see PathElement#denotesParent()
+ */
public boolean denotesParent() {
return false;
}
- // PathElement override
+ /**
+ * Returns false.
+ * @return false
+ * @see PathElement#denotesName()
+ */
public boolean denotesName() {
return false;
}
- // PathElement override
- public String toJCRName(NamespaceResolver resolver)
- throws NoPrefixDeclaredException {
- return "";
- }
-
- // Object override
+ /**
+ * @return {@link #LITERAL}
+ * @see Object#toString()
+ */
public String toString() {
return LITERAL;
}
@@ -1148,72 +1043,120 @@
super(QName.NS_DEFAULT_URI, LITERAL);
}
- // PathElement override
+ /**
+ * Returns false.
+ * @return false
+ * @see PathElement#denotesRoot()
+ */
public boolean denotesRoot() {
return false;
}
- // PathElement override
+ /**
+ * Returns true.
+ * @return true
+ */
public boolean denotesCurrent() {
return true;
}
- // PathElement override
+ /**
+ * Returns false.
+ * @return false
+ * @see PathElement#denotesParent()
+ */
public boolean denotesParent() {
return false;
}
- // PathElement override
+ /**
+ * Returns false.
+ * @return false
+ * @see PathElement#denotesName()
+ */
public boolean denotesName() {
return false;
}
- // PathElement override
+ /**
+ * Returns the JCR name of this path element.
+ *
+ * @param resolver
+ * @return {@link #LITERAL}
+ */
public String toJCRName(NamespaceResolver resolver)
throws NoPrefixDeclaredException {
return LITERAL;
}
- // Object override
+
+ /**
+ * @return {@link #LITERAL}
+ * @see Object#toString()
+ */
public String toString() {
return LITERAL;
}
}
- public static final class ParentElement extends PathElement {
+ private static final class ParentElement extends PathElement {
static final String LITERAL = "..";
private ParentElement() {
super(QName.NS_DEFAULT_URI, LITERAL);
}
- // PathElement override
+ /**
+ * Returns false.
+ * @return false
+ * @see PathElement#denotesRoot()
+ */
public boolean denotesRoot() {
return false;
}
- // PathElement override
+ /**
+ * Returns false.
+ * @return false
+ * @see PathElement#denotesCurrent()
+ */
public boolean denotesCurrent() {
return false;
}
- // PathElement override
+ /**
+ * Returns true.
+ * @return true
+ * @see PathElement#denotesParent()
+ */
public boolean denotesParent() {
return true;
}
- // PathElement override
+ /**
+ * Returns false.
+ * @return false
+ * @see PathElement#denotesName()
+ */
public boolean denotesName() {
return false;
}
- // PathElement override
+ /**
+ * Returns the JCR name of this path element.
+ *
+ * @param resolver
+ * @return {@link #LITERAL}
+ */
public String toJCRName(NamespaceResolver resolver)
throws NoPrefixDeclaredException {
return LITERAL;
}
- // Object override
+ /**
+ * @return {@link #LITERAL}
+ * @see Object#toString()
+ */
public String toString() {
return LITERAL;
}
@@ -1273,7 +1216,7 @@
throw new IllegalArgumentException("name must not be null");
}
this.name = name;
- this.index = 0;
+ this.index = INDEX_UNDEFINED;
}
/**
@@ -1287,7 +1230,7 @@
if (name == null) {
throw new IllegalArgumentException("name must not be null");
}
- if (index < 1) {
+ if (index < INDEX_DEFAULT) {
throw new IllegalArgumentException("index is 1-based");
}
this.index = index;
@@ -1314,6 +1257,18 @@
}
/**
+ * Returns the normalized index of this path element, i.e. the index
+ * is always equals or greater that {@link #INDEX_DEFAULT}.
+ */
+ public int getNormalizedIndex() {
+ if (index == INDEX_UNDEFINED) {
+ return INDEX_DEFAULT;
+ } else {
+ return index;
+ }
+ }
+
+ /**
* Returns true if this element denotes the root element,
* otherwise returns false.
*
@@ -1389,7 +1344,7 @@
public void toJCRName(NamespaceResolver resolver, StringBuffer buf)
throws NoPrefixDeclaredException {
// name
- name.toJCRName(resolver, buf);
+ NameFormat.format(name, resolver, buf);
// index
int index = getIndex();
/**
@@ -1411,6 +1366,7 @@
* method to get the prefixed string representation of the path element.
*
* @return string representation of the path element
+ * @see Object#toString()
*/
public String toString() {
StringBuffer sb = new StringBuffer();
@@ -1418,7 +1374,7 @@
sb.append(name.toString());
// index
int index = getIndex();
- if (index > 0) {
+ if (index > INDEX_UNDEFINED) {
sb.append('[');
sb.append(index);
sb.append(']');
Index: src/main/java/org/apache/jackrabbit/name/PathFormat.java
===================================================================
--- src/main/java/org/apache/jackrabbit/name/PathFormat.java (revision 0)
+++ src/main/java/org/apache/jackrabbit/name/PathFormat.java (revision 0)
@@ -0,0 +1,271 @@
+/*
+ * 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.name;
+
+import org.apache.jackrabbit.util.Text;
+import org.apache.xerces.util.XMLChar;
+
+import javax.jcr.NamespaceException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * PathFormat formats a {@link Path} using a
+ * {@link NamespaceResolver}.
+ */
+public class PathFormat {
+
+ /**
+ * Pattern used to validate and parse path elements:
+ *
+ * - group 1 is .
+ *
- group 2 is ..
+ *
- group 3 is namespace prefix incl. delimiter (colon)
+ *
- group 4 is namespace prefix excl. delimiter (colon)
+ *
- group 5 is localName
+ *
- group 6 is index incl. brackets
+ *
- group 7 is index excl. brackets
+ *
+ */
+ private static final Pattern PATH_ELEMENT_PATTERN =
+ Pattern.compile("(\\.)|"
+ + "(\\.\\.)|"
+ + "(([^ /:\\[\\]*'\"|](?:[^/:\\[\\]*'\"|]*[^ /:\\[\\]*'\"|])?):)?"
+ + "([^ /:\\[\\]*'\"|](?:[^/:\\[\\]*'\"|]*[^ /:\\[\\]*'\"|])?)"
+ + "(\\[([1-9]\\d*)\\])?");
+
+ /**
+ * Matcher instance as thread-local.
+ */
+ private static final ThreadLocal PATH_ELEMENT_MATCHER = new ThreadLocal() {
+ protected Object initialValue() {
+ return PATH_ELEMENT_PATTERN.matcher("dummy");
+ }
+ };
+
+ /**
+ * Parses jcrPath into a qualified path using
+ * resolver to convert prefixes into namespace URI's.
+ *
+ * @param jcrPath the jcr path.
+ * @param resolver the namespace resolver.
+ * @return qualified path.
+ * @throws MalformedPathException if jcrPath is malformed.
+ */
+ public static Path parse(String jcrPath, NamespaceResolver resolver)
+ throws MalformedPathException {
+ return parse(null, jcrPath, resolver);
+ }
+
+ /**
+ * Parses the give jcrPath and returns a Path. If
+ * parent is not null, it is prepended to the
+ * returned list. If resolver is null, this method
+ * only checks the format of the string and returns null.
+ *
+ * @param parent the parent path
+ * @param jcrPath the JCR path
+ * @param resolver the namespace resolver to get prefixes for namespace
+ * URI's.
+ * @return the fully qualified Path.
+ * @throws MalformedPathException if jcrPath is malformed.
+ */
+ public static Path parse(Path parent, String jcrPath, NamespaceResolver resolver)
+ throws MalformedPathException {
+ // shortcut
+ if ("/".equals(jcrPath)) {
+ return Path.ROOT;
+ }
+
+ // split path into path elements
+ String[] elems = Text.explode(jcrPath, '/', true);
+ if (elems.length == 0) {
+ throw new MalformedPathException("empty path");
+ }
+
+ Path.PathBuilder pathBuilder;
+ if (parent != null) {
+ // a parent path was specified; the 'jcrPath' argument is assumed
+ // to be a relative path
+ pathBuilder = new Path.PathBuilder(parent);
+ } else {
+ pathBuilder = new Path.PathBuilder();
+ }
+
+ for (int i = 0; i < elems.length; i++) {
+ // validate & parse path element
+ String prefix;
+ String localName;
+ int index;
+
+ String elem = elems[i];
+ if (i == 0 && elem.length() == 0) {
+ // path is absolute, i.e. the first element is the root element
+ if (parent != null) {
+ throw new MalformedPathException("'" + jcrPath + "' is not a relative path");
+ }
+ pathBuilder.addLast(Path.ROOT_ELEMENT);
+ continue;
+ }
+ if (elem.length() == 0 && i == elems.length - 1) {
+ // ignore trailing '/'
+ break;
+ }
+ Matcher matcher = (Matcher) PATH_ELEMENT_MATCHER.get();
+ matcher.reset(elem);
+ if (matcher.matches()) {
+ if (resolver == null) {
+ // check only
+ continue;
+ }
+
+ if (matcher.group(1) != null) {
+ // group 1 is .
+ pathBuilder.addLast(Path.CURRENT_ELEMENT);
+ } else if (matcher.group(2) != null) {
+ // group 2 is ..
+ pathBuilder.addLast(Path.PARENT_ELEMENT);
+ } else {
+ // element is a name
+
+ // check for prefix (group 3)
+ if (matcher.group(3) != null) {
+ // prefix specified
+ // group 4 is namespace prefix excl. delimiter (colon)
+ prefix = matcher.group(4);
+ // check if the prefix is a valid XML prefix
+ if (!XMLChar.isValidNCName(prefix)) {
+ // illegal syntax for prefix
+ throw new MalformedPathException("'" + jcrPath + "' is not a valid path: '"
+ + elem + "' specifies an illegal namespace prefix");
+ }
+ } else {
+ // no prefix specified
+ prefix = "";
+ }
+
+ // group 5 is localName
+ localName = matcher.group(5);
+
+ // check for index (group 6)
+ if (matcher.group(6) != null) {
+ // index specified
+ // group 7 is index excl. brackets
+ index = Integer.parseInt(matcher.group(7));
+ } else {
+ // no index specified
+ index = org.apache.jackrabbit.name.Path.INDEX_UNDEFINED;
+ }
+
+ String nsURI;
+ try {
+ nsURI = resolver.getURI(prefix);
+ } catch (NamespaceException nse) {
+ // unknown prefix
+ throw new MalformedPathException("'" + jcrPath + "' is not a valid path: '"
+ + elem + "' specifies an unmapped namespace prefix");
+ }
+
+ if (index == org.apache.jackrabbit.name.Path.INDEX_UNDEFINED) {
+ pathBuilder.addLast(new QName(nsURI, localName));
+ } else {
+ pathBuilder.addLast(new QName(nsURI, localName), index);
+ }
+ }
+ } else {
+ // illegal syntax for path element
+ throw new MalformedPathException("'" + jcrPath + "' is not a valid path: '"
+ + elem + "' is not a legal path element");
+ }
+ }
+ if (resolver != null) {
+ return pathBuilder.getPath();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Checks if jcrPath is a valid JCR-style absolute or relative
+ * path.
+ *
+ * @param jcrPath the path to be checked
+ * @throws MalformedPathException If jcrPath is not a valid
+ * JCR-style path.
+ */
+ public static void checkFormat(String jcrPath) throws MalformedPathException {
+ parse(null, jcrPath, null);
+ }
+
+ /**
+ * Returns a string representation of the qualified path in the
+ * JCR path format.
+ *
+ * @param path the qualified path to resolve.
+ * @param resolver the namespace resolver.
+ * @return JCR the formatted path.
+ * @throws NoPrefixDeclaredException if a namespace can not be resolved
+ */
+ public static String format(Path path, NamespaceResolver resolver)
+ throws NoPrefixDeclaredException {
+ if (path.denotesRoot()) {
+ // shortcut
+ return "/";
+ }
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < path.getLength(); i++) {
+ if (i > 0) {
+ sb.append('/');
+ }
+ // name
+ format(path.getElement(i), resolver, sb);
+ }
+ return sb.toString();
+ }
+
+ //-----------------------------------------------------------< internal >---
+
+ /**
+ * Appends the JCR name representation of this path element to the given
+ * string buffer.
+ *
+ * @param element the path element to format.
+ * @param resolver namespace resolver
+ * @param buf string buffer where the JCR name representation should be
+ * appended to
+ * @throws NoPrefixDeclaredException if the namespace of the path element
+ * name can not be resolved
+ */
+ private static void format(Path.PathElement element, NamespaceResolver resolver, StringBuffer buf)
+ throws NoPrefixDeclaredException {
+ // name
+ buf.append(resolver.getJCRName(element.getName()));
+ // index
+ int index = element.getIndex();
+ /**
+ * FIXME the [1] subscript should only be suppressed if the item
+ * in question can't have same-name siblings.
+ */
+ //if (index > 0) {
+ if (index > org.apache.jackrabbit.name.Path.INDEX_DEFAULT) {
+ buf.append('[');
+ buf.append(index);
+ buf.append(']');
+ }
+ }
+
+}
Property changes on: src\main\java\org\apache\jackrabbit\name\PathFormat.java
___________________________________________________________________
Name: svn:keywords
+ author date id revision url
Name: svn:eol-style
+ native
Index: src/main/java/org/apache/jackrabbit/name/QName.java
===================================================================
--- src/main/java/org/apache/jackrabbit/name/QName.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/name/QName.java (working copy)
@@ -16,12 +16,7 @@
*/
package org.apache.jackrabbit.name;
-import org.apache.xerces.util.XMLChar;
-
-import javax.jcr.NamespaceException;
import java.io.Serializable;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* Qualified name. A qualified name is a combination of a namespace URI
@@ -107,6 +102,11 @@
//------------------------------------------< general item name constants >
/**
+ * Extra QName for the root node
+ */
+ public static final QName ROOT = new QName(NS_DEFAULT_URI,"");
+
+ /**
* jcr:system
*/
public static final QName JCR_SYSTEM = new QName(NS_JCR_URI, "system");
@@ -503,30 +503,6 @@
public static final QName[] EMPTY_ARRAY = new QName[0];
- /**
- * The reqular expression pattern used to validate and parse
- * qualified names.
- *
- * The pattern contains the following groups:
- *
- * - group 1 is namespace prefix incl. delimiter (colon)
- *
- group 2 is namespace prefix excl. delimiter (colon)
- *
- group 3 is localName
- *
- */
- private static final Pattern NAME_PATTERN = Pattern.compile(
- "(([^ /:\\[\\]*'\"|](?:[^/:\\[\\]*'\"|]*[^ /:\\[\\]*'\"|])?):)?"
- + "([^ /:\\[\\]*'\"|](?:[^/:\\[\\]*'\"|]*[^ /:\\[\\]*'\"|])?)");
-
- /**
- * Matcher instance as thread-local.
- */
- private static final ThreadLocal NAME_MATCHER = new ThreadLocal() {
- protected Object initialValue() {
- return NAME_PATTERN.matcher("dummy");
- }
- };
-
/** The memorized hash code of this qualified name. */
private transient int hash;
@@ -544,10 +520,11 @@
* local part.
*
* Note that the format of the local part is not validated. The format
- * can be checked by calling {@link #checkFormat(String)}.
+ * can be checked by calling {@link NameFormat#checkFormat(String)}.
*
* @param namespaceURI namespace uri
* @param localName local part
+ * @throws IllegalArgumentException if localName is invalid.
*/
public QName(String namespaceURI, String localName) {
if (namespaceURI == null) {
@@ -575,29 +552,11 @@
* @return qualified name
* @throws IllegalNameException if the given name is not a valid JCR name
* @throws UnknownPrefixException if the JCR name prefix does not resolve
+ * @deprecated Use {@link NameFormat#parse(String, NamespaceResolver)} instead
*/
public static QName fromJCRName(String rawName, NamespaceResolver resolver)
throws IllegalNameException, UnknownPrefixException {
- if (resolver == null) {
- throw new NullPointerException("resolver must not be null");
- }
-
- if (rawName == null || rawName.length() == 0) {
- throw new IllegalNameException("empty name");
- }
-
- // parts[0]: prefix
- // parts[1]: localName
- String[] parts = parse(rawName);
-
- String uri;
- try {
- uri = resolver.getURI(parts[0]);
- } catch (NamespaceException nse) {
- throw new UnknownPrefixException(parts[0]);
- }
-
- return new QName(uri, parts[1]);
+ return NameFormat.parse(rawName, resolver);
}
/**
@@ -658,48 +617,10 @@
* the prefix (or empty string), the second the local name.
* @throws IllegalNameException If jcrName is not a valid
* JCR-style name.
+ * @deprecated Use {@link NameFormat#parse(String)} instead.
*/
public static String[] parse(String jcrName) throws IllegalNameException {
- if (jcrName == null || jcrName.length() == 0) {
- throw new IllegalNameException("empty name");
- }
-
- if (".".equals(jcrName) || "..".equals(jcrName)) {
- // illegal syntax for name
- throw new IllegalNameException("'" + jcrName + "' is not a valid name");
- }
-
- String prefix;
- String localName;
-
-
- Matcher matcher = (Matcher) NAME_MATCHER.get();
- matcher.reset(jcrName);
- if (matcher.matches()) {
- // check for prefix (group 1)
- if (matcher.group(1) != null) {
- // prefix specified
- // group 2 is namespace prefix excl. delimiter (colon)
- prefix = matcher.group(2);
- // check if the prefix is a valid XML prefix
- if (!XMLChar.isValidNCName(prefix)) {
- // illegal syntax for prefix
- throw new IllegalNameException("'" + jcrName
- + "' is not a valid name: illegal prefix");
- }
- } else {
- // no prefix specified
- prefix = "";
- }
-
- // group 3 is localName
- localName = matcher.group(3);
- } else {
- // illegal syntax for name
- throw new IllegalNameException("'" + jcrName + "' is not a valid name");
- }
-
- return new String[]{prefix, localName};
+ return NameFormat.parse(jcrName);
}
//-------------------------------------------------------< public methods >
@@ -729,12 +650,12 @@
* @param resolver namespace resolver
* @return prefixed name
* @throws NoPrefixDeclaredException if the namespace can not be resolved
+ * @deprecated Use {@link NameFormat#format(QName, NamespaceResolver)}
+ * instead.
*/
public String toJCRName(NamespaceResolver resolver)
throws NoPrefixDeclaredException {
- StringBuffer sb = new StringBuffer();
- toJCRName(resolver, sb);
- return sb.toString();
+ return NameFormat.format(this, resolver);
}
/**
@@ -747,27 +668,15 @@
* appended to
* @throws NoPrefixDeclaredException if the namespace can not be resolved
* @see #toJCRName(NamespaceResolver)
+ * @deprecated Use {@link NameFormat#format(QName, NamespaceResolver, StringBuffer)}
+ * instead.
*/
public void toJCRName(NamespaceResolver resolver, StringBuffer buf)
throws NoPrefixDeclaredException {
- // prefix
- String prefix;
- try {
- prefix = resolver.getPrefix(namespaceURI);
- } catch (NamespaceException nse) {
- throw new NoPrefixDeclaredException("no prefix declared for URI: "
- + namespaceURI);
- }
- if (prefix.length() == 0) {
- // default prefix (empty string)
- } else {
- buf.append(prefix);
- buf.append(':');
- }
- // name
- buf.append(localName);
+ NameFormat.format(this, resolver, buf);
}
+ //---------------------------------------------------------------< Object >
/**
* Returns the string representation of this QName in the
* following format:
@@ -776,6 +685,7 @@
*
* @return the string representation of this QName.
* @see #valueOf(String)
+ * @see Object#toString()
*/
public String toString() {
// QName is immutable, we can store the string representation
@@ -829,6 +739,7 @@
return h;
}
+ //------------------------------------------------------------< Cloneable >
/**
* Creates a clone of this qualified name.
* Overriden in order to make clone() public.
@@ -842,6 +753,7 @@
return super.clone();
}
+ //-----------------------------------------------------------< Comparable >
/**
* Compares two qualified names.
*
Index: src/main/java/org/apache/jackrabbit/util/PathMap.java
===================================================================
--- src/main/java/org/apache/jackrabbit/util/PathMap.java (revision 0)
+++ src/main/java/org/apache/jackrabbit/util/PathMap.java (revision 0)
@@ -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 exact is false,
+ * 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 null if exact is
+ * true
+ */
+ 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 true 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 nameIndex or null 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 nameIndex.
+ * @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 null
+ */
+ public Element remove(Path.PathElement nameIndex) {
+ return remove(nameIndex, true);
+ }
+
+ /**
+ * Remove a child. If shift is set to true,
+ * 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 null
+ */
+ 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, builder 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 MalformedPathException for simple
+ * path comparisons.
+ * @param path path to compare to
+ * @return true if this child has the path
+ * path, false 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 true if this element has the path given;
+ * otherwise false
+ */
+ 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 true 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 0 for the
+ * root element and n + 1 for some element if the depth of
+ * its parent is n.
+ */
+ 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 null 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);
+ }
+}
Property changes on: src\main\java\org\apache\jackrabbit\util\PathMap.java
___________________________________________________________________
Name: svn:keywords
+ author date id revision url
Name: svn:eol-style
+ native
Index: src/main/java/org/apache/jackrabbit/util/Text.java
===================================================================
--- src/main/java/org/apache/jackrabbit/util/Text.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/util/Text.java (working copy)
@@ -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 qname. If the
* prefix is missing, an empty string is returned. Please note, that this
* method does not validate the name or prefix.
@@ -637,6 +650,19 @@
}
/**
+ * 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);
+ }
+
+ /**
* Returns the nth absolute parent of the path, where n=level.
* Example:
*
Index: src/main/java/org/apache/jackrabbit/value/NameValue.java
===================================================================
--- src/main/java/org/apache/jackrabbit/value/NameValue.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/value/NameValue.java (working copy)
@@ -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());
}
Index: src/main/java/org/apache/jackrabbit/value/PathValue.java
===================================================================
--- src/main/java/org/apache/jackrabbit/value/PathValue.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/value/PathValue.java (working copy)
@@ -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());
}
Index: src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java
===================================================================
--- src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java (working copy)
@@ -21,22 +21,34 @@
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 ValueFactory interface.
+ * This class implements the ValueFactory interface.
*
* @see javax.jcr.Session#getValueFactory()
*/
public class ValueFactoryImpl implements ValueFactory {
+ private static final ValueFactory valueFactory = new ValueFactoryImpl();
+
/**
* Constructs a ValueFactory object.
*/
- public ValueFactoryImpl() {
+ private ValueFactoryImpl() {
}
+ //--------------------------------------------------------------------------
+ /**
+ *
+ * @return
+ */
+ public static ValueFactory getInstance() {
+ return valueFactory;
+ }
+
//---------------------------------------------------------< ValueFactory >
/**
* {@inheritDoc}
@@ -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;
}
}
Index: src/main/java/org/apache/jackrabbit/value/ValueHelper.java
===================================================================
--- src/main/java/org/apache/jackrabbit/value/ValueHelper.java (revision 417443)
+++ src/main/java/org/apache/jackrabbit/value/ValueHelper.java (working copy)
@@ -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,36 +49,105 @@
}
/**
+ * Same as {@link #convert(String, int, ValueFactory)} using
+ * ValueFactoryImpl.
+ *
* @param srcValue
* @param targetType
* @return
* @throws ValueFormatException
* @throws IllegalArgumentException
+ * @deprecated Use {@link #convert(String, int, ValueFactory)} instead.
*/
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
+ */
+ 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
+ * ValueFactoryImpl.
+ *
+ * @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
+ * ValueFactoryImpl.
+ *
* @param srcValues
* @param targetType
* @return
* @throws ValueFormatException
* @throws IllegalArgumentException
+ * @deprecated Use {@link #convert(String[], int, ValueFactory)} instead.
*/
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
+ * ValueFactoryImpl.
+ *
+ * @param srcValues
+ * @param targetType
+ * @return
+ * @throws ValueFormatException
+ * @throws IllegalArgumentException
+ */
+ 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;
}
@@ -89,7 +159,45 @@
* @throws ValueFormatException
* @throws IllegalArgumentException
*/
+ 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
+ * ValueFactoryImpl.
+ *
+ * @param srcValues
+ * @param targetType
+ * @return
+ * @throws ValueFormatException
+ * @throws IllegalArgumentException
+ * @deprecated Use {@link #convert(Value[], int, ValueFactory)} instead.
+ */
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
+ */
+ public static Value[] convert(Value[] srcValues, int targetType,
+ ValueFactory factory)
throws ValueFormatException, IllegalArgumentException {
if (srcValues == null) {
return null;
@@ -111,20 +219,39 @@
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
+ * ValueFactoryImpl.
+ *
* @param srcValue
* @param targetType
* @return
* @throws ValueFormatException
* @throws IllegalStateException
* @throws IllegalArgumentException
+ * @deprecated Use {@link #convert(Value, int, ValueFactory)} instead.
*/
public static Value convert(Value srcValue, int targetType)
+ throws ValueFormatException, IllegalStateException,
+ IllegalArgumentException {
+ return convert(srcValue, targetType, ValueFactoryImpl.getInstance());
+ }
+
+ /**
+ * @param srcValue
+ * @param targetType
+ * @param factory
+ * @return
+ * @throws ValueFormatException
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ */
+ public static Value convert(Value srcValue, int targetType, ValueFactory factory)
throws ValueFormatException, IllegalStateException,
IllegalArgumentException {
if (srcValue == null) {
@@ -143,7 +270,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 "
@@ -154,7 +281,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 "
@@ -165,7 +292,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 "
@@ -176,7 +303,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 "
@@ -187,7 +314,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 "
@@ -198,7 +325,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 "
@@ -227,7 +354,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:
@@ -265,7 +392,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:
@@ -299,10 +426,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:
@@ -328,11 +454,26 @@
}
/**
+ * Same as {@link #copy(Value, ValueFactory)} using ValueFactoryImpl.
+ *
* @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;
}
@@ -341,39 +482,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) {
@@ -383,18 +518,32 @@
}
/**
+ * Same as {@link #copy(Value[], ValueFactory)} using ValueFactoryImpl.
+ *
* @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;
}
@@ -470,6 +619,8 @@
/**
* Deserializes the given string to a Value of the given type.
+ * Same as {@link #deserialize(String, int, boolean, ValueFactory)} using
+ * ValueFactoryImpl.
*
* @param value string to be deserialized
* @param type type of value
@@ -481,10 +632,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 Value of the given type.
+ *
+ * @param value string to be deserialized
+ * @param type type of value
+ * @param decodeBlanks if true "_x0020_"
+ * character sequences will be decoded to single space
+ * characters each.
+ * @param factory ValueFactory used to build the Value object.
+ * @return the deserialized Value
+ * @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
@@ -498,19 +672,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
- * Value of the given type.
+ * Value of the given type. Same as
+ * {@link #deserialize(Reader, int, boolean, ValueFactory)} using
+ * ValueFactoryImpl.
*
* @param reader reader for the string data to be deserialized
* @param type type of value
@@ -524,10 +703,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
+ * Value of the given type.
+ *
+ * @param reader reader for the string data to be deserialized
+ * @param type type of value
+ * @param decodeBlanks if true "_x0020_"
+ * character sequences will be decoded to single space
+ * characters each.
+ * @param factory ValueFactory used to build the Value object.
+ * @return the deserialized Value
+ * @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
@@ -546,8 +751,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();
@@ -574,7 +779,7 @@
// decode encoded blanks in value
value = Text.replace(value, "_x0020_", " ");
}
- return convert(value, type);
+ return convert(value, type, factory);
}
}
}
Index: src/test/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefTest.java
===================================================================
--- src/test/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefTest.java (revision 417443)
+++ src/test/java/org/apache/jackrabbit/core/nodetype/compact/CompactNodeTypeDefTest.java (working copy)
@@ -27,8 +27,10 @@
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.name.QName;
import org.apache.jackrabbit.util.name.NamespaceMapping;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
import javax.jcr.PropertyType;
+import javax.jcr.ValueFactory;
import javax.jcr.version.OnParentVersionAction;
import java.io.FileReader;
import java.io.StringReader;
@@ -55,6 +57,8 @@
private static final QName REQUIRED_NODE_TYPE_2 = new QName(NS_URI, "RequiredNodeType2");
private static final QName[] REQUIRED_NODE_TYPES = new QName[]{REQUIRED_NODE_TYPE_1, REQUIRED_NODE_TYPE_2};
+ private static final ValueFactory VALUE_FACTORY = ValueFactoryImpl.getInstance();
+
private NodeTypeDef modelNodeTypeDef;
protected void setUp() throws Exception {
@@ -102,7 +106,7 @@
public void testCompactNodeTypeDef() throws Exception {
// Read in node type def from test file
- CompactNodeTypeDefReader cndReader = new CompactNodeTypeDefReader(new FileReader(TEST_FILE), TEST_FILE);
+ CompactNodeTypeDefReader cndReader = new CompactNodeTypeDefReader(new FileReader(TEST_FILE), TEST_FILE, VALUE_FACTORY);
List ntdList = cndReader.getNodeTypeDefs();
NamespaceMapping nsm = cndReader.getNamespaceMapping();
NodeTypeDef ntd = (NodeTypeDef)ntdList.get(0);
@@ -118,7 +122,7 @@
CompactNodeTypeDefWriter.write(ntdList, nsm, sw);
// Rerun the reader on the product of the writer
- cndReader = new CompactNodeTypeDefReader(new StringReader(sw.toString()), TEST_FILE);
+ cndReader = new CompactNodeTypeDefReader(new StringReader(sw.toString()), TEST_FILE, VALUE_FACTORY);
ntdList = cndReader.getNodeTypeDefs();
ntd = (NodeTypeDef)ntdList.get(0);
Index: src/test/java/org/apache/jackrabbit/core/nodetype/converter/SchemaConverterTest.java
===================================================================
--- src/test/java/org/apache/jackrabbit/core/nodetype/converter/SchemaConverterTest.java (revision 417443)
+++ src/test/java/org/apache/jackrabbit/core/nodetype/converter/SchemaConverterTest.java (working copy)
@@ -22,6 +22,7 @@
import org.apache.jackrabbit.util.name.NamespaceExtractor;
import org.apache.jackrabbit.core.nodetype.NodeTypeDef;
import org.apache.jackrabbit.name.NamespaceResolver;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -57,7 +58,7 @@
SchemaConverter nts = new SchemaConverter(TEST_INPUT_FILE);
List testList = nts.getNodeTypeDefs();
- CompactNodeTypeDefReader ntr = new CompactNodeTypeDefReader(new FileReader(MODEL_RESULT_FILE), MODEL_RESULT_FILE, nsm);
+ CompactNodeTypeDefReader ntr = new CompactNodeTypeDefReader(new FileReader(MODEL_RESULT_FILE), MODEL_RESULT_FILE, nsm, ValueFactoryImpl.getInstance());
List modelList = ntr.getNodeTypeDefs();
TreeMap orderedTestList = new TreeMap();
Index: src/test/java/org/apache/jackrabbit/core/nodetype/xml/TestAll.java
===================================================================
--- src/test/java/org/apache/jackrabbit/core/nodetype/xml/TestAll.java (revision 417443)
+++ src/test/java/org/apache/jackrabbit/core/nodetype/xml/TestAll.java (working copy)
@@ -28,6 +28,7 @@
import org.apache.jackrabbit.core.value.InternalValue;
import org.apache.jackrabbit.name.NamespaceResolver;
import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
import javax.jcr.NamespaceException;
import javax.jcr.NamespaceRegistry;
@@ -76,7 +77,7 @@
InputStream xml =
getClass().getClassLoader().getResourceAsStream(TEST_NODETYPES);
- types = NodeTypeReader.read(xml);
+ types = NodeTypeReader.read(xml, ValueFactoryImpl.getInstance());
registry = new SimpleNamespaceRegistry();
registry.registerNamespace("test", TEST_NAMESPACE);
@@ -569,7 +570,7 @@
NodeTypeWriter.write(xml, types, registry);
byte[] bytes = xml.toByteArray();
NodeTypeDef[] output =
- NodeTypeReader.read(new ByteArrayInputStream(bytes));
+ NodeTypeReader.read(new ByteArrayInputStream(bytes), ValueFactoryImpl.getInstance());
assertTrue("write output", Arrays.equals(types, output));
} catch (InvalidNodeTypeDefException e) {
fail(e.getMessage());
Index: src/test/java/org/apache/jackrabbit/name/PathTest.java
===================================================================
--- src/test/java/org/apache/jackrabbit/name/PathTest.java (revision 417443)
+++ src/test/java/org/apache/jackrabbit/name/PathTest.java (working copy)
@@ -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;