You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by al...@apache.org on 2013/10/10 14:00:40 UTC
svn commit: r1530931 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/plugins/name/
main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/
test/java/org/apache/jackrabbit/oak/plugins/name/
Author: alexparvulescu
Date: Thu Oct 10 12:00:39 2013
New Revision: 1530931
URL: http://svn.apache.org/r1530931
Log:
OAK-924 Optimize namespace lookups
- initial patch in, still WIP
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidator.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorProvider.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceConstants.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceValidator.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceValidatorProvider.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/Namespaces.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistry.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/InitialContent.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistryTest.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidator.java?rev=1530931&r1=1530930&r2=1530931&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidator.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidator.java Thu Oct 10 12:00:39 2013
@@ -20,6 +20,7 @@ import java.util.Set;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
import org.apache.jackrabbit.oak.spi.commit.DefaultValidator;
import org.apache.jackrabbit.oak.spi.commit.Validator;
import org.apache.jackrabbit.oak.spi.state.NodeState;
@@ -34,7 +35,11 @@ class NameValidator extends DefaultValid
private final Set<String> prefixes;
- public NameValidator(Set<String> prefixes) {
+ public NameValidator(NodeState root) {
+ this.prefixes = Namespaces.getNamespacePrefixesAsSet(new ImmutableTree(root));
+ }
+
+ NameValidator(Set<String> prefixes) {
this.prefixes = prefixes;
}
@@ -44,7 +49,7 @@ class NameValidator extends DefaultValid
String prefix = name.substring(0, colon);
if (prefix.isEmpty() || !prefixes.contains(prefix)) {
throw new CommitFailedException(
- CommitFailedException.NAME, 1, "Invalid namespace prefix: " + name);
+ CommitFailedException.NAME, 1, "Invalid namespace prefix("+prefixes+"): " + prefix);
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorProvider.java?rev=1530931&r1=1530930&r2=1530931&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NameValidatorProvider.java Thu Oct 10 12:00:39 2013
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.plugin
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
-import org.apache.jackrabbit.oak.core.ImmutableTree;
import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
import org.apache.jackrabbit.oak.spi.commit.Validator;
import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
@@ -35,8 +34,7 @@ public class NameValidatorProvider exten
@Override
public Validator getRootValidator(NodeState before, NodeState after) {
- return new NameValidator(
- Namespaces.getNamespaceMap(new ImmutableTree(after)).keySet());
+ return new NameValidator(after);
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceConstants.java?rev=1530931&r1=1530930&r2=1530931&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceConstants.java Thu Oct 10 12:00:39 2013
@@ -68,4 +68,15 @@ public interface NamespaceConstants {
NAMESPACE_REP,
NAMESPACE_SV
));
-}
\ No newline at end of file
+
+ String EMPTY_KEY = "oak:empty";
+
+ // index nodes for faster lookup
+
+ String NSDATA = "oak:namespaces";
+
+ String NSDATA_URIS = "oak:uris";
+
+ String NSDATA_PREFIXES = "oak:prefixes";
+
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceValidator.java?rev=1530931&r1=1530930&r2=1530931&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceValidator.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceValidator.java Thu Oct 10 12:00:39 2013
@@ -16,40 +16,70 @@
*/
package org.apache.jackrabbit.oak.plugins.name;
+import static javax.jcr.NamespaceRegistry.PREFIX_JCR;
+import static javax.jcr.NamespaceRegistry.PREFIX_MIX;
+import static javax.jcr.NamespaceRegistry.PREFIX_NT;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.plugins.name.NamespaceConstants.NSDATA;
+import static org.apache.jackrabbit.oak.plugins.name.NamespaceConstants.NSDATA_PREFIXES;
+import static org.apache.jackrabbit.oak.plugins.name.NamespaceConstants.NSDATA_URIS;
+import static org.apache.jackrabbit.oak.plugins.name.NamespaceConstants.REP_NAMESPACES;
+import static org.apache.jackrabbit.oak.plugins.name.Namespaces.encodeUri;
+import static org.apache.jackrabbit.oak.plugins.name.Namespaces.escapePropertyKey;
+import static org.apache.jackrabbit.oak.plugins.name.Namespaces.isValidPrefix;
+import static org.apache.jackrabbit.oak.plugins.name.Namespaces.safeGet;
+import static org.apache.jackrabbit.oak.plugins.name.Namespaces.unescapePropertyKey;
+
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.spi.commit.DefaultValidator;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.core.ImmutableTree;
+import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
-import static org.apache.jackrabbit.oak.api.Type.STRING;
+import com.google.common.collect.ImmutableSet;
/**
* TODO document
*/
-class NamespaceValidator extends DefaultValidator {
+class NamespaceValidator extends DefaultEditor {
- private final Map<String, String> map;
+ private final NodeBuilder builder;
- public NamespaceValidator(Map<String, String> map) {
- this.map = map;
+ private boolean modified = false;
+
+ private final NodeState namespaces;
+
+ public NamespaceValidator(NodeState root, NodeBuilder builder) {
+ this.namespaces = root.getChildNode(JCR_SYSTEM).getChildNode(
+ REP_NAMESPACES);
+ this.builder = builder;
}
- //----------------------------------------------------------< Validator >---
@Override
- public void propertyAdded(PropertyState after)
- throws CommitFailedException {
+ public void propertyAdded(PropertyState after) throws CommitFailedException {
String prefix = after.getName();
// ignore jcr:primaryType
- if (prefix.equals("jcr:primaryType")) {
+ if (JCR_PRIMARYTYPE.equals(prefix)) {
return;
}
- if (map.containsKey(prefix)) {
- throw new CommitFailedException(
- CommitFailedException.NAMESPACE, 1,
+
+ if (namespaces.hasProperty(prefix)) {
+ throw new CommitFailedException(CommitFailedException.NAMESPACE, 1,
"Namespace mapping already registered: " + prefix);
- } else if (Namespaces.isValidPrefix(prefix)) {
+ } else if (isValidPrefix(prefix)) {
if (after.isArray() || !STRING.equals(after.getType())) {
throw new CommitFailedException(
CommitFailedException.NAMESPACE, 2,
@@ -58,36 +88,90 @@ class NamespaceValidator extends Default
throw new CommitFailedException(
CommitFailedException.NAMESPACE, 3,
"XML prefixes are reserved: " + prefix);
- } else if (map.containsValue(after.getValue(STRING))) {
+ } else if (containsValue(namespaces, after.getValue(STRING))) {
throw modificationNotAllowed(prefix);
}
} else {
- throw new CommitFailedException(
- CommitFailedException.NAMESPACE, 4,
+ throw new CommitFailedException(CommitFailedException.NAMESPACE, 4,
"Not a valid namespace prefix: " + prefix);
}
+ modified = true;
+ }
+
+ private static boolean containsValue(NodeState namespaces, String value) {
+ return safeGet(new ImmutableTree(namespaces.getChildNode(NSDATA)),
+ NSDATA_URIS).contains(value);
}
@Override
public void propertyChanged(PropertyState before, PropertyState after)
throws CommitFailedException {
- if (map.containsKey(after.getName())) {
- throw modificationNotAllowed(after.getName());
- }
+ // TODO allow changes if there is no content referencing the mappings
+ throw modificationNotAllowed(after.getName());
}
@Override
public void propertyDeleted(PropertyState before)
throws CommitFailedException {
- if (map.containsKey(before.getName())) {
- // TODO: Check whether this namespace is still used in content
+
+ // FIXME Desired Behavior: if we enable it, there are a few generic
+ // #unregister tests that fail
+ // TODO allow changes if there is no content referencing the mappings
+ // throw modificationNotAllowed(before.getName());
+
+ // FIXME Best effort backwards compatible:
+ if (jcrSystemNS.contains(before.getName())) {
+ throw modificationNotAllowed(before.getName());
}
+ modified = true;
}
+ private static Set<String> jcrSystemNS = ImmutableSet.of(PREFIX_JCR,
+ PREFIX_NT, PREFIX_MIX, NamespaceConstants.PREFIX_SV);
+
private static CommitFailedException modificationNotAllowed(String prefix) {
- return new CommitFailedException(
- CommitFailedException.NAMESPACE, 5,
+ return new CommitFailedException(CommitFailedException.NAMESPACE, 5,
"Namespace modification not allowed: " + prefix);
}
+ @Override
+ public void leave(NodeState before, NodeState after)
+ throws CommitFailedException {
+ if (!modified) {
+ return;
+ }
+
+ Set<String> prefixes = new HashSet<String>();
+ Set<String> uris = new HashSet<String>();
+ Map<String, String> reverse = new HashMap<String, String>();
+
+ NodeBuilder namespaces = builder.child(JCR_SYSTEM)
+ .child(REP_NAMESPACES);
+ for (PropertyState property : namespaces.getProperties()) {
+ String prefix = unescapePropertyKey(property.getName());
+ if (STRING.equals(property.getType()) && isValidPrefix(prefix)) {
+ prefixes.add(prefix);
+ String uri = property.getValue(STRING);
+ uris.add(uri);
+ reverse.put(escapePropertyKey(uri), prefix);
+ }
+ }
+
+ NodeBuilder data = namespaces.setChildNode(NSDATA);
+ data.setProperty(NSDATA_PREFIXES, prefixes, Type.STRINGS);
+ data.setProperty(NSDATA_URIS, uris, Type.STRINGS);
+ for (Entry<String, String> e : reverse.entrySet()) {
+ data.setProperty(encodeUri(e.getKey()), e.getValue());
+ }
+ }
+
+ @Override
+ public Editor childNodeChanged(String name, NodeState before,
+ NodeState after) throws CommitFailedException {
+ if (NSDATA.equals(name) && !before.equals(after)) {
+ throw modificationNotAllowed(name);
+ }
+ return null;
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceValidatorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceValidatorProvider.java?rev=1530931&r1=1530930&r2=1530931&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceValidatorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/NamespaceValidatorProvider.java Thu Oct 10 12:00:39 2013
@@ -21,11 +21,11 @@ import static org.apache.jackrabbit.oak.
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
-import org.apache.jackrabbit.oak.core.ImmutableTree;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
-import org.apache.jackrabbit.oak.spi.commit.SubtreeValidator;
-import org.apache.jackrabbit.oak.spi.commit.Validator;
-import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
+import org.apache.jackrabbit.oak.spi.commit.SubtreeEditor;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
/**
@@ -35,13 +35,12 @@ import org.apache.jackrabbit.oak.spi.sta
*/
@Component
@Service(EditorProvider.class)
-public class NamespaceValidatorProvider extends ValidatorProvider {
+public class NamespaceValidatorProvider implements EditorProvider {
@Override
- public Validator getRootValidator(NodeState before, NodeState after) {
- Validator validator = new NamespaceValidator(
- Namespaces.getNamespaceMap(new ImmutableTree(before)));
- return new SubtreeValidator(validator, JCR_SYSTEM, REP_NAMESPACES);
+ public Editor getRootEditor(NodeState before, NodeState after,
+ NodeBuilder builder) throws CommitFailedException {
+ return new SubtreeEditor(new NamespaceValidator(before, builder), JCR_SYSTEM, REP_NAMESPACES);
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/Namespaces.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/Namespaces.java?rev=1530931&r1=1530930&r2=1530931&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/Namespaces.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/Namespaces.java Thu Oct 10 12:00:39 2013
@@ -16,16 +16,34 @@
*/
package org.apache.jackrabbit.oak.plugins.name;
+import static javax.jcr.NamespaceRegistry.NAMESPACE_EMPTY;
+import static javax.jcr.NamespaceRegistry.NAMESPACE_JCR;
+import static javax.jcr.NamespaceRegistry.NAMESPACE_MIX;
+import static javax.jcr.NamespaceRegistry.NAMESPACE_NT;
+import static javax.jcr.NamespaceRegistry.NAMESPACE_XML;
+import static javax.jcr.NamespaceRegistry.PREFIX_EMPTY;
+import static javax.jcr.NamespaceRegistry.PREFIX_JCR;
+import static javax.jcr.NamespaceRegistry.PREFIX_MIX;
+import static javax.jcr.NamespaceRegistry.PREFIX_NT;
+import static javax.jcr.NamespaceRegistry.PREFIX_XML;
import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+import static org.apache.jackrabbit.oak.api.Type.NAME;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
-
-import javax.jcr.NamespaceRegistry;
+import java.util.Set;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.util.Text;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
/**
* Internal static utility class for managing the persisted namespace registry.
@@ -35,40 +53,150 @@ public class Namespaces implements Names
private Namespaces() {
}
- private static final Map<String, String> DEFAULTS = new HashMap<String, String>();
- static {
+ public static void setupNamespaces(NodeBuilder system) {
+ if (system.hasChildNode(REP_NAMESPACES)) {
+ return;
+ }
+
+ NodeBuilder namespaces = system.child(REP_NAMESPACES);
+ namespaces.setProperty(JcrConstants.JCR_PRIMARYTYPE,
+ JcrConstants.NT_UNSTRUCTURED, NAME);
+
// Standard namespace specified by JCR (default one not included)
- DEFAULTS.put(NamespaceRegistry.PREFIX_EMPTY, NamespaceRegistry.NAMESPACE_EMPTY);
- DEFAULTS.put(NamespaceRegistry.PREFIX_JCR, NamespaceRegistry.NAMESPACE_JCR);
- DEFAULTS.put(NamespaceRegistry.PREFIX_NT, NamespaceRegistry.NAMESPACE_NT);
- DEFAULTS.put(NamespaceRegistry.PREFIX_MIX, NamespaceRegistry.NAMESPACE_MIX);
- DEFAULTS.put(NamespaceRegistry.PREFIX_XML, NamespaceRegistry.NAMESPACE_XML);
+ namespaces.setProperty(escapePropertyKey(PREFIX_EMPTY), NAMESPACE_EMPTY);
+ namespaces.setProperty(PREFIX_JCR, NAMESPACE_JCR);
+ namespaces.setProperty(PREFIX_NT, NAMESPACE_NT);
+ namespaces.setProperty(PREFIX_MIX, NAMESPACE_MIX);
+ namespaces.setProperty(PREFIX_XML, NAMESPACE_XML);
// Namespace included in Jackrabbit 2.x
- DEFAULTS.put(PREFIX_SV, NAMESPACE_SV);
- DEFAULTS.put(PREFIX_REP, NAMESPACE_REP);
+ namespaces.setProperty(PREFIX_SV, NAMESPACE_SV);
+ namespaces.setProperty(PREFIX_REP, NAMESPACE_REP);
+
+ // index node for faster lookup
+ NodeBuilder data = namespaces.child(NSDATA);
+ data.setProperty(NSDATA_PREFIXES, ImmutableList.of(PREFIX_EMPTY, PREFIX_JCR, PREFIX_NT, PREFIX_MIX, PREFIX_XML, PREFIX_SV, PREFIX_REP), STRINGS);
+ data.setProperty(NSDATA_URIS, ImmutableList.of(NAMESPACE_EMPTY, NAMESPACE_JCR, NAMESPACE_NT, NAMESPACE_MIX, NAMESPACE_XML, NAMESPACE_SV, NAMESPACE_REP), STRINGS);
+
+ data.setProperty(encodeUri(escapePropertyKey(NAMESPACE_EMPTY)), PREFIX_EMPTY);
+ data.setProperty(encodeUri(NAMESPACE_JCR), PREFIX_JCR);
+ data.setProperty(encodeUri(NAMESPACE_NT), PREFIX_NT);
+ data.setProperty(encodeUri(NAMESPACE_MIX), PREFIX_MIX);
+ data.setProperty(encodeUri(NAMESPACE_XML), PREFIX_XML);
+ data.setProperty(encodeUri(NAMESPACE_SV), PREFIX_SV);
+ data.setProperty(encodeUri(NAMESPACE_REP), PREFIX_REP);
+ }
+
+ private static Tree getNamespaceTree(Tree root) {
+ return root.getChild(JcrConstants.JCR_SYSTEM).getChild(REP_NAMESPACES);
}
public static Map<String, String> getNamespaceMap(Tree root) {
- Map<String, String> map = new HashMap<String, String>(DEFAULTS);
+ Map<String, String> map = new HashMap<String, String>();
- Tree namespaces = root.getChild(JcrConstants.JCR_SYSTEM).getChild(REP_NAMESPACES);
+ Tree namespaces = getNamespaceTree(root);
for (PropertyState property : namespaces.getProperties()) {
String prefix = property.getName();
- if (!property.isArray() && isValidPrefix(prefix)) {
- String value = property.getValue(STRING);
- if (STRING.equals(property.getType())) {
- map.put(prefix, value);
- }
+ if (STRING.equals(property.getType()) && isValidPrefix(prefix)) {
+ map.put(unescapePropertyKey(prefix), property.getValue(STRING));
}
}
return map;
}
+ static String[] getNamespacePrefixes(Tree root) {
+ Set<String> prefSet = getNamespacePrefixesAsSet(root);
+ String[] prefixes = prefSet.toArray(new String[prefSet.size()]);
+ Arrays.sort(prefixes);
+ return prefixes;
+ }
+
+ static Set<String> getNamespacePrefixesAsSet(Tree root) {
+ return safeGet(getNamespaceTree(root).getChild(NSDATA), NSDATA_PREFIXES);
+ }
+
+ static String getNamespacePrefix(Tree root, String uri) {
+ Tree namespaces = getNamespaceTree(root);
+ PropertyState ps = namespaces.getChild(NSDATA)
+ .getProperty(encodeUri(escapePropertyKey(uri)));
+ if (ps != null) {
+ return ps.getValue(STRING);
+ }
+ return null;
+ }
+
+ static String[] getNamespaceURIs(Tree root) {
+ Set<String> uris = safeGet(getNamespaceTree(root).getChild(NSDATA), NSDATA_URIS);
+ return uris.toArray(new String[uris.size()]);
+ }
+
+ static String getNamespaceURI(Tree root, String prefix) {
+ if (isValidPrefix(prefix)) {
+ PropertyState property = getNamespaceTree(root).getProperty(
+ escapePropertyKey(prefix));
+ if (property != null && STRING.equals(property.getType())) {
+ return property.getValue(STRING);
+ }
+ }
+ return null;
+ }
+
+ // utils
+
+ /**
+ * Replaces an empty string with the special {@link #EMPTY_KEY} value.
+ *
+ * @see #unescapePropertyKey(String)
+ * @param key property key
+ * @return escaped property key
+ */
+ static String escapePropertyKey(String key) {
+ if (key.equals("")) {
+ return EMPTY_KEY;
+ } else {
+ return key;
+ }
+ }
+
+ /**
+ * Converts the special {@link #EMPTY_KEY} value back to an empty string.
+ *
+ * @see #escapePropertyKey(String)
+ * @param key property key
+ * @return escaped property key
+ */
+ static String unescapePropertyKey(String key) {
+ if (key.equals(EMPTY_KEY)) {
+ return "";
+ } else {
+ return key;
+ }
+ }
+
+ /**
+ * encodes the uri value to be used as a property
+ *
+ * @param uri
+ * @return encoded uri
+ */
+ static String encodeUri(String uri) {
+ return Text.escapeIllegalJcrChars(uri);
+ }
+
+ static Set<String> safeGet(Tree tree, String name) {
+ PropertyState ps = tree.getProperty(name);
+ if (ps == null) {
+ return Sets.newHashSet();
+ }
+ return Sets.newHashSet(ps.getValue(Type.STRINGS));
+ }
+
+ // validation
+
public static boolean isValidPrefix(String prefix) {
// TODO: Other prefix rules?
- return !prefix.isEmpty() && prefix.indexOf(':') == -1;
+ return prefix.indexOf(':') == -1;
}
public static boolean isValidLocalName(String local) {
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java?rev=1530931&r1=1530930&r2=1530931&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadOnlyNamespaceRegistry.java Thu Oct 10 12:00:39 2013
@@ -16,9 +16,6 @@
*/
package org.apache.jackrabbit.oak.plugins.name;
-import java.util.Arrays;
-import java.util.Map;
-
import javax.annotation.Nonnull;
import javax.jcr.NamespaceException;
import javax.jcr.NamespaceRegistry;
@@ -63,11 +60,7 @@ public abstract class ReadOnlyNamespaceR
@Nonnull
public String[] getPrefixes() throws RepositoryException {
try {
- Tree root = getReadTree();
- Map<String, String> map = Namespaces.getNamespaceMap(root);
- String[] prefixes = map.keySet().toArray(new String[map.size()]);
- Arrays.sort(prefixes);
- return prefixes;
+ return Namespaces.getNamespacePrefixes(getReadTree());
} catch (RuntimeException e) {
throw new RepositoryException(
"Failed to retrieve registered namespace prefixes", e);
@@ -78,10 +71,7 @@ public abstract class ReadOnlyNamespaceR
@Nonnull
public String[] getURIs() throws RepositoryException {
try {
- Tree root = getReadTree();
- Map<String, String> map = Namespaces.getNamespaceMap(root);
- String[] uris = map.values().toArray(new String[map.size()]);
- return uris;
+ return Namespaces.getNamespaceURIs(getReadTree());
} catch (RuntimeException e) {
throw new RepositoryException(
"Failed to retrieve registered namespace URIs", e);
@@ -92,9 +82,7 @@ public abstract class ReadOnlyNamespaceR
@Nonnull
public String getURI(String prefix) throws RepositoryException {
try {
- Tree root = getReadTree();
- Map<String, String> map = Namespaces.getNamespaceMap(root);
- String uri = map.get(prefix);
+ String uri = Namespaces.getNamespaceURI(getReadTree(), prefix);
if (uri == null) {
throw new NamespaceException(
"No namespace registered for prefix " + prefix);
@@ -111,15 +99,12 @@ public abstract class ReadOnlyNamespaceR
@Nonnull
public String getPrefix(String uri) throws RepositoryException {
try {
- Tree root = getReadTree();
- Map<String, String> map = Namespaces.getNamespaceMap(root);
- for (Map.Entry<String, String> entry : map.entrySet()) {
- if (entry.getValue().equals(uri)) {
- return entry.getKey();
- }
- }
- throw new NamespaceException(
+ String prefix = Namespaces.getNamespacePrefix(getReadTree(), uri);
+ if (prefix == null) {
+ throw new NamespaceException(
"No namespace prefix registered for URI " + uri);
+ }
+ return prefix;
} catch (RuntimeException e) {
throw new RepositoryException(
"Failed to retrieve the namespace prefix for URI "
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistry.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistry.java?rev=1530931&r1=1530930&r2=1530931&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistry.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistry.java Thu Oct 10 12:00:39 2013
@@ -16,18 +16,15 @@
*/
package org.apache.jackrabbit.oak.plugins.name;
-import java.util.Map;
+import static org.apache.jackrabbit.oak.plugins.name.Namespaces.getNamespaceURI;
+
import javax.jcr.NamespaceException;
import javax.jcr.RepositoryException;
-import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
-import static org.apache.jackrabbit.oak.api.Type.NAME;
-import static org.apache.jackrabbit.oak.api.Type.STRING;
/**
* Writable namespace registry. Mainly for use to implement the full JCR API.
@@ -56,42 +53,22 @@ public abstract class ReadWriteNamespace
// do nothing
}
- private static Tree getOrCreate(Root root, String... path) {
- Tree tree = root.getTree("/");
- assert tree.exists();
- for (String name : path) {
- Tree child = tree.getChild(name);
- if (!child.exists()) {
- child = tree.addChild(name);
- }
- tree = child;
- }
- return tree;
- }
-
//--------------------------------------------------< NamespaceRegistry >---
@Override
public void registerNamespace(String prefix, String uri)
throws RepositoryException {
- Map<String, String> map = Namespaces.getNamespaceMap(getReadTree());
- if (uri.equals(map.get(prefix))) {
+ if (uri.equals(getNamespaceURI(getReadTree(), prefix))) {
return; // Namespace already registered, so we do nothing
}
-
try {
Root root = getWriteRoot();
- Tree namespaces =
- getOrCreate(root, JcrConstants.JCR_SYSTEM, REP_NAMESPACES);
- if (!namespaces.hasProperty(JcrConstants.JCR_PRIMARYTYPE)) {
- namespaces.setProperty(JcrConstants.JCR_PRIMARYTYPE,
- JcrConstants.NT_UNSTRUCTURED, NAME);
- }
+ Tree namespaces = root.getTree(NAMESPACES_PATH);
+
// remove existing mapping to given uri
- for (PropertyState p : namespaces.getProperties()) {
- if (!p.isArray() && p.getValue(STRING).equals(uri)) {
- namespaces.removeProperty(p.getName());
- }
+ String ns = Namespaces.getNamespacePrefix(namespaces, uri);
+ if (ns != null) {
+ namespaces.removeProperty(ns);
}
namespaces.setProperty(prefix, uri);
root.commit();
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/InitialContent.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/InitialContent.java?rev=1530931&r1=1530930&r2=1530931&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/InitialContent.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/InitialContent.java Thu Oct 10 12:00:39 2013
@@ -28,9 +28,12 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
import org.apache.jackrabbit.oak.plugins.memory.ModifiedNodeState;
+import org.apache.jackrabbit.oak.plugins.name.NamespaceValidatorProvider;
+import org.apache.jackrabbit.oak.plugins.name.Namespaces;
import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
import org.apache.jackrabbit.oak.plugins.nodetype.RegistrationEditorProvider;
import org.apache.jackrabbit.oak.plugins.version.VersionConstants;
+import org.apache.jackrabbit.oak.spi.commit.CompositeEditorProvider;
import org.apache.jackrabbit.oak.spi.commit.EditorHook;
import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
import org.apache.jackrabbit.oak.spi.state.ApplyDiff;
@@ -68,6 +71,8 @@ public class InitialContent implements R
.setProperty(JCR_PRIMARYTYPE, NT_REP_NODE_TYPES, Type.NAME);
system.child(VersionConstants.JCR_ACTIVITIES)
.setProperty(JCR_PRIMARYTYPE, VersionConstants.REP_ACTIVITIES, Type.NAME);
+
+ Namespaces.setupNamespaces(system);
}
if (!builder.hasChildNode(IndexConstants.INDEX_DEFINITIONS_NAME)) {
@@ -84,8 +89,9 @@ public class InitialContent implements R
NodeState base = builder.getNodeState();
NodeStore store = new MemoryNodeStore(base);
- BuiltInNodeTypes.register(new SystemRoot(
- store, new EditorHook(new RegistrationEditorProvider())));
+ BuiltInNodeTypes.register(new SystemRoot(store, new EditorHook(
+ new CompositeEditorProvider(new NamespaceValidatorProvider(),
+ new RegistrationEditorProvider()))));
NodeState target = store.getRoot();
target.compareAgainstBaseState(base, new ApplyDiff(builder));
}
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistryTest.java?rev=1530931&r1=1530930&r2=1530931&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistryTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistryTest.java Thu Oct 10 12:00:39 2013
@@ -21,10 +21,13 @@ import static org.junit.Assert.assertEqu
import javax.jcr.NamespaceRegistry;
import org.apache.jackrabbit.oak.NodeStoreFixture;
+import org.apache.jackrabbit.oak.Oak;
import org.apache.jackrabbit.oak.OakBaseTest;
import org.apache.jackrabbit.oak.api.ContentSession;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
import org.junit.Test;
public class ReadWriteNamespaceRegistryTest extends OakBaseTest {
@@ -33,6 +36,13 @@ public class ReadWriteNamespaceRegistryT
super(fixture);
}
+ @Override
+ protected ContentSession createContentSession() {
+ return new Oak(store).with(new OpenSecurityProvider())
+ .with(new InitialContent())
+ .with(new NamespaceValidatorProvider()).createContentSession();
+ }
+
@Test
public void testMappings() throws Exception {
final ContentSession session = createContentSession();