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 ju...@apache.org on 2014/01/31 16:12:23 UTC

svn commit: r1563143 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/name/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/ oak-core...

Author: jukka
Date: Fri Jan 31 15:12:23 2014
New Revision: 1563143

URL: http://svn.apache.org/r1563143
Log:
OAK-924: Optimize namespace lookups

Make LocalNameMapper a concrete class with a direct Map<String, String>
member variable that contains the local namespace remappings

Make SessionNamespaces extend from LocalNameMapper to streamline
access to namespace mappings. Also streamline the NamespaceRegistry classes.

Drop the snapshot mapping and the NamespaceRegistry references from
SessionNamespaces and instead use direct content lookups. With the
new content structure this is no longer slow like it used to be.

Synchronize access to all name mapping methods to avoid possible
concurrency issues

Treat the default empty namespace as a given, so it doesn't need
to be stored in the namespace registry

Removed:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/TestNameMapper.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/GlobalNameMapper.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/LocalNameMapper.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/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/BuiltInNodeTypes.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImplTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/PropertyStatesTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/name/ReadWriteNamespaceRegistryTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlListTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/RestrictionDefinitionImplTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/RestrictionImplTest.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionNamespaces.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java
    jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/TargetImportHandler.java
    jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/GlobalNameMapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/GlobalNameMapper.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/GlobalNameMapper.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/GlobalNameMapper.java Fri Jan 31 15:12:23 2014
@@ -28,19 +28,18 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.core.ImmutableTree;
-import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
-import org.apache.jackrabbit.oak.plugins.name.Namespaces;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
-import static org.apache.jackrabbit.oak.api.Type.NAME;
 import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 import static org.apache.jackrabbit.oak.plugins.name.NamespaceConstants.NAMESPACES_PATH;
 import static org.apache.jackrabbit.oak.plugins.name.NamespaceConstants.REP_NSDATA;
+import static org.apache.jackrabbit.oak.plugins.name.NamespaceConstants.REP_PREFIXES;
+import static org.apache.jackrabbit.oak.plugins.name.NamespaceConstants.REP_URIS;
 import static org.apache.jackrabbit.oak.plugins.name.Namespaces.encodeUri;
-import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.NT_REP_UNSTRUCTURED;
 
 /**
  * Name mapper with no local prefix remappings. URI to prefix mappings
@@ -70,32 +69,31 @@ public class GlobalNameMapper implements
         }
     }
 
-    private static Tree setupNamespaces(Map<String, String> global) {
-        NodeBuilder namespaces = EmptyNodeState.EMPTY_NODE.builder();
-        namespaces.setProperty(JCR_PRIMARYTYPE, NT_REP_UNSTRUCTURED, NAME);
-        for (Entry<String, String> entry : global.entrySet()) {
-            namespaces.setProperty(
-                    Namespaces.escapePropertyKey(entry.getKey()),
-                    entry.getValue());
-        }
-        Namespaces.buildIndexNode(namespaces);
-        return new ImmutableTree(namespaces.getNodeState());
-    }
-
     protected final Tree namespaces;
-    private final Tree nsdata;
+    protected final Tree nsdata;
 
     public GlobalNameMapper(Root root) {
-        this(root.getTree(NAMESPACES_PATH));
+        this.namespaces = root.getTree(NAMESPACES_PATH);
+        this.nsdata = namespaces.getChild(REP_NSDATA);
     }
 
-    public GlobalNameMapper(Map<String, String> namespaces) {
-        this(setupNamespaces(namespaces));
-    }
+    public GlobalNameMapper(Map<String, String> mappings) {
+        NodeBuilder forward = EMPTY_NODE.builder();
+        NodeBuilder reverse = EMPTY_NODE.builder();
+
+        for (Entry<String, String> entry : mappings.entrySet()) {
+            String prefix = entry.getKey();
+            if (!prefix.isEmpty()) {
+                String uri = entry.getValue();
+                forward.setProperty(prefix, uri);
+                reverse.setProperty(encodeUri(uri), prefix);
+            }
+        }
+        reverse.setProperty(REP_PREFIXES, mappings.keySet(), STRINGS);
+        reverse.setProperty(REP_URIS, mappings.values(), STRINGS);
 
-    private GlobalNameMapper(Tree namespaces) {
-        this.namespaces = namespaces;
-        this.nsdata = namespaces.getChild(REP_NSDATA);
+        this.namespaces = new ImmutableTree(forward.getNodeState());
+        this.nsdata = new ImmutableTree(reverse.getNodeState());
     }
 
     @Override @Nonnull
@@ -117,8 +115,7 @@ public class GlobalNameMapper implements
         return jcrName;
     }
 
-    @Nonnull
-    @Override
+    @Override @Nonnull
     public String getOakName(@Nonnull String jcrName) throws RepositoryException {
         String oakName = getOakNameOrNull(jcrName);
         if (oakName == null) {
@@ -156,11 +153,30 @@ public class GlobalNameMapper implements
     }
 
     @CheckForNull
-    protected String getOakPrefixOrNull(String uri) {
+    protected synchronized String getOakPrefixOrNull(String uri) {
+        if (uri.isEmpty()) {
+            return uri;
+        }
+
         PropertyState mapping = nsdata.getProperty(encodeUri(uri));
         if (mapping != null && mapping.getType() == STRING) {
             return mapping.getValue(STRING);
         }
+
+        return null;
+    }
+
+    @CheckForNull
+    protected synchronized String getOakURIOrNull(String prefix) {
+        if (prefix.isEmpty()) {
+            return prefix;
+        }
+
+        PropertyState mapping = namespaces.getProperty(prefix);
+        if (mapping != null && mapping.getType() == STRING) {
+            return mapping.getValue(STRING);
+        }
+
         return null;
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/LocalNameMapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/LocalNameMapper.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/LocalNameMapper.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/LocalNameMapper.java Fri Jan 31 15:12:23 2014
@@ -31,26 +31,32 @@ import org.apache.jackrabbit.oak.api.Roo
 /**
  * Name mapper with local namespace mappings.
  */
-public abstract class LocalNameMapper extends GlobalNameMapper {
+public class LocalNameMapper extends GlobalNameMapper {
 
-    public LocalNameMapper(Root root) {
+    protected final Map<String, String> local;
+
+    public LocalNameMapper(Root root, Map<String, String> local) {
         super(root);
+        this.local = local;
     }
 
-    public LocalNameMapper(Map<String, String> namespaces) {
-        super(namespaces);
+    public LocalNameMapper(
+            Map<String, String> global, Map<String, String> local) {
+        super(global);
+        this.local = local;
     }
 
     @Override @Nonnull
-    public abstract Map<String, String> getSessionLocalMappings();
+    public synchronized Map<String, String> getSessionLocalMappings() {
+        return local;
+    }
 
     @Override @CheckForNull
-    public String getJcrName(String oakName) {
+    public synchronized String getJcrName(String oakName) {
         checkNotNull(oakName);
         checkArgument(!oakName.startsWith(":"), oakName); // hidden name
         checkArgument(!isExpandedName(oakName), oakName); // expanded name
 
-        Map<String, String> local = getSessionLocalMappings();
         if (!local.isEmpty()) {
             int colon = oakName.indexOf(':');
             if (colon > 0) {
@@ -90,14 +96,16 @@ public abstract class LocalNameMapper ex
     }
 
     @Override @CheckForNull
-    public String getOakNameOrNull(String jcrName) {
+    public synchronized String getOakNameOrNull(String jcrName) {
         checkNotNull(jcrName);
 
         if (jcrName.startsWith("{")) {
-            return getOakNameFromExpanded(jcrName);
+            String oakName = getOakNameFromExpanded(jcrName);
+            if (oakName != jcrName) {
+                return oakName;
+            } // else not an expanded name, so fall through to local mapping
         }
 
-        Map<String, String> local = getSessionLocalMappings();
         if (!local.isEmpty()) {
             int colon = jcrName.indexOf(':');
             if (colon > 0) {

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=1563143&r1=1563142&r2=1563143&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 Fri Jan 31 15:12:23 2014
@@ -69,8 +69,6 @@ public interface NamespaceConstants {
             NAMESPACE_SV
     ));
 
-    String REP_EMPTY = "rep:empty";
-
     // index nodes for faster lookup
 
     String REP_NSDATA = "rep:nsdata";

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=1563143&r1=1563142&r2=1563143&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 Fri Jan 31 15:12:23 2014
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.plugin
 
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -30,15 +29,15 @@ import org.apache.jackrabbit.oak.api.Tre
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.apache.jackrabbit.util.Text;
 
 import static com.google.common.base.Preconditions.checkState;
-import static javax.jcr.NamespaceRegistry.NAMESPACE_EMPTY;
+import static com.google.common.collect.Maps.newConcurrentMap;
+import static com.google.common.collect.Maps.newHashMap;
+import static com.google.common.collect.Sets.newHashSet;
 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;
@@ -47,12 +46,18 @@ import static org.apache.jackrabbit.JcrC
 import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
 import static org.apache.jackrabbit.oak.api.Type.NAME;
 import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.util.Text.escapeIllegalJcrChars;
 
 /**
  * Internal static utility class for managing the persisted namespace registry.
  */
 public class Namespaces implements NamespaceConstants {
 
+    /**
+     * Global cache of encoded URIs.
+     */
+    private static final Map<String, String> ENCODED_URIS = newConcurrentMap();
+
     private Namespaces() {
     }
 
@@ -70,7 +75,6 @@ public class Namespaces implements Names
         namespaces.setProperty(JCR_PRIMARYTYPE, NodeTypeConstants.NT_REP_UNSTRUCTURED, NAME);
 
         // Standard namespace specified by JCR (default one not included)
-        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);
@@ -88,7 +92,7 @@ public class Namespaces implements Names
         // first look for an existing mapping for the given URI
         for (PropertyState property : namespaces.getProperties()) {
             if (property.getType() == STRING) {
-                String prefix = unescapePropertyKey(property.getName());
+                String prefix = property.getName();
                 if (isValidPrefix(prefix)
                         && uri.equals(property.getValue(STRING))) {
                     return prefix;
@@ -99,27 +103,29 @@ public class Namespaces implements Names
         // no existing mapping found for the URI, make sure prefix is unique
         String prefix = prefixHint;
         int iteration = 1;
-        while (namespaces.hasProperty(escapePropertyKey(prefix))) {
+        while (namespaces.hasProperty(prefix)) {
             prefix = prefixHint + ++iteration;
         }
 
         // add the new mapping with its unique prefix
-        namespaces.setProperty(escapePropertyKey(prefix), uri);
+        namespaces.setProperty(prefix, uri);
         return prefix;
     }
 
     public static void buildIndexNode(NodeBuilder namespaces) {
-        Set<String> prefixes = new HashSet<String>();
-        Set<String> uris = new HashSet<String>();
+        // initialize prefix and URI sets with the defaults namespace
+        // that's not stored along with the other mappings
+        Set<String> prefixes = newHashSet("");
+        Set<String> uris = newHashSet("");
         Map<String, String> reverse = new HashMap<String, String>();
 
         for (PropertyState property : namespaces.getProperties()) {
-            String prefix = unescapePropertyKey(property.getName());
+            String prefix = 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);
+                reverse.put(uri, prefix);
             }
         }
 
@@ -137,13 +143,14 @@ public class Namespaces implements Names
     }
 
     public static Map<String, String> getNamespaceMap(Tree root) {
-        Map<String, String> map = new HashMap<String, String>();
+        Map<String, String> map = newHashMap();
+        map.put("", ""); // default namespace, not included in tree
 
         Tree namespaces = getNamespaceTree(root);
         for (PropertyState property : namespaces.getProperties()) {
             String prefix = property.getName();
             if (STRING.equals(property.getType()) && isValidPrefix(prefix)) {
-                map.put(unescapePropertyKey(prefix), property.getValue(STRING));
+                map.put(prefix, property.getValue(STRING));
             }
         }
 
@@ -162,12 +169,16 @@ public class Namespaces implements Names
     }
 
     public static String getNamespacePrefix(Tree root, String uri) {
-        Tree namespaces = getNamespaceTree(root);
-        PropertyState ps = namespaces.getChild(REP_NSDATA)
-                .getProperty(encodeUri(escapePropertyKey(uri)));
+        if (uri.isEmpty()) {
+            return uri;
+        }
+
+        Tree nsdata = getNamespaceTree(root).getChild(REP_NSDATA);
+        PropertyState ps = nsdata.getProperty(encodeUri(uri));
         if (ps != null) {
             return ps.getValue(STRING);
         }
+
         return null;
     }
 
@@ -177,56 +188,38 @@ public class Namespaces implements Names
     }
 
     public static String getNamespaceURI(Tree root, String prefix) {
+        if (prefix.isEmpty()) {
+            return prefix;
+        }
+
         if (isValidPrefix(prefix)) {
-            PropertyState property = getNamespaceTree(root).getProperty(
-                    escapePropertyKey(prefix));
-            if (property != null && STRING.equals(property.getType())) {
+            PropertyState property = getNamespaceTree(root).getProperty(prefix);
+            if (property != null && property.getType() == STRING) {
                 return property.getValue(STRING);
             }
         }
+
         return null;
     }
 
     // utils
 
     /**
-     * Replaces an empty string with the special {@link #REP_EMPTY} value.
-     *
-     * @see #unescapePropertyKey(String)
-     * @param key property key
-     * @return escaped property key
-     */
-    public static String escapePropertyKey(String key) {
-        if (key.equals("")) {
-            return REP_EMPTY;
-        } else {
-            return key;
-        }
-    }
-
-    /**
-     * Converts the special {@link #REP_EMPTY} 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(REP_EMPTY)) {
-            return "";
-        } else {
-            return key;
-        }
-    }
-
-    /**
      * encodes the uri value to be used as a property
      * 
      * @param uri
      * @return encoded uri
      */
     public static String encodeUri(String uri) {
-        return Text.escapeIllegalJcrChars(uri);
+        String encoded = ENCODED_URIS.get(uri);
+        if (encoded == null) {
+            encoded =  escapeIllegalJcrChars(uri);
+            if (ENCODED_URIS.size() > 1000) {
+                ENCODED_URIS.clear(); // prevents DoS attacks
+            }
+            ENCODED_URIS.put(uri, encoded);
+        }
+        return encoded;
     }
 
     static Set<String> safeGet(Tree tree, String name) {

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=1563143&r1=1563142&r2=1563143&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 Fri Jan 31 15:12:23 2014
@@ -16,12 +16,19 @@
  */
 package org.apache.jackrabbit.oak.plugins.name;
 
+import static com.google.common.collect.Iterables.toArray;
+import static java.util.Collections.emptyList;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+
 import javax.annotation.Nonnull;
 import javax.jcr.NamespaceException;
 import javax.jcr.NamespaceRegistry;
 import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
 
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 
 /**
@@ -31,17 +38,25 @@ import org.apache.jackrabbit.oak.api.Tre
  * implementation that supports also namespace modifications and that's thus
  * better suited for use in in implementing the full JCR API.
  */
-public abstract class ReadOnlyNamespaceRegistry
+public class ReadOnlyNamespaceRegistry
         implements NamespaceRegistry, NamespaceConstants {
 
-    /**
-     * Called by the {@link NamespaceRegistry} implementation methods
-     * to acquire a root {@link Tree} instance from which to read the
-     * namespace mappings (under {@code jcr:system/rep:namespaces}).
-     *
-     * @return root {@link Tree} for reading the namespace mappings
-     */
-    protected abstract Tree getReadTree();
+    protected final Tree namespaces;
+    protected final Tree nsdata;
+
+    public ReadOnlyNamespaceRegistry(Root root) {
+        this.namespaces = root.getTree(NAMESPACES_PATH);
+        this.nsdata = namespaces.getChild(REP_NSDATA);
+    }
+
+    private Iterable<String> getNSData(String name) {
+        PropertyState property = nsdata.getProperty(name);
+        if (property != null && property.getType() == STRINGS) {
+            return property.getValue(STRINGS);
+        } else {
+            return emptyList();
+        }
+    }
 
     //--------------------------------------------------< NamespaceRegistry >---
 
@@ -56,60 +71,44 @@ public abstract class ReadOnlyNamespaceR
         throw new UnsupportedRepositoryOperationException();
     }
 
-    @Override
-    @Nonnull
-    public String[] getPrefixes() throws RepositoryException {
-        try {
-            return Namespaces.getNamespacePrefixes(getReadTree());
-        } catch (RuntimeException e) {
-            throw new RepositoryException(
-                    "Failed to retrieve registered namespace prefixes", e);
-        }
+    @Override @Nonnull
+    public String[] getPrefixes() {
+        return toArray(getNSData(REP_PREFIXES), String.class);
     }
 
-    @Override
-    @Nonnull
-    public String[] getURIs() throws RepositoryException {
-        try {
-            return Namespaces.getNamespaceURIs(getReadTree());
-        } catch (RuntimeException e) {
-            throw new RepositoryException(
-                    "Failed to retrieve registered namespace URIs", e);
-        }
+    @Override @Nonnull
+    public String[] getURIs() {
+        return toArray(getNSData(REP_URIS), String.class);
     }
 
-    @Override
-    @Nonnull
-    public String getURI(String prefix) throws RepositoryException {
-        try {
-            String uri = Namespaces.getNamespaceURI(getReadTree(), prefix);
-            if (uri == null) {
-                throw new NamespaceException(
-                        "No namespace registered for prefix " + prefix);
-            }
-            return uri;
-        } catch (RuntimeException e) {
-            throw new RepositoryException(
-                    "Failed to retrieve the namespace URI for prefix "
-                    + prefix, e);
+    @Override @Nonnull
+    public String getURI(String prefix) throws NamespaceException {
+        if (prefix.isEmpty()) {
+            return prefix; // the default empty namespace
         }
+
+        PropertyState property = namespaces.getProperty(prefix);
+        if (property != null && property.getType() == STRING) {
+            return property.getValue(STRING);
+        }
+
+        throw new NamespaceException(
+                "No namespace registered for prefix " + prefix);
     }
 
-    @Override
-    @Nonnull
-    public String getPrefix(String uri) throws RepositoryException {
-        try {
-            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 "
-                    + uri, e);
+    @Override @Nonnull
+    public String getPrefix(String uri) throws NamespaceException {
+        if (uri.isEmpty()) {
+            return uri; // the default empty namespace
+        }
+
+        PropertyState property = nsdata.getProperty(Namespaces.encodeUri(uri));
+        if (property != null && property.getType() == STRING) {
+            return property.getValue(STRING);
         }
+
+        throw new NamespaceException(
+                "No namespace prefix registered for URI " + 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=1563143&r1=1563142&r2=1563143&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 Fri Jan 31 15:12:23 2014
@@ -16,12 +16,13 @@
  */
 package org.apache.jackrabbit.oak.plugins.name;
 
-import static org.apache.jackrabbit.oak.plugins.name.Namespaces.getNamespaceURI;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
 
 import javax.jcr.NamespaceException;
 import javax.jcr.RepositoryException;
 
 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;
 
@@ -32,6 +33,10 @@ import org.apache.jackrabbit.oak.api.Tre
 public abstract class ReadWriteNamespaceRegistry
         extends ReadOnlyNamespaceRegistry {
 
+    public ReadWriteNamespaceRegistry(Root root) {
+        super(root);
+    }
+
     /**
      * Called by the write methods to acquire a fresh {@link Root} instance
      * that can be used to persist the requested namespace changes (and
@@ -58,31 +63,50 @@ public abstract class ReadWriteNamespace
     @Override
     public void registerNamespace(String prefix, String uri)
             throws RepositoryException {
-        if (uri.equals(getNamespaceURI(getReadTree(), prefix))) {
-            return; // Namespace already registered, so we do nothing
+        if (prefix.isEmpty() && uri.isEmpty()) {
+            return; // the default empty namespace is always registered
+        } else if (prefix.isEmpty() || uri.isEmpty()) {
+            throw new NamespaceException(
+                    "Cannot remap the default empty namespace");
         }
+
+        PropertyState property = namespaces.getProperty(prefix);
+        if (property != null && property.getType() == STRING
+                && uri.equals(property.getValue(STRING))) {
+            return; // common case: namespace already registered -> do nothing
+        }
+
         try {
             Root root = getWriteRoot();
             Tree namespaces = root.getTree(NAMESPACES_PATH);
 
-            // remove existing mapping to given uri
-            String ns = Namespaces.getNamespacePrefix(namespaces, uri);
-            if (ns != null) {
-                namespaces.removeProperty(ns);
+            // remove existing mapping to given URI
+            for (PropertyState mapping : namespaces.getProperties()) {
+                if (mapping.getType() == STRING
+                        && uri.equals(mapping.getValue(STRING))) {
+                    namespaces.removeProperty(mapping.getName());
+                }
             }
+
+            // add this mapping (overrides existing mapping with same prefix)
             namespaces.setProperty(prefix, uri);
+
             root.commit();
             refresh();
         } catch (CommitFailedException e) {
-            String message =
-                    "Failed to register namespace mapping from "
-                            + prefix + " to " + uri;
-            throw e.asRepositoryException(message);
+            throw e.asRepositoryException(
+                    "Failed to register namespace mapping "
+                    + prefix + " -> " + uri);
         }
     }
 
     @Override
     public void unregisterNamespace(String prefix) throws RepositoryException {
+        if (prefix.isEmpty()) {
+            throw new NamespaceException(
+                    "Cannot unregister the default empty namespace");
+        }
+
         Root root = getWriteRoot();
         Tree namespaces = root.getTree(NAMESPACES_PATH);
         if (!namespaces.exists() || !namespaces.hasProperty(prefix)) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/BuiltInNodeTypes.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/BuiltInNodeTypes.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/BuiltInNodeTypes.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/write/BuiltInNodeTypes.java Fri Jan 31 15:12:23 2014
@@ -65,11 +65,7 @@ class BuiltInNodeTypes {
             }
         };
 
-        this.nsReg = new ReadWriteNamespaceRegistry() {
-            @Override
-            protected Tree getReadTree() {
-                return root.getTree("/");
-            }
+        this.nsReg = new ReadWriteNamespaceRegistry(root) {
             @Override
             protected Root getWriteRoot() {
                 return root;

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineImpl.java Fri Jan 31 15:12:23 2014
@@ -93,16 +93,11 @@ public abstract class QueryEngineImpl im
 
     private static Query parseQuery(
             String statement, String language, ExecutionContext context,
-            final Map<String, String> mappings) throws ParseException {
+            Map<String, String> mappings) throws ParseException {
         LOG.debug("Parsing {} statement: {}", language, statement);
 
         NamePathMapper mapper = new NamePathMapperImpl(
-                new LocalNameMapper(context.getRoot()) {
-                    @Override
-                    public Map<String, String> getSessionLocalMappings() {
-                        return mappings;
-                    }
-                });
+                new LocalNameMapper(context.getRoot(), mappings));
 
         NodeState types = context.getBaseState()
                 .getChildNode(JCR_SYSTEM)

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImplTest.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImplTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImplTest.java Fri Jan 31 15:12:23 2014
@@ -30,7 +30,6 @@ import javax.jcr.RepositoryException;
 
 import com.google.common.collect.ImmutableMap;
 
-import org.apache.jackrabbit.oak.TestNameMapper;
 import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager;
 import org.junit.Test;
 
@@ -50,7 +49,7 @@ public class NamePathMapperImplTest {
             "foo", "http://www.example.com/foo",
             "quu", "http://www.example.com/quu");
 
-    private final NameMapper mapper = new TestNameMapper(GLOBAL, LOCAL);
+    private final NameMapper mapper = new LocalNameMapper(GLOBAL, LOCAL);
 
     private NamePathMapper npMapper = new NamePathMapperImpl(mapper);
 
@@ -173,8 +172,8 @@ public class NamePathMapperImplTest {
 
         NamePathMapper[] mappers = {
                 npMapper,
-                new NamePathMapperImpl(
-                        new TestNameMapper(GLOBAL, Collections.<String, String>emptyMap()))
+                new NamePathMapperImpl(new LocalNameMapper(
+                        GLOBAL, Collections.<String, String>emptyMap()))
         };
 
         for (NamePathMapper mapper : mappers) {

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/PropertyStatesTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/PropertyStatesTest.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/PropertyStatesTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/memory/PropertyStatesTest.java Fri Jan 31 15:12:23 2014
@@ -25,9 +25,9 @@ import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Value;
 
-import org.apache.jackrabbit.oak.TestNameMapper;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.namepath.LocalNameMapper;
 import org.apache.jackrabbit.oak.namepath.NamePathMapperImpl;
 import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
 import org.apache.jackrabbit.util.ISO8601;
@@ -38,9 +38,10 @@ import static org.junit.Assert.assertEqu
 
 public class PropertyStatesTest {
 
-    private final NamePathMapperImpl namePathMapper = new NamePathMapperImpl(new TestNameMapper(
-        singletonMap("oak-prefix", TestNameMapper.TEST_URI),
-        singletonMap("jcr-prefix", TestNameMapper.TEST_URI) ));
+    private final NamePathMapperImpl namePathMapper =
+            new NamePathMapperImpl(new LocalNameMapper(
+                    singletonMap("oak-prefix", "http://jackrabbit.apache.org"),
+                    singletonMap("jcr-prefix", "http://jackrabbit.apache.org")));
 
     @Test
     public void namePropertyFromNameValue() throws RepositoryException {

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=1563143&r1=1563142&r2=1563143&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 Fri Jan 31 15:12:23 2014
@@ -25,7 +25,6 @@ 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;
@@ -46,15 +45,16 @@ public class ReadWriteNamespaceRegistryT
     @Test
     public void testMappings() throws Exception {
         final ContentSession session = createContentSession();
-        NamespaceRegistry r = new ReadWriteNamespaceRegistry() {
-            @Override
-            protected Tree getReadTree() {
-                return session.getLatestRoot().getTree("/");
-            }
+        final Root root = session.getLatestRoot();
+        NamespaceRegistry r = new ReadWriteNamespaceRegistry(root) {
             @Override
             protected Root getWriteRoot() {
                 return session.getLatestRoot();
             }
+            @Override
+            protected void refresh() {
+                root.refresh();
+            }
         };
 
         assertEquals("", r.getURI(""));

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/AccessControlManagerImplTest.java Fri Jan 31 15:12:23 2014
@@ -54,7 +54,6 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy;
 import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
-import org.apache.jackrabbit.oak.TestNameMapper;
 import org.apache.jackrabbit.oak.api.ContentSession;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
@@ -81,6 +80,7 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import static java.util.Collections.singletonMap;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -94,7 +94,11 @@ import static org.junit.Assert.fail;
  */
 public class AccessControlManagerImplTest extends AbstractAccessControlTest implements AccessControlConstants {
 
-    private final String testName = TestNameMapper.TEST_PREFIX + ":testRoot";
+    public static final String TEST_LOCAL_PREFIX = "test";
+    public static final String TEST_PREFIX = "jr";
+    public static final String TEST_URI = "http://jackrabbit.apache.org";
+
+    private final String testName = TEST_PREFIX + ":testRoot";
     private final String testPath = '/' + testName;
 
     private Principal testPrincipal;
@@ -112,7 +116,7 @@ public class AccessControlManagerImplTes
     public void before() throws Exception {
         super.before();
 
-        registerNamespace(TestNameMapper.TEST_PREFIX, TestNameMapper.TEST_URI);
+        registerNamespace(TEST_PREFIX, TEST_URI);
         nameMapper = new GlobalNameMapper(root);
         npMapper = new NamePathMapperImpl(nameMapper);
 
@@ -318,15 +322,11 @@ public class AccessControlManagerImplTes
         List<Privilege> allPrivileges = Arrays.asList(getPrivilegeManager(root).getRegisteredPrivileges());
 
         List<String> testPaths = new ArrayList<String>();
-        testPaths.add('/' + TestNameMapper.TEST_LOCAL_PREFIX + ":testRoot");
-        testPaths.add("/{" + TestNameMapper.TEST_URI + "}testRoot");
+        testPaths.add('/' + TEST_LOCAL_PREFIX + ":testRoot");
+        testPaths.add("/{" + TEST_URI + "}testRoot");
 
-        NameMapper remapped = new LocalNameMapper(root) {
-            @Override
-            public Map<String, String> getSessionLocalMappings() {
-                return TestNameMapper.LOCAL_MAPPING;
-            }
-        };
+        NameMapper remapped = new LocalNameMapper(
+                root, singletonMap(TEST_LOCAL_PREFIX, TEST_URI));
 
         AccessControlManager acMgr =
                 getAccessControlManager(new NamePathMapperImpl(remapped));

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlListTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlListTest.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlListTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlListTest.java Fri Jan 31 15:12:23 2014
@@ -31,8 +31,8 @@ import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.security.Privilege;
 
-import org.apache.jackrabbit.oak.TestNameMapper;
 import org.apache.jackrabbit.oak.namepath.GlobalNameMapper;
+import org.apache.jackrabbit.oak.namepath.LocalNameMapper;
 import org.apache.jackrabbit.oak.namepath.NameMapper;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.namepath.NamePathMapperImpl;
@@ -44,6 +44,7 @@ import org.junit.Test;
 
 import com.google.common.collect.Lists;
 
+import static java.util.Collections.singletonMap;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -129,16 +130,18 @@ public abstract class AbstractAccessCont
 
     @Test
     public void testGetOakPath() {
-        NamePathMapper npMapper = new NamePathMapperImpl(new TestNameMapper());
+        NamePathMapper npMapper = new NamePathMapperImpl(new LocalNameMapper(
+                singletonMap("oak", "http://jackrabbit.apache.org"),
+                singletonMap("jcr", "http://jackrabbit.apache.org")));
         // map of jcr-path to oak path
         Map<String, String> paths = new HashMap<String, String>();
         paths.put(null, null);
         paths.put(getTestPath(), getTestPath());
         paths.put("/", "/");
-        String oakPath = '/' + TestNameMapper.TEST_PREFIX + ":testPath";
-        String jcrPath = '/' + TestNameMapper.TEST_LOCAL_PREFIX + ":testPath";
+        String oakPath = "/oak:testPath";
+        String jcrPath = "/jcr:testPath";
         paths.put(jcrPath, oakPath);
-        jcrPath = "/{" + TestNameMapper.TEST_URI + "}testPath";
+        jcrPath = "/{http://jackrabbit.apache.org}testPath";
         paths.put(jcrPath, oakPath);
 
         // test if oak-path is properly set.

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlTest.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlTest.java Fri Jan 31 15:12:23 2014
@@ -26,7 +26,6 @@ import javax.jcr.security.Privilege;
 
 import org.apache.jackrabbit.oak.AbstractSecurityTest;
 import org.apache.jackrabbit.oak.api.Root;
-import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.plugins.name.ReadWriteNamespaceRegistry;
 import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
 import org.apache.jackrabbit.oak.spi.security.authorization.restriction.Restriction;
@@ -40,16 +39,11 @@ public abstract class AbstractAccessCont
     private PrivilegeBitsProvider bitsProvider;
 
     protected void registerNamespace(String prefix, String uri) throws Exception {
-        NamespaceRegistry nsRegistry = new ReadWriteNamespaceRegistry() {
+        NamespaceRegistry nsRegistry = new ReadWriteNamespaceRegistry(root) {
             @Override
             protected Root getWriteRoot() {
                 return root;
             }
-
-            @Override
-            protected Tree getReadTree() {
-                return root.getTree("/");
-            }
         };
         nsRegistry.registerNamespace(prefix, uri);
     }

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/RestrictionDefinitionImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/RestrictionDefinitionImplTest.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/RestrictionDefinitionImplTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/RestrictionDefinitionImplTest.java Fri Jan 31 15:12:23 2014
@@ -19,7 +19,6 @@ package org.apache.jackrabbit.oak.spi.se
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.jackrabbit.oak.TestNameMapper;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AbstractAccessControlTest;
 import org.junit.Before;
@@ -42,7 +41,7 @@ public class RestrictionDefinitionImplTe
     public void before() throws Exception {
         super.before();
 
-        name = TestNameMapper.TEST_PREFIX + ":defName";
+        name = "test:defName";
         definition = new RestrictionDefinitionImpl(name, Type.NAME, true);
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/RestrictionImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/RestrictionImplTest.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/RestrictionImplTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/restriction/RestrictionImplTest.java Fri Jan 31 15:12:23 2014
@@ -22,7 +22,7 @@ import java.util.List;
 import javax.annotation.Nonnull;
 
 import com.google.common.collect.ImmutableList;
-import org.apache.jackrabbit.oak.TestNameMapper;
+
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
@@ -48,7 +48,7 @@ public class RestrictionImplTest extends
     public void before() throws Exception {
         super.before();
 
-        name = TestNameMapper.TEST_PREFIX + ":defName";
+        name = "test:defName";
         PropertyState property = createProperty(name, value);
         restriction = new RestrictionImpl(property, true);
     }

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java Fri Jan 31 15:12:23 2014
@@ -52,7 +52,6 @@ import org.apache.jackrabbit.oak.jcr.del
 import org.apache.jackrabbit.oak.jcr.observation.ObservationManagerImpl;
 import org.apache.jackrabbit.oak.jcr.security.AccessManager;
 import org.apache.jackrabbit.oak.jcr.session.operation.SessionOperation;
-import org.apache.jackrabbit.oak.namepath.LocalNameMapper;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.namepath.NamePathMapperImpl;
 import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
@@ -118,15 +117,9 @@ public class SessionContext implements N
         SessionStats sessionStats = delegate.getSessionStats();
         sessionStats.setAttributes(attributes);
 
-        this.namespaces = new SessionNamespaces(this);
-        LocalNameMapper nameMapper = new LocalNameMapper(delegate.getRoot()) {
-            @Override
-            public Map<String, String> getSessionLocalMappings() {
-                return SessionContext.this.namespaces.getSessionLocalMappings();
-            }
-        };
+        this.namespaces = new SessionNamespaces(delegate.getRoot());
         this.namePathMapper = new NamePathMapperImpl(
-                nameMapper, delegate.getIdManager());
+                namespaces, delegate.getIdManager());
         this.valueFactory = new ValueFactoryImpl(
                 delegate.getRoot(), namePathMapper);
     }

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionNamespaces.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionNamespaces.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionNamespaces.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionNamespaces.java Fri Jan 31 15:12:23 2014
@@ -16,10 +16,12 @@
  */
 package org.apache.jackrabbit.oak.jcr.session;
 
-import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.toArray;
+import static com.google.common.collect.Sets.newHashSet;
+import static java.util.Collections.emptyList;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+import static org.apache.jackrabbit.oak.plugins.name.NamespaceConstants.REP_PREFIXES;
 
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Map;
@@ -27,10 +29,11 @@ import java.util.Set;
 
 import javax.annotation.Nonnull;
 import javax.jcr.NamespaceException;
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.namepath.LocalNameMapper;
 import org.apache.jackrabbit.util.XMLChar;
 
 import com.google.common.collect.Maps;
@@ -41,44 +44,20 @@ import com.google.common.collect.Maps;
  * re-mappings and takes a snapshot of the namespace registry when initialized
  * (see JCR 2.0 specification, section 3.5.1).
  */
-class SessionNamespaces {
+class SessionNamespaces extends LocalNameMapper {
 
-    /**
-     * Local namespace remappings. Prefixes as keys and namespace URIs as values.
-     * <p/>
-     * This map is only accessed from synchronized methods (see
-     * <a href="https://issues.apache.org/jira/browse/JCR-1793">JCR-1793</a>).
-     */
-    private final Map<String, String> namespaces;
-
-    /**
-     * A snapshot of the namespace registry when these SessionNamespaces
-     * are first accessed. Key: prefix, value: uri
-     */
-    private Map<String, String> snapshotPrefixUri;
-    
-    /**
-     * A snapshot of the namespace registry when these SessionNamespaces
-     * are first accessed. Key: uri, value: prefix
-     */
-    private Map<String, String> snapshotUriPrefix;
-
-
-    private final SessionContext sessionContext;
-
-    SessionNamespaces(@Nonnull SessionContext sessionContext) {
-        this.namespaces = Maps.newHashMap();
-        this.sessionContext = checkNotNull(sessionContext);
+    SessionNamespaces(@Nonnull Root root) {
+        super(root, Maps.<String, String>newHashMap());
     }
 
-    // The code below was initially copied from JCR Commons AbstractSession, but
-    // provides information the "hasRemappings" information
+    // The code below was initially copied from JCR Commons AbstractSession,
+    // but has since been radically modified
 
     /**
      * @see Session#setNamespacePrefix(String, String)
      */
-    void setNamespacePrefix(String prefix, String uri) throws RepositoryException {
-        init();
+    synchronized void setNamespacePrefix(String prefix, String uri)
+            throws NamespaceException {
         if (prefix == null) {
             throw new IllegalArgumentException("Prefix must not be null");
         } else if (uri == null) {
@@ -97,153 +76,109 @@ class SessionNamespaces {
                     "Prefix is not a valid XML NCName: " + prefix);
         }
 
-        synchronized (namespaces) {
-            // Remove existing mapping for the given prefix
-            namespaces.remove(prefix);
-
-            // Remove existing mapping(s) for the given URI
-            Set<String> prefixes = new HashSet<String>();
-            for (Map.Entry<String, String> entry : namespaces.entrySet()) {
-                if (entry.getValue().equals(uri)) {
-                    prefixes.add(entry.getKey());
-                }
-            }
-            namespaces.keySet().removeAll(prefixes);
+        // remove the possible existing mapping for the given prefix
+        local.remove(prefix);
 
-            // Add the new mapping
-            namespaces.put(prefix, uri);
+        // remove the possible existing mapping(s) for the given URI
+        Set<String> prefixes = new HashSet<String>();
+        for (Map.Entry<String, String> entry : local.entrySet()) {
+            if (entry.getValue().equals(uri)) {
+                prefixes.add(entry.getKey());
+            }
         }
+        local.keySet().removeAll(prefixes);
 
-        if (snapshotPrefixUri.containsKey(prefix)) {
-            // make sure we have a prefix in case an existing
-            // namespace uri is re-mapped
-            getNamespacePrefix(snapshotPrefixUri.get(prefix));
-        }
+        // add the new mapping
+        local.put(prefix, uri);
     }
 
     /**
      * @see Session#getNamespacePrefixes()
      */
-    String[] getNamespacePrefixes() throws RepositoryException {
-        init();
-        synchronized (namespaces) {
-            if (namespaces.isEmpty()) {
-                Set<String> prefixes = snapshotPrefixUri.keySet();
-                return prefixes.toArray(new String[prefixes.size()]);
-            }
+    synchronized String[] getNamespacePrefixes() {
+        // get registered namespace prefixes
+        Iterable<String> global = emptyList();
+        PropertyState property = nsdata.getProperty(REP_PREFIXES);
+        if (property != null && property.getType() == STRINGS) {
+            global = property.getValue(STRINGS);
         }
-        Set<String> uris = new HashSet<String>();
-        uris.addAll(snapshotPrefixUri.values());
-        synchronized (namespaces) {
-            // Add namespace uris only visible to session
-            uris.addAll(namespaces.values());
+
+        // unless there are local remappings just use the registered ones
+        if (local.isEmpty()) {
+            return toArray(global, String.class);
         }
-        Set<String> prefixes = new HashSet<String>();
-        for (String uri : uris) {
-            prefixes.add(getNamespacePrefix(uri));
+
+        Set<String> prefixes = newHashSet(global);
+
+        // remove the prefixes of the namespaces that have been remapped
+        for (String uri : local.values()) {
+            String prefix = getOakPrefixOrNull(uri);
+            if (prefix != null) {
+                prefixes.remove(prefix);
+            }
         }
+
+        // add the prefixes in local remappings
+        prefixes.addAll(local.keySet());
+
         return prefixes.toArray(new String[prefixes.size()]);
     }
 
     /**
      * @see Session#getNamespaceURI(String)
      */
-    String getNamespaceURI(String prefix) throws RepositoryException {
-        init();
-        synchronized (namespaces) {
-            String uri = namespaces.get(prefix);
-
-            if (uri == null) {
-                // Not in local mappings, try snapshot ones
-                uri = snapshotPrefixUri.get(prefix);
-                if (uri == null) {
-                    // Not in snapshot mappings, try the global ones
-                    uri = getNamespaceRegistry().getURI(prefix);
-                    if (namespaces.containsValue(uri)) {
-                        // The global URI is locally mapped to some other prefix,
-                        // so there are no mappings for this prefix
-                        throw new NamespaceException("Namespace not found: " + prefix);
-                    }
-                }
+    synchronized String getNamespaceURI(String prefix)
+            throws NamespaceException {
+        // first check local remappings
+        String uri = local.get(prefix);
+        if (uri == null) {
+            // Not in snapshot mappings, try the global ones
+            uri = getOakURIOrNull(prefix);
+            if (uri == null || local.containsValue(uri)) {
+                // URI is either not registered or locally mapped to some
+                // other prefix, so there are no mappings for this prefix
+                throw new NamespaceException(
+                        "Unknown namespace prefix: " + prefix);
             }
-
-            return uri;
         }
+        return uri;
     }
 
     /**
      * @see Session#getNamespacePrefix(String)
      */
-    String getNamespacePrefix(String uri) throws RepositoryException {
-        init();
-        synchronized (namespaces) {
-            if (namespaces.size() > 0) {
-                for (Map.Entry<String, String> entry : namespaces.entrySet()) {
-                    if (entry.getValue().equals(uri)) {
-                        return entry.getKey();
-                    }
-                }
-            }
-
-            // try snapshot
-            String prefix = snapshotUriPrefix.get(uri);
-            if (prefix != null && !namespaces.containsKey(prefix)) {
-                return prefix;
-            }
-
-            // The following throws an exception if the URI is not found, that's OK
-            prefix = getNamespaceRegistry().getPrefix(uri);
-
-            // Generate a new prefix if the global mapping is already taken
-            String base = prefix;
-            for (int i = 2; namespaces.containsKey(prefix); i++) {
-                prefix = base + i;
+    synchronized String getNamespacePrefix(String uri)
+            throws NamespaceException {
+        // first check local remappings
+        for (Map.Entry<String, String> entry : local.entrySet()) {
+            if (entry.getValue().equals(uri)) {
+                return entry.getKey();
             }
+        }
 
-            if (!base.equals(prefix)) {
-                namespaces.put(prefix, uri);
-            }
-            return prefix;
+        // then try the global mappings
+        String prefix = getOakPrefixOrNull(uri);
+        if (prefix == null) {
+            throw new NamespaceException("Unknown namespace URI: " + uri);
         }
-    }
 
-    /**
-     * @return the session local namespaces that were remapped.
-     */
-    public Map<String, String> getSessionLocalMappings() {
-        synchronized (namespaces) {
-            if (namespaces.isEmpty()) {
-                return Collections.emptyMap();
-            }
-            return new HashMap<String, String>(namespaces);
+        // Generate a new prefix if already locally mapped to something else
+        String base = prefix;
+        for (int i = 2; local.containsKey(prefix); i++) {
+            prefix = base + i;
+        }
+        if (base != prefix) {
+            local.put(prefix, uri);
         }
+
+        return prefix;
     }
 
     /**
      * Clears the re-mapped namespaces map.
      */
-    void clear() {
-        synchronized (namespaces) {
-            namespaces.clear();
-        }
+    synchronized void clear() {
+        local.clear();
     }
 
-    private NamespaceRegistry getNamespaceRegistry() {
-        return sessionContext.getWorkspace().getNamespaceRegistry();
-    }
-
-    private void init() throws RepositoryException {
-        if (snapshotPrefixUri == null) {
-            NamespaceRegistry registry = getNamespaceRegistry();
-            Map<String, String> prefixUri = new HashMap<String, String>();
-            Map<String, String> uriPrefix = new HashMap<String, String>();
-            for (String prefix : registry.getPrefixes()) {
-                String uri = registry.getURI(prefix);
-                prefixUri.put(prefix, uri);
-                uriPrefix.put(uri, prefix);
-            }
-            snapshotPrefixUri = prefixUri;
-            snapshotUriPrefix = uriPrefix;
-        }
-    }
 }

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java Fri Jan 31 15:12:23 2014
@@ -206,17 +206,11 @@ public class WorkspaceImpl implements Ja
 
     @Override
     public NamespaceRegistry getNamespaceRegistry() {
-        return new ReadWriteNamespaceRegistry() {
-            @Override
-            protected Tree getReadTree() {
-                return sessionDelegate.getRoot().getTree("/");
-            }
-
+        return new ReadWriteNamespaceRegistry(sessionDelegate.getRoot()) {
             @Override
             protected Root getWriteRoot() {
                 return sessionDelegate.getContentSession().getLatestRoot();
             }
-
             @Override
             protected void refresh() throws RepositoryException {
                 getSession().refresh(true);

Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/TargetImportHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/TargetImportHandler.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/TargetImportHandler.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/TargetImportHandler.java Fri Jan 31 15:12:23 2014
@@ -16,8 +16,6 @@
  */
 package org.apache.jackrabbit.oak.jcr.xml;
 
-import static org.apache.jackrabbit.oak.plugins.name.NamespaceConstants.NAMESPACES_PATH;
-
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -27,7 +25,6 @@ import java.util.Set;
 
 import javax.jcr.RepositoryException;
 
-import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.jcr.session.SessionContext;
 import org.apache.jackrabbit.oak.namepath.LocalNameMapper;
@@ -111,13 +108,9 @@ public abstract class TargetImportHandle
     //--------------------------------------------------------
 
     public NamePathMapper currentNamePathMapper() {
-        Root root = sessionContext.getSessionDelegate().getRoot();
-        return new NamePathMapperImpl(new LocalNameMapper(root) {
-            @Override
-            public Map<String, String> getSessionLocalMappings() {
-                return documentPrefixMap;
-            }
-        });
+        return new NamePathMapperImpl(new LocalNameMapper(
+                sessionContext.getSessionDelegate().getRoot(),
+                documentPrefixMap));
     }
 
     private Map<String, String> createCurrentPrefixMap() {

Modified: jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java?rev=1563143&r1=1563142&r2=1563143&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java (original)
+++ jackrabbit/oak/trunk/oak-upgrade/src/main/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgrade.java Fri Jan 31 15:12:23 2014
@@ -104,6 +104,7 @@ import static org.apache.jackrabbit.core
 import static org.apache.jackrabbit.oak.api.Type.NAME;
 import static org.apache.jackrabbit.oak.api.Type.NAMES;
 import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+import static org.apache.jackrabbit.oak.plugins.name.Namespaces.addCustomMapping;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_AVAILABLE_QUERY_OPERATORS;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_IS_ABSTRACT;
 import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_IS_FULLTEXT_SEARCHABLE;
@@ -333,14 +334,14 @@ public class RepositoryUpgrade {
         Properties indexes  = loadProperties("/namespaces/ns_idx.properties");
 
         for (String prefixHint : registry.stringPropertyNames()) {
+            String prefix;
             String uri = registry.getProperty(prefixHint);
             if (".empty.key".equals(prefixHint)) {
-                prefixHint = "";
+                prefix = ""; // the default empty mapping is not stored
+            } else {
+                prefix = addCustomMapping(namespaces, uri, prefixHint);
             }
 
-            String prefix =
-                    Namespaces.addCustomMapping(namespaces, uri, prefixHint);
-
             String index = null;
             if (uri.isEmpty()) {
                 index = indexes.getProperty(".empty.key");