diff --git a/source/java/org/alfresco/repo/avm/AVMRepository.java b/source/java/org/alfresco/repo/avm/AVMRepository.java index dc47676c7d..1084131e40 100644 --- a/source/java/org/alfresco/repo/avm/AVMRepository.java +++ b/source/java/org/alfresco/repo/avm/AVMRepository.java @@ -1262,4 +1262,27 @@ public class AVMRepository AVMStore store = getAVMStoreByName(pathParts[0]); store.link(pathParts[1], name, toLink); } + + /** + * This is the danger version of link. It must be called on + * a copied and unsnapshotted directory. It blithely inserts + * a child without checking if a child exists with a conflicting name. + * @param parent The parent directory. + * @param name The name to give the child. + * @param child The child to link in. + */ + public void link(AVMNodeDescriptor parent, String name, AVMNodeDescriptor child) + { + AVMNode node = AVMContext.fgInstance.fAVMNodeDAO.getByID(parent.getId()); + if (!(node instanceof DirectoryNode)) + { + throw new AVMWrongTypeException("Not a Directory."); + } + DirectoryNode dir = (DirectoryNode)node; + if (!dir.getIsNew()) + { + throw new AVMException("Directory has not already been copied."); + } + dir.link(name, child); + } } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java index 461100f0b0..06323a2098 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java @@ -1065,4 +1065,22 @@ public class AVMServiceImpl implements AVMService } fAVMRepository.link(parentPath, name, toLink); } + + /** + * This is a more dangerous version of link, which assumes + * that copy on write has occurred for the parent node. This is + * an internal call. Don't use it if you don't know precisely + * what you are doing. + * @param parent The parent node. + * @param name The name to give the child. + * @param child The child node to link. + */ + public void link(AVMNodeDescriptor parent, String name, AVMNodeDescriptor child) + { + if (parent == null || child == null) + { + throw new AVMBadArgumentException("Illegal Null Argument."); + } + fAVMRepository.link(parent, name, child); + } } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTest.java b/source/java/org/alfresco/repo/avm/AVMServiceTest.java index 838361e43c..edd18d6d8d 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTest.java @@ -59,6 +59,56 @@ import org.alfresco.service.transaction.TransactionService; */ public class AVMServiceTest extends AVMServiceTestBase { + /** + * Test bulk update. + */ + public void testBulkUpdate() + { + try + { + BulkLoader loader = new BulkLoader(); + loader.setAvmService(fService); + fService.createAVMStore("layer"); + fService.createLayeredDirectory("main:/", "layer:/", "layer"); + loader.recursiveLoad("config/alfresco/bootstrap", "layer:/layer"); + List diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/"); + assertEquals(1, diffs.size()); + fService.createSnapshot("layer"); + fSyncService.update(diffs, false, false, false, false); + fService.createSnapshot("main"); + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/"); + assertEquals(0, diffs.size()); + fSyncService.flatten("layer:/layer", "main:/"); + System.out.println("Layer:"); + System.out.println(recursiveList("layer", -1, true)); + System.out.println("Main:"); + System.out.println(recursiveList("main", -1, true)); + fService.createAVMStore("layer2"); + fService.createLayeredDirectory("layer:/layer", "layer2:/", "layer"); + loader.recursiveLoad("config/alfresco/bootstrap", "layer2:/layer/bootstrap"); + fService.createSnapshot("layer2"); + diffs = fSyncService.compare(-1, "layer2:/layer", -1, "layer:/layer"); + assertEquals(1, diffs.size()); + fSyncService.update(diffs, false, false, false, false); + diffs = fSyncService.compare(-1, "layer2:/layer", -1, "layer:/layer"); + assertEquals(0, diffs.size()); + fSyncService.flatten("layer2:/layer", "layer:/layer"); + diffs = fSyncService.compare(-1, "layer:/layer", -1, "main:/"); + assertEquals(1, diffs.size()); + System.out.println("Layer2:"); + System.out.println(recursiveList("layer2", -1, true)); + System.out.println("Layer:"); + System.out.println(recursiveList("layer", -1, true)); + System.out.println("Main:"); + System.out.println(recursiveList("main", -1, true)); + } + catch (Exception e) + { + e.printStackTrace(System.err); + fail(); + } + } + /** * Test the flatten operation, with a little bit of compare and update. */ diff --git a/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java index f3fc8365eb..8f0f293678 100644 --- a/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMSyncServiceImpl.java @@ -392,22 +392,40 @@ public class AVMSyncServiceImpl implements AVMSyncService */ 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.createDirectory(parentPath, name); + String newParentPath = AVMNodeConverter.ExtendAVMPath(parentPath, name); + AVMNodeDescriptor parentDesc = fAVMService.lookup(-1, newParentPath, true); + Map children = + fAVMService.getDirectoryListing(toCopy, true); + for (Map.Entry entry : children.entrySet()) { - fAVMService.link(parentPath, name, toCopy); + recursiveCopy(parentDesc, entry.getKey(), entry.getValue()); + } + } + + /** + * Shortcutting helper that uses an AVMNodeDescriptor parent. + * @param parent The parent we are linking into. + * @param name The name to link in. + * @param toCopy The node to link in. + */ + private void recursiveCopy(AVMNodeDescriptor parent, String name, AVMNodeDescriptor toCopy) + { + // If it's a file or deleted simply link it in. + if (toCopy.isFile() || toCopy.isDeleted() || toCopy.isPlainDirectory()) + { + fAVMService.link(parent, 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); + fAVMService.createDirectory(parent.getPath(), name); + AVMNodeDescriptor newParentDesc = fAVMService.lookup(parent, name); Map children = - fAVMService.getDirectoryListing(-1, toCopy.getPath(), true); + fAVMService.getDirectoryListing(toCopy, true); for (Map.Entry entry : children.entrySet()) { - recursiveCopy(newParentPath, entry.getKey(), entry.getValue()); + recursiveCopy(newParentDesc, entry.getKey(), entry.getValue()); } } @@ -577,7 +595,7 @@ public class AVMSyncServiceImpl implements AVMSyncService } // Grab the listing Map underListing = - fAVMService.getDirectoryListing(-1, underlying.getPath(), true); + fAVMService.getDirectoryListing(underlying, true); boolean flattened = true; for (String name : layerListing.keySet()) { diff --git a/source/java/org/alfresco/repo/avm/DirectoryNode.java b/source/java/org/alfresco/repo/avm/DirectoryNode.java index 85ff3c1090..33bdf1cd9a 100644 --- a/source/java/org/alfresco/repo/avm/DirectoryNode.java +++ b/source/java/org/alfresco/repo/avm/DirectoryNode.java @@ -131,4 +131,12 @@ public interface DirectoryNode extends AVMNode * @param toLink The node to link in. */ public void link(Lookup lPath, String name, AVMNodeDescriptor toLink); + + /** + * Dangerous version of link that assumes that a child node of + * the given name does not already exist. + * @param name The name to give the child. + * @param toLink The child to link in. + */ + public void link(String name, AVMNodeDescriptor toLink); } \ No newline at end of file diff --git a/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java b/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java index fb0ce7507e..4f47d8efb8 100644 --- a/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java +++ b/source/java/org/alfresco/repo/avm/DirectoryNodeImpl.java @@ -17,6 +17,10 @@ package org.alfresco.repo.avm; +import org.alfresco.service.cmr.avm.AVMBadArgumentException; +import org.alfresco.service.cmr.avm.AVMNodeDescriptor; +import org.alfresco.service.cmr.avm.AVMNotFoundException; + /** * Base class for Directories. * @author britt @@ -40,4 +44,26 @@ abstract class DirectoryNodeImpl extends AVMNodeImpl implements DirectoryNode { super(id, repo); } + + /** + * Dangerous version of link. + * @param name The name to give the child. + * @param toLink The child to link in. + */ + public void link(String name, AVMNodeDescriptor toLink) + { + AVMNode node = AVMContext.fgInstance.fAVMNodeDAO.getByID(toLink.getId()); + if (node == null) + { + throw new AVMNotFoundException("Child node not found."); + } + if (node.getType() == AVMNodeType.LAYERED_DIRECTORY && + !((LayeredDirectoryNode)node).getPrimaryIndirection()) + { + throw new AVMBadArgumentException("Non primary layered directories cannot be linked."); + } + // Make the new ChildEntry and save. + ChildEntry newChild = new ChildEntryImpl(name, this, node); + AVMContext.fgInstance.fChildEntryDAO.save(newChild); + } } diff --git a/source/java/org/alfresco/service/cmr/avm/AVMService.java b/source/java/org/alfresco/service/cmr/avm/AVMService.java index a16a167578..24c99f3c40 100644 --- a/source/java/org/alfresco/service/cmr/avm/AVMService.java +++ b/source/java/org/alfresco/service/cmr/avm/AVMService.java @@ -685,4 +685,15 @@ public interface AVMService * @param toLink A descriptor for the node to insert. */ public void link(String parentPath, String name, AVMNodeDescriptor toLink); + + /** + * This is a more dangerous version of link, which assumes + * that copy on write has occurred for the parent node. This is + * an internal call. Don't use it if you don't know precisely + * what you are doing. + * @param parent The parent node. + * @param name The name to give the child. + * @param child The child node to link. + */ + public void link(AVMNodeDescriptor parent, String name, AVMNodeDescriptor child); }