You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2021/09/23 13:32:58 UTC
[jackrabbit-filevault] 01/01: JCRVLT-357 split up parser and
importer for DocView files
This is an automated email from the ASF dual-hosted git repository.
kwin pushed a commit to branch feature/JCRVLT-357-split-up-docviewsaximporter
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git
commit e08c755c6e71149f7c1ca62a2aeaf2bf5cfdc60f
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Thu Sep 23 15:32:47 2021 +0200
JCRVLT-357 split up parser and importer for DocView files
---
.../vault/fs/impl/io/AbstractArtifactHandler.java | 15 +-
.../vault/fs/impl/io/DocViewAdapter.java | 12 +-
.../vault/fs/impl/io/DocViewAnalyzer.java | 1 +
...ocViewSAXImporter.java => DocViewImporter.java} | 1107 ++++++++------------
.../vault/fs/impl/io/DocViewSAXHandler.java | 265 +++++
.../vault/fs/impl/io/FileArtifactHandler.java | 20 +-
.../vault/fs/impl/io/GenericArtifactHandler.java | 14 +-
.../vault/fs/impl/io/JackrabbitACLImporter.java | 87 +-
.../vault/fs/impl/io/JcrSysViewTransformer.java | 92 +-
.../jackrabbit/vault/fs/io/DocViewParser.java | 47 +
.../vault/fs/io/DocViewParserHandler.java | 29 +
.../apache/jackrabbit/vault/util/DocViewNode.java | 13 +-
.../apache/jackrabbit/vault/util/DocViewNode2.java | 80 ++
.../jackrabbit/vault/util/DocViewProperty.java | 3 +-
...{DocViewProperty.java => DocViewProperty2.java} | 115 +-
.../jackrabbit/vault/util/EffectiveNodeType.java | 1 +
16 files changed, 1065 insertions(+), 836 deletions(-)
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java
index 0f0ded9..ef13192 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/AbstractArtifactHandler.java
@@ -32,10 +32,13 @@ import org.apache.jackrabbit.vault.fs.api.ArtifactHandler;
import org.apache.jackrabbit.vault.fs.api.ArtifactSet;
import org.apache.jackrabbit.vault.fs.api.DumpContext;
import org.apache.jackrabbit.vault.fs.api.Dumpable;
+import org.apache.jackrabbit.vault.fs.api.IdConflictPolicy;
import org.apache.jackrabbit.vault.fs.api.ImportInfo;
import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
import org.apache.jackrabbit.vault.fs.impl.ArtifactSetImpl;
import org.apache.jackrabbit.vault.fs.io.AccessControlHandling;
+import org.apache.jackrabbit.vault.fs.io.DocViewParser;
+import org.apache.jackrabbit.vault.fs.io.DocViewParserHandler;
import org.apache.jackrabbit.vault.fs.io.ImportOptions;
import org.apache.jackrabbit.vault.fs.spi.ACLManagement;
import org.apache.jackrabbit.vault.fs.spi.ServiceProviderFactory;
@@ -160,13 +163,9 @@ public abstract class AbstractArtifactHandler implements ArtifactHandler, Dumpab
ctx.println(isLast, getClass().getSimpleName());
}
- protected void parseXmlWithSaxHandler(InputSource source, DefaultHandler handler) throws ParserConfigurationException, SAXException, IOException {
- SAXParserFactory factory = SAXParserFactory.newInstance();
- factory.setNamespaceAware(true);
- factory.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
- SAXParser parser = factory.newSAXParser();
- parser.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
- parser.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
- parser.parse(source, handler);
+ protected ImportInfoImpl importDocView(InputSource source, Node parentNode, String rootNodeName, ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy) throws IOException, RepositoryException {
+ DocViewImporter handler = new DocViewImporter(parentNode, rootNodeName, artifacts, wspFilter, idConflictPolicy, getAcHandling(), getCugHandling());
+ new DocViewParser().parse(rootNodeName, source, handler);
+ return handler.getInfo();
}
}
\ No newline at end of file
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAdapter.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAdapter.java
index 8980aa9..f690dec 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAdapter.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAdapter.java
@@ -20,13 +20,15 @@ import java.util.List;
import javax.jcr.RepositoryException;
-import org.apache.jackrabbit.vault.util.DocViewNode;
+import org.apache.jackrabbit.vault.util.DocViewNode2;
import org.xml.sax.SAXException;
/**
- * {@code DocViewAdapter} is used by the {@link org.apache.jackrabbit.vault.fs.impl.io.DocViewSAXImporter} to handle
+ * {@code DocViewAdapter} is used by the {@link org.apache.jackrabbit.vault.fs.impl.io.DocViewSAXHandler} to handle
* special content that is not importable using "normal" JCR calls. For example users and other protected content
* needs to be imported using the {@link javax.jcr.Session#importXML(String, java.io.InputStream, int)} or similar.
+ *
+ * TODO: check overlap with DocViewParserHandler
*/
public interface DocViewAdapter {
@@ -36,14 +38,14 @@ public interface DocViewAdapter {
* @throws SAXException if a parsing error occurs.
* @throws RepositoryException if a import exception occurs.
*/
- void startNode(DocViewNode node) throws SAXException, RepositoryException;
+ void startNode(DocViewNode2 node) throws RepositoryException;
/**
* Ends node is invoked when the importer ascends from an element.
* @throws SAXException if a parsing error occurs.
* @throws RepositoryException if a import exception occurs.
*/
- void endNode() throws SAXException, RepositoryException;
+ void endNode() throws RepositoryException;
/**
* Is called by the importer if the adapter is no longer used and must finalize the import.
@@ -51,6 +53,6 @@ public interface DocViewAdapter {
* @throws RepositoryException if a import exception occurs.
* @return The paths that were created.
*/
- List<String> close() throws SAXException, RepositoryException;
+ List<String> close() throws RepositoryException;
}
\ No newline at end of file
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAnalyzer.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAnalyzer.java
index 68b5dac..9caebe7 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAnalyzer.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewAnalyzer.java
@@ -42,6 +42,7 @@ import org.xml.sax.SAXException;
/**
* Implements a docview analyzer that scans the XML for nodes.
+ * TODO: not really necessary, replace with implementation of DocViewParserHandler....
*/
public class DocViewAnalyzer extends RejectingEntityDefaultHandler implements NamespaceResolver {
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXImporter.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewImporter.java
similarity index 70%
rename from vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXImporter.java
rename to vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewImporter.java
index 9f29a60..f57621a 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXImporter.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewImporter.java
@@ -1,4 +1,4 @@
-/*
+/*************************************************************************
* 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.
@@ -13,8 +13,7 @@
* 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.vault.fs.impl.io;
import java.io.IOException;
@@ -32,10 +31,12 @@ import java.util.UUID;
import javax.jcr.ImportUUIDBehavior;
import javax.jcr.Item;
+import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.NamespaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
@@ -45,15 +46,18 @@ import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
+import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.version.VersionException;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
import org.apache.jackrabbit.spi.commons.name.NameConstants;
-import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
-import org.apache.jackrabbit.util.ISO9075;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
import org.apache.jackrabbit.util.Text;
import org.apache.jackrabbit.vault.fs.api.Artifact;
import org.apache.jackrabbit.vault.fs.api.ArtifactType;
@@ -66,88 +70,56 @@ import org.apache.jackrabbit.vault.fs.api.WorkspaceFilter;
import org.apache.jackrabbit.vault.fs.impl.ArtifactSetImpl;
import org.apache.jackrabbit.vault.fs.impl.PropertyValueArtifact;
import org.apache.jackrabbit.vault.fs.io.AccessControlHandling;
+import org.apache.jackrabbit.vault.fs.io.DocViewParserHandler;
import org.apache.jackrabbit.vault.fs.spi.ACLManagement;
import org.apache.jackrabbit.vault.fs.spi.ServiceProviderFactory;
import org.apache.jackrabbit.vault.fs.spi.UserManagement;
import org.apache.jackrabbit.vault.fs.spi.impl.jcr20.JcrNamespaceHelper;
-import org.apache.jackrabbit.vault.util.DocViewNode;
+import org.apache.jackrabbit.vault.util.DocViewNode2;
import org.apache.jackrabbit.vault.util.DocViewProperty;
+import org.apache.jackrabbit.vault.util.DocViewProperty2;
import org.apache.jackrabbit.vault.util.EffectiveNodeType;
import org.apache.jackrabbit.vault.util.JcrConstants;
import org.apache.jackrabbit.vault.util.MimeTypes;
-import org.apache.jackrabbit.vault.util.RejectingEntityDefaultHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
-/**
- * Implements an importer that processes SAX events from a (modified) document
- * view. The behaviour for existing nodes works as follows:
- * TODO: better description
- * <pre>
- *
- * - extended docview always includes SNS indexes
- * - label is the last element of the path
- * - uuid "child" means uuid of a direct child node matches
- * - uuid "desc" means uuid of a descendant child node matches
- * - uuid "other" means uuid of a node outside of the node tree matches
- *
- * uuid | label | nt | result
- * - | no | - | create
- * - | yes | no | replace
- * - | yes | yes | reuse
- * no | no | - | create
- * no | yes | no | replace
- * no | yes | yes | reuse
- * child | no | no | replace
- * child | no | yes | replace
- * child | yes | no | replace
- * child | yes | yes | reuse
- * desc | - | - | *error*
- * other | - | - | *error*
- * </pre>
- */
-public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements NamespaceResolver {
-
- private static final String PROP_OAK_COUNTER = "oak:counter";
+public class DocViewImporter implements DocViewParserHandler {
- /**
- * the default logger
- */
- static final Logger log = LoggerFactory.getLogger(DocViewSAXImporter.class);
+ private static final Name NAME_REP_CUG_POLICY = NameFactoryImpl.getInstance().create(Name.NS_REP_URI, "principalNames");
+ private static final Name NAME_REP_MEMBERS = NameFactoryImpl.getInstance().create(Name.NS_REP_URI, "members");
+ private static final String NAMESPACE_OAK = "http://jackrabbit.apache.org/oak/ns/1.0";
+ private static final Name NAME_OAK_COUNTER = NameFactoryImpl.getInstance().create(NAMESPACE_OAK, "counter");
+
/**
- * empty attributes
+ * the default logger
*/
- static final Attributes EMPTY_ATTRIBUTES = new AttributesImpl();
+ static final Logger log = LoggerFactory.getLogger(DocViewImporter.class);
/**
* these properties are protected but can be set nevertheless via system view xml import
*/
- static final Set<String> PROTECTED_PROPERTIES;
+ static final Set<Name> PROTECTED_PROPERTIES;
static {
- Set<String> props = new HashSet<>();
- props.add(JcrConstants.JCR_PRIMARYTYPE);
- props.add(JcrConstants.JCR_MIXINTYPES);
- props.add(JcrConstants.JCR_UUID);
- props.add(JcrConstants.JCR_ISCHECKEDOUT);
- props.add(JcrConstants.JCR_BASEVERSION);
- props.add(JcrConstants.JCR_PREDECESSORS);
- props.add(JcrConstants.JCR_SUCCESSORS);
- props.add(JcrConstants.JCR_VERSIONHISTORY);
+ Set<Name> props = new HashSet<>();
+ props.add(NameConstants.JCR_PRIMARYTYPE);
+ props.add(NameConstants.JCR_MIXINTYPES);
+ props.add(NameConstants.JCR_UUID);
+ props.add(NameConstants.JCR_ISCHECKEDOUT);
+ props.add(NameConstants.JCR_BASEVERSION);
+ props.add(NameConstants.JCR_PREDECESSORS);
+ props.add(NameConstants.JCR_SUCCESSORS);
+ props.add(NameConstants.JCR_VERSIONHISTORY);
PROTECTED_PROPERTIES = Collections.unmodifiableSet(props);
}
- /**
- * the current namespace state
- */
- private NameSpace nsStack = null;
/**
* the importing session
@@ -160,19 +132,9 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
private final Node parentNode;
/**
- * the name of the root node
- */
- private final String rootNodeName;
-
- /**
- * the depth of the root node
- */
- private final int rootDepth;
-
- /**
- * current stack
+ * final import information
*/
- private DocViewSAXImporter.StackElement stack;
+ private ImportInfoImpl importInfo = new ImportInfoImpl();
/**
* Specified the filter that is used to check if child nodes are contained
@@ -188,7 +150,7 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
/**
* a map of binaries (attachments)
*/
- private Map<String, Map<String, DocViewSAXImporter.BlobInfo>> binaries
+ private Map<String, Map<String, BlobInfo>> binaries
= new HashMap<>();
/**
@@ -202,16 +164,6 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
private Set<String> preserveProperties = new HashSet<>();
/**
- * the default name path resolver
- */
- private final DefaultNamePathResolver npResolver = new DefaultNamePathResolver(this);
-
- /**
- * final import information
- */
- private ImportInfoImpl importInfo = new ImportInfoImpl();
-
- /**
* acl management
*/
private final ACLManagement aclManagement;
@@ -224,13 +176,13 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
/**
* the acl handling to apply
*/
- private AccessControlHandling aclHandling = AccessControlHandling.IGNORE;
+ private final AccessControlHandling aclHandling;
/**
* Closed user group handling to apply by default (when set to <code>null</code>)
* falls back to using aclHandling
*/
- private AccessControlHandling cugHandling = null;
+ private final @Nullable AccessControlHandling cugHandling;
/**
* flag indicating if SNS are supported by the underlying repository
@@ -245,7 +197,16 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
private final IdConflictPolicy idConflictPolicy;
/**
- * Creates a new importer that will receive SAX events and imports the
+ * current stack
+ */
+ private StackElement stack;
+
+ private int rootDepth;
+
+ private final NamePathResolver npResolver;
+
+ /**
+ * Creates a new importer that will imports the
* items below the given root.
*
* @param parentNode the (parent) node of the import
@@ -254,22 +215,27 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
* @param wspFilter workspace filter
* @throws RepositoryException if an error occurs.
*/
- public DocViewSAXImporter(Node parentNode, String rootNodeName,
- ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy)
- throws RepositoryException {
+ public DocViewImporter(Node parentNode, String rootNodeName,
+ ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy) throws RepositoryException {
+ this(parentNode, rootNodeName, artifacts, wspFilter, idConflictPolicy, AccessControlHandling.IGNORE, null);
+ }
+
+ public DocViewImporter(Node parentNode, String rootNodeName,
+ ArtifactSetImpl artifacts, WorkspaceFilter wspFilter, IdConflictPolicy idConflictPolicy, AccessControlHandling aclHandling, AccessControlHandling cugHandling) throws RepositoryException {
this.filter = artifacts.getCoverage();
this.wspFilter = wspFilter;
this.parentNode = parentNode;
this.rootDepth = parentNode.getDepth() + 1;
this.session = parentNode.getSession();
- this.rootNodeName = rootNodeName;
this.aclManagement = ServiceProviderFactory.getProvider().getACLManagement();
this.userManagement = ServiceProviderFactory.getProvider().getUserManagement();
this.snsSupported = session.getRepository().
getDescriptorValue(Repository.NODE_TYPE_MANAGEMENT_SAME_NAME_SIBLINGS_SUPPORTED).getBoolean();
this.nsHelper = new JcrNamespaceHelper(session, null);
this.idConflictPolicy = idConflictPolicy;
-
+ this.aclHandling = aclHandling;
+ this.cugHandling = cugHandling;
+
String rootPath = parentNode.getPath();
if (!rootPath.equals("/")) {
rootPath += "/";
@@ -285,116 +251,181 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
for (Artifact a : artifacts.values(ArtifactType.HINT)) {
hints.add(rootPath + a.getRelativePath());
}
+
+ stack = new StackElement(parentNode, parentNode.isNew());
+ npResolver = new DefaultNamePathResolver(parentNode.getSession());
}
- public AccessControlHandling getAclHandling() {
- return aclHandling;
- }
-
- public void setAclHandling(AccessControlHandling aclHandling) {
- this.aclHandling = aclHandling;
- }
-
- /**
- * returns closed user group handling
- * @return either current cugHandling value or <code>null</code>
- * if undefined and aclHandling is used instead
- */
- public AccessControlHandling getCugHandling() {
- return cugHandling;
- }
-
- /**
- * Sets closed user group handling for this importer
- * For backwards compatibility, if <code>null</code> is specified
- * then importer falls back to using aclHandling value instead.
- * @param cugHandling
- */
- public void setCugHandling(AccessControlHandling cugHandling) {
- this.cugHandling = cugHandling;
- }
+ @Override
+ public void startDocViewNode(String parentNodePath, DocViewNode2 docViewNode) throws IOException, RepositoryException {
- private void registerBinary(Artifact a, String rootPath)
- throws RepositoryException {
- String path = rootPath + a.getRelativePath();
- int idx = -1;
- int pos = path.indexOf('[', path.lastIndexOf('/'));
- if (pos > 0) {
- idx = Integer.parseInt(path.substring(pos + 1, path.length() - 1));
- path = path.substring(0, pos);
- }
- if (a.getType() == ArtifactType.FILE && a instanceof PropertyValueArtifact) {
- // hack, mark "file" properties just as present
- String parentPath = ((PropertyValueArtifact) a).getProperty().getParent().getPath();
- preserveProperties.add(parentPath + "/" + JcrConstants.JCR_DATA);
- preserveProperties.add(parentPath + "/" + JcrConstants.JCR_LASTMODIFIED);
- } else {
- preserveProperties.add(path);
- // hack, mark "file" properties just as present
- preserveProperties.add(path + "/jcr:content/jcr:data");
- preserveProperties.add(path + "/jcr:content/jcr:lastModified");
- preserveProperties.add(path + "/jcr:content/jcr:mimeType");
- String parentPath = Text.getRelativeParent(path, 1);
- String name = Text.getName(path);
- Map<String, DocViewSAXImporter.BlobInfo> infoSet = binaries.get(parentPath);
- if (infoSet == null) {
- infoSet = new HashMap<String, DocViewSAXImporter.BlobInfo>();
- binaries.put(parentPath, infoSet);
+ stack.addName(docViewNode.getName());
+ Node node = stack.getNode();
+ if (node == null) {
+ stack = stack.push();
+ DocViewAdapter xform = stack.getAdapter();
+ if (xform != null) {
+ xform.startNode(docViewNode);
+ } else {
+ log.trace("Skipping ignored node {}", docViewNode); // TODO: clarify what this means
}
- DocViewSAXImporter.BlobInfo info = infoSet.get(name);
- if (info == null) {
- info = new DocViewSAXImporter.BlobInfo(idx >= 0);
- infoSet.put(name, info);
+ } else {
+ final String path = parentNodePath + "/" + docViewNode.getName();
+ if (docViewNode.getProperties().isEmpty()) {
+ // only ordering node. skip
+ log.trace("Skipping empty node {}", path);
+ stack = stack.push();
+ return;
+ } else if (docViewNode.getIndex() > 1) {
+ // TODO: skip SNS nodes with index > 1
+ log.warn("Skipping unsupported SNS node with index > 1. Some content will be missing after import: {}", path);
+ stack = stack.push();
+ return;
}
- if (idx >= 0) {
- info.add(idx, a);
- } else {
- info.add(a);
+ try {
+ // is policy node?
+ if (aclManagement.isACLNodeType(docViewNode.getPrimaryType())) {
+ AccessControlHandling acHandling = getAcHandling(docViewNode.getName());
+ if (acHandling != AccessControlHandling.CLEAR && acHandling != AccessControlHandling.IGNORE) {
+ log.trace("Access control policy element detected. starting special transformation {}/{}", node.getPath(), docViewNode.getName());
+ if (aclManagement.ensureAccessControllable(node, npResolver.getJCRName(docViewNode.getName()))) {
+ log.debug("Adding access control policy element to non access-controllable parent - adding mixin: {}", node.getPath());
+ }
+ stack = stack.push();
+ if (NameConstants.REP_REPO_POLICY.equals(docViewNode.getName())) {
+ if (node.getDepth() == 0) {
+ stack.adapter = new JackrabbitACLImporter(session, acHandling);
+ stack.adapter.startNode(docViewNode);
+ } else {
+ log.debug("ignoring invalid location for repository level ACL: {}", node.getPath());
+ }
+ } else {
+ stack.adapter = new JackrabbitACLImporter(node, acHandling);
+ stack.adapter.startNode(docViewNode);
+ }
+ } else {
+ stack = stack.push();
+ }
+ } else if (userManagement != null && userManagement.isAuthorizableNodeType(docViewNode.getPrimaryType())) {
+ // is authorizable node?
+ handleAuthorizable(node, docViewNode);
+ } else {
+ // regular node
+ stack = stack.push(addNode(docViewNode));
+ }
+ } catch (RepositoryException | IOException e) {
+ if (e instanceof ConstraintViolationException && wspFilter.getImportMode(path) != ImportMode.REPLACE) {
+ // only warn in case of constraint violations for mode != replace (as best effort is used in that case)
+ log.warn("Error during processing of {}: {}, skip node due to import mode {}", path, e.toString(), wspFilter.getImportMode(path));
+ importInfo.onNop(path);
+ } else {
+ log.error("Error during processing of {}: {}", path, e.toString());
+ importInfo.onError(path, e);
+ }
+ stack = stack.push();
+ }
}
- }
- log.trace("scheduling binary: {}{}", rootPath, a.getRelativePath() + a.getExtension());
- }
-
- private boolean isIncluded(Item item, int depth) throws RepositoryException {
- String path = importInfo.getRemapped().map(item.getPath());
- return wspFilter.contains(path) && (depth == 0 || filter.contains(item, path, depth));
}
- public ImportInfoImpl getInfo() {
- return importInfo;
- }
- /**
- * {@inheritDoc}
- */
@Override
- public void startDocument() throws SAXException {
- try {
- stack = new StackElement(parentNode, parentNode.isNew());
- } catch (RepositoryException e) {
- throw new SAXException(e);
- }
+ public void endDocViewNode(String parentNodePath, DocViewNode2 docViewNode) throws IOException, RepositoryException {
+
+ // currentNode's import is finished, check if any child nodes
+ // need to be removed
+ NodeNameList childNames = stack.getChildNames();
+ Node node = stack.getNode();
+ int numChildren = 0;
+ if (node == null) {
+ DocViewAdapter adapter = stack.getAdapter();
+ if (adapter != null) {
+ adapter.endNode();
+ }
+ // close transformer if last in stack
+ if (stack.adapter != null) {
+ List<String> createdPaths = stack.adapter.close();
+ for (String createdPath : createdPaths) {
+ importInfo.onCreated(createdPath);
+ }
+ stack.adapter = null;
+ log.trace("Sysview transformation complete.");
+ }
+ } else {
+ NodeIterator iter = node.getNodes();
+ while (iter.hasNext()) {
+ numChildren++;
+ Node child = iter.nextNode();
+ String path = child.getPath();
+ String label = Text.getName(path);
+ AccessControlHandling acHandling = getAcHandling(npResolver.getQName(child.getName()));
+ if (!childNames.contains(label)
+ && !hints.contains(path)
+ && isIncluded(child, child.getDepth() - rootDepth)) {
+ // if the child is in the filter, it belongs to
+ // this aggregate and needs to be removed
+ if (aclManagement.isACLNode(child)) {
+ if (acHandling == AccessControlHandling.OVERWRITE
+ || acHandling == AccessControlHandling.CLEAR) {
+ importInfo.onDeleted(path);
+ aclManagement.clearACL(node);
+ }
+ } else {
+ if (wspFilter.getImportMode(path) == ImportMode.REPLACE) {
+ importInfo.onDeleted(path);
+ // check if child is not protected
+ if (child.getDefinition().isProtected()) {
+ log.debug("Refuse to delete protected child node: {}", path);
+ } else if (child.getDefinition().isMandatory()) {
+ log.debug("Refuse to delete mandatory child node: {}", path);
+ } else {
+ child.remove();
+ }
+ }
+ }
+ } else if (acHandling == AccessControlHandling.CLEAR
+ && aclManagement.isACLNode(child)
+ && isIncluded(child, child.getDepth() - rootDepth)) {
+ importInfo.onDeleted(path);
+ aclManagement.clearACL(node);
+ }
+ }
+ if (isIncluded(node, node.getDepth() - rootDepth)) {
+ // ensure order
+ stack.restoreOrder();
+ }
+ }
+ stack = stack.pop();
+ if (node != null && (numChildren == 0 && !childNames.isEmpty() || stack.isRoot())) {
+ importInfo.addNameList(node.getPath(), childNames);
+ }
}
/**
* {@inheritDoc}
+ * @throws RepositoryException
+ * @throws IOException
+ * @throws ConstraintViolationException
+ * @throws VersionException
+ * @throws LockException
+ * @throws NoSuchNodeTypeException
+ * @throws PathNotFoundException
+ * @throws ItemExistsException
*/
@Override
- public void endDocument() throws SAXException {
+ public void endDocument() throws RepositoryException, IOException {
if (!stack.isRoot()) {
throw new IllegalStateException("stack mismatch");
}
// process binaries
for (String parentPath : binaries.keySet()) {
- Map<String, DocViewSAXImporter.BlobInfo> blobs = binaries.get(parentPath);
+ Map<String, BlobInfo> blobs = binaries.get(parentPath);
// check for node
log.trace("processing binaries at {}", parentPath);
- try {
- if (session.nodeExists(parentPath)) {
+ if (session.nodeExists(parentPath)) {
Node node = session.getNode(parentPath);
for (String propName : blobs.keySet()) {
- DocViewSAXImporter.BlobInfo info = blobs.get(propName);
+ BlobInfo info = blobs.get(propName);
if (node.hasNode(propName)) {
handleBinNode(node.getNode(propName), info, true);
} else if (info.isFile()) {
@@ -417,7 +448,7 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
// assume below 'this' root.
Node node = null;
for (String propName : blobs.keySet()) {
- DocViewSAXImporter.BlobInfo info = blobs.get(propName);
+ BlobInfo info = blobs.get(propName);
if (info.isFile()) {
if (node == null) {
node = createNodeDeep(parentPath);
@@ -428,12 +459,60 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
}
}
}
- } catch (Exception e) {
- throw new SAXException(e);
+ }
+ }
+
+ private void registerBinary(Artifact a, String rootPath)
+ throws RepositoryException {
+ String path = rootPath + a.getRelativePath();
+ int idx = -1;
+ int pos = path.indexOf('[', path.lastIndexOf('/'));
+ if (pos > 0) {
+ idx = Integer.parseInt(path.substring(pos + 1, path.length() - 1));
+ path = path.substring(0, pos);
+ }
+ if (a.getType() == ArtifactType.FILE && a instanceof PropertyValueArtifact) {
+ // hack, mark "file" properties just as present
+ String parentPath = ((PropertyValueArtifact) a).getProperty().getParent().getPath();
+ preserveProperties.add(parentPath + "/" + JcrConstants.JCR_DATA);
+ preserveProperties.add(parentPath + "/" + JcrConstants.JCR_LASTMODIFIED);
+ } else {
+ preserveProperties.add(path);
+ // hack, mark "file" properties just as present
+ preserveProperties.add(path + "/jcr:content/jcr:data");
+ preserveProperties.add(path + "/jcr:content/jcr:lastModified");
+ preserveProperties.add(path + "/jcr:content/jcr:mimeType");
+ String parentPath = Text.getRelativeParent(path, 1);
+ String name = Text.getName(path);
+ Map<String, BlobInfo> infoSet = binaries.get(parentPath);
+ if (infoSet == null) {
+ infoSet = new HashMap<String, BlobInfo>();
+ binaries.put(parentPath, infoSet);
+ }
+ BlobInfo info = infoSet.get(name);
+ if (info == null) {
+ info = new BlobInfo(idx >= 0);
+ infoSet.put(name, info);
+ }
+ if (idx >= 0) {
+ info.add(idx, a);
+ } else {
+ info.add(a);
}
}
+ log.trace("scheduling binary: {}{}", rootPath, a.getRelativePath() + a.getExtension());
}
+ private boolean isIncluded(Item item, int depth) throws RepositoryException {
+ String path = importInfo.getRemapped().map(item.getPath());
+ return wspFilter.contains(path) && (depth == 0 || filter.contains(item, path, depth));
+ }
+
+ public ImportInfoImpl getInfo() {
+ return importInfo;
+ }
+
+
private Node createNodeDeep(String path) throws RepositoryException {
if (session.nodeExists(path)) {
return session.getNode(path);
@@ -456,7 +535,7 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
return node;
}
- private void handleBinNode(Node node, DocViewSAXImporter.BlobInfo info, boolean checkIfNtFileOk)
+ private void handleBinNode(Node node, BlobInfo info, boolean checkIfNtFileOk)
throws RepositoryException, IOException {
log.trace("handling binary file at {}", node.getPath());
if (info.isMulti) {
@@ -520,218 +599,30 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
}
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void characters(char ch[], int start, int length) throws SAXException {
- // can be ignored in docview
- }
/**
- * {@inheritDoc}
- * <p>
- * Pushes the mapping to the stack and updates the namespace mapping in the
- * session.
+ * Handle an authorizable node
+ *
+ * @param node the parent node
+ * @param docViewNode doc view node of the authorizable
+ * @throws RepositoryException if an error accessing the repository occurrs.
+ * @throws SAXException if an XML parsing error occurrs.
*/
- @Override
- public void startPrefixMapping(String prefix, String uri) throws SAXException {
- log.trace("-> prefixMapping for {}:{}", prefix, uri);
- NameSpace ns = new NameSpace(prefix, uri);
- // push on stack
- ns.next = nsStack;
- nsStack = ns;
- // check if uri is already registered
- String oldPrefix;
- try {
- oldPrefix = session.getNamespacePrefix(uri);
- } catch (NamespaceException e) {
- // assume uri never registered
- try {
- oldPrefix = nsHelper.registerNamespace(prefix, uri);
- } catch (RepositoryException e1) {
- throw new SAXException(e);
- }
- } catch (RepositoryException e) {
- throw new SAXException(e);
- }
- // update mapping
- if (!oldPrefix.equals(prefix)) {
- try {
- session.setNamespacePrefix(prefix, uri);
- } catch (RepositoryException e) {
- throw new SAXException(e);
- }
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Pops the mapping from the stack and updates the namespace mapping in the
- * session if necessary.
- */
- @Override
- public void endPrefixMapping(String prefix) throws SAXException {
- log.trace("<- prefixMapping for {}", prefix);
- NameSpace ns = nsStack;
- NameSpace prev = null;
- while (ns != null && !ns.prefix.equals(prefix)) {
- prev = ns;
- ns = ns.next;
- }
- if (ns == null) {
- throw new SAXException("Illegal state: prefix " + prefix + " never mapped.");
- }
- // remove from stack
- if (prev == null) {
- nsStack = ns.next;
- } else {
- prev.next = ns.next;
- }
- // find old prefix
- ns = ns.next;
- while (ns != null && !ns.prefix.equals(prefix)) {
- ns = ns.next;
- }
- // update mapping
- if (ns != null) {
- try {
- session.setNamespacePrefix(prefix, ns.uri);
- } catch (RepositoryException e) {
- throw new SAXException(e);
- }
- log.trace(" remapped: {}:{}", prefix, ns.uri);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
- // special handling for root node
- String label = ISO9075.decode(qName);
- if (stack.isRoot()
- && localName.equals(NameConstants.JCR_ROOT.getLocalName())
- && uri.equals(NameConstants.JCR_ROOT.getNamespaceURI())) {
- label = rootNodeName;
- }
- String name = label;
- log.trace("-> element {}", label);
- boolean snsNode = false;
- int idx = name.lastIndexOf('[');
- if (idx > 0) {
- if (!snsSupported) {
- int idx2 = name.indexOf(']', idx);
- if (idx2 > 0) {
- try {
- if (Integer.valueOf(name.substring(idx + 1, idx2)) > 1) {
- snsNode = true;
- }
- } catch (NumberFormatException e) {
- // ignore
- }
- }
- }
- name = name.substring(0, idx);
- }
- try {
- stack.addName(label);
- Node node = stack.getNode();
- if (node == null) {
- stack = stack.push();
- DocViewAdapter xform = stack.getAdapter();
- if (xform != null) {
- DocViewNode ni = new DocViewNode(name, label, attributes, npResolver);
- xform.startNode(ni);
- } else {
- log.trace("Skipping ignored element {}", name);
- }
- } else {
- final String path = (!node.getPath().equals("/") ? node.getPath() : "")+ "/" + name;
- if (attributes.getLength() == 0) {
- // only ordering node. skip
- log.trace("Skipping empty node {}", path);
- stack = stack.push();
- } else if (snsNode) {
- // skip SNS nodes with index > 1
- log.warn("Skipping unsupported SNS node with index > 1. Some content will be missing after import: {}", path);
- stack = stack.push();
- } else {
- try {
- DocViewNode ni = new DocViewNode(name, label, attributes, npResolver);
- // is policy node?
- if (aclManagement.isACLNodeType(ni.primary)) {
- AccessControlHandling acHandling = getAcHandling(label);
- if (acHandling != AccessControlHandling.CLEAR && acHandling != AccessControlHandling.IGNORE) {
- log.trace("Access control policy element detected. starting special transformation {}/{}", node.getPath(), name);
- if (aclManagement.ensureAccessControllable(node, ni.primary)) {
- log.debug("Adding access control policy element to non access-controllable parent - adding mixin: {}", node.getPath());
- }
- stack = stack.push();
- if ("rep:repoPolicy".equals(name)) {
- if (node.getDepth() == 0) {
- stack.adapter = new JackrabbitACLImporter(session, acHandling);
- stack.adapter.startNode(ni);
- } else {
- log.debug("ignoring invalid location for repository level ACL: {}", node.getPath());
- }
- } else {
- stack.adapter = new JackrabbitACLImporter(node, acHandling);
- stack.adapter.startNode(ni);
- }
- } else {
- stack = stack.push();
- }
- } else if (userManagement != null && userManagement.isAuthorizableNodeType(ni.primary)) {
- // is authorizable node?
- handleAuthorizable(node, ni);
- } else {
- // regular node
- stack = stack.push(addNode(ni));
- }
- } catch (RepositoryException | IOException e) {
- if (e instanceof ConstraintViolationException && wspFilter.getImportMode(path) != ImportMode.REPLACE) {
- // only warn in case of constraint violations for mode != replace (as best effort is used in that case)
- log.warn("Error during processing of {}: {}, skip node due to import mode {}", path, e.toString(), wspFilter.getImportMode(path));
- importInfo.onNop(path);
- } else {
- log.error("Error during processing of {}: {}", path, e.toString());
- importInfo.onError(path, e);
- }
- stack = stack.push();
- }
- }
- }
- } catch (RepositoryException e) {
- throw new SAXException("Fatal exception while parsing", e);
- }
- }
-
- /**
- * Handle an authorizable node
- *
- * @param node the parent node
- * @param ni doc view node of the authorizable
- * @throws RepositoryException if an error accessing the repository occurrs.
- * @throws SAXException if an XML parsing error occurrs.
- */
- private void handleAuthorizable(Node node, DocViewNode ni) throws RepositoryException, SAXException {
- String id = userManagement.getAuthorizableId(ni);
- String newPath = node.getPath() + "/" + ni.name;
- boolean isIncluded = wspFilter.contains(newPath);
- String oldPath = userManagement.getAuthorizablePath(this.session, id);
- if (oldPath == null) {
- if (!isIncluded) {
- log.trace("auto-creating authorizable node not in filter {}", newPath);
+ private void handleAuthorizable(Node node, DocViewNode2 docViewNode) throws RepositoryException {
+ String id = userManagement.getAuthorizableId(docViewNode);
+ String newPath = node.getPath() + "/" + docViewNode.name;
+ boolean isIncluded = wspFilter.contains(newPath);
+ String oldPath = userManagement.getAuthorizablePath(this.session, id);
+ if (oldPath == null) {
+ if (!isIncluded) {
+ log.trace("auto-creating authorizable node not in filter {}", newPath);
}
// just import the authorizable node
log.trace("Authorizable element detected. starting sysview transformation {}", newPath);
stack = stack.push();
stack.adapter = new JcrSysViewTransformer(node, wspFilter.getImportMode(newPath));
- stack.adapter.startNode(ni);
+ stack.adapter.startNode(docViewNode);
importInfo.onCreated(newPath);
return;
}
@@ -760,7 +651,7 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
case MERGE_PROPERTIES:
// remember desired memberships.
// todo: how to deal with multi-node memberships? see JCRVLT-69
- DocViewProperty prop = ni.props.get("rep:members");
+ DocViewProperty2 prop = docViewNode.getProperties().get(NAME_REP_MEMBERS);
if (prop != null) {
importInfo.registerMemberships(id, prop.values);
}
@@ -775,7 +666,7 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
log.trace("Authorizable element detected. starting sysview transformation {}", newPath);
stack = stack.push();
stack.adapter = new JcrSysViewTransformer(node, mode);
- stack.adapter.startNode(ni);
+ stack.adapter.startNode(docViewNode);
importInfo.onReplaced(newPath);
break;
@@ -787,13 +678,10 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
// we need to tweak the ni.name so that the sysview import does not
// rename the authorizable node name
String newName = Text.getName(oldPath);
- DocViewNode mapped = new DocViewNode(
- newName,
- newName,
- ni.uuid,
- ni.props,
- ni.mixins,
- ni.primary
+ DocViewNode2 mapped = new DocViewNode2(
+ npResolver.getQName(newName),
+ -1,
+ docViewNode.getProperties()
);
// but we need to augment with a potential rep:authorizableId
if (authNode.hasProperty("rep:authorizableId")) {
@@ -811,34 +699,34 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
}
}
- private StackElement addNode(DocViewNode ni) throws RepositoryException, IOException {
+ private StackElement addNode(DocViewNode2 docViewNode) throws RepositoryException, IOException {
final Node currentNode = stack.getNode();
Node existingNode = null;
- if ("".equals(ni.label)) {
+ if ("".equals(docViewNode.label)) {
// special case for root node update
existingNode = currentNode;
} else {
- if (stack.checkForNode() && currentNode.hasNode(ni.label)) {
- existingNode = currentNode.getNode(ni.label);
+ if (stack.checkForNode() && currentNode.hasNode(docViewNode.getName().toString())) {
+ existingNode = currentNode.getNode(docViewNode.getName().toString());
}
- if (ni.uuid != null && idConflictPolicy == IdConflictPolicy.FAIL) {
+ if (docViewNode.getIdentifier() != null && idConflictPolicy == IdConflictPolicy.FAIL) {
try {
// does uuid already exist in the repo?
- Node sameIdNode = session.getNodeByIdentifier(ni.uuid);
+ Node sameIdNode = session.getNodeByIdentifier(docViewNode.getIdentifier());
// edge-case: same node path -> uuid is kept
if (existingNode != null && existingNode.getPath().equals(sameIdNode.getPath())) {
- log.debug("Node with existing identifier {} at {} is being updated without modifying its uuid", ni.uuid, existingNode.getPath());
+ log.debug("Node with existing identifier {} at {} is being updated without modifying its uuid", docViewNode.getIdentifier(), existingNode.getPath());
} else {
// uuid found in path covered by filter
if (isIncluded(sameIdNode, 0)) {
- log.warn("Node identifier {} for to-be imported node {}/{} already taken by {}, trying to release it.", ni.uuid, currentNode.getPath(), ni.label, sameIdNode.getPath());
+ log.warn("Node identifier {} for to-be imported node {}/{} already taken by {}, trying to release it.", docViewNode.getIdentifier(), currentNode.getPath(), docViewNode.getName(), sameIdNode.getPath());
removeReferences(sameIdNode);
session.removeItem(sameIdNode.getPath());
existingNode = null;
} else {
// uuid found in path not-covered by filter
- throw new ReferentialIntegrityException("UUID " + ni.uuid + " already taken by node " + sameIdNode.getPath());
+ throw new ReferentialIntegrityException("UUID " + docViewNode.getIdentifier() + " already taken by node " + sameIdNode.getPath());
}
}
} catch (ItemNotFoundException e) {
@@ -848,20 +736,20 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
}
// check if new node needs to be checked in
- DocViewProperty coProp = ni.props.remove(JcrConstants.JCR_ISCHECKEDOUT);
+ DocViewProperty coProp = docViewNode.props.remove(JcrConstants.JCR_ISCHECKEDOUT);
boolean isCheckedIn = coProp != null && "false".equals(coProp.values[0]);
// create or update node
boolean isNew = existingNode == null;
if (isNew) {
// workaround for bug in jcr2spi if mixins are empty
- if (!ni.props.containsKey(JcrConstants.JCR_MIXINTYPES)) {
- ni.props.put(JcrConstants.JCR_MIXINTYPES,
+ if (!docViewNode.props.containsKey(JcrConstants.JCR_MIXINTYPES)) {
+ docViewNode.props.put(JcrConstants.JCR_MIXINTYPES,
new DocViewProperty(JcrConstants.JCR_MIXINTYPES, new String[0], true, PropertyType.NAME));
}
stack.ensureCheckedOut();
- existingNode = createNewNode(currentNode, ni);
+ existingNode = createNewNode(currentNode, docViewNode);
if (existingNode.getDefinition() == null) {
throw new RepositoryException("Child node not allowed.");
}
@@ -881,7 +769,7 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
importInfo.registerToVersion(existingNode.getPath());
}
ImportMode importMode = wspFilter.getImportMode(existingNode.getPath());
- Node updatedNode = updateExistingNode(existingNode, ni, importMode);
+ Node updatedNode = updateExistingNode(existingNode, docViewNode, importMode);
if (updatedNode != null) {
if (updatedNode.isNodeType(JcrConstants.NT_RESOURCE) && !updatedNode.hasProperty(JcrConstants.JCR_DATA)) {
importInfo.onMissing(existingNode.getPath() + "/" + JcrConstants.JCR_DATA);
@@ -904,7 +792,7 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
* @throws ReferentialIntegrityException in case some references can not be removed (outside filters)
* @throws RepositoryException in case some other error occurs
*/
- public void removeReferences(@NotNull Node node) throws ReferentialIntegrityException, RepositoryException {
+ private void removeReferences(@NotNull Node node) throws ReferentialIntegrityException, RepositoryException {
Collection<String> removableReferencePaths = new ArrayList<>();
PropertyIterator pIter = node.getReferences();
while (pIter.hasNext()) {
@@ -921,11 +809,11 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
}
}
- private @Nullable Node updateExistingNode(@NotNull Node node, @NotNull DocViewNode ni, @NotNull ImportMode importMode) throws RepositoryException {
+ private @Nullable Node updateExistingNode(@NotNull Node node, @NotNull DocViewNode2 ni, @NotNull ImportMode importMode) throws RepositoryException {
VersioningState vs = new VersioningState(stack, node);
Node updatedNode = null;
// try to set uuid via sysview import if it differs from existing one
- if (ni.uuid != null && !node.getIdentifier().equals(ni.uuid) && !"rep:root".equals(ni.primary)) {
+ if (!node.getIdentifier().equals(ni.getIdentifier()) && !"rep:root".equals(ni.getPrimaryType())) {
NodeStash stash = new NodeStash(session, node.getPath());
stash.stash();
Node parent = node.getParent();
@@ -936,23 +824,21 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
} else {
// TODO: is this faster than using sysview import?
// set new primary type (but never set rep:root)
- if (importMode == ImportMode.REPLACE && !"rep:root".equals(ni.primary)) {
- if (!node.getPrimaryNodeType().getName().equals(ni.primary)) {
+ if (importMode == ImportMode.REPLACE && !"rep:root".equals(ni.getPrimaryType())) {
+ if (!node.getPrimaryNodeType().getName().equals(ni.getPrimaryType())) {
vs.ensureCheckedOut();
- node.setPrimaryType(ni.primary);
+ node.setPrimaryType(ni.getPrimaryType());
updatedNode = node;
}
}
// calculate mixins to be added
Set<String> newMixins = new HashSet<>();
- AccessControlHandling acHandling = getAcHandling(ni.name);
- if (ni.mixins != null) {
- for (String mixin : ni.mixins) {
- // omit name if mix:AccessControllable and CLEAR
- if (!aclManagement.isAccessControllableMixin(mixin)
- || acHandling != AccessControlHandling.CLEAR) {
- newMixins.add(mixin);
- }
+ AccessControlHandling acHandling = getAcHandling(ni.getName());
+ for (String mixin : ni.getMixinTypes()) {
+ // omit name if mix:AccessControllable and CLEAR
+ if (!aclManagement.isAccessControllableMixin(mixin)
+ || acHandling != AccessControlHandling.CLEAR) {
+ newMixins.add(mixin);
}
}
// remove mixins not in package (only for mode = replace)
@@ -1011,7 +897,7 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
* @return the newly created node
* @throws RepositoryException
*/
- private @NotNull Node createNewNode(Node parentNode, DocViewNode ni)
+ private @NotNull Node createNewNode(Node parentNode, DocViewNode2 ni)
throws RepositoryException {
final int importUuidBehavior;
switch(idConflictPolicy) {
@@ -1038,48 +924,48 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
handler.startPrefixMapping(prefix, session.getNamespaceURI(prefix));
}
AttributesImpl attrs = new AttributesImpl();
- attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", ni.name);
+ attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", ni.getName().toString());
handler.startElement(Name.NS_SV_URI, "node", "sv:node", attrs);
// check if SNS and a helper uuid if needed
boolean addMixRef = false;
- if (!ni.label.equals(ni.name) && ni.uuid == null) {
- ni.uuid = UUID.randomUUID().toString();
- ni.props.put(JcrConstants.JCR_UUID, new DocViewProperty(
- JcrConstants.JCR_UUID, new String[]{ni.uuid}, false, PropertyType.STRING));
+ Map<Name, DocViewProperty2> properties = ni.getProperties();
+
+ if (ni.getIndex() > 0 && ni.getIdentifier() == null) {
+ properties.put(NameConstants.JCR_UUID, new DocViewProperty2(
+ NameConstants.JCR_UUID, new String[]{UUID.randomUUID().toString()}, false, PropertyType.STRING));
// check mixins
- DocViewProperty mix = ni.props.get(JcrConstants.JCR_MIXINTYPES);
+ DocViewProperty2 mix = properties.get(NameConstants.JCR_MIXINTYPES);
addMixRef = true;
if (mix == null) {
- mix = new DocViewProperty(JcrConstants.JCR_MIXINTYPES, new String[]{JcrConstants.MIX_REFERENCEABLE}, true, PropertyType.NAME);
- ni.props.put(mix.name, mix);
+ mix = new DocViewProperty2(NameConstants.JCR_MIXINTYPES, new String[]{JcrConstants.MIX_REFERENCEABLE}, true, PropertyType.NAME);
+ properties.put(mix.getName(), mix);
} else {
- for (String v : mix.values) {
+ for (String v : mix.getStringValues()) {
if (v.equals(JcrConstants.MIX_REFERENCEABLE)) {
addMixRef = false;
break;
}
}
if (addMixRef) {
- String[] vs = new String[mix.values.length + 1];
- System.arraycopy(mix.values, 0, vs, 0, mix.values.length);
- vs[mix.values.length] = JcrConstants.MIX_REFERENCEABLE;
- mix = new DocViewProperty(JcrConstants.JCR_MIXINTYPES, vs, true, PropertyType.NAME);
- ni.props.put(mix.name, mix);
+ Collection<String> mixinValues = mix.getStringValues();
+ mixinValues.add(JcrConstants.MIX_REFERENCEABLE);
+ mix = new DocViewProperty2(NameConstants.JCR_MIXINTYPES, mixinValues.toArray(new String[0]), true, PropertyType.NAME);
+ properties.put(mix.getName(), mix);
}
}
}
// add the properties
- for (DocViewProperty p : ni.props.values()) {
+ for (DocViewProperty2 p : properties.values()) {
if (p != null && p.values != null) {
// only pass 'protected' properties to the import
- if (PROTECTED_PROPERTIES.contains(p.name)) {
+ if (PROTECTED_PROPERTIES.contains(p.getName())) {
attrs = new AttributesImpl();
- attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", p.name);
- attrs.addAttribute(Name.NS_SV_URI, "type", "sv:type", "CDATA", PropertyType.nameFromValue(p.type));
+ attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", p.getName().toString());
+ attrs.addAttribute(Name.NS_SV_URI, "type", "sv:type", "CDATA", PropertyType.nameFromValue(p.getType()));
handler.startElement(Name.NS_SV_URI, "property", "sv:property", attrs);
- for (String v : p.values) {
- handler.startElement(Name.NS_SV_URI, "value", "sv:value", EMPTY_ATTRIBUTES);
+ for (String v : p.getStringValues()) {
+ handler.startElement(Name.NS_SV_URI, "value", "sv:value", DocViewSAXHandler.EMPTY_ATTRIBUTES);
handler.characters(v.toCharArray(), 0, v.length());
handler.endElement(Name.NS_SV_URI, "value", "sv:value");
}
@@ -1128,51 +1014,50 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
* @return{@code true} in case the property is protected, {@code false} otherwise
* @throws RepositoryException
*/
- private static boolean isPropertyProtected(@NotNull EffectiveNodeType effectiveNodeType, @NotNull DocViewProperty docViewProperty) throws RepositoryException {
- return effectiveNodeType.getApplicablePropertyDefinition(docViewProperty.name, docViewProperty.isMulti, docViewProperty.type).map(PropertyDefinition::isProtected).orElse(false);
+ private boolean isPropertyProtected(@NotNull EffectiveNodeType effectiveNodeType, @NotNull DocViewProperty2 docViewProperty) throws RepositoryException {
+ return effectiveNodeType.getApplicablePropertyDefinition(npResolver.getJCRName(docViewProperty.getName()), docViewProperty.isMultiValue(), docViewProperty.getType()).map(PropertyDefinition::isProtected).orElse(false);
}
- private Node getNodeByUUIDLabelOrName(@NotNull Node currentNode, @NotNull DocViewNode ni, boolean isUuidNewlyAssigned) throws RepositoryException {
+ private Node getNodeByUUIDLabelOrName(@NotNull Node currentNode, @NotNull DocViewNode2 ni, boolean isUuidNewlyAssigned) throws RepositoryException {
Node node = null;
- if (ni.uuid != null && !isUuidNewlyAssigned) {
+ if (ni.getIdentifier() != null && !isUuidNewlyAssigned) {
try {
- node = currentNode.getSession().getNodeByUUID(ni.uuid);
+ node = currentNode.getSession().getNodeByUUID(ni.getIdentifier());
} catch (RepositoryException e) {
- log.warn("Newly created node not found by uuid {}: {}", currentNode.getPath() + "/" + ni.name, e.toString());
+ log.warn("Newly created node not found by uuid {}: {}", currentNode.getPath() + "/" + ni.getName(), e.toString());
}
}
if (node == null) {
try {
- node = currentNode.getNode(ni.label);
+ node = currentNode.getNode(ni.getName().toString());
} catch (RepositoryException e) {
- log.warn("Newly created node not found by label {}: {}", currentNode.getPath() + "/" + ni.name, e.toString());
+ log.warn("Newly created node not found by label {}: {}", currentNode.getPath() + "/" + ni.getName(), e.toString());
}
}
if (node == null) {
try {
- node = currentNode.getNode(ni.name);
+ node = currentNode.getNode(ni.getName().toString());
} catch (RepositoryException e) {
- log.warn("Newly created node not found by name {}: {}", currentNode.getPath() + "/" + ni.name, e.toString());
+ log.warn("Newly created node not found by name {}: {}", currentNode.getPath() + "/" + ni.getName(), e.toString());
throw e;
}
}
return node;
}
- private boolean setUnprotectedProperties(@NotNull Node node, @NotNull DocViewNode ni, boolean overwriteExistingProperties, @Nullable VersioningState vs) throws RepositoryException {
+ private boolean setUnprotectedProperties(@NotNull Node node, @NotNull DocViewNode2 ni, boolean overwriteExistingProperties, @Nullable VersioningState vs) throws RepositoryException {
boolean isAtomicCounter = false;
- if (ni.mixins != null) {
- for (String mixin : ni.mixins) {
+ for (String mixin : ni.getMixinTypes()) {
if ("mix:atomicCounter".equals(mixin)) {
isAtomicCounter = true;
}
}
- }
+
EffectiveNodeType effectiveNodeType = EffectiveNodeType.ofNode(node);
boolean modified = false;
// add properties
- for (DocViewProperty prop : ni.props.values()) {
- if (prop != null && !isPropertyProtected(effectiveNodeType, prop) && (overwriteExistingProperties || !node.hasProperty(prop.name)) && wspFilter.includesProperty(node.getPath() + "/" + prop.name)) {
+ for (DocViewProperty2 prop : ni.getProperties().values()) {
+ if (prop != null && !isPropertyProtected(effectiveNodeType, prop) && (overwriteExistingProperties || !node.hasProperty(prop.getName().toString())) && wspFilter.includesProperty(node.getPath() + "/" + npResolver.getJCRName(prop.getName()))) {
// check if property is allowed
try {
modified |= prop.apply(node);
@@ -1187,7 +1072,7 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
} catch (RepositoryException e1) {
// be lenient in case of mode != replace
if (wspFilter.getImportMode(node.getPath()) != ImportMode.REPLACE) {
- log.warn("Error while setting property {} (ignore due to mode {}): {}", prop.name, wspFilter.getImportMode(node.getPath()), e1);
+ log.warn("Error while setting property {} (ignore due to mode {}): {}", prop.getName(), wspFilter.getImportMode(node.getPath()), e1);
} else {
throw e;
}
@@ -1197,14 +1082,14 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
}
// adjust oak atomic counter
- if (isAtomicCounter && wspFilter.includesProperty(node.getPath() + "/" + PROP_OAK_COUNTER)) {
+ if (isAtomicCounter && wspFilter.includesProperty(node.getPath() + "/" + npResolver.getJCRName(NAME_OAK_COUNTER))) {
long previous = 0;
- if (node.hasProperty(PROP_OAK_COUNTER)) {
- previous = node.getProperty(PROP_OAK_COUNTER).getLong();
+ if (node.hasProperty(NAME_OAK_COUNTER.toString())) {
+ previous = node.getProperty(NAME_OAK_COUNTER.toString()).getLong();
}
long counter = 0;
try {
- counter = Long.valueOf(ni.getValue(PROP_OAK_COUNTER));
+ counter = Long.valueOf(ni.getPropertyValue(NAME_OAK_COUNTER));
} catch (NumberFormatException e) {
// ignore
}
@@ -1219,85 +1104,6 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
/**
* {@inheritDoc}
*/
- @Override
- public void endElement(String uri, String localName, String qName) throws SAXException {
- log.trace("<- element {}", qName);
- try {
- // currentNode's import is finished, check if any child nodes
- // need to be removed
- NodeNameList childNames = stack.getChildNames();
- Node node = stack.getNode();
- int numChildren = 0;
- if (node == null) {
- DocViewAdapter adapter = stack.getAdapter();
- if (adapter != null) {
- adapter.endNode();
- }
- // close transformer if last in stack
- if (stack.adapter != null) {
- List<String> createdPaths = stack.adapter.close();
- for (String createdPath : createdPaths) {
- importInfo.onCreated(createdPath);
- }
- stack.adapter = null;
- log.trace("Sysview transformation complete.");
- }
- } else {
- NodeIterator iter = node.getNodes();
- while (iter.hasNext()) {
- numChildren++;
- Node child = iter.nextNode();
- String path = child.getPath();
- String label = Text.getName(path);
- AccessControlHandling acHandling = getAcHandling(child.getName());
- if (!childNames.contains(label)
- && !hints.contains(path)
- && isIncluded(child, child.getDepth() - rootDepth)) {
- // if the child is in the filter, it belongs to
- // this aggregate and needs to be removed
- if (aclManagement.isACLNode(child)) {
- if (acHandling == AccessControlHandling.OVERWRITE
- || acHandling == AccessControlHandling.CLEAR) {
- importInfo.onDeleted(path);
- aclManagement.clearACL(node);
- }
- } else {
- if (wspFilter.getImportMode(path) == ImportMode.REPLACE) {
- importInfo.onDeleted(path);
- // check if child is not protected
- if (child.getDefinition().isProtected()) {
- log.debug("Refuse to delete protected child node: {}", path);
- } else if (child.getDefinition().isMandatory()) {
- log.debug("Refuse to delete mandatory child node: {}", path);
- } else {
- child.remove();
- }
- }
- }
- } else if (acHandling == AccessControlHandling.CLEAR
- && aclManagement.isACLNode(child)
- && isIncluded(child, child.getDepth() - rootDepth)) {
- importInfo.onDeleted(path);
- aclManagement.clearACL(node);
- }
- }
- if (isIncluded(node, node.getDepth() - rootDepth)) {
- // ensure order
- stack.restoreOrder();
- }
- }
- stack = stack.pop();
- if (node != null && (numChildren == 0 && !childNames.isEmpty() || stack.isRoot())) {
- importInfo.addNameList(node.getPath(), childNames);
- }
- } catch (RepositoryException e) {
- throw new SAXException(e);
- }
- }
-
- /**
- * {@inheritDoc}
- */
public String getURI(String prefix) throws NamespaceException {
try {
return session.getNamespaceURI(prefix);
@@ -1325,117 +1131,20 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
* everything else
*/
@NotNull
- private AccessControlHandling getAcHandling(@NotNull String nodeName) {
- if (cugHandling != null && "rep:cugPolicy".equals(nodeName)) {
+ private AccessControlHandling getAcHandling(@NotNull Name nodeName) {
+ if (cugHandling != null && NAME_REP_CUG_POLICY.equals(nodeName)) {
return cugHandling;
} else {
return aclHandling;
}
}
- /**
- * Helper class that stores information about attachments
- */
- private static class BlobInfo {
-
- private final boolean isMulti;
-
- private final List<Artifact> artifacts = new ArrayList<Artifact>();
-
- public BlobInfo(boolean multi) {
- isMulti = multi;
- }
-
- public boolean isFile() {
- return artifacts.size() > 0 && artifacts.get(0).getType() == ArtifactType.FILE;
- }
-
- public void add(Artifact a) {
- assert artifacts.isEmpty();
- artifacts.add(a);
- }
-
- public void add(int idx, Artifact a) {
- while (idx >= artifacts.size()) {
- artifacts.add(null);
- }
- artifacts.set(idx, a);
- }
-
- public Value[] getValues(Session session)
- throws RepositoryException, IOException {
- Value[] values = new Value[artifacts.size()];
- for (int i = 0; i < values.length; i++) {
- Artifact a = artifacts.get(i);
- try (InputStream input = a.getInputStream()) {
- values[i] = session.getValueFactory().createValue(input);
- }
- }
- return values;
- }
-
- public Value getValue(Session session)
- throws RepositoryException, IOException {
- Artifact a = artifacts.get(0);
- try (InputStream input = a.getInputStream()) {
- return session.getValueFactory().createValue(input);
- }
- }
-
- public void detach() {
- for (Artifact a : artifacts) {
- if (a instanceof PropertyValueArtifact) {
- try {
- ((PropertyValueArtifact) a).detach();
- } catch (IOException e) {
- log.warn("error while detaching property artifact", e);
- } catch (RepositoryException e) {
- log.warn("error while detaching property artifact", e);
- }
- }
- }
- }
- }
-
- private class VersioningState {
-
- private final StackElement stack;
-
- private final Node node;
-
- private boolean isCheckedOut;
-
- private boolean isParentCheckedOut;
-
- private VersioningState(StackElement stack, Node node) throws RepositoryException {
- this.stack = stack;
- this.node = node;
- isCheckedOut = node == null || !node.isNodeType(JcrConstants.MIX_VERSIONABLE) || node.isCheckedOut();
- isParentCheckedOut = stack.isCheckedOut();
- }
-
- public void ensureCheckedOut() throws RepositoryException {
- if (!isCheckedOut) {
- importInfo.registerToVersion(node.getPath());
- try {
- node.checkout();
- } catch (RepositoryException e) {
- log.warn("error while checkout node (ignored)", e);
- }
- isCheckedOut = true;
- }
- if (!isParentCheckedOut) {
- stack.ensureCheckedOut();
- isParentCheckedOut = true;
- }
- }
- }
private class StackElement {
private final Node node;
- private DocViewSAXImporter.StackElement parent;
+ private StackElement parent;
private final NodeNameList childNames = new NodeNameList();
@@ -1486,7 +1195,7 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
return !isNew || parent == null;
}
- public void addName(String name) {
+ public void addName(Name name) {
childNames.addName(name);
}
@@ -1524,40 +1233,102 @@ public class DocViewSAXImporter extends RejectingEntityDefaultHandler implements
}
-}
+ /**
+ * Helper class that stores information about attachments
+ */
+ private static class BlobInfo {
+ private final boolean isMulti;
-/**
- * A representation of a namespace. One of these will
- * be pushed on the namespace stack for each
- * element.
- */
-class NameSpace {
+ private final List<Artifact> artifacts = new ArrayList<Artifact>();
- /**
- * Next NameSpace element on the stack.
- */
- public NameSpace next = null;
+ public BlobInfo(boolean multi) {
+ isMulti = multi;
+ }
- /**
- * Prefix of this NameSpace element.
- */
- public String prefix;
+ public boolean isFile() {
+ return artifacts.size() > 0 && artifacts.get(0).getType() == ArtifactType.FILE;
+ }
- /**
- * Namespace URI of this NameSpace element.
- */
- public String uri; // if null, then Element namespace is empty.
+ public void add(Artifact a) {
+ assert artifacts.isEmpty();
+ artifacts.add(a);
+ }
- /**
- * Construct a namespace for placement on the
- * result tree namespace stack.
- *
- * @param prefix Prefix of this element
- * @param uri URI of this element
- */
- public NameSpace(String prefix, String uri) {
- this.prefix = prefix;
- this.uri = uri;
+ public void add(int idx, Artifact a) {
+ while (idx >= artifacts.size()) {
+ artifacts.add(null);
+ }
+ artifacts.set(idx, a);
+ }
+
+ public Value[] getValues(Session session)
+ throws RepositoryException, IOException {
+ Value[] values = new Value[artifacts.size()];
+ for (int i = 0; i < values.length; i++) {
+ Artifact a = artifacts.get(i);
+ try (InputStream input = a.getInputStream()) {
+ values[i] = session.getValueFactory().createValue(input);
+ }
+ }
+ return values;
+ }
+
+ public Value getValue(Session session)
+ throws RepositoryException, IOException {
+ Artifact a = artifacts.get(0);
+ try (InputStream input = a.getInputStream()) {
+ return session.getValueFactory().createValue(input);
+ }
+ }
+
+ public void detach() {
+ for (Artifact a : artifacts) {
+ if (a instanceof PropertyValueArtifact) {
+ try {
+ ((PropertyValueArtifact) a).detach();
+ } catch (IOException e) {
+ log.warn("error while detaching property artifact", e);
+ } catch (RepositoryException e) {
+ log.warn("error while detaching property artifact", e);
+ }
+ }
+ }
+ }
}
+
+ private class VersioningState {
+
+ private final StackElement stack;
+
+ private final Node node;
+
+ private boolean isCheckedOut;
+
+ private boolean isParentCheckedOut;
+
+ private VersioningState(StackElement stack, Node node) throws RepositoryException {
+ this.stack = stack;
+ this.node = node;
+ isCheckedOut = node == null || !node.isNodeType(JcrConstants.MIX_VERSIONABLE) || node.isCheckedOut();
+ isParentCheckedOut = stack.isCheckedOut();
+ }
+
+ public void ensureCheckedOut() throws RepositoryException {
+ if (!isCheckedOut) {
+ importInfo.registerToVersion(node.getPath());
+ try {
+ node.checkout();
+ } catch (RepositoryException e) {
+ log.warn("error while checkout node (ignored)", e);
+ }
+ isCheckedOut = true;
+ }
+ if (!isParentCheckedOut) {
+ stack.ensureCheckedOut();
+ isParentCheckedOut = true;
+ }
+ }
+ }
+
}
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXHandler.java
new file mode 100644
index 0000000..572cb04
--- /dev/null
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewSAXHandler.java
@@ -0,0 +1,265 @@
+/*
+ * 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.vault.fs.impl.io;
+
+import java.io.IOException;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.NamespaceException;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
+import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
+import org.apache.jackrabbit.util.ISO9075;
+import org.apache.jackrabbit.util.Text;
+import org.apache.jackrabbit.vault.fs.io.DocViewParserHandler;
+import org.apache.jackrabbit.vault.util.DocViewNode2;
+import org.apache.jackrabbit.vault.util.DocViewProperty2;
+import org.apache.jackrabbit.vault.util.RejectingEntityDefaultHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.NamespaceSupport;
+
+/**
+ * Implements an importer that processes SAX events from a (modified) document
+ * view. The behaviour for existing nodes works as follows:
+ * TODO: better description
+ * <pre>
+ *
+ * - extended docview always includes SNS indexes
+ * - label is the last element of the path
+ * - uuid "child" means uuid of a direct child node matches
+ * - uuid "desc" means uuid of a descendant child node matches
+ * - uuid "other" means uuid of a node outside of the node tree matches
+ *
+ * uuid | label | nt | result
+ * - | no | - | create
+ * - | yes | no | replace
+ * - | yes | yes | reuse
+ * no | no | - | create
+ * no | yes | no | replace
+ * no | yes | yes | reuse
+ * child | no | no | replace
+ * child | no | yes | replace
+ * child | yes | no | replace
+ * child | yes | yes | reuse
+ * desc | - | - | *error*
+ * other | - | - | *error*
+ * </pre>
+ */
+public class DocViewSAXHandler extends RejectingEntityDefaultHandler implements NamespaceResolver {
+
+
+ private static final NameFactory FACTORY = NameFactoryImpl.getInstance();
+
+ /**
+ * the default logger
+ */
+ static final Logger log = LoggerFactory.getLogger(DocViewSAXHandler.class);
+
+ /**
+ * empty attributes
+ */
+ static final Attributes EMPTY_ATTRIBUTES = new AttributesImpl();
+
+ /**
+ * the current namespace state
+ */
+ private final NamespaceSupport nsSupport;
+
+ /**
+ * the default name path resolver
+ */
+ private final DefaultNamePathResolver npResolver = new DefaultNamePathResolver(this);
+
+
+ private final DocViewParserHandler handler;
+
+ private final String rootNodePath;
+
+ private boolean hasVisitedFirstElement = false;
+
+ public DocViewSAXHandler(DocViewParserHandler handler, String rootNodePath) {
+ super();
+ this.handler = handler;
+ this.rootNodePath = rootNodePath;
+ nsSupport = new NamespaceSupport();
+ }
+
+
+ @Override
+ public void setDocumentLocator(Locator locator) {
+ // TODO Auto-generated method stub
+ super.setDocumentLocator(locator);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void startDocument() throws SAXException {
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void endDocument() throws SAXException {
+ try {
+ handler.endDocument();
+ } catch (RepositoryException | IOException e) {
+ throw new SAXException(e);
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void characters(char ch[], int start, int length) throws SAXException {
+ // can be ignored in docview
+ }
+
+ @Override
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ log.trace("-> prefixMapping for {}:{}", prefix, uri);
+ nsSupport.declarePrefix(prefix, uri);
+ }
+
+ @Override
+ public void endPrefixMapping(String prefix) throws SAXException {
+ log.trace("<- prefixMapping for {}", prefix);
+ nsSupport.popContext();
+ }
+
+
+ /**
+ * Extracts the index and the original item name from a name according to <a href="https://docs.adobe.com/content/docs/en/spec/jcr/2.0/22_Same-Name_Siblings.html#22.2%20Addressing%20Same-Name%20Siblings%20by%20Path>JCR 2.0 22.2</a>
+ * @param name
+ * @return
+ */
+ private Map.Entry<String, Integer> getNameAndIndex(String name) {
+ int idx = name.lastIndexOf('[');
+ int index = -1;
+ if (idx > 0) {
+ // extract index
+ int idx2 = name.indexOf(']', idx);
+ if (idx2 > 0) {
+ try {
+ index = Integer.valueOf(name.substring(idx + 1, idx2));
+ } catch (NumberFormatException e) {
+ // ignore
+ }
+ }
+ name = name.substring(0, idx);
+ }
+ return new SimpleEntry<>(name, index);
+ }
+
+
+ @Override
+ public String getURI(String prefix) throws NamespaceException {
+ String uri = nsSupport.getURI(prefix);
+ if (uri == null) {
+ throw new NamespaceException("Unknown prefix " + prefix);
+ }
+ return uri;
+ }
+
+ @Override
+ public String getPrefix(String uri) throws NamespaceException {
+ String prefix = nsSupport.getPrefix(uri);
+ if (prefix == null) {
+ throw new NamespaceException("Unmapped URL " + uri);
+ }
+ return prefix;
+ }
+
+ public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
+ // special handling for root node
+ log.trace("-> element {}", qName);
+ Name name;
+ final int index;
+ if (!hasVisitedFirstElement
+ && localName.equals(NameConstants.JCR_ROOT.getLocalName())
+ && uri.equals(NameConstants.JCR_ROOT.getNamespaceURI())) {
+ Map.Entry<String, Integer> nameAndIndex = getNameAndIndex(Text.getName(rootNodePath));
+ index = nameAndIndex.getValue();
+ try {
+ name = npResolver.getQName(nameAndIndex.getKey());
+ } catch (NamespaceException | IllegalNameException e) {
+ throw new SAXException("Invalid name space", e);
+ }
+ } else {
+ Map.Entry<String, Integer> nameAndIndex = getNameAndIndex(ISO9075.decode(localName));
+ index = nameAndIndex.getValue();
+ name = FACTORY.create(uri, nameAndIndex.getKey());
+ }
+ hasVisitedFirstElement = true;
+ try {
+ Map<Name, DocViewProperty2> props = new HashMap<>();
+ for (int i = 0; i < attributes.getLength(); i++) {
+ // ignore non CDATA attributes
+ if (!attributes.getType(i).equals("CDATA")) {
+ continue;
+ }
+ Name pName = FACTORY.create(
+ attributes.getURI(i),
+ ISO9075.decode(attributes.getLocalName(i)));
+ DocViewProperty2 property = DocViewProperty2.parse(
+ pName.toString(),
+ attributes.getValue(i));
+ props.put(property.name, property);
+
+ }
+ DocViewNode2 ni = new DocViewNode2(name, index, props);
+ // TODO: path
+ handler.startDocViewNode(null, ni);
+
+ } catch (RepositoryException|IOException e) {
+ throw new SAXException("Error while processing element " + qName, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ log.trace("<- element {}", qName);
+ try {
+ handler.endDocViewNode(qName, null);
+ } catch (RepositoryException|IOException e) {
+ throw new SAXException(e);
+ }
+ }
+}
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java
index 7486ad7..9d14429 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/FileArtifactHandler.java
@@ -227,15 +227,7 @@ public class FileArtifactHandler extends AbstractArtifactHandler {
mode = wspFilter.getImportMode(path);
}
if (mode != ImportMode.MERGE) {
- try {
- DocViewSAXImporter handler = new DocViewSAXImporter(newParent, newName, newSet, wspFilter, options.getIdConflictPolicy());
- handler.setAclHandling(getAcHandling());
- handler.setCugHandling(getCugHandling());
- parseXmlWithSaxHandler(file.getInputSource(), handler);
- info.merge(handler.getInfo());
- } catch (ParserConfigurationException|SAXException e) {
- throw new RepositoryException(e);
- }
+ info.merge(importDocView(file.getInputSource(), newParent, newName, newSet, wspFilter, options.getIdConflictPolicy()));
} else {
info.onNop(path);
}
@@ -322,15 +314,7 @@ public class FileArtifactHandler extends AbstractArtifactHandler {
if (idx > 0) {
rootName = rootName.substring(0, idx);
}
- DocViewSAXImporter handler = new DocViewSAXImporter(parent, rootName, artifacts, wspFilter, options.getIdConflictPolicy());
- handler.setAclHandling(getAcHandling());
- handler.setCugHandling(getCugHandling());
- try {
- parseXmlWithSaxHandler(source, handler);
- return handler.getInfo();
- } catch (ParserConfigurationException|SAXException e) {
- throw new RepositoryException(e);
- }
+ return importDocView(source, parent, rootName, artifacts, wspFilter, options.getIdConflictPolicy());
}
private boolean importNtResource(ImportInfo info, Node content, Artifact artifact)
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/GenericArtifactHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/GenericArtifactHandler.java
index 518bbac..de38b78 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/GenericArtifactHandler.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/GenericArtifactHandler.java
@@ -88,19 +88,7 @@ public class GenericArtifactHandler extends AbstractArtifactHandler {
}
}
}
- try {
- DocViewSAXImporter handler = new DocViewSAXImporter(parent, name, artifacts, wspFilter, options.getIdConflictPolicy());
- handler.setAclHandling(getAcHandling());
- handler.setCugHandling(getCugHandling());
- parseXmlWithSaxHandler(source, handler);
- info.merge(handler.getInfo());
- } catch (ParserConfigurationException e) {
- throw new RepositoryException(e);
- } catch (SAXException e) {
- info = new ImportInfoImpl();
- info.onError(path, e);
- log.error("Error while parsing {}: {}", source.getSystemId(), e);
- }
+ info.merge(importDocView(source, parent, name, artifacts, wspFilter, options.getIdConflictPolicy()));
}
return info;
}
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JackrabbitACLImporter.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JackrabbitACLImporter.java
index 964aa86..829ebbb 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JackrabbitACLImporter.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JackrabbitACLImporter.java
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.vault.fs.impl.io;
import java.security.Principal;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -45,11 +46,15 @@ import org.apache.jackrabbit.api.security.authorization.PrincipalSetPolicy;
import org.apache.jackrabbit.api.security.principal.PrincipalManager;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
import org.apache.jackrabbit.vault.fs.io.AccessControlHandling;
import org.apache.jackrabbit.vault.util.DocViewNode;
+import org.apache.jackrabbit.vault.util.DocViewNode2;
import org.apache.jackrabbit.vault.util.DocViewProperty;
+import org.apache.jackrabbit.vault.util.DocViewProperty2;
import org.slf4j.Logger;
-import org.xml.sax.SAXException;
/**
* Implements a doc view adapter that reads the ACL information of the docview hierarchy and applies it to the
@@ -57,10 +62,13 @@ import org.xml.sax.SAXException;
*/
public class JackrabbitACLImporter implements DocViewAdapter {
+ private static final Name NAME_REP_EFFECTIVE_PATH = NameFactoryImpl.getInstance().create(Name.NS_REP_URI, "effectivePath");
+ private static final Name NAME_REP_PRINCIPAL_NAMES = NameFactoryImpl.getInstance().create(Name.NS_REP_URI, "principalNames");
+
/**
* default logger
*/
- private static final Logger log = DocViewSAXImporter.log;
+ private static final Logger log = DocViewSAXHandler.log;
private final JackrabbitSession session;
@@ -108,21 +116,21 @@ public class JackrabbitACLImporter implements DocViewAdapter {
this.states.push(State.INITIAL);
}
- public void startNode(DocViewNode node) {
+ public void startNode(DocViewNode2 node) {
State state = states.peek();
switch (state) {
case INITIAL:
- if ("rep:ACL".equals(node.primary)) {
+ if ("rep:ACL".equals(node.getPrimaryType())) {
importPolicy = new ImportedAcList();
state = State.ACL;
- } else if ("rep:CugPolicy".equals(node.primary)) {
+ } else if ("rep:CugPolicy".equals(node.getPrimaryType())) {
importPolicy = new ImportedPrincipalSet(node);
state = State.PRINCIPAL_SET_POLICY;
- } else if ("rep:PrincipalPolicy".equals(node.primary)) {
+ } else if ("rep:PrincipalPolicy".equals(node.getPrimaryType())) {
importPolicy = new ImportedPrincipalAcList(node);
state = State.ACL;
} else {
- log.error("Error while reading access control content: Expected rep:ACL or rep:CugPolicy but was: {}", node.primary);
+ log.error("Error while reading access control content: Expected rep:ACL or rep:CugPolicy but was: {}", node.getPrimaryType());
state = State.ERROR;
}
break;
@@ -141,12 +149,12 @@ public class JackrabbitACLImporter implements DocViewAdapter {
states.push(state);
}
- public void endNode() throws SAXException {
+ public void endNode() {
State state = states.pop();
importPolicy.endNode(state);
}
- public List<String> close() throws SAXException, RepositoryException {
+ public List<String> close() throws RepositoryException {
if (states.peek() != State.INITIAL) {
log.error("Unexpected end state: {}", states.peek());
}
@@ -163,7 +171,7 @@ public class JackrabbitACLImporter implements DocViewAdapter {
private abstract class ImportedPolicy<T extends AccessControlPolicy> {
- abstract State append(State state, DocViewNode childNode);
+ abstract State append(State state, DocViewNode2 node);
abstract void endNode(State state);
@@ -235,7 +243,7 @@ public class JackrabbitACLImporter implements DocViewAdapter {
}
@Override
- State append(State state, DocViewNode childNode) {
+ State append(State state, DocViewNode2 childNode) {
if (state == State.ACL) {
try {
currentACE = new ACE(childNode);
@@ -249,7 +257,7 @@ public class JackrabbitACLImporter implements DocViewAdapter {
currentACE.addRestrictions(childNode);
return State.RESTRICTION;
} else {
- log.error("Error while reading access control content: Unexpected node: {} for state {}", childNode.primary, state);
+ log.error("Error while reading access control content: Unexpected node: {} for state {}", childNode.getPrimaryType(), state);
return State.ERROR;
}
}
@@ -322,18 +330,18 @@ public class JackrabbitACLImporter implements DocViewAdapter {
private final class ImportedPrincipalSet extends ImportedPolicy<PrincipalSetPolicy> {
- private final String[] principalNames;
+ private final Collection<String> principalNames;
- private ImportedPrincipalSet(DocViewNode node) {
+ private ImportedPrincipalSet(DocViewNode2 node) {
// don't change the status as a cug policy may not have child nodes.
// just collect the rep:principalNames property
// any subsequent state would indicate an error
- principalNames = node.getValues("rep:principalNames");
+ principalNames = node.getPropertyValues(NAME_REP_PRINCIPAL_NAMES);
}
@Override
- State append(State state, DocViewNode childNode) {
- log.error("Error while reading access control content: Unexpected node: {} for state {}", childNode.primary, state);
+ State append(State state, DocViewNode2 childNode) {
+ log.error("Error while reading access control content: Unexpected node: {} for state {}", childNode.getPrimaryType(), state);
return State.ERROR;
}
@@ -356,10 +364,7 @@ public class JackrabbitACLImporter implements DocViewAdapter {
}
// TODO: correct behavior for MERGE and MERGE_PRESERVE?
- Principal[] principals = new Principal[principalNames.length];
- for (int i = 0; i < principals.length; i++) {
- principals[i] = getPrincipal(principalNames[i]);
- }
+ Principal[] principals = principalNames.stream().map(name -> getPrincipal(name)).toArray(Principal[]::new);
psPolicy.addPrincipals(principals);
acMgr.setPolicy(accessControlledPath, psPolicy);
@@ -378,8 +383,8 @@ public class JackrabbitACLImporter implements DocViewAdapter {
private final List<PrincipalEntry> entries = new ArrayList<>();
private PrincipalEntry currentEntry;
- private ImportedPrincipalAcList(DocViewNode node) {
- String principalName = node.getValue("rep:principalName");
+ private ImportedPrincipalAcList(DocViewNode2 node) {
+ String principalName = node.getPropertyValue(NameConstants.REP_PRINCIPAL_NAME);
Principal p = pMgr.getPrincipal(principalName);
if (p == null) {
try {
@@ -398,10 +403,10 @@ public class JackrabbitACLImporter implements DocViewAdapter {
}
@Override
- State append(State state, DocViewNode childNode) {
+ State append(State state, DocViewNode2 childNode) {
if (state == State.ACL) {
- if (!"rep:PrincipalEntry".equals(childNode.primary)) {
- log.error("Unexpected node type of access control entry: {}", childNode.primary);
+ if (!"rep:PrincipalEntry".equals(childNode.getPrimaryType())) {
+ log.error("Unexpected node type of access control entry: {}", childNode.getPrimaryType());
return State.ERROR;
}
currentEntry = new PrincipalEntry(childNode);
@@ -411,7 +416,7 @@ public class JackrabbitACLImporter implements DocViewAdapter {
currentEntry.addRestrictions(childNode);
return State.RESTRICTION;
} else {
- log.error("Error while reading access control content: Unexpected node: {} for state {}", childNode.primary, state);
+ log.error("Error while reading access control content: Unexpected node: {} for state {}", childNode.getPrimaryType(), state);
return State.ERROR;
}
}
@@ -462,16 +467,16 @@ public class JackrabbitACLImporter implements DocViewAdapter {
private static class AbstractEntry {
- private final String[] privileges;
- private final Map<String, DocViewProperty> restrictions = new HashMap<String, DocViewProperty>();
+ private final Collection<String> privileges;
+ private final Map<Name, DocViewProperty2> restrictions = new HashMap<>();
- private AbstractEntry(DocViewNode node) {
- privileges = node.getValues("rep:privileges");
+ private AbstractEntry(DocViewNode2 node) {
+ privileges = node.getPropertyValues(NameConstants.REP_PRIVILEGES);
addRestrictions(node);
}
- void addRestrictions(DocViewNode node) {
- restrictions.putAll(node.props);
+ void addRestrictions(DocViewNode2 node) {
+ restrictions.putAll(node.getProperties());
}
void convertRestrictions(JackrabbitAccessControlList acl, ValueFactory vf, Map<String, Value> svRestrictions, Map<String, Value[]> mvRestrictions) throws RepositoryException {
@@ -502,16 +507,16 @@ public class JackrabbitACLImporter implements DocViewAdapter {
private final boolean allow;
private final String principalName;
- private ACE(DocViewNode node) {
- super(node);
- if ("rep:GrantACE".equals(node.primary)) {
+ private ACE(DocViewNode2 childNode) {
+ super(childNode);
+ if ("rep:GrantACE".equals(childNode.getPrimaryType())) {
allow = true;
- } else if ("rep:DenyACE".equals(node.primary)) {
+ } else if ("rep:DenyACE".equals(childNode.getPrimaryType())) {
allow = false;
} else {
- throw new IllegalArgumentException("Unexpected node ACE type: " + node.primary);
+ throw new IllegalArgumentException("Unexpected node ACE type: " + childNode.getPrimaryType());
}
- principalName = node.getValue("rep:principalName");
+ principalName = childNode.getPropertyValue(NameConstants.REP_PRINCIPAL_NAME);
}
}
@@ -519,9 +524,9 @@ public class JackrabbitACLImporter implements DocViewAdapter {
private final String effectivePath;
- private PrincipalEntry(DocViewNode node) {
+ private PrincipalEntry(DocViewNode2 node) {
super(node);
- String v = node.getValue("rep:effectivePath");
+ String v = node.getPropertyValue(NAME_REP_EFFECTIVE_PATH);
if (v.isEmpty()) {
effectivePath = null;
} else {
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JcrSysViewTransformer.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JcrSysViewTransformer.java
index 11dea93..129784f 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JcrSysViewTransformer.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/JcrSysViewTransformer.java
@@ -22,6 +22,7 @@ import java.util.List;
import java.util.Set;
import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.InvalidSerializedDataException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PropertyType;
@@ -31,7 +32,9 @@ import javax.jcr.Session;
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.vault.fs.api.ImportMode;
import org.apache.jackrabbit.vault.util.DocViewNode;
+import org.apache.jackrabbit.vault.util.DocViewNode2;
import org.apache.jackrabbit.vault.util.DocViewProperty;
+import org.apache.jackrabbit.vault.util.DocViewProperty2;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@@ -75,11 +78,11 @@ public class JcrSysViewTransformer implements DocViewAdapter {
private long ignoreLevel = 0;
- public JcrSysViewTransformer(@NotNull Node node, @NotNull ImportMode importMode) throws SAXException, RepositoryException {
+ public JcrSysViewTransformer(@NotNull Node node, @NotNull ImportMode importMode) throws RepositoryException {
this(node, null, importMode);
}
- JcrSysViewTransformer(@NotNull Node node, @Nullable String existingPath, @NotNull ImportMode importMode) throws RepositoryException, SAXException {
+ JcrSysViewTransformer(@NotNull Node node, @Nullable String existingPath, @NotNull ImportMode importMode) throws RepositoryException {
Session session = node.getSession();
parent = node;
handler = session.getImportContentHandler(
@@ -90,9 +93,13 @@ public class JcrSysViewTransformer implements DocViewAdapter {
);
// first define the current namespaces
String[] prefixes = session.getNamespacePrefixes();
- handler.startDocument();
- for (String prefix: prefixes) {
- handler.startPrefixMapping(prefix, session.getNamespaceURI(prefix));
+ try {
+ handler.startDocument();
+ for (String prefix: prefixes) {
+ handler.startPrefixMapping(prefix, session.getNamespaceURI(prefix));
+ }
+ } catch (SAXException e) {
+ throw new RepositoryException("Can not use sysview handler", e);
}
this.existingPath = existingPath;
@@ -105,8 +112,13 @@ public class JcrSysViewTransformer implements DocViewAdapter {
this.importMode = importMode;
}
- public List<String> close() throws SAXException {
- handler.endDocument();
+ @Override
+ public List<String> close() throws InvalidSerializedDataException {
+ try {
+ handler.endDocument();
+ } catch (SAXException e) {
+ throw new InvalidSerializedDataException("Invalid sysview", e);
+ }
// get list of created paths
List<String> paths = new ArrayList<String>();
@@ -142,43 +154,48 @@ public class JcrSysViewTransformer implements DocViewAdapter {
}
}
- public void startNode(DocViewNode ni) throws SAXException {
+ @Override
+ public void startNode(DocViewNode2 ni) throws RepositoryException {
if (ignoreLevel > 0) {
- DocViewSAXImporter.log.trace("ignoring child node of excluded node: {}", ni.name);
+ DocViewSAXHandler.log.trace("ignoring child node of excluded node: {}", ni.getName());
ignoreLevel++;
return;
}
- if (excludedNodeNames.contains(ni.name)) {
- DocViewSAXImporter.log.trace("Ignoring excluded node {}", ni.name);
+ if (excludedNodeNames.contains(ni.getName())) {
+ DocViewSAXHandler.log.trace("Ignoring excluded node {}", ni.getName());
ignoreLevel = 1;
return;
}
- DocViewSAXImporter.log.trace("Transforming element to sysview {}", ni.name);
-
- AttributesImpl attrs = new AttributesImpl();
-
- attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", ni.name);
- handler.startElement(Name.NS_SV_URI, "node", "sv:node", attrs);
+ DocViewSAXHandler.log.trace("Transforming element to sysview {}", ni.getName());
- // add the properties
- for (DocViewProperty p: ni.props.values()) {
- if (p != null && p.values != null) {
- attrs = new AttributesImpl();
- attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", p.name);
- attrs.addAttribute(Name.NS_SV_URI, "type", "sv:type", "CDATA", PropertyType.nameFromValue(p.type));
- if (p.isMulti) {
- attrs.addAttribute(Name.NS_SV_URI, "multiple", "sv:multiple", "CDATA", "true");
- }
-
- handler.startElement(Name.NS_SV_URI, "property", "sv:property", attrs);
- for (String v: p.values) {
- handler.startElement(Name.NS_SV_URI, "value", "sv:value", DocViewSAXImporter.EMPTY_ATTRIBUTES);
- handler.characters(v.toCharArray(), 0, v.length());
- handler.endElement(Name.NS_SV_URI, "value", "sv:value");
+ try {
+ AttributesImpl attrs = new AttributesImpl();
+
+ attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", ni.getName().toString());
+ handler.startElement(Name.NS_SV_URI, "node", "sv:node", attrs);
+
+ // add the properties
+ for (DocViewProperty2 p: ni.getProperties().values()) {
+ if (p != null && p.values != null) {
+ attrs = new AttributesImpl();
+ attrs.addAttribute(Name.NS_SV_URI, "name", "sv:name", "CDATA", p.name);
+ attrs.addAttribute(Name.NS_SV_URI, "type", "sv:type", "CDATA", PropertyType.nameFromValue(p.type));
+ if (p.isMulti) {
+ attrs.addAttribute(Name.NS_SV_URI, "multiple", "sv:multiple", "CDATA", "true");
+ }
+
+ handler.startElement(Name.NS_SV_URI, "property", "sv:property", attrs);
+ for (String v: p.values) {
+ handler.startElement(Name.NS_SV_URI, "value", "sv:value", DocViewSAXHandler.EMPTY_ATTRIBUTES);
+ handler.characters(v.toCharArray(), 0, v.length());
+ handler.endElement(Name.NS_SV_URI, "value", "sv:value");
+ }
+ handler.endElement(Name.NS_SV_URI, "property", "sv:property");
}
- handler.endElement(Name.NS_SV_URI, "property", "sv:property");
}
+ } catch (SAXException e) {
+ throw new InvalidSerializedDataException("Invalid sysview", e);
}
if (rootName == null) {
@@ -186,12 +203,17 @@ public class JcrSysViewTransformer implements DocViewAdapter {
}
}
- public void endNode() throws SAXException {
+ @Override
+ public void endNode() throws RepositoryException {
if (ignoreLevel > 0) {
ignoreLevel--;
return;
}
- handler.endElement(Name.NS_SV_URI, "node", "sv:node");
+ try {
+ handler.endElement(Name.NS_SV_URI, "node", "sv:node");
+ } catch (SAXException e) {
+ throw new InvalidSerializedDataException("Invalid sysview", e);
+ }
}
public JcrSysViewTransformer excludeNode(String name) {
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java
new file mode 100644
index 0000000..34a4c03
--- /dev/null
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParser.java
@@ -0,0 +1,47 @@
+package org.apache.jackrabbit.vault.fs.io;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.jackrabbit.vault.fs.impl.io.DocViewSAXHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class DocViewParser {
+
+ private SAXParser createSaxParser() throws ParserConfigurationException, SAXException {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
+ SAXParser parser = factory.newSAXParser();
+ parser.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ parser.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
+ return parser;
+ }
+
+ /**
+ *
+ * @param inputSource
+ * @param handler
+ * @throws IOException
+ */
+ public void parse(String rootNodePath, InputSource inputSource, DocViewParserHandler handler) throws IOException, RepositoryException {
+ final SAXParser parser;
+ try {
+ parser = createSaxParser();
+ } catch (ParserConfigurationException|SAXException e) {
+ throw new IllegalStateException("Could not create SAX parser" + e.getMessage(), e);
+ }
+ try {
+ parser.parse(inputSource, new DocViewSAXHandler(handler, rootNodePath));
+ } catch (SAXException e) {
+ // all other exception just pass on as IOException
+ throw new IllegalArgumentException("Could not parse " + inputSource, e);
+ }
+ }
+}
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParserHandler.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParserHandler.java
new file mode 100644
index 0000000..8fcebc2
--- /dev/null
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/io/DocViewParserHandler.java
@@ -0,0 +1,29 @@
+/*************************************************************************
+ * 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.vault.fs.io;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.vault.util.DocViewNode2;
+
+public interface DocViewParserHandler {
+ void startDocViewNode(String parentNodePath, DocViewNode2 docViewNode) throws IOException, RepositoryException;
+ void endDocViewNode(String parentNodePath, DocViewNode2 docViewNode) throws IOException, RepositoryException; // TODO: how to access stack (i.e.
+ void endDocument() throws RepositoryException, IOException; // only called once
+}
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode.java
index 09c0771..98a742e 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode.java
@@ -32,12 +32,14 @@ import org.jetbrains.annotations.Nullable;
import org.xml.sax.Attributes;
/**
- * Helper class that represents a (jcr) node abstraction based on
+ * Helper class that represents a JCR node abstraction encapsulating multiple
* {@link org.apache.jackrabbit.vault.util.DocViewProperty properties}.
+ * @deprecated Use {@link DocViewNode2} instead.
*/
+@Deprecated
public class DocViewNode {
- public final @NotNull String name;
+ public final @NotNull String name; // always use expanded names here
/** usually equal to {@link #name} except when this node has a same name sibling, in that case label has format {@code <name>[index]}, https://docs.adobe.com/content/docs/en/spec/jcr/2.0/22_Same-Name_Siblings.html#22.2%20Addressing%20Same-Name%20Siblings%20by%20Path */
public final @NotNull String label;
public final @NotNull Map<String, DocViewProperty> props = new HashMap<>();
@@ -54,8 +56,13 @@ public class DocViewNode {
this.props.putAll(props);
}
+ @Deprecated
public DocViewNode(@NotNull String name, @NotNull String label, Attributes attributes, NamePathResolver npResolver)
throws NamespaceException {
+ this(name, label, attributes);
+ }
+ public DocViewNode(@NotNull String name, @NotNull String label, Attributes attributes)
+ throws NamespaceException {
this.name = name;
this.label = label;
String uuid = null;
@@ -70,7 +77,7 @@ public class DocViewNode {
attributes.getURI(i),
ISO9075.decode(attributes.getLocalName(i)));
DocViewProperty info = DocViewProperty.parse(
- npResolver.getJCRName(pName),
+ pName.toString(),
attributes.getValue(i));
props.put(info.name, info);
if (pName.equals(NameConstants.JCR_UUID)) {
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode2.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode2.java
new file mode 100644
index 0000000..d19610e
--- /dev/null
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewNode2.java
@@ -0,0 +1,80 @@
+/*************************************************************************
+ * 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.vault.util;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Helper class that represents an immutable JCR node abstraction encapsulating multiple
+ * {@link org.apache.jackrabbit.vault.util.DocViewProperty2 properties}.
+ */
+public class DocViewNode2 {
+
+ private final @NotNull Name name;
+ /** usually equal to {@link #name} except when this node has a same name sibling, in that case label has format {@code <name>[index]}, https://docs.adobe.com/content/docs/en/spec/jcr/2.0/22_Same-Name_Siblings.html#22.2%20Addressing%20Same-Name%20Siblings%20by%20Path */
+ private final int index; // either 0 if no same-name sibling or 1 and above for SNS
+ private final @NotNull Map<Name, DocViewProperty2> properties = new HashMap<>();
+
+ public DocViewNode2(@NotNull Name name, int index, @NotNull Map<Name, DocViewProperty2> props) {
+ this.name = name;
+ this.index = index;
+ this.properties.putAll(props);
+ }
+
+ public Name getName() {
+ return name;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public @NotNull Map<Name, DocViewProperty2> getProperties() {
+ return properties;
+ }
+
+ public @NotNull Collection<String> getPropertyValues(@NotNull Name name) {
+ DocViewProperty2 prop = properties.get(name);
+ return prop == null ? null : prop.getStringValues();
+ }
+
+ public @Nullable String getPropertyValue(@NotNull Name name) {
+ DocViewProperty2 prop = properties.get(name);
+ return prop == null ? null : prop.getStringValue();
+ }
+
+
+ public @Nullable String getPrimaryType() {
+ return getPropertyValue(NameConstants.JCR_PRIMARYTYPE);
+ }
+
+ public @NotNull Collection<String> getMixinTypes() {
+ return getPropertyValues(NameConstants.JCR_MIXINTYPES);
+ }
+
+ public @Nullable String getIdentifier() {
+ return getPropertyValue(NameConstants.JCR_UUID);
+ }
+
+}
\ No newline at end of file
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java
index 0c9b065..3a6621a 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java
@@ -55,8 +55,9 @@ import org.jetbrains.annotations.NotNull;
* value := is a string representation of the value where the following characters are escaped: ',\[{' with a leading '\'
* </code>
* </pre>
- *
+ * @deprecated Use {@link DocViewProperty2} instead.
*/
+@Deprecated
public class DocViewProperty {
public static final String BINARY_REF = "BinaryRef";
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty2.java
similarity index 85%
copy from vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java
copy to vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty2.java
index 0c9b065..37ccfce 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/DocViewProperty2.java
@@ -19,6 +19,7 @@ package org.apache.jackrabbit.vault.util;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -38,10 +39,15 @@ import javax.jcr.version.VersionException;
import org.apache.jackrabbit.api.ReferenceBinary;
import org.apache.jackrabbit.commons.jackrabbit.SimpleReferenceBinary;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
import org.apache.jackrabbit.util.Text;
import org.apache.jackrabbit.util.XMLChar;
import org.apache.jackrabbit.value.ValueHelper;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* Helper class that represents a JCR property in the FileVault (enhanced) document view format.
@@ -57,43 +63,45 @@ import org.jetbrains.annotations.NotNull;
* </pre>
*
*/
-public class DocViewProperty {
+public class DocViewProperty2 {
public static final String BINARY_REF = "BinaryRef";
+ private static final NameFactory FACTORY = NameFactoryImpl.getInstance();
+
/**
* name of the property
*/
- public final String name;
+ private final Name name;
/**
* value(s) of the property. always contains at least one value if this is
* not a mv property.
*/
- public final String[] values;
+ private final String[] values;
/**
* indicates a multi-value property
*/
- public final boolean isMulti;
+ private final boolean isMultiValue;
/**
* type of this property (can be undefined)
*/
- public final int type;
+ private final int type;
/**
* indicates a binary ref property
*/
- public final boolean isReferenceProperty;
+ private final boolean isReferenceProperty;
/**
* set of unambigous property names (which never need an explicit type descriptor as the types are defined by the spec)
*/
- private static final Set<String> UNAMBIGOUS = new HashSet<>();
+ private static final Set<Name> UNAMBIGOUS = new HashSet<>();
static {
- UNAMBIGOUS.add("jcr:primaryType");
- UNAMBIGOUS.add("jcr:mixinTypes");
+ UNAMBIGOUS.add(NameConstants.JCR_PRIMARYTYPE);
+ UNAMBIGOUS.add(NameConstants.JCR_MIXINTYPES);
}
/**
@@ -107,7 +115,7 @@ public class DocViewProperty {
* @return the new property
* @throws RepositoryException
*/
- public static DocViewProperty fromValues(@NotNull String name, @NotNull Value[] values, int type, boolean isMulti, boolean sort, boolean useBinaryReferences) throws RepositoryException {
+ public static DocViewProperty2 fromValues(@NotNull Name name, @NotNull Value[] values, int type, boolean isMulti, boolean sort, boolean useBinaryReferences) throws RepositoryException {
List<String> strValues = new ArrayList<>();
if (isMulti) {
if (sort) {
@@ -135,7 +143,7 @@ public class DocViewProperty {
if (isBinaryRef == null) {
isBinaryRef = false;
}
- return new DocViewProperty(name, strValues.toArray(new String[0]), isMulti, type, isBinaryRef);
+ return new DocViewProperty2(name, strValues.toArray(new String[0]), isMulti, type, isBinaryRef);
}
/**
@@ -147,7 +155,7 @@ public class DocViewProperty {
* @throws IllegalArgumentException if single value property and not exactly 1 value is given.
* @throws RepositoryException if another error occurs
*/
- public static DocViewProperty fromProperty(@NotNull Property prop, boolean sort, boolean useBinaryReferences) throws RepositoryException {
+ public static DocViewProperty2 fromProperty(@NotNull Property prop, boolean sort, boolean useBinaryReferences) throws RepositoryException {
boolean isMultiValue = prop.getDefinition().isMultiple();
final Value[] values;
if (isMultiValue) {
@@ -155,7 +163,7 @@ public class DocViewProperty {
} else {
values = new Value[] { prop.getValue() };
}
- return fromValues(prop.getName(), values, prop.getType(), isMultiValue, sort, useBinaryReferences);
+ return fromValues(FACTORY.create(prop.getName()), values, prop.getType(), isMultiValue, sort, useBinaryReferences);
}
static String serializeValue(Value value, boolean useBinaryReferences) throws RepositoryException {
@@ -186,7 +194,7 @@ public class DocViewProperty {
* @param type type of the property
* @throws IllegalArgumentException if single value property and not exactly 1 value is given.
*/
- public DocViewProperty(String name, String[] values, boolean multi, int type) {
+ public DocViewProperty2(Name name, String[] values, boolean multi, int type) {
this(name, values, multi, type, false);
}
@@ -194,23 +202,23 @@ public class DocViewProperty {
* Creates a new property.
* @param name name of the property
* @param values string representation of values.
- * @param multi indicates if this is a multi-value property
+ * @param isMultiValue indicates if this is a multi-value property
* @param type type of the property
* @param isRef {@code true} to indicate that this is a binary reference property
* @throws IllegalArgumentException if single value property and not exactly 1 value is given.
*/
- public DocViewProperty(String name, String[] values, boolean multi, int type, boolean isRef) {
+ public DocViewProperty2(Name name, String[] values, boolean isMultiValue, int type, boolean isRef) {
this.name = name;
this.values = values;
- isMulti = multi;
+ this.isMultiValue = isMultiValue;
// validate type
if (type == PropertyType.UNDEFINED) {
- if ("jcr:primaryType".equals(name) || "jcr:mixinTypes".equals(name)) {
+ if (NameConstants.JCR_PRIMARYTYPE.equals(name) || NameConstants.JCR_MIXINTYPES.equals(name)) {
type = PropertyType.NAME;
}
}
this.type = type;
- if (!isMulti && values.length != 1) {
+ if (!isMultiValue && values.length != 1) {
throw new IllegalArgumentException("Single value property needs exactly 1 value.");
}
this.isReferenceProperty = isRef;
@@ -222,7 +230,7 @@ public class DocViewProperty {
* @param value (attribute) value
* @return a property
*/
- public static DocViewProperty parse(String name, String value) {
+ public static DocViewProperty2 parse(String name, String value) {
boolean isMulti = false;
boolean isBinaryRef = false;
int type = PropertyType.UNDEFINED;
@@ -337,7 +345,7 @@ public class DocViewProperty {
} else {
values = new String[]{tmp.toString()};
}
- return new DocViewProperty(name, values, isMulti, type, isBinaryRef);
+ return new DocViewProperty2(FACTORY.create(name), values, isMulti, type, isBinaryRef);
}
/**
* Formats (serializes) the given JCR property value according to the enhanced docview syntax.
@@ -378,7 +386,7 @@ public class DocViewProperty {
}
attrValue.append('{').append(strType).append('}');
}
- if (isMulti) {
+ if (isMultiValue) {
attrValue.append('[');
}
for (int i=0;i<values.length;i++) {
@@ -394,14 +402,14 @@ public class DocViewProperty {
case PropertyType.STRING:
case PropertyType.NAME:
case PropertyType.PATH:
- attrValue.append(escape(value, isMulti));
+ attrValue.append(escape(value, isMultiValue));
break;
default:
attrValue.append(value);
}
}
}
- if (isMulti) {
+ if (isMultiValue) {
attrValue.append(']');
}
return attrValue.toString();
@@ -411,29 +419,29 @@ public class DocViewProperty {
* Escapes the value
* @param buf buffer to append to
* @param value value to escape
- * @param isMulti indicates multi value property
+ * @param isMultiValue indicates multi-value property
* @deprecated Rather use {@link #escape(String, boolean)}
*/
@Deprecated
- protected static void escape(StringBuffer buf, String value, boolean isMulti) {
- buf.append(escape(value, isMulti));
+ protected static void escape(StringBuffer buf, String value, boolean isMultiValue) {
+ buf.append(escape(value, isMultiValue));
}
/**
* Escapes the value
* @param value value to escape
- * @param isMulti indicates multi value property
+ * @param isMultiValue indicates multi-value property
* @return the escaped value
*/
- protected static String escape(String value, boolean isMulti) {
+ protected static String escape(String value, boolean isMultiValue) {
StringBuilder buf = new StringBuilder();
for (int i=0; i<value.length(); i++) {
char c = value.charAt(i);
if (c == '\\') {
buf.append("\\\\");
- } else if (c == ',' && isMulti) {
+ } else if (c == ',' && isMultiValue) {
buf.append("\\,");
- } else if (i == 0 && !isMulti && (c == '[' || c == '{')) {
+ } else if (i == 0 && !isMultiValue && (c == '[' || c == '{')) {
buf.append('\\').append(c);
} else if ( XMLChar.isInvalid(c)) {
buf.append("\\u");
@@ -472,7 +480,7 @@ public class DocViewProperty {
* @param name the name
* @return {@code true} if type information should be emitted, otherwise {@code false}
*/
- private static boolean isAmbiguous(int type, String name) {
+ private static boolean isAmbiguous(int type, Name name) {
return type != PropertyType.STRING && !UNAMBIGOUS.contains(name);
}
@@ -484,7 +492,7 @@ public class DocViewProperty {
* @throws RepositoryException if a repository error occurs
*/
public boolean apply(Node node) throws RepositoryException {
- Property prop = node.hasProperty(name) ? node.getProperty(name) : null;
+ Property prop = node.hasProperty(name.toString()) ? node.getProperty(name.toString()) : null;
// check if multiple flags are equal
if (prop != null && isMulti != prop.getDefinition().isMultiple()) {
prop.remove();
@@ -515,9 +523,9 @@ public class DocViewProperty {
}
}
if (type == PropertyType.UNDEFINED) {
- node.setProperty(name, values);
+ node.setProperty(name.toString(), values);
} else {
- node.setProperty(name, values, type);
+ node.setProperty(name.toString(), values, type);
}
// assume modified
return true;
@@ -529,13 +537,13 @@ public class DocViewProperty {
if (v == null || !v.getString().equals(values[0])) {
try {
if (type == PropertyType.UNDEFINED) {
- node.setProperty(name, values[0]);
+ node.setProperty(name.toString(), values[0]);
} else {
- node.setProperty(name, values[0], type);
+ node.setProperty(name.toString(), values[0], type);
}
} catch (ValueFormatException e) {
// forcing string
- node.setProperty(name, values[0], PropertyType.STRING);
+ node.setProperty(name.toString(), values[0], PropertyType.STRING);
}
return true;
}
@@ -576,9 +584,9 @@ public class DocViewProperty {
return false;
}
if (isMulti) {
- node.setProperty(name, binaryValues.toArray(new Value[0]));
+ node.setProperty(name.toString(), binaryValues.toArray(new Value[0]));
} else {
- node.setProperty(name, binaryValues.get(0));
+ node.setProperty(name.toString(), binaryValues.get(0));
}
// the binary property is always modified (TODO: check if still correct with JCRVLT-110)
return true;
@@ -593,7 +601,7 @@ public class DocViewProperty {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + (isMulti ? 1231 : 1237);
+ result = prime * result + (isMultiValue ? 1231 : 1237);
result = prime * result + (isReferenceProperty ? 1231 : 1237);
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + type;
@@ -609,8 +617,8 @@ public class DocViewProperty {
return false;
if (getClass() != obj.getClass())
return false;
- DocViewProperty other = (DocViewProperty) obj;
- if (isMulti != other.isMulti)
+ DocViewProperty2 other = (DocViewProperty2) obj;
+ if (isMultiValue != other.isMultiValue)
return false;
if (isReferenceProperty != other.isReferenceProperty)
return false;
@@ -632,8 +640,27 @@ public class DocViewProperty {
*/
@Override
public String toString() {
- return "DocViewProperty [name=" + name + ", values=" + Arrays.toString(values) + ", isMulti=" + isMulti + ", type=" + PropertyType.nameFromValue(type)
+ return "DocViewProperty [name=" + name + ", values=" + Arrays.toString(values) + ", isMultiValue=" + isMultiValue + ", type=" + PropertyType.nameFromValue(type)
+ ", isReferenceProperty=" + isReferenceProperty + "]";
}
+ public @NotNull Name getName() {
+ return name;
+ }
+
+ public boolean isMultiValue() {
+ return isMultiValue;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public @Nullable String getStringValue() {
+
+ }
+
+ public @NotNull Collection<String> getStringValues() {
+
+ }
}
\ No newline at end of file
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/EffectiveNodeType.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/EffectiveNodeType.java
index 7ac2488..dad5090 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/util/EffectiveNodeType.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/util/EffectiveNodeType.java
@@ -143,6 +143,7 @@ public final class EffectiveNodeType {
private static <T extends ItemDefinition> Optional<T> getApplicableItemDefinition(List<T> itemDefinitions, Predicate<T> predicate, @Nullable String name) {
final Predicate<ItemDefinition> namePredicate;
if (name != null) {
+ // TODO: support expanded and qualified names!
namePredicate = pd -> name.equals(pd.getName());
} else {
namePredicate = pd -> "*".equals(pd.getName());