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:57 UTC
[jackrabbit-filevault] branch
feature/JCRVLT-357-split-up-docviewsaximporter created (now e08c755)
This is an automated email from the ASF dual-hosted git repository.
kwin pushed a change to branch feature/JCRVLT-357-split-up-docviewsaximporter
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git.
at e08c755 JCRVLT-357 split up parser and importer for DocView files
This branch includes the following new commits:
new e08c755 JCRVLT-357 split up parser and importer for DocView files
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[jackrabbit-filevault] 01/01: JCRVLT-357 split up parser and
importer for DocView files
Posted by kw...@apache.org.
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());