You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by an...@apache.org on 2006/07/10 09:08:39 UTC
svn commit: r420449 [1/2] - in /jackrabbit/trunk/jackrabbit/src:
main/java/org/apache/jackrabbit/core/
main/java/org/apache/jackrabbit/core/lock/
main/java/org/apache/jackrabbit/core/state/
main/java/org/apache/jackrabbit/core/xml/ main/java/org/apache...
Author: angela
Date: Mon Jul 10 00:08:37 2006
New Revision: 420449
URL: http://svn.apache.org/viewvc?rev=420449&view=rev
Log:
JCR-473: Some enhancements to jackrabbit commons
Added:
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java (with props)
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/PathFormat.java (with props)
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/PathMap.java (with props)
Removed:
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/PathMap.java
Modified:
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/CachingNamespaceResolver.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/NodeReferences.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/NamespaceContext.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/AbstractNamespaceResolver.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NamespaceListener.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NamespaceResolver.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/Path.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/QName.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/util/Text.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/NameValue.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/PathValue.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueFactoryImpl.java
jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/value/ValueHelper.java
jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/name/PathTest.java
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java Mon Jul 10 00:08:37 2006
@@ -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;
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/CachingNamespaceResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/CachingNamespaceResolver.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/CachingNamespaceResolver.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/CachingNamespaceResolver.java Mon Jul 10 00:08:37 2006
@@ -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 <code>CachingNamespaceResolver</code>.
*/
public void dispose() {
@@ -126,6 +147,15 @@
* Invalidates all cached mappings.
*/
public void namespaceRemapped(String oldPrefix, String newPrefix, String uri) {
+ qnameToJCRName.clear();
+ jcrNameToQName.clear();
+ }
+
+ /**
+ * @inheritDoc
+ * Invalidates all cached mappings.
+ */
+ public void namespaceRemoved(String uri) {
qnameToJCRName.clear();
jcrNameToQName.clear();
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/LocalNamespaceMappings.java Mon Jul 10 00:08:37 2006
@@ -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);
+ }
+ }
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/NodeImpl.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/NodeImpl.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/NodeImpl.java Mon Jul 10 00:08:37 2006
@@ -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);
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/SessionImpl.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/SessionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/SessionImpl.java Mon Jul 10 00:08:37 2006
@@ -1244,7 +1244,7 @@
public ValueFactory getValueFactory()
throws UnsupportedRepositoryOperationException, RepositoryException {
if (valueFactory == null) {
- valueFactory = new ValueFactoryImpl();
+ valueFactory = ValueFactoryImpl.getInstance();
}
return valueFactory;
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/lock/LockManagerImpl.java Mon Jul 10 00:08:37 2006
@@ -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 {
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/NodeReferences.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/NodeReferences.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/NodeReferences.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/NodeReferences.java Mon Jul 10 00:08:37 2006
@@ -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;
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/NamespaceContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/NamespaceContext.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/NamespaceContext.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/xml/NamespaceContext.java Mon Jul 10 00:08:37 2006
@@ -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
@@ -126,6 +129,14 @@
/** {@inheritDoc} */
public String getJCRName(QName name) throws NoPrefixDeclaredException {
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} */
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/AbstractNamespaceResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/AbstractNamespaceResolver.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/AbstractNamespaceResolver.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/AbstractNamespaceResolver.java Mon Jul 10 00:08:37 2006
@@ -40,16 +40,30 @@
/**
* @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);
}
/**
@@ -162,6 +176,32 @@
}
for (int i = 0; i < currentListeners.length; i++) {
currentListeners[i].namespaceRemapped(oldPrefix, newPrefix, uri);
+ }
+ }
+
+ /**
+ * Notifies the listeners that the namespace with the given <code>uri</code>
+ * 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);
}
}
}
Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java?rev=420449&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java Mon Jul 10 00:08:37 2006
@@ -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.jackrabbit.util.XMLChar;
+
+import javax.jcr.NamespaceException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <code>NameFormat</code> formats a {@link QName} using a
+ * {@link NamespaceResolver}.
+ */
+public class NameFormat {
+
+ /**
+ * The reqular expression pattern used to validate and parse
+ * qualified names.
+ * <p>
+ * The pattern contains the following groups:
+ * <ul>
+ * <li>group 1 is namespace prefix incl. delimiter (colon)
+ * <li>group 2 is namespace prefix excl. delimiter (colon)
+ * <li>group 3 is localName
+ * </ul>
+ */
+ 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");
+ }
+ };
+
+ /**
+ * Parses the <code>jcrName</code> 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 <code>jcrName</code> 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 <code>jcrName</code> 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 <code>jcrName</code> 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 <code>jcrName</code> is a valid JCR-style name.
+ *
+ * @param jcrName the name to be checked
+ * @throws IllegalNameException If <code>jcrName</code> is not a valid
+ * JCR-style name.
+ */
+ public static void checkFormat(String jcrName) throws IllegalNameException {
+ parse(jcrName);
+ }
+
+ /**
+ * Returns a string representation of the qualified <code>name</code> 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 <code>name</code> 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());
+ }
+}
Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NameFormat.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NamespaceListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NamespaceListener.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NamespaceListener.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NamespaceListener.java Mon Jul 10 00:08:37 2006
@@ -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);
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NamespaceResolver.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NamespaceResolver.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NamespaceResolver.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/NamespaceResolver.java Mon Jul 10 00:08:37 2006
@@ -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;
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/Path.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/Path.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/Path.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/Path.java Mon Jul 10 00:08:37 2006
@@ -17,15 +17,11 @@
package org.apache.jackrabbit.name;
import org.apache.jackrabbit.util.Text;
-import org.apache.jackrabbit.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 <code>Path</code> 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,32 +104,19 @@
public static final Path ROOT = new Path(new PathElement[]{ROOT_ELEMENT}, true);
/**
- * Pattern used to validate and parse path elements:<p>
- * <ul>
- * <li>group 1 is .
- * <li>group 2 is ..
- * <li>group 3 is namespace prefix incl. delimiter (colon)
- * <li>group 4 is namespace prefix excl. delimiter (colon)
- * <li>group 5 is localName
- * <li>group 6 is index incl. brackets
- * <li>group 7 is index excl. brackets
- * </ul>
+ * Constant representing an undefined index value
*/
- private static final Pattern PATH_ELEMENT_PATTERN =
- Pattern.compile("(\\.)|"
- + "(\\.\\.)|"
- + "(([^ /:\\[\\]*'\"|](?:[^/:\\[\\]*'\"|]*[^ /:\\[\\]*'\"|])?):)?"
- + "([^ /:\\[\\]*'\"|](?:[^/:\\[\\]*'\"|]*[^ /:\\[\\]*'\"|])?)"
- + "(\\[([1-9]\\d*)\\])?");
+ public static final int INDEX_UNDEFINED = 0;
/**
- * Matcher instance as thread-local.
+ * Constant representing the default (initial) index value.
*/
- private static final ThreadLocal PATH_ELEMENT_MATCHER = new ThreadLocal() {
- protected Object initialValue() {
- return PATH_ELEMENT_PATTERN.matcher("dummy");
- }
- };
+ public static final int INDEX_DEFAULT = 1;
+
+ /**
+ * Constant defining the depth of the root path
+ */
+ public static final int ROOT_DEPTH = 0;
/**
* the elements of this path
@@ -177,6 +160,18 @@
//------------------------------------------------------< factory methods >
/**
+ * @param elements
+ * @return
+ */
+ public static Path create(PathElement[] elements) {
+ // Path constructor uses elements array as is
+ // need to copy here because Path.create() is public
+ PathElement[] tmp = new PathElement[elements.length];
+ System.arraycopy(elements, 0, tmp, 0, elements.length);
+ return new Path(tmp, true);
+ }
+
+ /**
* Creates a new <code>Path</code> from the given <code>jcrPath</code>
* string. If <code>normalize</code> is <code>true</code>, 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 <code>relPath</code> 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 <code>Path</code> out of the given <code>parent<code> path
- * and the give name and index. If <code>normalize</code> is
- * <code>true</code>, 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 <code>jcrPath</code> 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 <code>i</code><sup>th</sup> element of this path.
+ *
+ * @param i element index.
+ * @return the <code>i</code><sup>th</sup> element of this path.
+ * @throws ArrayIndexOutOfBoundsException if this path does not have an
+ * element at index <code>i</code>.
+ */
+ public PathElement getElement(int i) {
+ return elements[i];
+ }
+
+ /**
* Returns a string representation of this <code>Path</code> 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 <code>Path</code>.
* <p/>
@@ -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 <code>true</code> if this element denotes the <i>root</i> element,
* otherwise returns <code>false</code>.
*
@@ -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(']');
Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/PathFormat.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/PathFormat.java?rev=420449&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/PathFormat.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/PathFormat.java Mon Jul 10 00:08:37 2006
@@ -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.jackrabbit.util.XMLChar;
+
+import javax.jcr.NamespaceException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <code>PathFormat</code> formats a {@link Path} using a
+ * {@link NamespaceResolver}.
+ */
+public class PathFormat {
+
+ /**
+ * Pattern used to validate and parse path elements:<p>
+ * <ul>
+ * <li>group 1 is .
+ * <li>group 2 is ..
+ * <li>group 3 is namespace prefix incl. delimiter (colon)
+ * <li>group 4 is namespace prefix excl. delimiter (colon)
+ * <li>group 5 is localName
+ * <li>group 6 is index incl. brackets
+ * <li>group 7 is index excl. brackets
+ * </ul>
+ */
+ 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 <code>jcrPath</code> into a qualified path using
+ * <code>resolver</code> to convert prefixes into namespace URI's.
+ *
+ * @param jcrPath the jcr path.
+ * @param resolver the namespace resolver.
+ * @return qualified path.
+ * @throws MalformedPathException if <code>jcrPath</code> is malformed.
+ */
+ public static Path parse(String jcrPath, NamespaceResolver resolver)
+ throws MalformedPathException {
+ return parse(null, jcrPath, resolver);
+ }
+
+ /**
+ * Parses the give <code>jcrPath</code> and returns a <code>Path</code>. If
+ * <code>parent</code> is not <code>null</code>, it is prepended to the
+ * returned list. If <code>resolver</code> is <code>null</code>, this method
+ * only checks the format of the string and returns <code>null</code>.
+ *
+ * @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 <code>jcrPath</code> 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 <code>jcrPath</code> is a valid JCR-style absolute or relative
+ * path.
+ *
+ * @param jcrPath the path to be checked
+ * @throws MalformedPathException If <code>jcrPath</code> 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 <code>path</code> 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(']');
+ }
+ }
+
+}
Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/PathFormat.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/PathFormat.java
------------------------------------------------------------------------------
svn:keywords = author date id revision url
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/QName.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/QName.java?rev=420449&r1=420448&r2=420449&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/QName.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/name/QName.java Mon Jul 10 00:08:37 2006
@@ -16,13 +16,7 @@
*/
package org.apache.jackrabbit.name;
-import javax.jcr.NamespaceException;
-
-import org.apache.jackrabbit.util.XMLChar;
-
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
@@ -108,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");
@@ -504,30 +503,6 @@
public static final QName[] EMPTY_ARRAY = new QName[0];
- /**
- * The reqular expression pattern used to validate and parse
- * qualified names.
- * <p>
- * The pattern contains the following groups:
- * <ul>
- * <li>group 1 is namespace prefix incl. delimiter (colon)
- * <li>group 2 is namespace prefix excl. delimiter (colon)
- * <li>group 3 is localName
- * </ul>
- */
- 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;
@@ -545,10 +520,11 @@
* local part.
* <p/>
* 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 <code>localName</code> is invalid.
*/
public QName(String namespaceURI, String localName) {
if (namespaceURI == null) {
@@ -576,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);
}
/**
@@ -659,48 +617,10 @@
* the prefix (or empty string), the second the local name.
* @throws IllegalNameException If <code>jcrName</code> 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 >
@@ -730,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);
}
/**
@@ -748,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 <code>QName</code> in the
* following format:
@@ -777,6 +685,7 @@
*
* @return the string representation of this <code>QName</code>.
* @see #valueOf(String)
+ * @see Object#toString()
*/
public String toString() {
// QName is immutable, we can store the string representation
@@ -830,6 +739,7 @@
return h;
}
+ //------------------------------------------------------------< Cloneable >
/**
* Creates a clone of this qualified name.
* Overriden in order to make <code>clone()</code> public.
@@ -843,6 +753,7 @@
return super.clone();
}
+ //-----------------------------------------------------------< Comparable >
/**
* Compares two qualified names.
*