This is an automated email from the ASF dual-hosted git repository.
baedke pushed a commit to branch OAK-9586
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/OAK-9586 by this push:
new 1372efd135 OAK-9586: SysViewImportHandler does not support expanded
names in sv:name attributes
1372efd135 is described below
commit 1372efd135c942c3b8095200069b6ba8ae547337
Author: Manfred Baedke <[email protected]>
AuthorDate: Thu Apr 10 16:48:58 2025 +0200
OAK-9586: SysViewImportHandler does not support expanded names in sv:name
attributes
Prelimary fix, needs beautification.
---
.../oak/jcr/xml/SysViewImportHandler.java | 42 +++++-
.../apache/jackrabbit/oak/jcr/xml/ImportTest.java | 155 +++++++++++++++++++++
2 files changed, 195 insertions(+), 2 deletions(-)
diff --git
a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/SysViewImportHandler.java
b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/SysViewImportHandler.java
index 933446142f..7cfb1c63b1 100644
---
a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/SysViewImportHandler.java
+++
b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/xml/SysViewImportHandler.java
@@ -20,8 +20,10 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
+import java.util.UUID;
import javax.jcr.InvalidSerializedDataException;
+import javax.jcr.NamespaceException;
import javax.jcr.NamespaceRegistry;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
@@ -93,6 +95,42 @@ class SysViewImportHandler extends TargetImportHandler {
}
}
+ //TODO avoid code duplication (this is stolen from GlobalNameMapper)
+ private static boolean isExpandedName(String name) {
+ if (name.startsWith("{")) {
+ int brace = name.indexOf('}', 1);
+ if (brace != -1) {
+ String namespace = name.substring(1, brace);
+ // the empty namespace and "internal" are valid as well,
otherwise it always contains a colon (as it is a URI)
+ // compare with RFC 3986, Section 3
(https://datatracker.ietf.org/doc/html/rfc3986#section-3)
+ if (namespace.isEmpty() ||
namespace.equals(NamespaceConstants.NAMESPACE_REP)|| namespace.indexOf(':') !=
-1) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private NameInfo getNameInfo(String svName) throws RepositoryException {
+ if (isExpandedName(svName)) {
+ String namespaceUri = svName.substring(svName.indexOf("{") + 1,
svName.indexOf("}"));
+ String localName = svName.substring(svName.indexOf("}") + 1);
+ NamespaceRegistry namespaceRegistry =
sessionContext.getWorkspace().getNamespaceRegistry();
+ String prefix;
+ try {
+ prefix = namespaceRegistry.getPrefix(namespaceUri);
+ } catch (NamespaceException expected) {
+ // this is an expanded svName using an unregistered namespace
+ // we need to make up a prefix for the namespace
+ prefix = "ns_" + UUID.randomUUID().toString().substring(0, 8);
+ namespaceRegistry.registerNamespace(prefix, namespaceUri);
+ }
+ return new NameInfo(prefix, localName);
+ } else {
+ return new
NameInfo(sessionContext.getJcrName(sessionContext.getOakName(svName)));
+ }
+ }
+
//-------------------------------------------------------< ContentHandler >
@Override
@@ -123,7 +161,7 @@ class SysViewImportHandler extends TargetImportHandler {
// push new ImportState instance onto the stack
ImportState state = new ImportState();
try {
- state.nodeName = new NameInfo(svName).getRepoQualifiedName();
+ state.nodeName = getNameInfo(svName).getRepoQualifiedName();
} catch (RepositoryException e) {
throw new SAXException(new
InvalidSerializedDataException("illegal node name: " + svName, e));
}
@@ -141,7 +179,7 @@ class SysViewImportHandler extends TargetImportHandler {
"missing mandatory sv:name attribute of element
sv:property"));
}
try {
- currentPropName = new NameInfo(svName);
+ currentPropName = getNameInfo(svName);
} catch (RepositoryException e) {
throw new SAXException(new
InvalidSerializedDataException("illegal property name: " + svName, e));
}
diff --git
a/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/xml/ImportTest.java
b/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/xml/ImportTest.java
index 631f3cbdc2..16157a07bb 100644
--- a/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/xml/ImportTest.java
+++ b/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/xml/ImportTest.java
@@ -24,17 +24,20 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
import java.util.UUID;
import javax.jcr.ImportUUIDBehavior;
import javax.jcr.ItemExistsException;
import javax.jcr.Node;
+import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.nodetype.ConstraintViolationException;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.junit.Ignore;
public class ImportTest extends AbstractJCRTest {
@@ -310,4 +313,156 @@ public class ImportTest extends AbstractJCRTest {
assertEquals("b", p2.getString());
assertNotEquals(p1.getName(), p2.getName());
}
+
+ private String createExpandedNameWithPrefixDefXml(String nid) {
+ return "<sv:node xmlns:sv=\"http://www.jcp.org/jcr/sv/1.0\" " +
+ "xmlns:definedPrefix=\"" + "urn:" + nid + "\"" +
+ " sv:name=\"foo\">" +
+ "<sv:node sv:name=\"{urn:" + nid + "}bar\">" +
+ "<sv:property sv:type=\"Boolean\" sv:name=\"{" + "urn:" + nid
+ "}bar\">" +
+ "<sv:value>true</sv:value>" +
+ "</sv:property>" +
+ "</sv:node>" +
+ "</sv:node>";
+ }
+
+ private String createExpandedNameWithoutPrefixDefXml(String nid) {
+ return "<sv:node xmlns:sv=\"http://www.jcp.org/jcr/sv/1.0\" " +
+ " sv:name=\"foo\">" +
+ "<sv:node sv:name=\"{urn:" + nid + "}bar\">" +
+ "<sv:property sv:type=\"Boolean\" sv:name=\"{" + "urn:" + nid
+ "}bar\">" +
+ "<sv:value>true</sv:value>" +
+ "</sv:property>" +
+ "</sv:node>" +
+ "</sv:node>";
+ }
+
+ // Expanded names in content, prefix definition in XML, namespace not yet
registered
+ // OAK-9586
+ public void testExpandedNameImportWithPrefixDefinition() throws Exception {
+ String nid = "unregisteredNS";
+ String prefix = null;
+ try {
+ String xml = createExpandedNameWithPrefixDefXml(nid);
+ InputStream input = new
ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+ superuser.importXML(
+ "/", input,
ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
+ NodeIterator nodes =
superuser.getRootNode().getNode("foo").getNodes();
+ assertTrue(nodes.hasNext());
+ Node node = nodes.nextNode();
+
+ prefix = superuser.getNamespacePrefix("urn:" + nid);
+ assertEquals("definedPrefix", prefix);
+ String name = node.getName();
+ assertEquals("definedPrefix:bar", name);
+ Property p = node.getProperty("{urn:" + nid + "}bar");
+ assertNotNull(p);
+ Property q = node.getProperty("definedPrefix:bar");
+ assertNotNull(q);
+ assertEquals(p.getName(), q.getName());
+ assertEquals(p.getBoolean(), q.getBoolean());
+ } finally {
+ if (prefix != null) {
+ try {
+
superuser.getWorkspace().getNamespaceRegistry().unregisterNamespace(prefix);
+ } catch (Exception ignored) {}
+ }
+ }
+ }
+
+ // Expanded names in content, prefix definition in XML, prefix already
registered
+ // OAK-9586
+ public void testExpandedNameImportWithCollidingPrefixDefinition() throws
Exception {
+ String nid = "registeredNS";
+ String prefix = null;
+ try {
+
superuser.getWorkspace().getNamespaceRegistry().registerNamespace("registeredPrefix",
"urn:" + nid);
+ //superuser.setNamespacePrefix("registeredPrefix", "urn:" + nid);
+ String xml = createExpandedNameWithPrefixDefXml(nid);
+ InputStream input = new
ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+ superuser.importXML(
+ "/", input,
ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
+ NodeIterator nodes =
superuser.getRootNode().getNode("foo").getNodes();
+ assertTrue(nodes.hasNext());
+ Node node = nodes.nextNode();
+
+ prefix = superuser.getNamespacePrefix("urn:" + nid);
+ assertEquals("registeredPrefix", prefix);
+ String name = node.getName();
+ assertEquals("registeredPrefix:bar", name);
+ Property p = node.getProperty("{urn:" + nid + "}bar");
+ assertNotNull(p);
+ Property q = node.getProperty("registeredPrefix:bar");
+ assertNotNull(q);
+ assertEquals(p.getName(), q.getName());
+ assertEquals(p.getBoolean(), q.getBoolean());
+ } finally {
+ if (prefix != null) {
+ try {
+
superuser.getWorkspace().getNamespaceRegistry().unregisterNamespace(prefix);
+ } catch (Exception ignored) {}
+ }
+ }
+ }
+
+ // Expanded names in content, no prefix definition in XML, prefix already
registered
+ // OAK-9586
+ public void testExpandedNameImportWithoutPrefixDefinitionAndRegisteredNS()
throws Exception {
+ String nid = "registeredNS";
+ String prefix = null;
+ try {
+
superuser.getWorkspace().getNamespaceRegistry().registerNamespace("registeredPrefix",
"urn:" + nid);
+ String xml = createExpandedNameWithoutPrefixDefXml(nid);
+ InputStream input = new
ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+ superuser.importXML(
+ "/", input,
ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
+ NodeIterator nodes =
superuser.getRootNode().getNode("foo").getNodes();
+ assertTrue(nodes.hasNext());
+ Node node = nodes.nextNode();
+
+ prefix = superuser.getNamespacePrefix("urn:" + nid);
+ assertEquals("registeredPrefix", prefix);
+ String name = node.getName();
+ assertEquals("registeredPrefix:bar", name);
+ Property p = node.getProperty("{urn:" + nid + "}bar");
+ assertNotNull(p);
+ Property q = node.getProperty("registeredPrefix:bar");
+ assertNotNull(q);
+ assertEquals(p.getName(), q.getName());
+ assertEquals(p.getBoolean(), q.getBoolean());
+ } finally {
+ if (prefix != null) {
+ try {
+
superuser.getWorkspace().getNamespaceRegistry().unregisterNamespace(prefix);
+ } catch (Exception ignored) {}
+ }
+ }
+ }
+
+ // Expanded names in content, no prefix definition in XML, prefix not yet
registered
+ // OAK-9586
+ public void
testExpandedNameImportWithoutPrefixDefinitionAndUnregisteredNS() throws
Exception {
+ String nid = "unregisteredNS";
+ String prefix = null;
+ try {
+ String xml = createExpandedNameWithoutPrefixDefXml(nid);
+ InputStream input = new
ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+ superuser.importXML(
+ "/", input,
ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
+ NodeIterator nodes =
superuser.getRootNode().getNode("foo").getNodes();
+ assertTrue(nodes.hasNext());
+ Node node = nodes.nextNode();
+
+ prefix = superuser.getNamespacePrefix("urn:" + nid);
+ assertNotNull(prefix);
+ Property p = node.getProperty("{urn:" + nid + "}bar");
+ assertNotNull(p);
+ } finally {
+ if (prefix != null) {
+ try {
+
superuser.getWorkspace().getNamespaceRegistry().unregisterNamespace(prefix);
+ } catch (Exception ignored) {}
+ }
+ }
+ }
}
\ No newline at end of file