/* * Copyright (C) 2005-2014 Alfresco Software Limited. * * This file is part of Alfresco * * Alfresco is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Alfresco is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Alfresco. If not, see . */ package org.alfresco.service.cmr.model; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.namespace.QName; /** * Higher level utility methods to be used in conjunction with the FileFolderService. * * @author mrogers */ public class FileFolderUtil { /** * Checks for the presence of, and creates as necessary, the folder * structure in the provided path. *

* An empty path list is not allowed as it would be impossible to * necessarily return file info for the parent node - it might not be a * folder node. * * @param parentNodeRef * the node under which the path will be created * @param pathElements * the folder name path to create - may not be empty * @param folderTypeQName * the types of nodes to create. This must be a valid subtype of * {@link org.alfresco.model.ContentModel#TYPE_FOLDER they folder * type}. * @return Returns the info of the last folder in the path. */ public static FileInfo makeFolders(FileFolderService service, NodeRef parentNodeRef, List pathElements, QName folderTypeQName) { return makeFolders(service, parentNodeRef,pathElements, folderTypeQName, null, null); } /** * Same as above, with option to disable parent behaviour(s) when creating sub-folder * * @param service * @param parentNodeRef * @param pathElements * @param folderTypeQName * @param behaviourFilter * @param parentBehavioursToDisable * @return */ public static FileInfo makeFolders(FileFolderService service, NodeRef parentNodeRef, List pathElements, QName folderTypeQName, BehaviourFilter behaviourFilter, Set parentBehavioursToDisable) { validate(pathElements, service, folderTypeQName); List list = new ArrayList<>(pathElements.size()); for (String pathElement : pathElements) { list.add(new PathElementDetails(pathElement, null)); } FileInfo fileInfo = makeFolders(service, null, parentNodeRef, list, folderTypeQName, behaviourFilter, parentBehavioursToDisable); // Should we check the type? return fileInfo; } /** * Checks for the presence of, and creates as necessary, the folder * structure in the provided paths with the following options: *

* * @param service the FileFolderService object * @param nodeService the NodeService object * @param parentNodeRef the node under which the path will be created * @param pathElementDetails the list of folder hierarchy where each folder * can have its own set of aspects - may not be empty * @param folderTypeQName the types of nodes to create. This must be a valid * subtype of {@link org.alfresco.model.ContentModel#TYPE_FOLDER * they folder type} * @param behaviourFilter the BehaviourFilter object * @param parentBehavioursToDisable the set of behaviours that must be * disabled * @return Returns the {@code FileInfo} of the last folder in the path. */ public static FileInfo makeFolders(FileFolderService service, NodeService nodeService, NodeRef parentNodeRef, List pathElementDetails, QName folderTypeQName, BehaviourFilter behaviourFilter, Set parentBehavioursToDisable) { validate(pathElementDetails, service, folderTypeQName); NodeRef currentParentRef = parentNodeRef; // just loop and create if necessary for (PathElementDetails pathElement : pathElementDetails) { // does it exist? // Navigation should not check permissions NodeRef nodeRef = AuthenticationUtil.runAs( new SearchAsSystem(service, currentParentRef, pathElement.getFolderName()), AuthenticationUtil.getSystemUserName()); if (nodeRef == null) { if ((behaviourFilter != null) && (parentBehavioursToDisable != null)) { for (QName parentBehaviourToDisable : parentBehavioursToDisable) { behaviourFilter.disableBehaviour(currentParentRef, parentBehaviourToDisable); } } try { // not present - make it // If this uses the public service it will check create // permissions FileInfo createdFileInfo = service.create(currentParentRef, pathElement.getFolderName(), folderTypeQName); currentParentRef = createdFileInfo.getNodeRef(); Map> requireddAspects = pathElement.getAspects(); if (requireddAspects.size() > 0 && nodeService != null) { for (QName aspect : requireddAspects.keySet()) { nodeService.addAspect(currentParentRef, aspect, requireddAspects.get(aspect)); } } } finally { if ((behaviourFilter != null) && (parentBehavioursToDisable != null)) { for (QName parentBehaviourToDisable : parentBehavioursToDisable) { behaviourFilter.enableBehaviour(currentParentRef, parentBehaviourToDisable); } } } } else { // it exists currentParentRef = nodeRef; } } // done // Used to call toFileInfo((currentParentRef, true); // If this uses the public service this will check the final read access FileInfo fileInfo = service.getFileInfo(currentParentRef); // Should we check the type? return fileInfo; } private static void validate(List pathElements, FileFolderService service, QName folderTypeQName) { if (pathElements.size() == 0) { throw new IllegalArgumentException("Path element list is empty"); } // make sure that the folder is correct boolean isFolder = service.getType(folderTypeQName) == FileFolderServiceType.FOLDER; if (!isFolder) { throw new IllegalArgumentException("Type is invalid to make folders with: " + folderTypeQName); } } private static class SearchAsSystem implements RunAsWork { FileFolderService service; NodeRef node; String name; SearchAsSystem(FileFolderService service, NodeRef node, String name) { this.service = service; this.node = node; this.name = name; } public NodeRef doWork() throws Exception { return service.searchSimple(node, name); } } /** * A simple POJO to hold information about the folder which will be created. * * @author Jamal Kaabi-Mofrad */ public static class PathElementDetails { private final String folderName; private final Map> aspects; public PathElementDetails(String folderName, Map> aspects) { this.folderName = folderName; if (aspects == null) { this.aspects = Collections.emptyMap(); } else { this.aspects = Collections.unmodifiableMap(aspects); } } /** * @return the folderName */ public String getFolderName() { return this.folderName; } /** * @return the aspects */ public Map> getAspects() { return this.aspects; } } }