diff --git a/config/alfresco/model-specific-services-context.xml b/config/alfresco/model-specific-services-context.xml index 74c4333916..9159902644 100644 --- a/config/alfresco/model-specific-services-context.xml +++ b/config/alfresco/model-specific-services-context.xml @@ -14,6 +14,12 @@ + + + http://www.alfresco.org/model/application/1.0 + http://www.alfresco.org/model/site/1.0 + + /${spaces.company_home.childname} diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java index 0bc5abad58..723eacf110 100644 --- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java +++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImpl.java @@ -103,6 +103,7 @@ public class FileFolderServiceImpl implements FileFolderService private SearchService searchService; private ContentService contentService; private MimetypeService mimetypeService; + private Set systemNamespaces; // TODO: Replace this with a more formal means of identifying "system" folders (i.e. aspect or UUID) private List systemPaths; @@ -112,6 +113,7 @@ public class FileFolderServiceImpl implements FileFolderService */ public FileFolderServiceImpl() { + systemNamespaces = new HashSet(5); } public void setNamespaceService(NamespaceService namespaceService) @@ -149,6 +151,22 @@ public class FileFolderServiceImpl implements FileFolderService this.mimetypeService = mimetypeService; } + /** + * Set the namespaces that should be treated as 'system' namespaces. + *

+ * When files or folders are renamed, the association path (QName) is normally + * modified to follow the name of the node. If, however, the namespace of the + * patch QName is in this list, the association path is left alone. This allows + * parts of the application to use well-known paths even if the end-user is + * able to modify the objects cm:name value. + * + * @param systemNamespaces a list of system namespaces + */ + public void setSystemNamespaces(List systemNamespaces) + { + this.systemNamespaces.addAll(systemNamespaces); + } + // TODO: Replace this with a more formal means of identifying "system" folders (i.e. aspect or UUID) public void setSystemPaths(List systemPaths) { @@ -572,8 +590,9 @@ public class FileFolderServiceImpl implements FileFolderService } } + QName existingQName = assocRef.getQName(); QName qname; - if (nameChanged) + if (nameChanged && !systemNamespaces.contains(existingQName.getNamespaceURI())) { // Change the localname to match the new name qname = QName.createQName( @@ -583,9 +602,7 @@ public class FileFolderServiceImpl implements FileFolderService else { // Keep the localname - qname = QName.createQName( - assocRef.getQName().getNamespaceURI(), - assocRef.getQName().getLocalName()); + qname = existingQName; } QName targetParentType = nodeService.getType(targetParentRef); @@ -714,6 +731,16 @@ public class FileFolderServiceImpl implements FileFolderService } public FileInfo create(NodeRef parentNodeRef, String name, QName typeQName) throws FileExistsException + { + return createImpl(parentNodeRef, name, typeQName, null); + } + + public FileInfo create(NodeRef parentNodeRef, String name, QName typeQName, QName assocQName) throws FileExistsException + { + return createImpl(parentNodeRef, name, typeQName, assocQName); + } + + private FileInfo createImpl(NodeRef parentNodeRef, String name, QName typeQName, QName assocQName) throws FileExistsException { // file or folder boolean isFolder = false; @@ -738,16 +765,19 @@ public class FileFolderServiceImpl implements FileFolderService } // create the node - QName qname = QName.createQName( - NamespaceService.CONTENT_MODEL_1_0_URI, - QName.createValidLocalName(name)); + if (assocQName == null) + { + assocQName = QName.createQName( + NamespaceService.CONTENT_MODEL_1_0_URI, + QName.createValidLocalName(name)); + } ChildAssociationRef assocRef = null; try { assocRef = nodeService.createNode( parentNodeRef, ContentModel.ASSOC_CONTAINS, - qname, + assocQName, typeQName, properties); } diff --git a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java index dbda9fba3c..981f0951c6 100644 --- a/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java +++ b/source/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java @@ -299,6 +299,35 @@ public class FileFolderServiceImplTest extends TestCase assertNotNull("Folder info for new name is not present", checkInfo); } + public void testRenameWithoutAssocQNameChange() throws Exception + { + FileInfo folderInfo = getByName(NAME_L0_FOLDER_A, true); + assertNotNull(folderInfo); + NodeRef folderNodeRef = folderInfo.getNodeRef(); + // Create a child file + QName assocQName = QName.createQName(NamespaceService.APP_MODEL_1_0_URI, "abc"); + NodeRef newFileNodeRef = fileFolderService.create( + folderNodeRef, + "AnotherFile.txt", + ContentModel.TYPE_CONTENT, + assocQName).getNodeRef(); + // Make sure that the correct association QName was used + QName checkQName = nodeService.getPrimaryParent(newFileNodeRef).getQName(); + assertEquals( + "The given assoc QName was not used for the path", + assocQName, + checkQName); + // Rename + String newName = "AnotherFile-new.txt"; + folderInfo = fileFolderService.rename(newFileNodeRef, newName); + // Make sure that the association QName did not change + checkQName = nodeService.getPrimaryParent(newFileNodeRef).getQName(); + assertEquals( + "The given assoc QName was not used for the path after a rename", + assocQName, + nodeService.getPrimaryParent(newFileNodeRef).getQName()); + } + public void testRenameDuplicate() throws Exception { FileInfo folderInfo = getByName(NAME_L0_FOLDER_A, true); diff --git a/source/java/org/alfresco/service/cmr/model/FileFolderService.java b/source/java/org/alfresco/service/cmr/model/FileFolderService.java index c7936af746..d1ed8156f5 100644 --- a/source/java/org/alfresco/service/cmr/model/FileFolderService.java +++ b/source/java/org/alfresco/service/cmr/model/FileFolderService.java @@ -169,18 +169,37 @@ public interface FileFolderService throws FileExistsException, FileNotFoundException; /** - * Create a file or folder; or any valid node of type derived from file or folder + * Create a file or folder; or any valid node of type derived from file or folder. + *

+ * The association QName for the patch defaults to cm:filename i.e. the + * Content Model namespace with the filename as the local name. * * @param parentNodeRef the parent node. The parent must be a valid - * {@link org.alfresco.model.ContentModel#TYPE_CONTAINER container}. + * {@link org.alfresco.model.ContentModel#TYPE_FOLDER folder}. * @param name the name of the node * @param typeQName the type to create * @return Returns the new node's file information * @throws FileExistsException + * + * @see {@link #create(NodeRef, String, QName, QName)} */ @Auditable(key = Auditable.Key.ARG_0, parameters = {"parentNodeRef", "name", "typeQName"}) public FileInfo create(NodeRef parentNodeRef, String name, QName typeQName) throws FileExistsException; + /** + * Create a file or folder; or any valid node of type derived from file or folder + * + * @param parentNodeRef the parent node. The parent must be a valid + * {@link org.alfresco.model.ContentModel#TYPE_FOLDER folder}. + * @param name the name of the node + * @param typeQName the type to create + * @param assocQName the association QName to set for the path (may be null). + * @return Returns the new node's file information + * @throws FileExistsException + */ + @Auditable(key = Auditable.Key.ARG_0, parameters = {"parentNodeRef", "name", "typeQName"}) + public FileInfo create(NodeRef parentNodeRef, String name, QName typeQName, QName assocQName) throws FileExistsException; + /** * Delete a file or folder *