mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Moving to root below branch label
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2005 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -0,0 +1,768 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.model.filefolder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.search.QueryParameterDefImpl;
|
||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
|
||||
import org.alfresco.service.cmr.model.FileExistsException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.CopyService;
|
||||
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||
import org.alfresco.service.cmr.repository.MimetypeService;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.Path;
|
||||
import org.alfresco.service.cmr.search.QueryParameterDefinition;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.SearchLanguageConversion;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Implementation of the file/folder-specific service.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class FileFolderServiceImpl implements FileFolderService
|
||||
{
|
||||
/** Shallow search for all files */
|
||||
private static final String XPATH_QUERY_SHALLOW_FILES =
|
||||
"./*" +
|
||||
"[(subtypeOf('" + ContentModel.TYPE_CONTENT + "'))]";
|
||||
|
||||
/** Shallow search for all folder */
|
||||
private static final String XPATH_QUERY_SHALLOW_FOLDERS =
|
||||
"./*" +
|
||||
"[not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "'))]";
|
||||
|
||||
/** Shallow search for all files and folders */
|
||||
private static final String XPATH_QUERY_SHALLOW_ALL =
|
||||
"./*" +
|
||||
"[like(@cm:name, $cm:name, false)" +
|
||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "'))]";
|
||||
|
||||
/** Deep search for files and folders with a name pattern */
|
||||
private static final String XPATH_QUERY_DEEP_ALL =
|
||||
".//*" +
|
||||
"[like(@cm:name, $cm:name, false)" +
|
||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "'))]";
|
||||
|
||||
/** empty parameters */
|
||||
private static final QueryParameterDefinition[] PARAMS_EMPTY = new QueryParameterDefinition[0];
|
||||
private static final QueryParameterDefinition[] PARAMS_ANY_NAME = new QueryParameterDefinition[1];
|
||||
|
||||
private static Log logger = LogFactory.getLog(FileFolderServiceImpl.class);
|
||||
|
||||
private NamespaceService namespaceService;
|
||||
private DictionaryService dictionaryService;
|
||||
private NodeService nodeService;
|
||||
private CopyService copyService;
|
||||
private SearchService searchService;
|
||||
private ContentService contentService;
|
||||
private MimetypeService mimetypeService;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public FileFolderServiceImpl()
|
||||
{
|
||||
}
|
||||
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
{
|
||||
this.namespaceService = namespaceService;
|
||||
}
|
||||
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setCopyService(CopyService copyService)
|
||||
{
|
||||
this.copyService = copyService;
|
||||
}
|
||||
|
||||
public void setSearchService(SearchService searchService)
|
||||
{
|
||||
this.searchService = searchService;
|
||||
}
|
||||
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
this.contentService = contentService;
|
||||
}
|
||||
|
||||
public void setMimetypeService(MimetypeService mimetypeService)
|
||||
{
|
||||
this.mimetypeService = mimetypeService;
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
PARAMS_ANY_NAME[0] = new QueryParameterDefImpl(
|
||||
ContentModel.PROP_NAME,
|
||||
dictionaryService.getDataType(DataTypeDefinition.TEXT),
|
||||
true,
|
||||
"%");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to convert node reference instances to file info
|
||||
*
|
||||
* @param nodeRefs the node references
|
||||
* @return Return a list of file info
|
||||
* @throws InvalidTypeException if the node is not a valid type
|
||||
*/
|
||||
private List<FileInfo> toFileInfo(List<NodeRef> nodeRefs) throws InvalidTypeException
|
||||
{
|
||||
List<FileInfo> results = new ArrayList<FileInfo>(nodeRefs.size());
|
||||
for (NodeRef nodeRef : nodeRefs)
|
||||
{
|
||||
FileInfo fileInfo = toFileInfo(nodeRef);
|
||||
results.add(fileInfo);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to convert a node reference instance to a file info
|
||||
*/
|
||||
private FileInfo toFileInfo(NodeRef nodeRef) throws InvalidTypeException
|
||||
{
|
||||
// get the file attributes
|
||||
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
|
||||
// is it a folder
|
||||
QName typeQName = nodeService.getType(nodeRef);
|
||||
boolean isFolder = isFolder(typeQName);
|
||||
|
||||
// construct the file info and add to the results
|
||||
FileInfo fileInfo = new FileInfoImpl(nodeRef, isFolder, properties);
|
||||
// done
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a file or folder with the given name does not already exist
|
||||
*
|
||||
* @throws FileExistsException if a same-named file or folder already exists
|
||||
*/
|
||||
private void checkExists(NodeRef parentFolderRef, String name)
|
||||
throws FileExistsException
|
||||
{
|
||||
// check for existing file or folder
|
||||
List<FileInfo> existingFileInfos = this.search(parentFolderRef, name, true, true, false);
|
||||
if (existingFileInfos.size() > 0)
|
||||
{
|
||||
throw new FileExistsException(existingFileInfos.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception when the type is not a valid File or Folder type
|
||||
*
|
||||
* @see ContentModel#TYPE_CONTENT
|
||||
* @see ContentModel#TYPE_FOLDER
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
private static class InvalidTypeException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = -310101369475434280L;
|
||||
|
||||
public InvalidTypeException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the type for whether it is a file or folder. All invalid types
|
||||
* lead to runtime exceptions.
|
||||
*
|
||||
* @param typeQName the type to check
|
||||
* @return Returns true if the type is a valid folder type, false if it is a file.
|
||||
* @throws AlfrescoRuntimeException if the type is not handled by this service
|
||||
*/
|
||||
private boolean isFolder(QName typeQName) throws InvalidTypeException
|
||||
{
|
||||
if (dictionaryService.isSubClass(typeQName, ContentModel.TYPE_FOLDER))
|
||||
{
|
||||
if (dictionaryService.isSubClass(typeQName, ContentModel.TYPE_SYSTEM_FOLDER))
|
||||
{
|
||||
throw new InvalidTypeException("This service should ignore type " + ContentModel.TYPE_SYSTEM_FOLDER);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (dictionaryService.isSubClass(typeQName, ContentModel.TYPE_CONTENT))
|
||||
{
|
||||
// it is a regular file
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unhandled type
|
||||
throw new InvalidTypeException("Type is not handled by this service: " + typeQName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Use Lucene search to get file attributes without having to visit the node service
|
||||
*/
|
||||
public List<FileInfo> list(NodeRef contextNodeRef)
|
||||
{
|
||||
// execute the query
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(
|
||||
contextNodeRef,
|
||||
XPATH_QUERY_SHALLOW_ALL,
|
||||
PARAMS_ANY_NAME,
|
||||
namespaceService,
|
||||
false);
|
||||
// convert the noderefs
|
||||
List<FileInfo> results = toFileInfo(nodeRefs);
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Shallow search for files and folders: \n" +
|
||||
" context: " + contextNodeRef + "\n" +
|
||||
" results: " + results);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Use Lucene search to get file attributes without having to visit the node service
|
||||
*/
|
||||
public List<FileInfo> listFiles(NodeRef contextNodeRef)
|
||||
{
|
||||
// execute the query
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(
|
||||
contextNodeRef,
|
||||
XPATH_QUERY_SHALLOW_FILES,
|
||||
PARAMS_EMPTY,
|
||||
namespaceService,
|
||||
false);
|
||||
// convert the noderefs
|
||||
List<FileInfo> results = toFileInfo(nodeRefs);
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Shallow search for files: \n" +
|
||||
" context: " + contextNodeRef + "\n" +
|
||||
" results: " + results);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Use Lucene search to get file attributes without having to visit the node service
|
||||
*/
|
||||
public List<FileInfo> listFolders(NodeRef contextNodeRef)
|
||||
{
|
||||
// execute the query
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(
|
||||
contextNodeRef,
|
||||
XPATH_QUERY_SHALLOW_FOLDERS,
|
||||
PARAMS_EMPTY,
|
||||
namespaceService,
|
||||
false);
|
||||
// convert the noderefs
|
||||
List<FileInfo> results = toFileInfo(nodeRefs);
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Shallow search for folders: \n" +
|
||||
" context: " + contextNodeRef + "\n" +
|
||||
" results: " + results);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #search(NodeRef, String, boolean, boolean, boolean)
|
||||
*/
|
||||
public List<FileInfo> search(NodeRef contextNodeRef, String namePattern, boolean includeSubFolders)
|
||||
{
|
||||
return search(contextNodeRef, namePattern, true, true, includeSubFolders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Full search with all options
|
||||
*/
|
||||
public List<FileInfo> search(
|
||||
NodeRef contextNodeRef,
|
||||
String namePattern,
|
||||
boolean fileSearch,
|
||||
boolean folderSearch,
|
||||
boolean includeSubFolders)
|
||||
{
|
||||
// shortcut if the search is requesting nothing
|
||||
if (!fileSearch && !folderSearch)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// if the name pattern is null, then we use the ANY pattern
|
||||
QueryParameterDefinition[] params = null;
|
||||
if (namePattern != null)
|
||||
{
|
||||
// the interface specifies the Lucene syntax, so perform a conversion
|
||||
namePattern = SearchLanguageConversion.convert(
|
||||
SearchLanguageConversion.DEF_LUCENE,
|
||||
SearchLanguageConversion.DEF_XPATH_LIKE,
|
||||
namePattern);
|
||||
|
||||
params = new QueryParameterDefinition[1];
|
||||
params[0] = new QueryParameterDefImpl(
|
||||
ContentModel.PROP_NAME,
|
||||
dictionaryService.getDataType(DataTypeDefinition.TEXT),
|
||||
true,
|
||||
namePattern);
|
||||
}
|
||||
else
|
||||
{
|
||||
params = PARAMS_ANY_NAME;
|
||||
}
|
||||
// determine the correct query to use
|
||||
String query = null;
|
||||
if (includeSubFolders)
|
||||
{
|
||||
query = XPATH_QUERY_DEEP_ALL;
|
||||
}
|
||||
else
|
||||
{
|
||||
query = XPATH_QUERY_SHALLOW_ALL;
|
||||
}
|
||||
// execute the query
|
||||
List<NodeRef> nodeRefs = searchService.selectNodes(
|
||||
contextNodeRef,
|
||||
query,
|
||||
params,
|
||||
namespaceService,
|
||||
false);
|
||||
List<FileInfo> results = toFileInfo(nodeRefs);
|
||||
// eliminate unwanted files/folders
|
||||
Iterator<FileInfo> iterator = results.iterator();
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
FileInfo file = iterator.next();
|
||||
if (file.isFolder() && !folderSearch)
|
||||
{
|
||||
iterator.remove();
|
||||
}
|
||||
else if (!file.isFolder() && !fileSearch)
|
||||
{
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Deep search: \n" +
|
||||
" context: " + contextNodeRef + "\n" +
|
||||
" pattern: " + namePattern + "\n" +
|
||||
" files: " + fileSearch + "\n" +
|
||||
" folders: " + folderSearch + "\n" +
|
||||
" deep: " + includeSubFolders + "\n" +
|
||||
" results: " + results);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #move(NodeRef, NodeRef, String)
|
||||
*/
|
||||
public FileInfo rename(NodeRef sourceNodeRef, String newName) throws FileExistsException, FileNotFoundException
|
||||
{
|
||||
return move(sourceNodeRef, null, newName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #moveOrCopy(NodeRef, NodeRef, String, boolean)
|
||||
*/
|
||||
public FileInfo move(NodeRef sourceNodeRef, NodeRef targetParentRef, String newName) throws FileExistsException, FileNotFoundException
|
||||
{
|
||||
return moveOrCopy(sourceNodeRef, targetParentRef, newName, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #moveOrCopy(NodeRef, NodeRef, String, boolean)
|
||||
*/
|
||||
public FileInfo copy(NodeRef sourceNodeRef, NodeRef targetParentRef, String newName) throws FileExistsException, FileNotFoundException
|
||||
{
|
||||
return moveOrCopy(sourceNodeRef, targetParentRef, newName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements both move and copy behaviour
|
||||
*
|
||||
* @param move true to move, otherwise false to copy
|
||||
*/
|
||||
private FileInfo moveOrCopy(NodeRef sourceNodeRef, NodeRef targetParentRef, String newName, boolean move) throws FileExistsException, FileNotFoundException
|
||||
{
|
||||
// get file/folder in its current state
|
||||
FileInfo beforeFileInfo = toFileInfo(sourceNodeRef);
|
||||
// check the name - null means keep the existing name
|
||||
if (newName == null)
|
||||
{
|
||||
newName = beforeFileInfo.getName();
|
||||
}
|
||||
|
||||
// we need the current association type
|
||||
ChildAssociationRef assocRef = nodeService.getPrimaryParent(sourceNodeRef);
|
||||
if (targetParentRef == null)
|
||||
{
|
||||
targetParentRef = assocRef.getParentRef();
|
||||
}
|
||||
|
||||
// there is nothing to do if both the name and parent folder haven't changed
|
||||
if (targetParentRef.equals(assocRef.getParentRef()) && newName.equals(beforeFileInfo.getName()))
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Doing nothing - neither filename or parent has not changed: \n" +
|
||||
" parent: " + targetParentRef + "\n" +
|
||||
" before: " + beforeFileInfo + "\n" +
|
||||
" new name: " + newName);
|
||||
}
|
||||
return beforeFileInfo;
|
||||
}
|
||||
|
||||
// check for existing file or folder
|
||||
checkExists(targetParentRef, newName);
|
||||
|
||||
QName qname = QName.createQName(
|
||||
NamespaceService.CONTENT_MODEL_1_0_URI,
|
||||
QName.createValidLocalName(newName));
|
||||
|
||||
// move or copy
|
||||
NodeRef targetNodeRef = null;
|
||||
if (move)
|
||||
{
|
||||
// move the node so that the association moves as well
|
||||
ChildAssociationRef newAssocRef = nodeService.moveNode(
|
||||
sourceNodeRef,
|
||||
targetParentRef,
|
||||
assocRef.getTypeQName(),
|
||||
qname);
|
||||
targetNodeRef = newAssocRef.getChildRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy the node
|
||||
targetNodeRef = copyService.copy(
|
||||
sourceNodeRef,
|
||||
targetParentRef,
|
||||
assocRef.getTypeQName(),
|
||||
qname,
|
||||
true);
|
||||
}
|
||||
// changed the name property
|
||||
nodeService.setProperty(targetNodeRef, ContentModel.PROP_NAME, newName);
|
||||
|
||||
// get the details after the operation
|
||||
FileInfo afterFileInfo = toFileInfo(targetNodeRef);
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("" + (move ? "Moved" : "Copied") + " node: \n" +
|
||||
" parent: " + targetParentRef + "\n" +
|
||||
" before: " + beforeFileInfo + "\n" +
|
||||
" after: " + afterFileInfo);
|
||||
}
|
||||
return afterFileInfo;
|
||||
}
|
||||
|
||||
public FileInfo create(NodeRef parentNodeRef, String name, QName typeQName) throws FileExistsException
|
||||
{
|
||||
// file or folder
|
||||
boolean isFolder = false;
|
||||
try
|
||||
{
|
||||
isFolder = isFolder(typeQName);
|
||||
}
|
||||
catch (InvalidTypeException e)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("The type is not supported by this service: " + typeQName);
|
||||
}
|
||||
|
||||
// check for existing file or folder
|
||||
checkExists(parentNodeRef, name);
|
||||
|
||||
// set up initial properties
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(11);
|
||||
properties.put(ContentModel.PROP_NAME, (Serializable) name);
|
||||
if (!isFolder)
|
||||
{
|
||||
// guess a mimetype based on the filename
|
||||
String mimetype = mimetypeService.guessMimetype(name);
|
||||
ContentData contentData = new ContentData(null, mimetype, 0L, "UTF-8");
|
||||
properties.put(ContentModel.PROP_CONTENT, contentData);
|
||||
}
|
||||
|
||||
// create the node
|
||||
QName qname = QName.createQName(
|
||||
NamespaceService.CONTENT_MODEL_1_0_URI,
|
||||
QName.createValidLocalName(name));
|
||||
ChildAssociationRef assocRef = nodeService.createNode(
|
||||
parentNodeRef,
|
||||
ContentModel.ASSOC_CONTAINS,
|
||||
qname,
|
||||
typeQName,
|
||||
properties);
|
||||
NodeRef nodeRef = assocRef.getChildRef();
|
||||
FileInfo fileInfo = toFileInfo(nodeRef);
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
FileInfo parentFileInfo = toFileInfo(parentNodeRef);
|
||||
logger.debug("Created: \n" +
|
||||
" parent: " + parentFileInfo + "\n" +
|
||||
" created: " + fileInfo);
|
||||
}
|
||||
return fileInfo;
|
||||
}
|
||||
|
||||
public void delete(NodeRef nodeRef)
|
||||
{
|
||||
nodeService.deleteNode(nodeRef);
|
||||
}
|
||||
|
||||
public FileInfo makeFolders(NodeRef parentNodeRef, List<String> pathElements, QName folderTypeQName)
|
||||
{
|
||||
if (pathElements.size() == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Path element list is empty");
|
||||
}
|
||||
|
||||
// make sure that the folder is correct
|
||||
boolean isFolder = isFolder(folderTypeQName);
|
||||
if (!isFolder)
|
||||
{
|
||||
throw new IllegalArgumentException("Type is invalid to make folders with: " + folderTypeQName);
|
||||
}
|
||||
|
||||
NodeRef currentParentRef = parentNodeRef;
|
||||
// just loop and create if necessary
|
||||
FileInfo lastFileInfo = null;
|
||||
for (String pathElement : pathElements)
|
||||
{
|
||||
try
|
||||
{
|
||||
// not present - make it
|
||||
FileInfo createdFileInfo = create(currentParentRef, pathElement, folderTypeQName);
|
||||
currentParentRef = createdFileInfo.getNodeRef();
|
||||
lastFileInfo = createdFileInfo;
|
||||
}
|
||||
catch (FileExistsException e)
|
||||
{
|
||||
// it exists - just get it
|
||||
List<FileInfo> fileInfos = search(currentParentRef, pathElement, false, true, false);
|
||||
if (fileInfos.size() == 0)
|
||||
{
|
||||
// ? It must have been removed
|
||||
throw new AlfrescoRuntimeException("Path element has just been removed: " + pathElement);
|
||||
}
|
||||
currentParentRef = fileInfos.get(0).getNodeRef();
|
||||
lastFileInfo = fileInfos.get(0);
|
||||
}
|
||||
}
|
||||
// done
|
||||
return lastFileInfo;
|
||||
}
|
||||
|
||||
public List<FileInfo> getNamePath(NodeRef rootNodeRef, NodeRef nodeRef) throws FileNotFoundException
|
||||
{
|
||||
// check the root
|
||||
if (rootNodeRef == null)
|
||||
{
|
||||
rootNodeRef = nodeService.getRootNode(nodeRef.getStoreRef());
|
||||
}
|
||||
try
|
||||
{
|
||||
List<FileInfo> results = new ArrayList<FileInfo>(10);
|
||||
// get the primary path
|
||||
Path path = nodeService.getPath(nodeRef);
|
||||
// iterate and turn the results into file info objects
|
||||
boolean foundRoot = false;
|
||||
for (Path.Element element : path)
|
||||
{
|
||||
// ignore everything down to the root
|
||||
Path.ChildAssocElement assocElement = (Path.ChildAssocElement) element;
|
||||
NodeRef childNodeRef = assocElement.getRef().getChildRef();
|
||||
if (childNodeRef.equals(rootNodeRef))
|
||||
{
|
||||
// just found the root - but we don't put in an entry for it
|
||||
foundRoot = true;
|
||||
continue;
|
||||
}
|
||||
else if (!foundRoot)
|
||||
{
|
||||
// keep looking for the root
|
||||
continue;
|
||||
}
|
||||
// we found the root and expect to be building the path up
|
||||
FileInfo pathInfo = toFileInfo(childNodeRef);
|
||||
results.add(pathInfo);
|
||||
}
|
||||
// check that we found the root
|
||||
if (!foundRoot || results.size() == 0)
|
||||
{
|
||||
throw new FileNotFoundException(nodeRef);
|
||||
}
|
||||
// done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Built name path for node: \n" +
|
||||
" root: " + rootNodeRef + "\n" +
|
||||
" node: " + nodeRef + "\n" +
|
||||
" path: " + results);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
catch (InvalidNodeRefException e)
|
||||
{
|
||||
throw new FileNotFoundException(nodeRef);
|
||||
}
|
||||
}
|
||||
|
||||
public FileInfo resolveNamePath(NodeRef rootNodeRef, List<String> pathElements) throws FileNotFoundException
|
||||
{
|
||||
if (pathElements.size() == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Path elements list is empty");
|
||||
}
|
||||
// walk the folder tree first
|
||||
NodeRef parentNodeRef = rootNodeRef;
|
||||
StringBuilder currentPath = new StringBuilder(pathElements.size() * 20);
|
||||
int folderCount = pathElements.size() - 1;
|
||||
for (int i = 0; i < folderCount; i++)
|
||||
{
|
||||
String pathElement = pathElements.get(i);
|
||||
FileInfo pathElementInfo = getPathElementInfo(currentPath, rootNodeRef, parentNodeRef, pathElement, true);
|
||||
parentNodeRef = pathElementInfo.getNodeRef();
|
||||
}
|
||||
// we have resolved the folder path - resolve the last component
|
||||
String pathElement = pathElements.get(pathElements.size() - 1);
|
||||
FileInfo result = getPathElementInfo(currentPath, rootNodeRef, parentNodeRef, pathElement, false);
|
||||
// found it
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Resoved path element: \n" +
|
||||
" root: " + rootNodeRef + "\n" +
|
||||
" path: " + currentPath + "\n" +
|
||||
" node: " + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to dig down a level for a node based on name
|
||||
*/
|
||||
private FileInfo getPathElementInfo(
|
||||
StringBuilder currentPath,
|
||||
NodeRef rootNodeRef,
|
||||
NodeRef parentNodeRef,
|
||||
String pathElement,
|
||||
boolean folderOnly) throws FileNotFoundException
|
||||
{
|
||||
currentPath.append("/").append(pathElement);
|
||||
|
||||
boolean includeFiles = (folderOnly ? false : true);
|
||||
List<FileInfo> pathElementInfos = search(parentNodeRef, pathElement, includeFiles, true, false);
|
||||
// check
|
||||
if (pathElementInfos.size() == 0)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
sb.append(folderOnly ? "Folder" : "File or folder").append(" not found: \n")
|
||||
.append(" root: ").append(rootNodeRef).append("\n")
|
||||
.append(" path: ").append(currentPath);
|
||||
throw new FileNotFoundException(sb.toString());
|
||||
}
|
||||
else if (pathElementInfos.size() > 1)
|
||||
{
|
||||
// we have detected a duplicate name - warn, but allow
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
sb.append("Duplicate file or folder found: \n")
|
||||
.append(" root: ").append(rootNodeRef).append("\n")
|
||||
.append(" path: ").append(currentPath);
|
||||
logger.warn(sb);
|
||||
}
|
||||
FileInfo pathElementInfo = pathElementInfos.get(0);
|
||||
return pathElementInfo;
|
||||
}
|
||||
|
||||
public FileInfo getFileInfo(NodeRef nodeRef)
|
||||
{
|
||||
try
|
||||
{
|
||||
return toFileInfo(nodeRef);
|
||||
}
|
||||
catch (InvalidTypeException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ContentReader getReader(NodeRef nodeRef)
|
||||
{
|
||||
FileInfo fileInfo = toFileInfo(nodeRef);
|
||||
if (fileInfo.isFolder())
|
||||
{
|
||||
throw new InvalidTypeException("Unable to get a content reader for a folder: " + fileInfo);
|
||||
}
|
||||
return contentService.getReader(nodeRef, ContentModel.PROP_CONTENT);
|
||||
}
|
||||
|
||||
public ContentWriter getWriter(NodeRef nodeRef)
|
||||
{
|
||||
FileInfo fileInfo = toFileInfo(nodeRef);
|
||||
if (fileInfo.isFolder())
|
||||
{
|
||||
throw new InvalidTypeException("Unable to get a content writer for a folder: " + fileInfo);
|
||||
}
|
||||
return contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
||||
}
|
||||
}
|
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.model.filefolder;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.transaction.UserTransaction;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.model.FileExistsException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FileNotFoundException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.view.ImporterService;
|
||||
import org.alfresco.service.cmr.view.Location;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* @see org.alfresco.repo.model.filefolder.FileFolderServiceImpl
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class FileFolderServiceImplTest extends TestCase
|
||||
{
|
||||
private static final String IMPORT_VIEW = "filefolder/filefolder-test-import.xml";
|
||||
|
||||
private static final String NAME_L0_FILE_A = "L0: File A";
|
||||
private static final String NAME_L0_FILE_B = "L0: File B";
|
||||
private static final String NAME_L0_FOLDER_A = "L0: Folder A";
|
||||
private static final String NAME_L0_FOLDER_B = "L0: Folder B";
|
||||
private static final String NAME_L0_FOLDER_C = "L0: Folder C";
|
||||
private static final String NAME_L1_FOLDER_A = "L1: Folder A";
|
||||
private static final String NAME_L1_FOLDER_B = "L1: Folder B";
|
||||
private static final String NAME_L1_FILE_A = "L1: File A";
|
||||
private static final String NAME_L1_FILE_B = "L1: File B";
|
||||
private static final String NAME_L1_FILE_C = "L1: File C (%_)";
|
||||
private static final String NAME_DUPLICATE = "DUPLICATE";
|
||||
|
||||
private static final ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||
|
||||
private TransactionService transactionService;
|
||||
private NodeService nodeService;
|
||||
private FileFolderService fileFolderService;
|
||||
private UserTransaction txn;
|
||||
private NodeRef rootNodeRef;
|
||||
private NodeRef workingRootNodeRef;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry");
|
||||
transactionService = serviceRegistry.getTransactionService();
|
||||
nodeService = serviceRegistry.getNodeService();
|
||||
fileFolderService = serviceRegistry.getFileFolderService();
|
||||
AuthenticationComponent authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
|
||||
|
||||
// start the transaction
|
||||
txn = transactionService.getUserTransaction();
|
||||
txn.begin();
|
||||
|
||||
// authenticate
|
||||
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
|
||||
|
||||
// create a test store
|
||||
StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, getName() + System.currentTimeMillis());
|
||||
rootNodeRef = nodeService.getRootNode(storeRef);
|
||||
|
||||
// create a folder to import into
|
||||
workingRootNodeRef = nodeService.createNode(
|
||||
rootNodeRef,
|
||||
ContentModel.ASSOC_CHILDREN,
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "working root"),
|
||||
ContentModel.TYPE_FOLDER).getChildRef();
|
||||
|
||||
// import the test data
|
||||
ImporterService importerService = serviceRegistry.getImporterService();
|
||||
Location importLocation = new Location(workingRootNodeRef);
|
||||
InputStream is = getClass().getClassLoader().getResourceAsStream(IMPORT_VIEW);
|
||||
if (is == null)
|
||||
{
|
||||
throw new NullPointerException("Test resource not found: " + IMPORT_VIEW);
|
||||
}
|
||||
Reader reader = new InputStreamReader(is);
|
||||
importerService.importView(reader, importLocation, null, null);
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception
|
||||
{
|
||||
txn.rollback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the names and numbers of files and folders in the provided list is correct
|
||||
*
|
||||
* @param files the list of files
|
||||
* @param expectedFileCount the number of uniquely named files expected
|
||||
* @param expectedFolderCount the number of uniquely named folders expected
|
||||
* @param expectedNames the names of the files and folders expected
|
||||
*/
|
||||
private void checkFileList(List<FileInfo> files, int expectedFileCount, int expectedFolderCount, String[] expectedNames)
|
||||
{
|
||||
int fileCount = 0;
|
||||
int folderCount = 0;
|
||||
List<String> check = new ArrayList<String>(8);
|
||||
for (String filename : expectedNames)
|
||||
{
|
||||
check.add(filename);
|
||||
}
|
||||
for (FileInfo file : files)
|
||||
{
|
||||
if (file.isFolder())
|
||||
{
|
||||
folderCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fileCount++;
|
||||
}
|
||||
check.remove(file.getName());
|
||||
}
|
||||
assertTrue("Name list was not exact - remaining: " + check, check.size() == 0);
|
||||
assertEquals("Incorrect number of files", expectedFileCount, fileCount);
|
||||
assertEquals("Incorrect number of folders", expectedFolderCount, folderCount);
|
||||
}
|
||||
|
||||
public void testShallowFilesAndFoldersList() throws Exception
|
||||
{
|
||||
List<FileInfo> files = fileFolderService.list(workingRootNodeRef);
|
||||
// check
|
||||
String[] expectedNames = new String[] {NAME_L0_FILE_A, NAME_L0_FILE_B, NAME_L0_FOLDER_A, NAME_L0_FOLDER_B, NAME_L0_FOLDER_C};
|
||||
checkFileList(files, 2, 3, expectedNames);
|
||||
}
|
||||
|
||||
public void testShallowFilesOnlyList() throws Exception
|
||||
{
|
||||
List<FileInfo> files = fileFolderService.listFiles(workingRootNodeRef);
|
||||
// check
|
||||
String[] expectedNames = new String[] {NAME_L0_FILE_A, NAME_L0_FILE_B};
|
||||
checkFileList(files, 2, 0, expectedNames);
|
||||
}
|
||||
|
||||
public void testShallowFoldersOnlyList() throws Exception
|
||||
{
|
||||
List<FileInfo> files = fileFolderService.listFolders(workingRootNodeRef);
|
||||
// check
|
||||
String[] expectedNames = new String[] {NAME_L0_FOLDER_A, NAME_L0_FOLDER_B, NAME_L0_FOLDER_C};
|
||||
checkFileList(files, 0, 3, expectedNames);
|
||||
}
|
||||
|
||||
public void testShallowFileSearch() throws Exception
|
||||
{
|
||||
List<FileInfo> files = fileFolderService.search(
|
||||
workingRootNodeRef,
|
||||
NAME_L0_FILE_B,
|
||||
true,
|
||||
false,
|
||||
false);
|
||||
// check
|
||||
String[] expectedNames = new String[] {NAME_L0_FILE_B};
|
||||
checkFileList(files, 1, 0, expectedNames);
|
||||
}
|
||||
|
||||
public void testDeepFilesAndFoldersSearch() throws Exception
|
||||
{
|
||||
List<FileInfo> files = fileFolderService.search(
|
||||
workingRootNodeRef,
|
||||
"?1:*",
|
||||
true,
|
||||
true,
|
||||
true);
|
||||
// check
|
||||
String[] expectedNames = new String[] {NAME_L1_FOLDER_A, NAME_L1_FOLDER_B, NAME_L1_FILE_A, NAME_L1_FILE_B, NAME_L1_FILE_C};
|
||||
checkFileList(files, 3, 2, expectedNames);
|
||||
}
|
||||
|
||||
public void testDeepFilesOnlySearch() throws Exception
|
||||
{
|
||||
List<FileInfo> files = fileFolderService.search(
|
||||
workingRootNodeRef,
|
||||
"?1:*",
|
||||
true,
|
||||
false,
|
||||
true);
|
||||
// check
|
||||
String[] expectedNames = new String[] {NAME_L1_FILE_A, NAME_L1_FILE_B, NAME_L1_FILE_C};
|
||||
checkFileList(files, 3, 0, expectedNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to fetch a file or folder by name
|
||||
*
|
||||
* @param name the name of the file or folder
|
||||
* @param isFolder true if we want a folder, otherwise false if we want a file
|
||||
* @return Returns the info for the file or folder
|
||||
*/
|
||||
private FileInfo getByName(String name, boolean isFolder) throws Exception
|
||||
{
|
||||
List<FileInfo> results = fileFolderService.search(workingRootNodeRef, name, !isFolder, isFolder, true);
|
||||
if (results.size() > 1)
|
||||
{
|
||||
throw new AlfrescoRuntimeException("Name is not unique in hierarchy: \n" +
|
||||
" name: " + name + "\n" +
|
||||
" is folder: " + isFolder);
|
||||
}
|
||||
else if (results.size() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return results.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that an internal method is working - it gets used extensively by following tests
|
||||
*
|
||||
* @see #getByName(String, boolean)
|
||||
*/
|
||||
public void testGetByName() throws Exception
|
||||
{
|
||||
FileInfo fileInfo = getByName(NAME_DUPLICATE, true);
|
||||
assertNotNull(fileInfo);
|
||||
assertTrue(fileInfo.isFolder());
|
||||
|
||||
fileInfo = getByName(NAME_DUPLICATE, false);
|
||||
assertNotNull(fileInfo);
|
||||
assertFalse(fileInfo.isFolder());
|
||||
}
|
||||
|
||||
public void testRenameNormal() throws Exception
|
||||
{
|
||||
FileInfo folderInfo = getByName(NAME_L0_FOLDER_A, true);
|
||||
assertNotNull(folderInfo);
|
||||
// rename normal
|
||||
String newName = "DUPLICATE - renamed";
|
||||
folderInfo = fileFolderService.rename(folderInfo.getNodeRef(), newName);
|
||||
// check it
|
||||
FileInfo checkInfo = getByName(NAME_L0_FOLDER_A, true);
|
||||
assertNull("Folder info should have been renamed away", checkInfo);
|
||||
checkInfo = getByName(newName, true);
|
||||
assertNotNull("Folder info for new name is not present", checkInfo);
|
||||
}
|
||||
|
||||
public void testRenameDuplicate() throws Exception
|
||||
{
|
||||
FileInfo folderInfo = getByName(NAME_L0_FOLDER_A, true);
|
||||
assertNotNull(folderInfo);
|
||||
// rename duplicate. A file with that name already exists
|
||||
String newName = NAME_L0_FILE_A;
|
||||
try
|
||||
{
|
||||
folderInfo = fileFolderService.rename(folderInfo.getNodeRef(), newName);
|
||||
fail("Existing file not detected");
|
||||
}
|
||||
catch (FileExistsException e)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testMove() throws Exception
|
||||
{
|
||||
FileInfo folderToMoveInfo = getByName(NAME_L1_FOLDER_A, true);
|
||||
assertNotNull(folderToMoveInfo);
|
||||
NodeRef folderToMoveRef = folderToMoveInfo.getNodeRef();
|
||||
// move it to the root
|
||||
fileFolderService.move(folderToMoveRef, workingRootNodeRef, null);
|
||||
// make sure that it is an immediate child of the root
|
||||
List<FileInfo> checkFileInfos = fileFolderService.search(workingRootNodeRef, NAME_L1_FOLDER_A, false);
|
||||
assertEquals("Folder not moved to root", 1, checkFileInfos.size());
|
||||
// attempt illegal rename (existing)
|
||||
try
|
||||
{
|
||||
fileFolderService.move(folderToMoveRef, null, NAME_L0_FOLDER_A);
|
||||
fail("Existing folder not detected");
|
||||
}
|
||||
catch (FileExistsException e)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
// rename properly
|
||||
FileInfo checkFileInfo = fileFolderService.move(folderToMoveRef, null, "new name");
|
||||
checkFileInfos = fileFolderService.search(workingRootNodeRef, checkFileInfo.getName(), false);
|
||||
assertEquals("Folder not renamed in root", 1, checkFileInfos.size());
|
||||
}
|
||||
|
||||
public void testCopy() throws Exception
|
||||
{
|
||||
FileInfo folderToCopyInfo = getByName(NAME_L1_FOLDER_A, true);
|
||||
assertNotNull(folderToCopyInfo);
|
||||
NodeRef folderToCopyRef = folderToCopyInfo.getNodeRef();
|
||||
// copy it to the root
|
||||
folderToCopyInfo = fileFolderService.copy(folderToCopyRef, workingRootNodeRef, null);
|
||||
folderToCopyRef = folderToCopyInfo.getNodeRef();
|
||||
// make sure that it is an immediate child of the root
|
||||
List<FileInfo> checkFileInfos = fileFolderService.search(workingRootNodeRef, NAME_L1_FOLDER_A, false);
|
||||
assertEquals("Folder not copied to root", 1, checkFileInfos.size());
|
||||
// attempt illegal copy (existing)
|
||||
try
|
||||
{
|
||||
fileFolderService.copy(folderToCopyRef, null, NAME_L0_FOLDER_A);
|
||||
fail("Existing folder not detected");
|
||||
}
|
||||
catch (FileExistsException e)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
// copy properly
|
||||
FileInfo checkFileInfo = fileFolderService.copy(folderToCopyRef, null, "new name");
|
||||
checkFileInfos = fileFolderService.search(workingRootNodeRef, checkFileInfo.getName(), false);
|
||||
assertEquals("Folder not renamed in root", 1, checkFileInfos.size());
|
||||
}
|
||||
|
||||
public void testCreateFolder() throws Exception
|
||||
{
|
||||
FileInfo parentFolderInfo = getByName(NAME_L0_FOLDER_A, true);
|
||||
assertNotNull(parentFolderInfo);
|
||||
NodeRef parentFolderRef = parentFolderInfo.getNodeRef();
|
||||
// create a file that already exists
|
||||
try
|
||||
{
|
||||
fileFolderService.create(parentFolderRef, NAME_L1_FILE_A, ContentModel.TYPE_CONTENT);
|
||||
fail("Failed to detect duplicate filename");
|
||||
}
|
||||
catch (FileExistsException e)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
// create folder of illegal type
|
||||
try
|
||||
{
|
||||
fileFolderService.create(parentFolderRef, "illegal folder", ContentModel.TYPE_SYSTEM_FOLDER);
|
||||
fail("Illegal type not detected");
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
// create a file
|
||||
FileInfo fileInfo = fileFolderService.create(parentFolderRef, "newFile", ContentModel.TYPE_CONTENT);
|
||||
// check
|
||||
assertTrue("Node not created", nodeService.exists(fileInfo.getNodeRef()));
|
||||
assertFalse("File type expected", fileInfo.isFolder());
|
||||
}
|
||||
|
||||
public void testCreateInRoot() throws Exception
|
||||
{
|
||||
fileFolderService.create(rootNodeRef, "New Folder", ContentModel.TYPE_FOLDER);
|
||||
}
|
||||
|
||||
public void testMakeFolders() throws Exception
|
||||
{
|
||||
// create a completely new path below the root
|
||||
List<String> namePath = new ArrayList<String>(4);
|
||||
namePath.add("A");
|
||||
namePath.add("B");
|
||||
namePath.add("C");
|
||||
namePath.add("D");
|
||||
|
||||
FileInfo lastFileInfo = fileFolderService.makeFolders(rootNodeRef, namePath, ContentModel.TYPE_FOLDER);
|
||||
assertNotNull("First makeFolder failed", lastFileInfo);
|
||||
// check that a repeat works
|
||||
FileInfo lastFileInfoAgain = fileFolderService.makeFolders(rootNodeRef, namePath, ContentModel.TYPE_FOLDER);
|
||||
assertNotNull("Repeat makeFolders failed", lastFileInfoAgain);
|
||||
assertEquals("Repeat created new leaf", lastFileInfo.getNodeRef(), lastFileInfoAgain.getNodeRef());
|
||||
// check that it worked
|
||||
List<FileInfo> checkInfos = fileFolderService.search(rootNodeRef, "D", false, true, true);
|
||||
assertEquals("Expected to find a result", 1, checkInfos.size());
|
||||
// get the path
|
||||
List<FileInfo> checkPathInfos = fileFolderService.getNamePath(rootNodeRef, checkInfos.get(0).getNodeRef());
|
||||
assertEquals("Path created is incorrect", namePath.size(), checkPathInfos.size());
|
||||
int i = 0;
|
||||
for (FileInfo checkInfo : checkPathInfos)
|
||||
{
|
||||
assertEquals("Path mismatch", namePath.get(i), checkInfo.getName());
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
public void testGetNamePath() throws Exception
|
||||
{
|
||||
FileInfo fileInfo = getByName(NAME_L1_FILE_A, false);
|
||||
assertNotNull(fileInfo);
|
||||
NodeRef nodeRef = fileInfo.getNodeRef();
|
||||
|
||||
List<FileInfo> infoPaths = fileFolderService.getNamePath(workingRootNodeRef, nodeRef);
|
||||
assertEquals("Not enough elements", 2, infoPaths.size());
|
||||
assertEquals("First level incorrent", NAME_L0_FOLDER_A, infoPaths.get(0).getName());
|
||||
assertEquals("Second level incorrent", NAME_L1_FILE_A, infoPaths.get(1).getName());
|
||||
|
||||
// pass in a null root and make sure that it still works
|
||||
infoPaths = fileFolderService.getNamePath(null, nodeRef);
|
||||
assertEquals("Not enough elements", 3, infoPaths.size());
|
||||
assertEquals("First level incorrent", workingRootNodeRef.getId(), infoPaths.get(0).getName());
|
||||
assertEquals("Second level incorrent", NAME_L0_FOLDER_A, infoPaths.get(1).getName());
|
||||
assertEquals("Third level incorrent", NAME_L1_FILE_A, infoPaths.get(2).getName());
|
||||
|
||||
// check that a non-aligned path is detected
|
||||
NodeRef startRef = getByName(NAME_L0_FOLDER_B, true).getNodeRef();
|
||||
try
|
||||
{
|
||||
fileFolderService.getNamePath(startRef, nodeRef);
|
||||
fail("Failed to detect non-aligned path from root to target node");
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
public void testResolveNamePath() throws Exception
|
||||
{
|
||||
FileInfo fileInfo = getByName(NAME_L1_FILE_A, false);
|
||||
List<String> pathElements = new ArrayList<String>(3);
|
||||
pathElements.add(NAME_L0_FOLDER_A);
|
||||
pathElements.add(NAME_L1_FILE_A);
|
||||
|
||||
FileInfo fileInfoCheck = fileFolderService.resolveNamePath(workingRootNodeRef, pathElements);
|
||||
assertNotNull("File info not found", fileInfoCheck);
|
||||
assertEquals("Path not resolved to correct node", fileInfo.getNodeRef(), fileInfoCheck.getNodeRef());
|
||||
}
|
||||
|
||||
public void testGetReaderWriter() throws Exception
|
||||
{
|
||||
FileInfo dirInfo = getByName(NAME_L0_FOLDER_A, true);
|
||||
try
|
||||
{
|
||||
fileFolderService.getWriter(dirInfo.getNodeRef());
|
||||
fail("Failed to detect content write to folder");
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
// expected
|
||||
}
|
||||
|
||||
FileInfo fileInfo = getByName(NAME_L1_FILE_A, false);
|
||||
|
||||
ContentWriter writer = fileFolderService.getWriter(fileInfo.getNodeRef());
|
||||
assertNotNull("Writer is null", writer);
|
||||
// write some content
|
||||
String content = "ABC";
|
||||
writer.putContent(content);
|
||||
// read the content
|
||||
ContentReader reader = fileFolderService.getReader(fileInfo.getNodeRef());
|
||||
assertNotNull("Reader is null", reader);
|
||||
String checkContent = reader.getContentString();
|
||||
assertEquals("Content mismatch", content, checkContent);
|
||||
}
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.repo.model.filefolder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.repository.ContentData;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Common file information implementation.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
*/
|
||||
public class FileInfoImpl implements FileInfo
|
||||
{
|
||||
private NodeRef nodeRef;
|
||||
private boolean isFolder;
|
||||
private Map<QName, Serializable> properties;
|
||||
|
||||
/**
|
||||
* Package-level constructor
|
||||
*/
|
||||
/* package */ FileInfoImpl(NodeRef nodeRef, boolean isFolder, Map<QName, Serializable> properties)
|
||||
{
|
||||
this.nodeRef = nodeRef;
|
||||
this.isFolder = isFolder;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
sb.append("FileInfo")
|
||||
.append("[name=").append(getName())
|
||||
.append(", isFolder=").append(isFolder)
|
||||
.append(", nodeRef=").append(nodeRef)
|
||||
.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public NodeRef getNodeRef()
|
||||
{
|
||||
return nodeRef;
|
||||
}
|
||||
|
||||
public boolean isFolder()
|
||||
{
|
||||
return isFolder;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return (String) properties.get(ContentModel.PROP_NAME);
|
||||
}
|
||||
|
||||
public Date getCreatedDate()
|
||||
{
|
||||
return DefaultTypeConverter.INSTANCE.convert(Date.class, properties.get(ContentModel.PROP_CREATED));
|
||||
}
|
||||
|
||||
public Date getModifiedDate()
|
||||
{
|
||||
return DefaultTypeConverter.INSTANCE.convert(Date.class, properties.get(ContentModel.PROP_MODIFIED));
|
||||
}
|
||||
|
||||
public ContentData getContentData()
|
||||
{
|
||||
return DefaultTypeConverter.INSTANCE.convert(ContentData.class, properties.get(ContentModel.PROP_CONTENT));
|
||||
}
|
||||
|
||||
public Map<QName, Serializable> getProperties()
|
||||
{
|
||||
return properties;
|
||||
}
|
||||
}
|
8
source/java/org/alfresco/repo/model/package.html
Normal file
8
source/java/org/alfresco/repo/model/package.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
Implementations of model-specific services.
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user