Index: modeshape-graph/src/main/java/org/modeshape/graph/GraphI18n.java =================================================================== --- modeshape-graph/src/main/java/org/modeshape/graph/GraphI18n.java (revision 1895) +++ modeshape-graph/src/main/java/org/modeshape/graph/GraphI18n.java (working copy) @@ -60,6 +60,7 @@ public final class GraphI18n { public static I18n unableToDiscoverPropertyTypeForNullValue; public static I18n unableToObtainValidRepositoryAfterAttempts; public static I18n validPathMayNotContainEmptySegment; + public static I18n missingClosingBrace; public static I18n valueJavaTypeNotCompatibleWithPropertyType; public static I18n pathExpressionMayNotBeBlank; public static I18n pathExpressionIsInvalid; Index: modeshape-graph/src/main/java/org/modeshape/graph/property/basic/IdentifierPath.java =================================================================== --- modeshape-graph/src/main/java/org/modeshape/graph/property/basic/IdentifierPath.java (revision 1895) +++ modeshape-graph/src/main/java/org/modeshape/graph/property/basic/IdentifierPath.java (working copy) @@ -202,7 +202,7 @@ public class IdentifierPath extends AbstractPath { */ @Override public String getString() { - return Path.DELIMITER_STR; + return idSegment.getString(); } /** @@ -212,7 +212,7 @@ public class IdentifierPath extends AbstractPath { */ @Override public String getString( TextEncoder encoder ) { - return Path.DELIMITER_STR; + return idSegment.getString(encoder); } /** @@ -223,7 +223,7 @@ public class IdentifierPath extends AbstractPath { @Override public String getString( NamespaceRegistry namespaceRegistry ) { CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry"); - return Path.DELIMITER_STR; + return idSegment.getString(namespaceRegistry); } /** @@ -236,7 +236,7 @@ public class IdentifierPath extends AbstractPath { public String getString( NamespaceRegistry namespaceRegistry, TextEncoder encoder ) { CheckArg.isNotNull(namespaceRegistry, "namespaceRegistry"); - return Path.DELIMITER_STR; + return idSegment.getString(namespaceRegistry, encoder); } /** @@ -249,7 +249,8 @@ public class IdentifierPath extends AbstractPath { public String getString( NamespaceRegistry namespaceRegistry, TextEncoder encoder, TextEncoder delimiterEncoder ) { - return (delimiterEncoder == null) ? DELIMITER_STR : delimiterEncoder.encode(DELIMITER_STR); + return (delimiterEncoder == null) ? getString(namespaceRegistry, encoder) : delimiterEncoder.encode(getString(namespaceRegistry, + encoder)); } /** Index: modeshape-graph/src/main/java/org/modeshape/graph/property/basic/LocalNamespaceRegistry.java =================================================================== --- modeshape-graph/src/main/java/org/modeshape/graph/property/basic/LocalNamespaceRegistry.java (revision 1895) +++ modeshape-graph/src/main/java/org/modeshape/graph/property/basic/LocalNamespaceRegistry.java (working copy) @@ -83,7 +83,13 @@ public class LocalNamespaceRegistry extends SimpleNamespaceRegistry { @Override public String getNamespaceForPrefix( String prefix ) { String result = super.getNamespaceForPrefix(prefix); - if (result == null) result = this.delegate.getNamespaceForPrefix(prefix); + if (result == null) { + result = this.delegate.getNamespaceForPrefix(prefix); + // Catch if this namespace was remapped + if (result != null && super.getPrefixForNamespaceUri(result, false) != null) { + return null; + } + } return result; } @@ -133,7 +139,15 @@ public class LocalNamespaceRegistry extends SimpleNamespaceRegistry { public String getPrefixForNamespaceUri( String namespaceUri, boolean generateIfMissing ) { String result = super.getPrefixForNamespaceUri(namespaceUri, false); - if (result == null) result = this.delegate.getPrefixForNamespaceUri(namespaceUri, false); + if (result == null) { + result = this.delegate.getPrefixForNamespaceUri(namespaceUri, false); + if (result != null) { + // This was remapped at the session layer + if (!this.getNamespaceForPrefix(result).equals(namespaceUri)) { + result = null; + } + } + } if (result == null && generateIfMissing) result = super.getPrefixForNamespaceUri(namespaceUri, true); return result; } Index: modeshape-graph/src/main/java/org/modeshape/graph/property/basic/PathValueFactory.java =================================================================== --- modeshape-graph/src/main/java/org/modeshape/graph/property/basic/PathValueFactory.java (revision 1895) +++ modeshape-graph/src/main/java/org/modeshape/graph/property/basic/PathValueFactory.java (working copy) @@ -160,7 +160,8 @@ public class PathValueFactory extends AbstractValueFactory implements Path // Parse the path into its segments ... List segments = new ArrayList(); - String[] pathSegments = DELIMITER_PATTERN.split(trimmedValue); + // String[] pathSegments = DELIMITER_PATTERN.split(trimmedValue); + String[] pathSegments = splitPath(trimmedValue); if (pathSegments.length == 0) { throw new ValueFormatException(value, getPropertyType(), GraphI18n.validPathMayNotContainEmptySegment.text(value)); } @@ -185,6 +186,45 @@ public class PathValueFactory extends AbstractValueFactory implements Path return new BasicPath(segments, absolute); } + String[] splitPath( String rawPath ) { + List segments = new LinkedList(); + + int curr = 0; + int nextBrace = rawPath.indexOf('{'); + int nextSlash = rawPath.indexOf('/'); + + while (true) { + // Next brace comes before next slash + if ((nextSlash == -1 && nextBrace > -1) || (nextBrace > -1 && nextBrace < nextSlash)) { + int nextClosingBrace = rawPath.indexOf('}', nextBrace); + + if (nextClosingBrace == -1) { + throw new ValueFormatException(rawPath, getPropertyType(), GraphI18n.missingClosingBrace.text(rawPath)); + } + + // Move the next checks past the end of the braced section, but don't add to the result set yet + nextSlash = rawPath.indexOf('/', nextClosingBrace + 1); + nextBrace = rawPath.indexOf('{', nextClosingBrace + 1); + } + // Next slash comes before next brace + else if ((nextBrace == -1 && nextSlash > -1) || (nextSlash > -1 && nextSlash < nextBrace)) { + if (nextSlash > 0) { + // Don't add an empty string from the beginning of an absolute path + segments.add(rawPath.substring(curr, nextSlash)); + } + + curr = nextSlash + 1; + + nextSlash = rawPath.indexOf('/', curr); + } + // No more slashes or braces + else { + segments.add(rawPath.substring(curr)); + return segments.toArray(new String[segments.size()]); + } + } + } + /** * {@inheritDoc} */ Index: modeshape-graph/src/main/resources/org/modeshape/graph/GraphI18n.properties =================================================================== --- modeshape-graph/src/main/resources/org/modeshape/graph/GraphI18n.properties (revision 1895) +++ modeshape-graph/src/main/resources/org/modeshape/graph/GraphI18n.properties (working copy) @@ -48,6 +48,7 @@ unableToCreateValue = Unable to create {0} value from {1} "{2}": undefined type unableToDiscoverPropertyTypeForNullValue = Unable to discover property type for null value unableToObtainValidRepositoryAfterAttempts = Unable to obtain a valid repository after {0} attempts validPathMayNotContainEmptySegment = The path "{0}" is not valid because it contains an empty segment +missingClosingBrace = The path "{0}" is not valid because it is missing a closing brace ("}") valueJavaTypeNotCompatibleWithPropertyType = Value is instance of Java type "{0}" and is not compatible with the "{1}" property type pathExpressionMayNotBeBlank = The path expression may not be blank pathExpressionIsInvalid = The path expression {0} is not valid Index: modeshape-graph/src/test/java/org/modeshape/graph/property/basic/PathValueFactoryTest.java =================================================================== --- modeshape-graph/src/test/java/org/modeshape/graph/property/basic/PathValueFactoryTest.java (revision 1895) +++ modeshape-graph/src/test/java/org/modeshape/graph/property/basic/PathValueFactoryTest.java (working copy) @@ -24,17 +24,18 @@ package org.modeshape.graph.property.basic; import static org.hamcrest.core.Is.is; -import static org.modeshape.graph.property.basic.IsPathContaining.hasSegments; import static org.junit.Assert.assertThat; +import static org.modeshape.graph.property.basic.IsPathContaining.hasSegments; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import org.junit.Before; +import org.junit.Test; import org.modeshape.common.text.TextEncoder; import org.modeshape.graph.property.Name; import org.modeshape.graph.property.Path; import org.modeshape.graph.property.ValueFactory; -import org.junit.Before; -import org.junit.Test; +import org.modeshape.graph.property.ValueFormatException; /** * @author Randall Hauch @@ -132,4 +133,24 @@ public class PathValueFactoryTest { } } + @Test + public void shouldSplitPathWithExpandedNamespace() { + String[] splits = factory.splitPath("/{http://www.jcp.org/jcr/1.0}foo/bar/{blah}baz"); + String[] correctSplits = new String[] {"{http://www.jcp.org/jcr/1.0}foo", "bar", "{blah}baz"}; + + assertThat(splits, is(correctSplits)); + } + + @Test + public void shouldSplitPathWithoutExpandedNamespace() { + String[] splits = factory.splitPath("/jcr:foo/bar/blah:baz"); + String[] correctSplits = new String[] {"jcr:foo", "bar", "blah:baz"}; + + assertThat(splits, is(correctSplits)); + } + + @Test( expected = ValueFormatException.class ) + public void shouldThrowValueFormatExceptionOnMalformedName() { + factory.splitPath("/jcr:foo/{foobar"); + } } Index: modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java =================================================================== --- modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java (revision 1895) +++ modeshape-jcr/src/main/java/org/modeshape/jcr/JcrSession.java (working copy) @@ -172,7 +172,7 @@ class JcrSession implements Session { // Create an execution context for this session, which should use the local namespace registry ... this.executionContext = sessionContext; NamespaceRegistry local = sessionContext.getNamespaceRegistry(); - this.sessionRegistry = new JcrNamespaceRegistry(Behavior.JSR170_SESSION, local, globalNamespaceRegistry, this); + this.sessionRegistry = new JcrNamespaceRegistry(Behavior.JSR283_SESSION, local, globalNamespaceRegistry, this); this.rootPath = this.executionContext.getValueFactories().getPathFactory().createRootPath(); // Set up the graph to use for this session (which uses the session's namespace registry and context) ... @@ -680,7 +680,7 @@ class JcrSession implements Session { public AbstractJcrProperty getProperty( String absolutePath ) throws PathNotFoundException, RepositoryException { CheckArg.isNotEmpty(absolutePath, "absolutePath"); // Return root node if path is "/" - Path path = executionContext.getValueFactories().getPathFactory().create(absolutePath); + Path path = pathFor(absolutePath, "absolutePath"); if (path.isRoot()) { throw new PathNotFoundException(JcrI18n.rootNodeIsNotProperty.text()); } @@ -715,7 +715,7 @@ class JcrSession implements Session { public boolean propertyExists( String absolutePath ) throws RepositoryException { CheckArg.isNotEmpty(absolutePath, "absolutePath"); // Return root node if path is "/" - Path path = executionContext.getValueFactories().getPathFactory().create(absolutePath); + Path path = pathFor(absolutePath, "absolutePath"); if (path.isRoot() || path.isIdentifier()) { return false; } Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrPropertyDefinitionTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/JcrPropertyDefinitionTest.java (revision 1895) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrPropertyDefinitionTest.java (working copy) @@ -418,7 +418,7 @@ public class JcrPropertyDefinitionTest extends AbstractSessionTest { // Test that old names fail after namespace remaps session.setNamespacePrefix("newprefix", TestLexicon.Namespace.URI); - assertThat(prop.satisfiesConstraints(valueFor("modetest:constrainedType", PropertyType.NAME)), is(true)); + assertThat(prop.satisfiesConstraints(valueFor("modetest:constrainedType", PropertyType.NAME)), is(false)); } @Test Index: modeshape-jcr/src/test/java/org/modeshape/jcr/JcrTckTest.java =================================================================== --- modeshape-jcr/src/test/java/org/modeshape/jcr/JcrTckTest.java (revision 1895) +++ modeshape-jcr/src/test/java/org/modeshape/jcr/JcrTckTest.java (working copy) @@ -44,6 +44,7 @@ import org.apache.jackrabbit.test.api.NamePropertyTest; import org.apache.jackrabbit.test.api.NameTest; import org.apache.jackrabbit.test.api.NamespaceRegistryReadMethodsTest; import org.apache.jackrabbit.test.api.NamespaceRegistryTest; +import org.apache.jackrabbit.test.api.NamespaceRemappingTest; import org.apache.jackrabbit.test.api.NodeAddMixinTest; import org.apache.jackrabbit.test.api.NodeCanAddMixinTest; import org.apache.jackrabbit.test.api.NodeDiscoveringNodeTypesTest; @@ -57,6 +58,7 @@ import org.apache.jackrabbit.test.api.NodeSetPrimaryTypeTest; import org.apache.jackrabbit.test.api.NodeTest; import org.apache.jackrabbit.test.api.NodeUUIDTest; import org.apache.jackrabbit.test.api.PathPropertyTest; +import org.apache.jackrabbit.test.api.PathTest; import org.apache.jackrabbit.test.api.PropertyItemIsModifiedTest; import org.apache.jackrabbit.test.api.PropertyItemIsNewTest; import org.apache.jackrabbit.test.api.PropertyReadMethodsTest; @@ -238,11 +240,12 @@ public class JcrTckTest { // return new JCRTestSuite(); // Or uncomment the following lines to execute the different sets/suites of tests ... - TestSuite suite = new TestSuite("JCR 1.0 API tests"); + TestSuite suite = new TestSuite("JCR 2.0 API tests"); suite.addTest(levelOneSuite()); - suite.addTest(levelTwoSuite()); - suite.addTest(new OptionalFeatureTests()); + // suite.addTest(levelTwoSuite()); + // suite.addTest(new OptionalFeatureTests()); + return suite; } @@ -281,7 +284,7 @@ public class JcrTckTest { suite.addTestSuite(UndefinedPropertyTest.class); suite.addTestSuite(NamespaceRegistryReadMethodsTest.class); - // suite.addTestSuite(NamespaceRemappingTest.class); + suite.addTestSuite(NamespaceRemappingTest.class); suite.addTestSuite(NodeIteratorTest.class); suite.addTestSuite(PropertyReadMethodsTest.class); suite.addTestSuite(RepositoryDescriptorTest.class); @@ -292,8 +295,6 @@ public class JcrTckTest { suite.addTestSuite(ExportSysViewTest.class); suite.addTestSuite(ExportDocViewTest.class); - // suite.addTestSuite(PathTest.class); - // The tests in this suite are level one // suite.addTest(org.apache.jackrabbit.test.api.nodetype.TestAll.suite()); @@ -378,8 +379,9 @@ public class JcrTckTest { suite.addTestSuite(NodeSetPrimaryTypeTest.class); - // This isn't marked as read-only, so it causes problems if you put it with the L1 tests + // These two tests aren't marked as read-only, so they causes problems for read-only connectors with the L1 tests suite.addTestSuite(NameTest.class); + suite.addTestSuite(PathTest.class); suite.addTestSuite(WorkspaceCloneReferenceableTest.class); suite.addTestSuite(WorkspaceCloneSameNameSibsTest.class); Index: modeshape-repository/src/main/java/org/modeshape/repository/sequencer/StreamSequencerAdapter.java =================================================================== --- modeshape-repository/src/main/java/org/modeshape/repository/sequencer/StreamSequencerAdapter.java (revision 1895) +++ modeshape-repository/src/main/java/org/modeshape/repository/sequencer/StreamSequencerAdapter.java (working copy) @@ -312,7 +312,7 @@ public class StreamSequencerAdapter implements Sequencer { ValueFactories factories = context.getExecutionContext().getValueFactories(); Path path = factories.getPathFactory().create(input.getLocation().getPath()); - Set props = Collections.unmodifiableSet(input.getPropertiesByName().values()); + Set props = Collections.unmodifiableSet(input.getPropertiesByName().values()); Name fileName = path.getLastSegment().getName(); if (JcrLexicon.CONTENT.equals(fileName) && !path.isRoot()) { // We're actually sequencing the "jcr:content" child node of an "nt:file" node, but the name of Index: web/modeshape-web-jcr-rest-war/src/main/resources/configRepository.xml =================================================================== --- web/modeshape-web-jcr-rest-war/src/main/resources/configRepository.xml (revision 1895) +++ web/modeshape-web-jcr-rest-war/src/main/resources/configRepository.xml (working copy) @@ -35,13 +35,13 @@ repositorySource - - + + - + - + Index: web/modeshape-web-jcr-webdav-war/src/main/resources/configRepository.xml =================================================================== --- web/modeshape-web-jcr-webdav-war/src/main/resources/configRepository.xml (revision 1895) +++ web/modeshape-web-jcr-webdav-war/src/main/resources/configRepository.xml (working copy) @@ -35,13 +35,13 @@ repositorySource - - + + - + - + Index: web/modeshape-web-jcr-webdav/pom.xml =================================================================== --- web/modeshape-web-jcr-webdav/pom.xml (revision 1895) +++ web/modeshape-web-jcr-webdav/pom.xml (working copy) @@ -32,11 +32,6 @@ - javax.jcr - jcr - - - org.slf4j slf4j-log4j12 runtime Index: web/modeshape-web-jcr-webdav/src/test/resources/configRepository.xml =================================================================== --- web/modeshape-web-jcr-webdav/src/test/resources/configRepository.xml (revision 1895) +++ web/modeshape-web-jcr-webdav/src/test/resources/configRepository.xml (working copy) @@ -35,13 +35,13 @@ repositorySource - - + + - + - +