You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by mr...@apache.org on 2013/09/10 11:24:47 UTC
svn commit: r1521392 - in /jackrabbit/oak/trunk/oak-jcr: ./
src/main/java/org/apache/jackrabbit/oak/jcr/
src/main/java/org/apache/jackrabbit/oak/jcr/delegate/
src/test/java/org/apache/jackrabbit/oak/jcr/
Author: mreutegg
Date: Tue Sep 10 09:24:47 2013
New Revision: 1521392
URL: http://svn.apache.org/r1521392
Log:
OAK-915: Workspace#copy of referenceable nodes does not generate new UUIDs
Added:
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/WorkspaceDelegate.java (with props)
Modified:
jackrabbit/oak/trunk/oak-jcr/pom.xml
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/WorkspaceImpl.java
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
Modified: jackrabbit/oak/trunk/oak-jcr/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/pom.xml?rev=1521392&r1=1521391&r2=1521392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-jcr/pom.xml Tue Sep 10 09:24:47 2013
@@ -47,7 +47,6 @@
org.apache.jackrabbit.test.api.NodeUUIDTest#testSaveMovedRefNode <!-- OAK-66 -->
org.apache.jackrabbit.test.api.SetValueValueFormatExceptionTest#testNodeNotReferenceable
org.apache.jackrabbit.test.api.NodeSetPrimaryTypeTest#testLocked
- org.apache.jackrabbit.test.api.WorkspaceCopyReferenceableTest#testCopyNodesNewUUID <!-- OAK-118 -->
org.apache.jackrabbit.test.api.WorkspaceCopyVersionableTest#testCopyNodesVersionableAndCheckedIn <!-- OAK-118 -->
org.apache.jackrabbit.test.api.WorkspaceMoveReferenceableTest#testMoveNodesReferenceableNodesNewUUID <!-- OAK-118 -->
org.apache.jackrabbit.test.api.WorkspaceMoveVersionableTest#testMoveNodesVersionableAndCheckedIn <!-- OAK-118 -->
Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/WorkspaceImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/WorkspaceImpl.java?rev=1521392&r1=1521391&r2=1521392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/WorkspaceImpl.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/WorkspaceImpl.java Tue Sep 10 09:24:47 2013
@@ -39,7 +39,9 @@ import org.apache.jackrabbit.oak.api.Com
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate;
+import org.apache.jackrabbit.oak.jcr.delegate.WorkspaceDelegate;
import org.apache.jackrabbit.oak.jcr.lock.LockManagerImpl;
+import org.apache.jackrabbit.oak.jcr.operation.SessionOperation;
import org.apache.jackrabbit.oak.jcr.query.QueryManagerImpl;
import org.apache.jackrabbit.oak.jcr.version.VersionManagerImpl;
import org.apache.jackrabbit.oak.jcr.xml.ImportHandler;
@@ -60,6 +62,7 @@ public class WorkspaceImpl implements Ja
private final SessionContext sessionContext;
private final SessionDelegate sessionDelegate;
+ private final WorkspaceDelegate workspaceDelegate;
private final QueryManagerImpl queryManager;
private final VersionManagerImpl versionManager;
private final ReadWriteNodeTypeManager nodeTypeManager;
@@ -67,6 +70,7 @@ public class WorkspaceImpl implements Ja
public WorkspaceImpl(final SessionContext sessionContext) {
this.sessionContext = sessionContext;
this.sessionDelegate = sessionContext.getSessionDelegate();
+ this.workspaceDelegate = new WorkspaceDelegate(sessionContext);
this.queryManager = new QueryManagerImpl(sessionContext);
this.versionManager = new VersionManagerImpl(sessionContext);
this.nodeTypeManager = new ReadWriteNodeTypeManager() {
@@ -122,24 +126,35 @@ public class WorkspaceImpl implements Ja
}
@Override
- public void copy(String srcWorkspace, String srcAbsPath, String destAbsPath) throws RepositoryException {
+ public void copy(String srcWorkspace,
+ String srcAbsPath,
+ final String destAbsPath) throws RepositoryException {
final String srcOakPath = getOakPathOrThrowNotFound(srcAbsPath);
final String destOakPath = getOakPathOrThrowNotFound(destAbsPath);
- // TODO: use perform()
- ensureIsAlive();
-
if (!getName().equals(srcWorkspace)) {
throw new UnsupportedRepositoryOperationException("Not implemented.");
}
- sessionDelegate.checkProtectedNode(getParentPath(srcOakPath));
- sessionDelegate.checkProtectedNode(getParentPath(destOakPath));
+ sessionDelegate.perform(new SessionOperation<Object>(true) {
+ @Override
+ public void checkPreconditions() throws RepositoryException {
+ super.checkPreconditions();
+ ensureIsAlive();
+ }
- SessionImpl.checkIndexOnName(sessionContext, destAbsPath);
+ @Override
+ public Object perform() throws RepositoryException {
+ sessionDelegate.checkProtectedNode(getParentPath(srcOakPath));
+ sessionDelegate.checkProtectedNode(getParentPath(destOakPath));
+
+ SessionImpl.checkIndexOnName(sessionContext, destAbsPath);
+
+ workspaceDelegate.copy(srcOakPath, destOakPath);
+ return null;
+ }
+ });
- sessionDelegate.copy(
- srcOakPath, destOakPath, sessionContext.getAccessManager());
}
@Override
Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java?rev=1521392&r1=1521391&r2=1521392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/SessionDelegate.java Tue Sep 10 09:24:47 2013
@@ -349,46 +349,6 @@ public class SessionDelegate {
}
/**
- * Copy a node
- * @param srcPath oak path to the source node to copy
- * @param destPath oak path to the destination
- * @throws RepositoryException
- */
- public void copy(String srcPath, String destPath, AccessManager accessManager) throws RepositoryException {
- // check destination
- Tree dest = root.getTree(destPath);
- if (dest.exists()) {
- throw new ItemExistsException(destPath);
- }
-
- // check parent of destination
- String destParentPath = PathUtils.getParentPath(destPath);
- Tree destParent = root.getTree(destParentPath);
- if (!destParent.exists()) {
- throw new PathNotFoundException(PathUtils.getParentPath(destPath));
- }
-
- // check source exists
- Tree src = root.getTree(srcPath);
- if (!src.exists()) {
- throw new PathNotFoundException(srcPath);
- }
-
- accessManager.checkPermissions(destPath, Permissions.getString(Permissions.NODE_TYPE_MANAGEMENT));
-
- try {
- Root currentRoot = contentSession.getLatestRoot();
- if (!currentRoot.copy(srcPath, destPath)) {
- throw new RepositoryException("Cannot copy node at " + srcPath + " to " + destPath);
- }
- currentRoot.commit();
- refresh(false);
- } catch (CommitFailedException e) {
- throw newRepositoryException(e);
- }
- }
-
- /**
* Move a node
* @param srcPath oak path to the source node to copy
* @param destPath oak path to the destination
Added: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/WorkspaceDelegate.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/WorkspaceDelegate.java?rev=1521392&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/WorkspaceDelegate.java (added)
+++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/WorkspaceDelegate.java Tue Sep 10 09:24:47 2013
@@ -0,0 +1,215 @@
+/*
+ * 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.oak.jcr.delegate;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.ItemExistsException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.core.IdentifierManager;
+import org.apache.jackrabbit.oak.jcr.SessionContext;
+import org.apache.jackrabbit.oak.jcr.security.AccessManager;
+import org.apache.jackrabbit.oak.plugins.memory.GenericPropertyState;
+import org.apache.jackrabbit.oak.plugins.memory.MultiGenericPropertyState;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
+
+import com.google.common.collect.Maps;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.JcrConstants.JCR_UUID;
+
+/**
+ * Delegate class for workspace operations.
+ */
+public class WorkspaceDelegate {
+
+ private final SessionContext context;
+
+ public WorkspaceDelegate(SessionContext context) {
+ this.context = checkNotNull(context);
+ }
+
+ /**
+ * Copy a node
+ * @param srcPath oak path to the source node to copy
+ * @param destPath oak path to the destination
+ * @throws RepositoryException
+ */
+ public void copy(String srcPath, String destPath) throws RepositoryException {
+ SessionDelegate sessionDelegate = context.getSessionDelegate();
+ AccessManager accessManager = context.getAccessManager();
+ Root root = sessionDelegate.getContentSession().getLatestRoot();
+ // check destination
+ Tree dest = root.getTree(destPath);
+ if (dest.exists()) {
+ throw new ItemExistsException(destPath);
+ }
+
+ // check parent of destination
+ String destParentPath = PathUtils.getParentPath(destPath);
+ Tree destParent = root.getTree(destParentPath);
+ if (!destParent.exists()) {
+ throw new PathNotFoundException(PathUtils.getParentPath(destPath));
+ }
+
+ // check source exists
+ Tree src = root.getTree(srcPath);
+ if (!src.exists()) {
+ throw new PathNotFoundException(srcPath);
+ }
+
+ accessManager.checkPermissions(destPath, Permissions.getString(Permissions.NODE_TYPE_MANAGEMENT));
+
+ try {
+ new WorkspaceCopy(root, srcPath, destPath).perform();
+ root.commit();
+ sessionDelegate.refresh(true);
+ } catch (CommitFailedException e) {
+ throw e.asRepositoryException();
+ }
+ }
+
+ //---------------------------< internal >-----------------------------------
+
+ private class WorkspaceCopy {
+
+ private final Map<String, String> translated = Maps.newHashMap();
+ private final String srcPath;
+ private final String destPath;
+ private final Root currentRoot;
+
+ public WorkspaceCopy(Root currentRoot, String srcPath, String destPath) {
+ this.srcPath = checkNotNull(srcPath);
+ this.destPath = checkNotNull(destPath);
+ this.currentRoot = checkNotNull(currentRoot);
+ }
+
+ public void perform() throws RepositoryException {
+ if (!currentRoot.copy(srcPath, destPath)) {
+ throw new RepositoryException("Cannot copy node at " + srcPath + " to " + destPath);
+ }
+ Tree src = currentRoot.getTree(srcPath);
+ Tree dest = currentRoot.getTree(destPath);
+ generateNewIdentifiers(dest);
+ updateReferences(src, dest);
+ }
+
+ public void generateNewIdentifiers(Tree t) throws RepositoryException {
+ if (t.hasProperty(JCR_UUID)) {
+ getNewId(t);
+ }
+ for (Tree c : t.getChildren()) {
+ generateNewIdentifiers(c);
+ }
+ }
+
+ /**
+ * Recursively updates references on the destination tree as defined by
+ * <code>Workspace.copy()</code>.
+ *
+ * @param src the source tree of the copy operation.
+ * @param dest the unprocessed copy of the tree.
+ */
+ private void updateReferences(Tree src, Tree dest)
+ throws RepositoryException {
+ for (PropertyState prop : src.getProperties()) {
+ Type<?> type = prop.getType();
+ if (type == Type.REFERENCE
+ || type == Type.REFERENCES
+ || type == Type.WEAKREFERENCE
+ || type == Type.WEAKREFERENCES) {
+ updateProperty(prop, dest);
+ }
+ }
+ for (Tree child : src.getChildren()) {
+ updateReferences(child, dest.getChild(child.getName()));
+ }
+ }
+
+ private void updateProperty(PropertyState prop, Tree dest)
+ throws RepositoryException {
+ boolean multi = prop.isArray();
+ boolean weak = prop.getType() == Type.WEAKREFERENCE
+ || prop.getType() == Type.WEAKREFERENCES;
+ List<String> ids = new ArrayList<String>();
+ for (int i = 0; i < prop.count(); i++) {
+ String id;
+ if (weak) {
+ id = prop.getValue(Type.WEAKREFERENCE, i);
+ } else {
+ id = prop.getValue(Type.REFERENCE, i);
+ }
+ translateId(id, ids);
+ }
+ PropertyState p;
+ if (multi) {
+ if (weak) {
+ p = MultiGenericPropertyState.weakreferenceProperty(
+ prop.getName(), ids);
+ } else {
+ p = MultiGenericPropertyState.referenceProperty(
+ prop.getName(), ids);
+ }
+ } else {
+ if (weak) {
+ p = GenericPropertyState.weakreferenceProperty(prop.getName(), ids.get(0));
+ } else {
+ p = GenericPropertyState.referenceProperty(prop.getName(), ids.get(0));
+ }
+ }
+ dest.setProperty(p);
+ }
+
+ private void translateId(String id, List<String> ids)
+ throws RepositoryException {
+ String newId = translated.get(id);
+ if (newId != null) {
+ ids.add(newId);
+ } else {
+ ids.add(id);
+ }
+ }
+
+ private String getNewId(Tree t) throws RepositoryException {
+ PropertyState uuid = t.getProperty(JCR_UUID);
+ if (uuid == null) {
+ // not referenceable?
+ throw new RepositoryException(
+ "Node is not referenceable: " + t.getPath());
+ }
+ String targetId = uuid.getValue(Type.STRING);
+ // new id needed?
+ if (!translated.containsKey(targetId)) {
+ String newId = IdentifierManager.generateUUID();
+ translated.put(targetId, newId);
+ t.setProperty(JCR_UUID, newId, Type.STRING);
+ }
+ return translated.get(targetId);
+ }
+ }
+
+}
Propchange: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/WorkspaceDelegate.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/WorkspaceDelegate.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev URL
Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java?rev=1521392&r1=1521391&r2=1521392&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/RepositoryTest.java Tue Sep 10 09:24:47 2013
@@ -1888,6 +1888,34 @@ public class RepositoryTest extends Abst
}
}
+ @Test
+ public void workspaceCopyWithReferences() throws RepositoryException {
+ Session session = getAdminSession();
+ ValueFactory vf = session.getValueFactory();
+ Node root = session.getRootNode();
+ Node other = root.addNode("other");
+ other.addMixin("mix:referenceable");
+ Node src = root.addNode("src");
+ Node test = src.addNode("test");
+ test.addMixin("mix:referenceable");
+ src.setProperty("test", test);
+ src.setProperty("other", other);
+ src.setProperty("multi", new Value[]{vf.createValue(test), vf.createValue(other)});
+ session.save();
+ session.getWorkspace().copy("/src", "/dest");
+ Node dest = root.getNode("dest");
+ assertEquals("/dest/test", dest.getProperty("test").getNode().getPath());
+ assertEquals("/other", dest.getProperty("other").getNode().getPath());
+ Value[] refs = dest.getProperty("multi").getValues();
+ assertEquals(2, refs.length);
+ Set<String> paths = new HashSet<String>();
+ for (Value v : refs) {
+ paths.add(session.getNodeByIdentifier(v.getString()).getPath());
+ }
+ assertTrue(paths.contains("/other"));
+ assertTrue(paths.contains("/dest/test"));
+ }
+
//------------------------------------------------------------< private >---
private Node getNode(String path) throws RepositoryException {