diff --git a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/SystemViewTest.java b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/SystemViewTest.java index d36968654c1..c72dceff07c 100644 --- a/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/SystemViewTest.java +++ b/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/xml/SystemViewTest.java @@ -19,21 +19,32 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import javax.jcr.ImportUUIDBehavior; import javax.jcr.ItemExistsException; +import javax.jcr.NamespaceException; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; import javax.jcr.RepositoryException; import javax.jcr.nodetype.NodeDefinition; import javax.jcr.nodetype.NodeType; import javax.jcr.nodetype.NodeTypeManager; +import junit.framework.TestResult; +import org.junit.Before; + +import org.apache.jackrabbit.core.NamespaceRegistryImpl; +import org.apache.jackrabbit.core.RepositoryImpl; import org.apache.jackrabbit.core.SessionImpl; import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException; import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry; import org.apache.jackrabbit.core.nodetype.xml.NodeTypeReader; import org.apache.jackrabbit.spi.QNodeTypeDefinition; import org.apache.jackrabbit.test.AbstractJCRTest; +import org.apache.jackrabbit.test.JCRTestResult; /** * Jackrabbit-specific test cases for the system view XML format. @@ -42,6 +53,20 @@ public class SystemViewTest extends AbstractJCRTest { private static final String TEST_NODETYPES = "org/apache/jackrabbit/core/nodetype/xml/test_nodetypes.xml"; + private static final String EXPANDED_NAMES_IMPORT_TEST_ROOT = "expandedNamesImportTestRoot"; + private static final String NID_REGISTERED = "nsRegistered"; + private static final String NID_UNREGISTERED = "nsUnregistered"; + private static final String PREFIX_REGISTERED = "prefixRegistered"; + private static final String PREFIX_XML_DEFINED = "prefixXmlDefined"; + private static final String LOCAL_NODE_NAME_XML_DEFINED = "nodeXmlDefined"; + private static final String LOCAL_PROP_NAME_XML_DEFINED = "propXmlDefined"; + + @Before + private void before() throws RepositoryException { + superuser.getWorkspace().getNamespaceRegistry().registerNamespace(PREFIX_REGISTERED, "urn:" + NID_REGISTERED); + superuser.getWorkspace().getNamespaceRegistry().registerNamespace(PREFIX_XML_DEFINED, "urn:otherRegisteredNS"); + } + private String createCollidingNodeXml(String id) { return " \n" + " \n" + @@ -108,4 +133,216 @@ private void importTestNodeTypes() throws IOException, InvalidNodeTypeDefExcepti } assertTrue(TEST_NODETYPES + " has changed? Expected child node def 'test:defaultTypeNode' with sameNameSiblings=false", foundRequiredDef); } + + // The parameter testIndex is needed to avoid side effects between test cases, + // because Jackrabbit doesn't support unregistering namespaces. + private static String createXmlWithExpandedName(String nid, boolean definePrefix, int testIndex) { + return "" + + "" + + "" + + "true" + + "" + + "" + + ""; + } + + // Expanded names in content, prefix defined in XML but not yet registered, namespace not yet registered + // Expectation: prefix and namespace URI from XML will be used + // OAK-9586 + public void testExpandedNameImportWithPrefixDefinition() throws Exception { + final int testindex = 0; + String prefix = null; + String xml = createXmlWithExpandedName(NID_UNREGISTERED, true, testindex); + try (InputStream input = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) { + superuser.importXML( + "/", input, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); + NodeIterator nodes = superuser.getRootNode().getNode(EXPANDED_NAMES_IMPORT_TEST_ROOT).getNodes(); + assertTrue(nodes.hasNext()); + Node node = nodes.nextNode(); + + prefix = superuser.getNamespacePrefix("urn:" + NID_UNREGISTERED + testindex); + assertEquals(PREFIX_XML_DEFINED + testindex, prefix); + String name = node.getName(); + assertEquals(PREFIX_XML_DEFINED + testindex + ":" + LOCAL_NODE_NAME_XML_DEFINED, name); + Property p = node.getProperty("{urn:" + NID_UNREGISTERED + testindex + "}" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(p); + Property q = node.getProperty(PREFIX_XML_DEFINED + testindex + ":" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(q); + assertEquals(p.getName(), q.getName()); + assertEquals(p.getBoolean(), q.getBoolean()); + } + } + + // Expanded names in content, prefix defined in XML but not yet registered, namespace already registered + // Expectation: prefix and namespace URI from registry will be used + // OAK-9586 + public void testExpandedNameImportWithPrefixDefinitionKnownNS() throws Exception { + final int testindex = 1; + String prefix = null; + String xml = createXmlWithExpandedName(NID_REGISTERED, true, testindex); + try (InputStream input = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) { + superuser.getWorkspace().getNamespaceRegistry().registerNamespace(PREFIX_REGISTERED + testindex, "urn:" + NID_REGISTERED + testindex); + superuser.importXML( + "/", input, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); + NodeIterator nodes = superuser.getRootNode().getNode(EXPANDED_NAMES_IMPORT_TEST_ROOT).getNodes(); + assertTrue(nodes.hasNext()); + Node node = nodes.nextNode(); + + prefix = superuser.getNamespacePrefix("urn:" + NID_REGISTERED + testindex); + assertEquals(PREFIX_REGISTERED + testindex, prefix); + String name = node.getName(); + assertEquals(PREFIX_REGISTERED + testindex + ":" + LOCAL_NODE_NAME_XML_DEFINED, name); + Property p = node.getProperty("{urn:" + NID_REGISTERED + testindex + "}" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(p); + Property q = node.getProperty(PREFIX_REGISTERED + testindex + ":" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(q); + assertEquals(p.getName(), q.getName()); + assertEquals(p.getBoolean(), q.getBoolean()); + } + } + + // Expanded names in content, prefix defined in XML and already registered for the given namespace + // Expectation: prefix and namespace URI from XML will be used + // OAK-9586 + public void testExpandedNameImportWithPrefixDefinitionKnownNSAndPrefix() throws Exception { + final int testindex = 2; + String prefix = null; + String xml = createXmlWithExpandedName(NID_REGISTERED, true, testindex); + try (InputStream input = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) { + superuser.getWorkspace().getNamespaceRegistry().registerNamespace(PREFIX_REGISTERED + testindex, "urn:" + NID_REGISTERED + testindex); + superuser.setNamespacePrefix(PREFIX_REGISTERED + testindex, "urn:" + NID_REGISTERED + testindex); + superuser.importXML( + "/", input, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); + NodeIterator nodes = superuser.getRootNode().getNode(EXPANDED_NAMES_IMPORT_TEST_ROOT).getNodes(); + assertTrue(nodes.hasNext()); + Node node = nodes.nextNode(); + + prefix = superuser.getNamespacePrefix("urn:" + NID_REGISTERED + testindex); + assertEquals(PREFIX_REGISTERED + testindex, prefix); + String name = node.getName(); + assertEquals(PREFIX_REGISTERED + testindex + ":" + LOCAL_NODE_NAME_XML_DEFINED, name); + Property p = node.getProperty("{urn:" + NID_REGISTERED + testindex + "}" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(p); + Property q = node.getProperty(PREFIX_REGISTERED + testindex + ":" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(q); + assertEquals(p.getName(), q.getName()); + assertEquals(p.getBoolean(), q.getBoolean()); + } + } + + // Expanded names in content, prefix defined in XML and already registered for a different namespace, namespace not yet registered + // Expectation: new prefix will be created for the given namespace URI + // OAK-9586 + public void testExpandedNameImportWithCollidingPrefixDefinitionNsUnreg() throws Exception { + final int testindex = 3; + String otherNid = "otherRegisteredNS"; + String prefix = null; + String xml = createXmlWithExpandedName(NID_UNREGISTERED, true, testindex); + try (InputStream input = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) { + superuser.getWorkspace().getNamespaceRegistry().registerNamespace(PREFIX_XML_DEFINED + testindex, "urn:" + otherNid + testindex); + superuser.importXML( + "/", input, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); + NodeIterator nodes = superuser.getRootNode().getNode(EXPANDED_NAMES_IMPORT_TEST_ROOT).getNodes(); + assertTrue(nodes.hasNext()); + Node node = nodes.nextNode(); + + prefix = superuser.getNamespacePrefix("urn:" + NID_UNREGISTERED + testindex); + assertNotNull(prefix); + String name = node.getName(); + assertEquals(prefix + ":" + LOCAL_NODE_NAME_XML_DEFINED, name); + Property p = node.getProperty("{urn:" + NID_UNREGISTERED + testindex + "}" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(p); + Property q = node.getProperty(prefix + ":" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(q); + assertEquals(p.getName(), q.getName()); + assertEquals(p.getBoolean(), q.getBoolean()); + } + } + + // Expanded names in content, prefix defined in XML and already registered for a different namespace, namespace already registered + // Expectation: prefix and namespace URI from registry will be used + // OAK-9586 + public void testExpandedNameImportWithCollidingPrefixDefinitionNsReg() throws Exception { + final int testindex = 4; + String otherNid = "otherRegisteredNS"; + String prefix = null; + String xml = createXmlWithExpandedName(NID_REGISTERED, true, testindex); + try (InputStream input = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) { + superuser.getWorkspace().getNamespaceRegistry().registerNamespace(PREFIX_REGISTERED + testindex, "urn:" + NID_REGISTERED + testindex); + superuser.getWorkspace().getNamespaceRegistry().registerNamespace(PREFIX_XML_DEFINED + testindex, "urn:" + otherNid + testindex); + superuser.importXML( + "/", input, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); + NodeIterator nodes = superuser.getRootNode().getNode(EXPANDED_NAMES_IMPORT_TEST_ROOT).getNodes(); + assertTrue(nodes.hasNext()); + Node node = nodes.nextNode(); + + prefix = superuser.getNamespacePrefix("urn:" + NID_REGISTERED + testindex); + assertEquals(PREFIX_REGISTERED + testindex, prefix); + String name = node.getName(); + assertEquals(PREFIX_REGISTERED + testindex + ":" + LOCAL_NODE_NAME_XML_DEFINED, name); + Property p = node.getProperty("{urn:" + NID_REGISTERED + testindex + "}" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(p); + Property q = node.getProperty(PREFIX_REGISTERED + testindex + ":" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(q); + assertEquals(p.getName(), q.getName()); + assertEquals(p.getBoolean(), q.getBoolean()); + } + } + + // Expanded names in content, prefix not defined in XML, namespace not yet registered + // Expectation: new prefix will be created for the given namespace URI + // OAK-9586 + public void testExpandedNameImportWithoutPrefixDefinitionAndUnregisteredNS() throws Exception { + final int testindex = 5; + String prefix = null; + String xml = createXmlWithExpandedName(NID_UNREGISTERED, false, testindex); + try (InputStream input = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) { + superuser.importXML( + "/", input, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); + NodeIterator nodes = superuser.getRootNode().getNode(EXPANDED_NAMES_IMPORT_TEST_ROOT).getNodes(); + assertTrue(nodes.hasNext()); + Node node = nodes.nextNode(); + + prefix = superuser.getNamespacePrefix("urn:" + NID_UNREGISTERED + testindex); + assertNotNull(prefix); + String name = node.getName(); + assertEquals(prefix + ":" + LOCAL_NODE_NAME_XML_DEFINED, name); + Property p = node.getProperty("{urn:" + NID_UNREGISTERED + testindex + "}" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(p); + Property q = node.getProperty(prefix + ":" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(q); + assertEquals(p.getName(), q.getName()); + assertEquals(p.getBoolean(), q.getBoolean()); + } + } + + // Expanded names in content, prefix not defined in XML, namespace already registered + // Expectation: prefix and namespace URI from registry will be used + // OAK-9586 + public void testExpandedNameImportWithoutPrefixDefinitionAndRegisteredNS() throws Exception { + final int testindex = 5; + String prefix = null; + String xml = createXmlWithExpandedName(NID_REGISTERED, false, testindex); + try (InputStream input = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))) { + superuser.getWorkspace().getNamespaceRegistry().registerNamespace(PREFIX_REGISTERED + testindex, "urn:" + NID_REGISTERED + testindex); + superuser.importXML( + "/", input, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW); + NodeIterator nodes = superuser.getRootNode().getNode(EXPANDED_NAMES_IMPORT_TEST_ROOT).getNodes(); + assertTrue(nodes.hasNext()); + Node node = nodes.nextNode(); + + prefix = superuser.getNamespacePrefix("urn:" + NID_REGISTERED + testindex); + assertEquals(PREFIX_REGISTERED + testindex, prefix); + String name = node.getName(); + assertEquals(prefix + ":" + LOCAL_NODE_NAME_XML_DEFINED, name); + Property p = node.getProperty("{urn:" + NID_REGISTERED + testindex + "}" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(p); + Property q = node.getProperty(prefix + ":" + LOCAL_PROP_NAME_XML_DEFINED); + assertNotNull(q); + assertEquals(p.getName(), q.getName()); + assertEquals(p.getBoolean(), q.getBoolean()); + } + } }