JCRVLT-104 Access to root node in DocViewSAXImporter and JcrSysViewTransformer
git-svn-id: https://svn.apache.org/repos/asf/jackrabbit/commons/filevault/trunk@1708204 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/ChildNodeStash.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/ChildNodeStash.java
new file mode 100644
index 0000000..9be95cb
--- /dev/null
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/ChildNodeStash.java
@@ -0,0 +1,145 @@
+/*
+ * 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 javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.vault.fs.api.ImportInfo;
+import org.apache.jackrabbit.vault.util.JcrConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper class isolating the task of temporarily moving child nodes to a
+ * different location in order to be able to recover (and properly merge) them
+ * later on.
+ */
+public class ChildNodeStash {
+
+ static final Logger log = LoggerFactory.getLogger(ChildNodeStash.class);
+
+ private final Session session;
+
+ private Node tmpNode;
+
+ /**
+ * List of potential roots where the transient temporary node will be created.
+ * Note that the node is never persisted.
+ */
+ private static final String[] ROOTS = {"/", "/tmp", "/var", "/etc", "/content"};
+
+
+ /**
+ * Creates a new child node stash utility class
+ * @param session session to operate on
+ */
+ public ChildNodeStash(Session session) {
+ this.session = session;
+ }
+
+ /**
+ * create a transient node for temporarily stash the child nodes
+ * @return the temporary node
+ * @throws RepositoryException if an error occurrs
+ */
+ private Node getOrCreateTemporaryNode() throws RepositoryException {
+ if (tmpNode != null) {
+ return tmpNode;
+ }
+ for (String rootPath: ROOTS) {
+ try {
+ Node root = session.getNode(rootPath);
+ return tmpNode = root.addNode("tmp" + System.currentTimeMillis(), JcrConstants.NT_UNSTRUCTURED);
+ } catch (RepositoryException e) {
+ log.debug("unable to create temporary stash location below {}.", rootPath);
+ }
+ }
+ throw new RepositoryException("Unable to create temporary root below.");
+ }
+
+ /**
+ * Moves the nodes below the given parent path to a temporary location.
+ * @param parentPath the path of the parent node.
+ * @throws RepositoryException if an error occurrs
+ */
+ public void stashChildren(String parentPath) throws RepositoryException {
+ stashChildren(session.getNode(parentPath));
+ }
+
+ /**
+ * Moves the nodes below the given parent to a temporary location.
+ * @param parent the parent node.
+ */
+ public void stashChildren(Node parent) {
+ try {
+ NodeIterator iter = parent.getNodes();
+ while (iter.hasNext()) {
+ Node child = iter.nextNode();
+ Node tmp = getOrCreateTemporaryNode();
+ try {
+ session.move(child.getPath(), tmp.getPath() + "/" + child.getName());
+ } catch (RepositoryException e) {
+ log.error("Error while moving child node to temporary location. Child will be removed.", e);
+ }
+ }
+ } catch (RepositoryException e) {
+ log.warn("error while moving child nodes (ignored)", e);
+ }
+ }
+
+ /**
+ * Moves the stashed nodes back below the given parent path.
+ * @param parentPath the path of the new parent node
+ * @throws RepositoryException if an error occurrs
+ */
+ public void recoverChildren(String parentPath) throws RepositoryException {
+ recoverChildren(session.getNode(parentPath), null);
+ }
+
+ /**
+ * Moves the stashed nodes back below the given parent path.
+ * @param parent the new parent node
+ * @throws RepositoryException if an error occurrs
+ */
+ public void recoverChildren(Node parent, ImportInfo importInfo) throws RepositoryException {
+ // move the old child nodes back
+ if (tmpNode != null) {
+ NodeIterator iter = tmpNode.getNodes();
+ boolean hasErrors = false;
+ while (iter.hasNext()) {
+ Node child = iter.nextNode();
+ String newPath = parent.getPath() + "/" + child.getName();
+ try {
+ session.move(child.getPath(), newPath);
+ } catch (RepositoryException e) {
+ log.warn("Unable to move child back to new location at {} due to: {}. Node will remain in temporary location: {}",
+ new Object[]{newPath, e.getMessage(), child.getPath()});
+ if (importInfo != null) {
+ importInfo.onError(newPath, e);
+ hasErrors = true;
+ }
+ }
+ }
+ if (!hasErrors) {
+ tmpNode.remove();
+ }
+ }
+ }
+}
\ No newline at end of file
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/DocViewSAXImporter.java
index 9db893a..c2ef44e 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/DocViewSAXImporter.java
@@ -823,25 +823,9 @@
// check versionable
new VersioningState(stack, oldNode).ensureCheckedOut();
- // replace node
- Node tmpNode = null;
- try {
- // if old node exist, try to 'save' the child nodes
- NodeIterator iter = oldNode.getNodes();
- while (iter.hasNext()) {
- Node child = iter.nextNode();
- if (tmpNode == null) {
- tmpNode = session.getRootNode().addNode("tmp" + System.currentTimeMillis(), JcrConstants.NT_UNSTRUCTURED);
- }
- try {
- session.move(child.getPath(), tmpNode.getPath() + "/" + child.getName());
- } catch (RepositoryException e) {
- log.error("Error while moving child node to temporary location. Child will be removed.", e);
- }
- }
- } catch (RepositoryException e) {
- log.warn("error while moving child nodes (ignored)", e);
- }
+ ChildNodeStash recovery = new ChildNodeStash(session);
+ recovery.stashChildren(oldNode);
+
// ensure that existing binaries are not sourced from a property
// that is about to be removed
Map<String, DocViewSAXImporter.BlobInfo> blobs = binaries.get(oldNode.getPath());
@@ -855,26 +839,9 @@
// now create the new node
node = createNode(currentNode, ni);
- // move the old child nodes back
- if (tmpNode != null) {
- NodeIterator iter = tmpNode.getNodes();
- boolean hasErrors = false;
- while (iter.hasNext()) {
- Node child = iter.nextNode();
- String newPath = node.getPath() + "/" + child.getName();
- try {
- session.move(child.getPath(), newPath);
- } catch (RepositoryException e) {
- log.warn("Unable to move child back to new location at {} due to: {}. Node will remain in temporary location: {}",
- new Object[]{newPath, e.getMessage(), child.getPath()});
- importInfo.onError(newPath, e);
- hasErrors = true;
- }
- }
- if (!hasErrors) {
- tmpNode.remove();
- }
- }
+ // move the children back
+ recovery.recoverChildren(node, importInfo);
+
importInfo.onReplaced(node.getPath());
return new StackElement(node, false);
}
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 41021f2..5cf5aef 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
@@ -29,7 +29,6 @@
import org.apache.jackrabbit.spi.Name;
import org.apache.jackrabbit.vault.util.DocViewNode;
import org.apache.jackrabbit.vault.util.DocViewProperty;
-import org.apache.jackrabbit.vault.util.JcrConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler;
@@ -55,9 +54,9 @@
private ContentHandler handler;
/**
- * temporary node when 'rescuing' the child nodes
+ * temporary recovery helper when 'rescuing' the child nodes
*/
- private Node tmpNode;
+ private ChildNodeStash recovery;
private String rootName;
@@ -87,25 +86,9 @@
this.existingPath = existingPath;
if (existingPath != null) {
- Node existingNode = session.getNode(existingPath);
// check if there is an existing node with the name
- try {
- // if old node exist, try to 'save' the child nodes
- NodeIterator iter = existingNode.getNodes();
- while (iter.hasNext()) {
- Node child = iter.nextNode();
- if (tmpNode == null) {
- tmpNode = session.getRootNode().addNode("tmp" + System.currentTimeMillis(), JcrConstants.NT_UNSTRUCTURED);
- }
- try {
- session.move(child.getPath(), tmpNode.getPath() + "/" + child.getName());
- } catch (RepositoryException e) {
- log.error("Error while moving child node to temporary location. Child will be removed.", e);
- }
- }
- } catch (RepositoryException e) {
- log.warn("error while moving child nodes (ignored)", e);
- }
+ recovery = new ChildNodeStash(session);
+ recovery.stashChildren(existingPath);
}
}
@@ -125,25 +108,13 @@
}
// check for rescued child nodes
- // move the old child nodes back
- if (tmpNode != null) {
+ if (recovery != null) {
try {
- Session session = tmpNode.getSession();
- Node node = session.getNode(existingPath);
- NodeIterator iter = tmpNode.getNodes();
- while (iter.hasNext()) {
- Node child = iter.nextNode();
- String newPath = node.getPath() + "/" + child.getName();
- try {
- session.move(child.getPath(), newPath);
- } catch (RepositoryException e) {
- log.warn("Unable to move child back to new location at {} due to: {}. Node will remain in temporary location: {}",
- new Object[]{newPath, e.getMessage(), child.getPath()});
- }
- }
- tmpNode.remove();
+ recovery.recoverChildren(existingPath);
} catch (RepositoryException e) {
log.error("Error while processing rescued child nodes");
+ } finally {
+ recovery = null;
}
}