diff --git a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java index 02edc9ab35..72c762e806 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceImpl.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceImpl.java @@ -28,6 +28,7 @@ import java.util.Map; import java.util.SortedMap; import org.alfresco.repo.avm.AVMRepository; +import org.alfresco.repo.domain.DbAccessControlList; import org.alfresco.repo.domain.PropertyValue; import org.alfresco.service.cmr.avm.AVMBadArgumentException; import org.alfresco.service.cmr.avm.AVMException; @@ -1176,4 +1177,81 @@ public class AVMServiceImpl implements AVMService } return fAVMRepository.forceCopy(path); } + + /** + * Copy (possibly recursively) the source into the destination + * directory. + * @param srcVersion The version of the source. + * @param srcPath The path to the source. + * @param dstPath The destination directory. + * @param name The name to give the copy. + */ + public void copy(int srcVersion, String srcPath, String dstPath, String name) + { + if (srcPath == null || dstPath == null) + { + throw new AVMBadArgumentException("Null Path."); + } + if (srcVersion < 0) + { + String canonicalSrc = + AVMNodeConverter.ToAVMVersionPath( + AVMNodeConverter.ToNodeRef(srcVersion, srcPath)).getSecond(); + String canonicalDst = + AVMNodeConverter.ToAVMVersionPath( + AVMNodeConverter.ToNodeRef(-1, dstPath)).getSecond(); + if (!canonicalSrc.endsWith("/")) + { + canonicalSrc = canonicalSrc + "/"; + } + if (canonicalDst.indexOf(canonicalSrc) == 0) + { + throw new AVMBadArgumentException("Infinite Copy."); + } + } + if (!FileNameValidator.IsValid(name)) + { + throw new AVMBadArgumentException("Illegal name."); + } + AVMNodeDescriptor srcDesc = lookup(srcVersion, srcPath); + recursiveCopy(srcVersion, srcDesc, dstPath, name); + } + + /** + * Do the actual work of copying. + * @param desc The src descriptor. + * @param path The destination parent path. + * @param name The name to give the copy. + */ + private void recursiveCopy(int version, AVMNodeDescriptor desc, String path, String name) + { + String newPath = path + '/' + name; + if (desc.isFile()) + { + InputStream in = getFileInputStream(version, desc.getPath()); + createFile(path, name, in); + } + else // desc is a directory. + { + createDirectory(path, name); + Map listing = getDirectoryListing(desc); + for (Map.Entry entry : listing.entrySet()) + { + recursiveCopy(version, entry.getValue(), newPath, entry.getKey()); + } + } + // In either case copy properties, aspects, and acls. + Map props = getNodeProperties(version, desc.getPath()); + setNodeProperties(newPath, props); + List aspects = getAspects(version, desc.getPath()); + for (QName aspect : aspects) + { + addAspect(newPath, aspect); + } + DbAccessControlList acl = fAVMRepository.getACL(version, desc.getPath()); + if (acl != null) + { + fAVMRepository.setACL(newPath, acl.getCopy()); + } + } } diff --git a/source/java/org/alfresco/repo/avm/AVMServiceTest.java b/source/java/org/alfresco/repo/avm/AVMServiceTest.java index 7a89301374..330a0aa945 100644 --- a/source/java/org/alfresco/repo/avm/AVMServiceTest.java +++ b/source/java/org/alfresco/repo/avm/AVMServiceTest.java @@ -66,6 +66,43 @@ import org.alfresco.util.Pair; */ public class AVMServiceTest extends AVMServiceTestBase { + /** + * Test copy. + */ + public void testCopy() + { + try + { + setupBasicTree(); + // Copy a file. + fService.copy(-1, "main:/a/b/c/foo", "main:/d", "fooCopy"); + AVMNodeDescriptor desc = fService.lookup(-1, "main:/d/fooCopy"); + assertTrue(desc.isFile()); + // Copy a whole tree + fService.copy(-1, "main:/a", "main:/d/e", "aCopy"); + desc = fService.lookup(-1, "main:/d/e/aCopy"); + assertTrue(desc.isDirectory()); + desc = fService.lookup(-1, "main:/a/b/c/bar"); + AVMNodeDescriptor desc2 = fService.lookup(-1, "main:/d/e/aCopy/b/c/bar"); + assertTrue(desc2.isFile()); + assertEquals(desc.getLength(), desc2.getLength()); + // Check that it rejects infinite copies. + try + { + fService.copy(-1, "main:/", "main://d/e", "illegal"); + fail(); + } + catch (AVMException ae) + { + // This is a success. + } + } + catch (Exception e) + { + e.printStackTrace(); + fail(); + } + } /** * Test cyclic lookup behavior. */ diff --git a/source/java/org/alfresco/service/cmr/avm/AVMService.java b/source/java/org/alfresco/service/cmr/avm/AVMService.java index 843bf67000..ee5f8b4328 100644 --- a/source/java/org/alfresco/service/cmr/avm/AVMService.java +++ b/source/java/org/alfresco/service/cmr/avm/AVMService.java @@ -734,4 +734,14 @@ public interface AVMService * @param path The path to force. */ public AVMNodeDescriptor forceCopy(String path); + + /** + * Copy (possibly recursively) the source into the destination + * directory. + * @param srcVersion The version of the source. + * @param srcPath The path to the source. + * @param dstPath The destination directory. + * @param name The name to give the destination. + */ + public void copy(int srcVersion, String srcPath, String dstPath, String name); }