Index: oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/NamePathMapper.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/NamePathMapper.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/NamePathMapper.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -62,11 +62,6 @@ return jcrPath; } - @Override - public String getOakPathKeepIndex(String jcrPath) { - return jcrPath; - } - @Nonnull @Override public String getJcrPath(String oakPath) { \ No newline at end of file Index: oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImpl.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImpl.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -77,72 +77,6 @@ //---------------------------------------------------------< PathMapper >--- @Override public String getOakPath(String jcrPath) { - return getOakPath(jcrPath, false); - } - - @Override - public String getOakPathKeepIndex(String jcrPath) { - return getOakPath(jcrPath, true); - } - - - @Override - @Nonnull - public String getJcrPath(final String oakPath) { - if ("/".equals(oakPath)) { - // avoid the need to special case the root path later on - return "/"; - } else if (oakPath.isEmpty()) { - // empty path: map to "." - return "."; - } else if (nameMapper.getSessionLocalMappings().isEmpty()) { - // no local namespace mappings - return oakPath; - } - - PathListener listener = new PathListener() { - @Override - public boolean current() { - // nothing to do here - return false; - } - - @Override - public void error(String message) { - throw new IllegalArgumentException(message); - } - - @Override - public boolean name(String name, int index) { - String p = nameMapper.getJcrName(name); - if (index == 0) { - elements.add(p); - } else { - elements.add(p + '[' + index + ']'); - } - return true; - } - }; - - JcrPathParser.parse(oakPath, listener); - - StringBuilder jcrPath = new StringBuilder(); - for (String element : listener.elements) { - if (element.isEmpty()) { - // root - jcrPath.append('/'); - } - else { - jcrPath.append(element); - jcrPath.append('/'); - } - } - - jcrPath.deleteCharAt(jcrPath.length() - 1); - return jcrPath.toString(); - } - - private String getOakPath(final String jcrPath, final boolean keepIndex) { if (!needsFullMapping(jcrPath)) { return jcrPath; } @@ -172,19 +106,20 @@ @Override public boolean name(String name, int index) { - if (!keepIndex && index > 1) { - error("index > 1"); + if (index < 0) { + error("invalid index: " + index); return false; } - String p = nameMapper.getOakNameOrNull(name); - if (p == null) { + + String oakName = nameMapper.getOakNameOrNull(name); + if (oakName == null) { error("Invalid name: " + name); return false; } - if (keepIndex && index > 0) { - p += "[" + index + ']'; + if (index > 1) { + oakName += "[" + index + ']'; } - elements.add(p); + elements.add(oakName); return true; } }; @@ -216,6 +151,62 @@ // be considered here oakPath.deleteCharAt(oakPath.length() - 1); return oakPath.toString(); + } + + @Override + @Nonnull + public String getJcrPath(final String oakPath) { + if ("/".equals(oakPath)) { + // avoid the need to special case the root path later on + return "/"; + } else if (oakPath.isEmpty()) { + // empty path: map to "." + return "."; + } else if (nameMapper.getSessionLocalMappings().isEmpty()) { + // no local namespace mappings + return oakPath; + } + + PathListener listener = new PathListener() { + @Override + public boolean current() { + // nothing to do here + return false; + } + + @Override + public void error(String message) { + throw new IllegalArgumentException(message); + } + + @Override + public boolean name(String name, int index) { + String p = nameMapper.getJcrName(name); + if (index == 0) { + elements.add(p); + } else { + elements.add(p + '[' + index + ']'); + } + return true; + } + }; + + JcrPathParser.parse(oakPath, listener); + + StringBuilder jcrPath = new StringBuilder(); + for (String element : listener.elements) { + if (element.isEmpty()) { + // root + jcrPath.append('/'); + } + else { + jcrPath.append(element); + jcrPath.append('/'); + } + } + + jcrPath.deleteCharAt(jcrPath.length() - 1); + return jcrPath.toString(); } /** Index: oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/PathMapper.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/PathMapper.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/namepath/PathMapper.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -41,15 +41,6 @@ String getOakPath(String jcrPath); /** - * As {@link #getOakPath(String)}, but preserving the index information - * - * @param jcrPath JCR path - * @return mapped path, or {@code null} - */ - @CheckForNull - String getOakPathKeepIndex(String jcrPath); - - /** * Returns the JCR path for the given Oak path. The given path is * expected to have come from a valid Oak repository that contains * only valid paths whose name elements only use proper namespace Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImpl.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AuthorizablePropertiesImpl.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -302,7 +302,7 @@ if (relPath == null || relPath.isEmpty() || relPath.charAt(0) == '/') { throw new RepositoryException("Relative path expected. Found " + relPath); } - String oakPath = namePathMapper.getOakPathKeepIndex(relPath); + String oakPath = namePathMapper.getOakPath(relPath); if (oakPath == null) { throw new RepositoryException("Failed to resolve relative path: " + relPath); } Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -16,10 +16,13 @@ */ package org.apache.jackrabbit.oak.security.user; +import static com.google.common.base.Preconditions.checkNotNull; + import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.util.Iterator; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -57,8 +60,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static com.google.common.base.Preconditions.checkNotNull; - /** * UserManagerImpl... */ @@ -117,7 +118,7 @@ @Override public Authorizable getAuthorizableByPath(String path) throws RepositoryException { - String oakPath = namePathMapper.getOakPathKeepIndex(path); + String oakPath = namePathMapper.getOakPath(path); if (oakPath == null) { throw new RepositoryException("Invalid path " + path); } @@ -152,7 +153,7 @@ checkValidPrincipal(principal, false); if (intermediatePath != null) { - intermediatePath = namePathMapper.getOakPathKeepIndex(intermediatePath); + intermediatePath = namePathMapper.getOakPath(intermediatePath); } Tree userTree = userProvider.createUser(userID, intermediatePath); setPrincipal(userTree, principal); @@ -204,7 +205,7 @@ checkValidPrincipal(principal, true); if (intermediatePath != null) { - intermediatePath = namePathMapper.getOakPathKeepIndex(intermediatePath); + intermediatePath = namePathMapper.getOakPath(intermediatePath); } Tree groupTree = userProvider.createGroup(groupID, intermediatePath); setPrincipal(groupTree, principal); \ No newline at end of file Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlManager.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlManager.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/AbstractAccessControlManager.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -148,7 +148,7 @@ if (jcrPath == null) { return null; } else { - String oakPath = namePathMapper.getOakPathKeepIndex(jcrPath); + String oakPath = namePathMapper.getOakPath(jcrPath); if (oakPath == null || !PathUtils.isAbsolute(oakPath)) { throw new RepositoryException("Failed to resolve JCR path " + jcrPath); } Index: oak-core/src/test/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImplTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImplTest.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/namepath/NamePathMapperImplTest.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -16,21 +16,22 @@ */ package org.apache.jackrabbit.oak.namepath; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; + import javax.jcr.RepositoryException; import com.google.common.collect.ImmutableMap; import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - public class NamePathMapperImplTest { private static final Map GLOBAL = ImmutableMap.of( @@ -100,38 +101,14 @@ } @Test - public void testJcrToOakKeepIndex() { - assertEquals("/", npMapper.getOakPathKeepIndex("/")); - assertEquals("foo", npMapper.getOakPathKeepIndex("{}foo")); - assertEquals("/oak-foo:bar", npMapper.getOakPathKeepIndex("/foo:bar")); - assertEquals("/oak-foo:bar/oak-quu:qux", npMapper.getOakPathKeepIndex("/foo:bar/quu:qux")); - assertEquals("oak-foo:bar", npMapper.getOakPathKeepIndex("foo:bar")); - assertEquals("oak-nt:unstructured", npMapper.getOakPathKeepIndex("{http://www.jcp.org/jcr/nt/1.0}unstructured")); - assertEquals("foobar/oak-jcr:content", npMapper.getOakPathKeepIndex("foobar/{http://www.jcp.org/jcr/1.0}content")); - assertEquals("foobar", npMapper.getOakPathKeepIndex("foobar/{http://www.jcp.org/jcr/1.0}content/..")); - assertEquals("", npMapper.getOakPathKeepIndex("foobar/{http://www.jcp.org/jcr/1.0}content/../..")); - assertEquals("..", npMapper.getOakPathKeepIndex("foobar/{http://www.jcp.org/jcr/1.0}content/../../..")); - assertEquals("../..", npMapper.getOakPathKeepIndex("foobar/{http://www.jcp.org/jcr/1.0}content/../../../..")); - assertEquals("oak-jcr:content", npMapper.getOakPathKeepIndex("foobar/../{http://www.jcp.org/jcr/1.0}content")); - assertEquals("../oak-jcr:content", npMapper.getOakPathKeepIndex("foobar/../../{http://www.jcp.org/jcr/1.0}content")); - assertEquals("..", npMapper.getOakPathKeepIndex("..")); - assertEquals("", npMapper.getOakPathKeepIndex(".")); - assertEquals("foobar/oak-jcr:content", npMapper.getOakPathKeepIndex("foobar/{http://www.jcp.org/jcr/1.0}content/.")); - assertEquals("foobar/oak-jcr:content", npMapper.getOakPathKeepIndex("foobar/{http://www.jcp.org/jcr/1.0}content/./.")); - assertEquals("foobar/oak-jcr:content", npMapper.getOakPathKeepIndex("foobar/./{http://www.jcp.org/jcr/1.0}content")); - assertEquals("oak-jcr:content", npMapper.getOakPathKeepIndex("foobar/./../{http://www.jcp.org/jcr/1.0}content")); - assertEquals("/a/b[1]/c[1]", npMapper.getOakPathKeepIndex("/a/b[1]/c[01]")); - } - - @Test public void testJcrToOakKeepIndexNoRemap() { NameMapper mapper = new GlobalNameMapper(GLOBAL); NamePathMapper npMapper = new NamePathMapperImpl(mapper); - assertEquals("/", npMapper.getOakPathKeepIndex("/")); - assertEquals("/foo:bar", npMapper.getOakPathKeepIndex("/foo:bar")); - assertEquals("/foo:bar/quu:qux", npMapper.getOakPathKeepIndex("/foo:bar/quu:qux")); - assertEquals("foo:bar", npMapper.getOakPathKeepIndex("foo:bar")); + assertEquals("/", npMapper.getOakPath("/")); + assertEquals("/foo:bar", npMapper.getOakPath("/foo:bar")); + assertEquals("/foo:bar/quu:qux", npMapper.getOakPath("/foo:bar/quu:qux")); + assertEquals("foo:bar", npMapper.getOakPath("foo:bar")); } @Test Index: oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ACLTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ACLTest.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/ACLTest.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -16,6 +16,13 @@ */ package org.apache.jackrabbit.oak.security.authorization.accesscontrol; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.security.Principal; import java.security.acl.Group; import java.util.ArrayList; @@ -25,6 +32,7 @@ import java.util.List; import java.util.Map; import java.util.Set; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.jcr.PropertyType; @@ -62,13 +70,6 @@ import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - /** * Test abstract {@code ACL} implementation. */ @@ -99,7 +100,7 @@ @Nonnull List entries, @Nonnull NamePathMapper namePathMapper, final @Nonnull RestrictionProvider restrictionProvider) { - String path = (jcrPath == null) ? null : namePathMapper.getOakPathKeepIndex(jcrPath); + String path = (jcrPath == null) ? null : namePathMapper.getOakPath(jcrPath); return new ACL(path, entries, namePathMapper) { @Override public RestrictionProvider getRestrictionProvider() { \ No newline at end of file Index: oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ImmutableACLTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ImmutableACLTest.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authorization/accesscontrol/ImmutableACLTest.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -16,10 +16,16 @@ */ package org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.security.Principal; import java.util.ArrayList; import java.util.Collections; import java.util.List; + import javax.jcr.Value; import javax.jcr.security.AccessControlEntry; import javax.jcr.security.AccessControlException; @@ -28,16 +34,11 @@ import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry; import org.apache.jackrabbit.api.security.JackrabbitAccessControlList; import org.apache.jackrabbit.oak.namepath.NamePathMapper; -import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants; import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider; +import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - /** * Test for {@code ImmutableACL} */ @@ -58,7 +59,7 @@ @Override protected ImmutableACL createACL(String jcrPath, List entries, NamePathMapper namePathMapper, RestrictionProvider restrictionProvider) { - String oakPath = (jcrPath == null) ? null : namePathMapper.getOakPathKeepIndex(jcrPath); + String oakPath = (jcrPath == null) ? null : namePathMapper.getOakPath(jcrPath); return new ImmutableACL(oakPath, entries, restrictionProvider, namePathMapper); } \ No newline at end of file Index: oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -25,6 +25,7 @@ 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.NAMES; +import static org.apache.jackrabbit.oak.jcr.session.SessionImpl.checkIndexOnName; import static org.apache.jackrabbit.oak.util.TreeUtil.getNames; import java.io.InputStream; @@ -249,7 +250,7 @@ oakTypeName = null; } - SessionImpl.checkIndexOnName(sessionContext, relPath); + checkIndexOnName(relPath); return perform(new ItemWriteOperation("addNode") { @Override public Node perform() throws RepositoryException { Index: oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionContext.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -16,12 +16,17 @@ */ package org.apache.jackrabbit.oak.jcr.session; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Sets.newHashSet; +import static com.google.common.collect.Sets.newTreeSet; + import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.jcr.PathNotFoundException; @@ -66,10 +71,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.Sets.newHashSet; -import static com.google.common.collect.Sets.newTreeSet; - /** * Instances of this class are passed to all JCR implementation classes * (e.g. {@code SessionImpl}, {@code NodeImpl}, etc.) and provide access to @@ -306,12 +307,6 @@ } @Override - @CheckForNull - public String getOakPathKeepIndex(String jcrPath) { - return namePathMapper.getOakPathKeepIndex(jcrPath); - } - - @Override @Nonnull public String getJcrPath(String oakPath) { return namePathMapper.getJcrPath(oakPath); @@ -331,13 +326,7 @@ if (oakPath != null) { return oakPath; } else { - // check if the path is an SNS path with an index > 1 and throw a PathNotFoundException instead (see OAK-1216) - if (getOakPathKeepIndex(jcrPath) != null) { - throw new PathNotFoundException(jcrPath); - } else { - throw new RepositoryException("Invalid name or path: " + jcrPath); + throw new RepositoryException("Invalid name or path: " + jcrPath); - } - } } Index: oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -91,14 +91,26 @@ sessionContext.getCounter(Type.SESSION_LOGIN_COUNTER).incrementAndGet(); } - static void checkIndexOnName(SessionContext sessionContext, String path) throws RepositoryException { - String oakPath = sessionContext.getOakPathKeepIndex(path); - if (oakPath != null) { - if (PathUtils.getName(oakPath).contains("[")) { + static void checkIndexOnName(String jcrPath) throws RepositoryException { + int pos = jcrPath.length() - 1; + if (pos < 2 || jcrPath.charAt(pos) != ']') { + return; + } + + if ("0123456789".indexOf(jcrPath.charAt(--pos)) == -1) { + return; + } + + while (--pos >= 0) { + char ch = jcrPath.charAt(pos); + if (ch == '[') { throw new RepositoryException("Cannot create a new node using a name including an index"); } + if ("0123456789".indexOf(ch) == -1) { + return; - } - } + } + } + } private abstract class ReadOperation extends SessionOperation { protected ReadOperation(String name) { @@ -368,7 +380,7 @@ @Override public void move(String srcAbsPath, final String destAbsPath) throws RepositoryException { - checkIndexOnName(sessionContext, destAbsPath); + checkIndexOnName(destAbsPath); final String srcOakPath = getOakPathOrThrowNotFound(srcAbsPath); final String destOakPath = getOakPathOrThrowNotFound(destAbsPath); sd.perform(new WriteOperation("move") { Index: oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -17,6 +17,7 @@ package org.apache.jackrabbit.oak.jcr.session; import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath; +import static org.apache.jackrabbit.oak.jcr.session.SessionImpl.checkIndexOnName; import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.NODE_TYPES_PATH; import java.io.IOException; @@ -149,7 +150,7 @@ sessionDelegate.checkProtectedNode(getParentPath(srcOakPath)); sessionDelegate.checkProtectedNode(getParentPath(destOakPath)); - SessionImpl.checkIndexOnName(sessionContext, destAbsPath); + checkIndexOnName(destAbsPath); workspaceDelegate.copy(srcOakPath, destOakPath); return null; @@ -189,7 +190,7 @@ sessionDelegate.checkProtectedNode(getParentPath(srcOakPath)); sessionDelegate.checkProtectedNode(getParentPath(destOakPath)); - SessionImpl.checkIndexOnName(sessionContext, destAbsPath); + checkIndexOnName(destAbsPath); sessionDelegate.move(srcOakPath, destOakPath, false); } Index: oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/ImporterImpl.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/ImporterImpl.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/ImporterImpl.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -132,7 +132,7 @@ Root root, int uuidBehavior, boolean isWorkspaceImport) throws RepositoryException { - String oakPath = sessionContext.getOakPathKeepIndex(absPath); + String oakPath = sessionContext.getOakPath(absPath); if (oakPath == null) { throw new RepositoryException("Invalid name or path: " + absPath); } Index: oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/AbstractRepositoryTest.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -102,14 +102,18 @@ } } - protected Repository getRepository() { + protected Repository getRepository() throws RepositoryException { if (repository == null) { - nodeStore = fixture.createNodeStore(); + nodeStore = createNodeStore(fixture); repository = new Jcr(nodeStore) .withObservationQueueLength(observationQueueLength) .createRepository(); } return repository; + } + + protected NodeStore createNodeStore(NodeStoreFixture fixture) throws RepositoryException { + return fixture.createNodeStore(); } protected Session getAdminSession() throws RepositoryException { Index: oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNameSiblingTest.java =================================================================== --- oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNameSiblingTest.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) +++ oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/SameNameSiblingTest.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.jackrabbit.oak.jcr; + +import static com.google.common.collect.Lists.asList; +import static com.google.common.collect.Sets.newHashSet; +import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE; +import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED; +import static org.apache.jackrabbit.oak.api.Type.NAME; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Set; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.jackrabbit.api.JackrabbitNode; +import org.apache.jackrabbit.oak.api.CommitFailedException; +import org.apache.jackrabbit.oak.spi.commit.CommitInfo; +import org.apache.jackrabbit.oak.spi.commit.EmptyHook; +import org.apache.jackrabbit.oak.spi.state.NodeBuilder; +import org.apache.jackrabbit.oak.spi.state.NodeStore; +import org.junit.Before; +import org.junit.Test; + +public class SameNameSiblingTest extends AbstractRepositoryTest { + private static final String SIBLING = "sibling"; + + private static final String[] SIBLINGS = new String[] { + SIBLING + "[1]", SIBLING+ "[2]", SIBLING + "[3]", SIBLING + "[4]"}; + + private Session session; + private Node sns; + + public SameNameSiblingTest(NodeStoreFixture fixture) { + super(fixture); + } + + @Before + public void setup() throws RepositoryException { + session = getAdminSession(); + sns = session.getNode("/sns"); + } + + @Override + protected NodeStore createNodeStore(NodeStoreFixture fixture) throws RepositoryException { + try { + NodeStore nodeStore = super.createNodeStore(fixture); + + NodeBuilder root = nodeStore.getRoot().builder(); + NodeBuilder sns = root.setChildNode("sns"); + sns.setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED, NAME); + for (String sibling : asList(SIBLING, SIBLINGS)) { + if (!sibling.endsWith("[1]")) { + sns.setChildNode(sibling).setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED, NAME); + } + } + nodeStore.merge(root, EmptyHook.INSTANCE, CommitInfo.EMPTY); + return nodeStore; + } catch (CommitFailedException e) { + throw new RepositoryException(e); + } + } + + @Test + public void iterateSiblings() throws RepositoryException { + Set expected = newHashSet(SIBLINGS); + expected.add(SIBLING); + expected.remove(SIBLINGS[0]); + + NodeIterator siblings = sns.getNodes(); + while (siblings.hasNext()) { + Node sib = siblings.nextNode(); + assertTrue("Unexpected node: " + sib.getPath(), expected.remove(sib.getName())); + } + + assertTrue("Missing nodes: " + expected, expected.isEmpty()); + } + + @Test + public void getSiblings() throws RepositoryException { + for (String name : asList(SIBLING, SIBLINGS)) { + assertTrue(sns.hasNode(name)); + Node sib = sns.getNode(name); + session.getNode(sns.getPath() + '/' + name); + } + } + + @Test + public void modifySiblings() throws RepositoryException { + for (String name : SIBLINGS) { + Node sib = sns.getNode(name); + sib.addNode("node"); + sib.setProperty("prop", 42); + } + session.save(); + + for (String name : asList(SIBLING, SIBLINGS)) { + Node sib = sns.getNode(name); + assertTrue(sib.hasNode("node")); + assertEquals(42L, sib.getProperty("prop").getLong()); + } + } + + private static String rename(String name) { + return name.replace('[', '_').replace(']', '_'); + } + + @Test + public void moveSiblings() throws RepositoryException { + Node target = session.getRootNode().addNode("target"); + session.save(); + + for (String name : SIBLINGS) { + session.move(sns.getPath() + '/' + name, target.getPath() + '/' + rename(name)); + } + session.save(); + + for (String name : SIBLINGS) { + assertFalse(sns.hasNode(name)); + assertTrue(target.hasNode(rename(name))); + } + } + + @Test + public void renameSiblings() throws RepositoryException { + for (String name : SIBLINGS) { + JackrabbitNode sib = (JackrabbitNode) sns.getNode(name); + sib.rename(rename(name)); + } + session.save(); + + for (String name : SIBLINGS) { + assertFalse(sns.hasNode(name)); + assertTrue(sns.hasNode(rename(name))); + } + } +} Index: oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgradeTest.java IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgradeTest.java (revision 290bd149384ff8d58092481864902f1e01448bc8) +++ oak-upgrade/src/test/java/org/apache/jackrabbit/oak/upgrade/RepositoryUpgradeTest.java (revision d1110eb0b1b4f17bd0d2bb780afafa2d322726d5) @@ -68,6 +68,7 @@ import javax.jcr.Binary; import javax.jcr.NamespaceRegistry; import javax.jcr.Node; +import javax.jcr.NodeIterator; import javax.jcr.Property; import javax.jcr.PropertyIterator; import javax.jcr.PropertyType; @@ -86,6 +87,7 @@ import javax.jcr.version.VersionManager; import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import org.apache.jackrabbit.api.JackrabbitSession; import org.apache.jackrabbit.api.JackrabbitWorkspace; import org.apache.jackrabbit.api.security.authorization.PrivilegeManager; @@ -157,6 +159,11 @@ child.addNode("child2", NT_UNSTRUCTURED); session.save(); + Node sns = root.addNode("sns"); + sns.addNode("sibling"); + sns.addNode("sibling"); + sns.addNode("sibling"); + session.getWorkspace().getVersionManager().checkin("/versionable"); Node properties = root.addNode("properties", "test:unstructured"); @@ -541,6 +548,25 @@ assertTrue(history.isNodeType("rep:VersionablePaths")); Property versionablePath = history.getProperty("default"); assertEquals("/versionable", versionablePath.getString()); + } finally { + session.logout(); + } + } + + @Test + public void verifySNS() throws RepositoryException { + Set nodeNames = Sets.newHashSet("sibling", "sibling[2]", "sibling[3]"); + Session session = createAdminSession(); + try { + Node sns = session.getNode("/sns"); + NodeIterator ns = sns.getNodes(); + int c = 0; + while (ns.hasNext()) { + Node node = ns.nextNode(); + String name = node.getName(); + assertTrue("Unexpected node: " + name, nodeNames.remove(name)); + } + assertTrue("Missing nodes: " + nodeNames, nodeNames.isEmpty()); } finally { session.logout(); }