From 83b4cdb76d2bb51304b369e719093d8f22762fdb Mon Sep 17 00:00:00 2001 From: Britt Park Date: Fri, 15 Sep 2006 03:04:57 +0000 Subject: [PATCH] Fixed an embarassing not so corner case failure. Non primary layered directories cannot be just linked in for update, but must instead be recursively linked in. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3801 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../org/alfresco/repo/avm/AVMServiceTest.java | 11 ++++ .../org/alfresco/repo/avm/AVMStoreImpl.java | 2 +- .../alfresco/repo/avm/AVMSyncServiceImpl.java | 62 ++++++++++++++++--- .../org/alfresco/repo/avm/DirectoryNode.java | 4 +- .../repo/avm/LayeredDirectoryNodeImpl.java | 13 ++-- .../repo/avm/PlainDirectoryNodeImpl.java | 13 ++-- 6 files changed, 85 insertions(+), 20 deletions(-) diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTest.java b/source/java/org/alfresco/repo/avm/AVMServiceTest.java index 7bf52a2482..89f42d495d 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTest.java @@ -35,6 +35,7 @@ import org.alfresco.repo.avm.util.BulkLoader; import org.alfresco.repo.domain.PropertyValue; import org.alfresco.repo.security.authentication.AuthenticationComponent; import org.alfresco.repo.transaction.TransactionUtil; +import org.alfresco.service.cmr.avm.AVMBadArgumentException; import org.alfresco.service.cmr.avm.AVMException; import org.alfresco.service.cmr.avm.AVMExistsException; import org.alfresco.service.cmr.avm.AVMNodeDescriptor; @@ -359,6 +360,16 @@ public class AVMServiceTest extends AVMServiceTestBase { // Do nothing. } + // Try to link /layer/b to /frinx. It should fail. + try + { + fService.link("main:/", "frinx", fService.lookup(-1, "main:/layer/b")); + fail(); + } + catch (AVMBadArgumentException ba) + { + // Do nothing. + } // Delete /layer/b/bar and redo. It should work. fService.removeNode("main:/layer/b", "bar"); fService.link("main:/layer/b", "bar", fService.lookup(-1, "main:/layer/b/c/bar")); diff --git a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java index 581e1aa15a..24503a6582 100644 --- a/source/java/org/alfresco/repo/avm/AVMStoreImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMStoreImpl.java @@ -1146,6 +1146,6 @@ public class AVMStoreImpl implements AVMStore, Serializable { Lookup lPath = lookupDirectory(-1, parentPath, true); DirectoryNode dir = (DirectoryNode)lPath.getCurrentNode(); - dir.link(lPath, name, toLink.getId()); + dir.link(lPath, name, toLink); } } diff --git a/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java index f3b6fb37e3..053228f88c 100644 --- a/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java @@ -308,11 +308,7 @@ public class AVMSyncServiceImpl implements AVMSyncService case AVMDifference.NEWER : { // You can't delete what isn't there. - if (dstDesc != null) - { - fAVMService.removeNode(dstParts[0], dstParts[1]); - } - fAVMService.link(dstParts[0], dstParts[1], srcDesc); + linkIn(dstParts[0], dstParts[1], srcDesc, dstDesc != null); continue; } case AVMDifference.OLDER : @@ -320,8 +316,7 @@ public class AVMSyncServiceImpl implements AVMSyncService // You can force it. if (overrideOlder) { - fAVMService.removeNode(dstParts[0], dstParts[1]); - fAVMService.link(dstParts[0], dstParts[1], srcDesc); + linkIn(dstParts[0], dstParts[1], srcDesc, true); continue; } // You can ignore it. @@ -337,8 +332,7 @@ public class AVMSyncServiceImpl implements AVMSyncService // You can force it. if (overrideConflicts) { - fAVMService.removeNode(dstParts[0], dstParts[1]); - fAVMService.link(dstParts[0], dstParts[1], srcDesc); + linkIn(dstParts[0], dstParts[1], srcDesc, true); continue; } // You can ignore it. @@ -367,6 +361,56 @@ public class AVMSyncServiceImpl implements AVMSyncService } } + /** + * Do the actual work of connecting nodes to the destination tree. + * @param parentPath The parent path the node will go in. + * @param name The name it will have. + * @param toLink The node descriptor. + * @param removeFirst Whether to do a removeNode before linking in. + */ + private void linkIn(String parentPath, String name, AVMNodeDescriptor toLink, boolean removeFirst) + { + if (removeFirst) + { + fAVMService.removeNode(parentPath, name); + } + if (toLink.isLayeredDirectory() && !toLink.isPrimary()) + { + recursiveCopy(parentPath, name, toLink); + return; + } + fAVMService.link(parentPath, name, toLink); + } + + // TODO doesn't handle copies from non head nodes. + + /** + * Recursively copy a node into the given position. + * @param parentPath The place to put it. + * @param name The name to give it. + * @param toCopy The it to put. + */ + private void recursiveCopy(String parentPath, String name, AVMNodeDescriptor toCopy) + { + // TODO Can we just do a link if it's a plain directory. + // If it's a file or deleted simply link it in. + if (toCopy.isFile() || toCopy.isDeleted()) + { + fAVMService.link(parentPath, name, toCopy); + return; + } + // Otherwise make a directory in the target parent, and recursiveCopy all the source + // children into it. + fAVMService.createDirectory(parentPath, name); + String newParentPath = AVMNodeConverter.ExtendAVMPath(parentPath, name); + Map children = + fAVMService.getDirectoryListing(-1, toCopy.getPath(), true); + for (Map.Entry entry : children.entrySet()) + { + recursiveCopy(newParentPath, entry.getKey(), entry.getValue()); + } + } + /** * The workhorse of comparison and updating. Determine the versioning relationship * of two nodes. diff --git a/source/java/org/alfresco/repo/avm/DirectoryNode.java b/source/java/org/alfresco/repo/avm/DirectoryNode.java index 79b1b0daba..95a8d3a7a7 100644 --- a/source/java/org/alfresco/repo/avm/DirectoryNode.java +++ b/source/java/org/alfresco/repo/avm/DirectoryNode.java @@ -119,7 +119,7 @@ public interface DirectoryNode extends AVMNode * Link a node with the given id into this directory. * @param lPath The Lookup for this node. * @param name The name to give the node. - * @param id The id of the node to insert. + * @param toLink The node to link in. */ - public void link(Lookup lPath, String name, long id); + public void link(Lookup lPath, String name, AVMNodeDescriptor toLink); } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java index 8b47b652b4..e5de705e80 100644 --- a/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/LayeredDirectoryNodeImpl.java @@ -772,14 +772,19 @@ class LayeredDirectoryNodeImpl extends DirectoryNodeImpl implements LayeredDirec * Link a node with the given id into this directory. * @param lPath The Lookup for this. * @param name The name to give the node. - * @param id The id of the node to insert. + * @param toLink The node to link in. */ - public void link(Lookup lPath, String name, long id) + public void link(Lookup lPath, String name, AVMNodeDescriptor toLink) { - AVMNode node = AVMContext.fgInstance.fAVMNodeDAO.getByID(id); + AVMNode node = AVMContext.fgInstance.fAVMNodeDAO.getByID(toLink.getId()); if (node == null) { - throw new AVMNotFoundException("Not Found: " + id); + throw new AVMNotFoundException("Not Found: " + toLink.getId()); + } + if (node.getType() == AVMNodeType.LAYERED_DIRECTORY && + !((LayeredDirectoryNode)node).getPrimaryIndirection()) + { + throw new AVMBadArgumentException("Non primary layered directories cannot be linked."); } // Look for an existing child of that name. AVMNode existing = lookupChild(lPath, name, -1, false, true); diff --git a/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java index 32b8fedad0..40f620a89b 100644 --- a/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/PlainDirectoryNodeImpl.java @@ -407,15 +407,20 @@ class PlainDirectoryNodeImpl extends DirectoryNodeImpl implements PlainDirectory * Link a node with the given id into this directory. * @param lPath The Lookup for this directory. * @param name The name to give the node. - * @param id The id of the node to insert. + * @param toLink The node to link in. */ - public void link(Lookup lPath, String name, long id) + public void link(Lookup lPath, String name, AVMNodeDescriptor toLink) { // Assure that the incoming node exists. - AVMNode node = AVMContext.fgInstance.fAVMNodeDAO.getByID(id); + AVMNode node = AVMContext.fgInstance.fAVMNodeDAO.getByID(toLink.getId()); if (node == null) { - throw new AVMNotFoundException("Node not found: " + id); + throw new AVMNotFoundException("Node not found: " + toLink.getId()); + } + if (node.getType() == AVMNodeType.LAYERED_DIRECTORY && + !((LayeredDirectoryNode)node).getPrimaryIndirection()) + { + throw new AVMBadArgumentException("Non primary layered directories cannot be linked."); } // Check for an existing child by the given name. ChildEntry child = AVMContext.fgInstance.fChildEntryDAO.getByNameParent(name, this);