mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
Merged V1.3 to HEAD (3180:3203, 3204:3217)
svn merge svn://www.alfresco.org:3691/alfresco/BRANCHES/V1.3@3180 svn://www.alfresco.org:3691/alfresco/BRANCHES/V1.3@3203 . svn merge svn://www.alfresco.org:3691/alfresco/BRANCHES/V1.3@3204 svn://www.alfresco.org:3691/alfresco/BRANCHES/V1.3@3217 . git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@3407 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -45,6 +45,9 @@ 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.ResultSet;
|
||||
import org.alfresco.service.cmr.search.ResultSetRow;
|
||||
import org.alfresco.service.cmr.search.SearchParameters;
|
||||
import org.alfresco.service.cmr.search.SearchService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
@@ -59,17 +62,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
*/
|
||||
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 files and folders with a name pattern */
|
||||
private static final String XPATH_QUERY_SHALLOW_ALL =
|
||||
"./*" +
|
||||
@@ -77,6 +69,23 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "'))]";
|
||||
|
||||
/** Shallow search for all files and folders */
|
||||
private static final String LUCENE_QUERY_SHALLOW_ALL =
|
||||
"+PARENT:\"${cm:parent}\"" +
|
||||
"-TYPE:\"" + ContentModel.TYPE_SYSTEM_FOLDER + "\" ";
|
||||
|
||||
/** Shallow search for all files and folders */
|
||||
private static final String LUCENE_QUERY_SHALLOW_FOLDERS =
|
||||
"+PARENT:\"${cm:parent}\"" +
|
||||
"-TYPE:\"" + ContentModel.TYPE_SYSTEM_FOLDER + "\" " +
|
||||
"+TYPE:\"" + ContentModel.TYPE_FOLDER + "\" ";
|
||||
|
||||
/** Shallow search for all files and folders */
|
||||
private static final String LUCENE_QUERY_SHALLOW_FILES =
|
||||
"+PARENT:\"${cm:parent}\"" +
|
||||
"-TYPE:\"" + ContentModel.TYPE_SYSTEM_FOLDER + "\" " +
|
||||
"+TYPE:\"" + ContentModel.TYPE_CONTENT + "\" ";
|
||||
|
||||
/** Deep search for files and folders with a name pattern */
|
||||
private static final String XPATH_QUERY_DEEP_ALL =
|
||||
".//*" +
|
||||
@@ -85,8 +94,8 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
" 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 final QName PARAM_QNAME_PARENT = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, "parent");
|
||||
|
||||
private static Log logger = LogFactory.getLog(FileFolderServiceImpl.class);
|
||||
|
||||
@@ -100,6 +109,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
|
||||
// TODO: Replace this with a more formal means of identifying "system" folders (i.e. aspect or UUID)
|
||||
private List systemPaths;
|
||||
private DataTypeDefinition dataTypeNodeRef;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
@@ -157,6 +167,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
dictionaryService.getDataType(DataTypeDefinition.TEXT),
|
||||
true,
|
||||
"%");
|
||||
dataTypeNodeRef = dictionaryService.getDataType(DataTypeDefinition.NODE_REF);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,12 +213,17 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
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)
|
||||
// the name is never a wildcard, so we can perform an exact search
|
||||
List<NodeRef> nodeRefs = searchInternal(parentFolderRef, name, true, true, false);
|
||||
if (nodeRefs.size() == 0)
|
||||
{
|
||||
throw new FileExistsException(existingFileInfos.get(0));
|
||||
// no match
|
||||
return;
|
||||
}
|
||||
// we found a match, so raise the exception
|
||||
NodeRef duplicateNodeRef = nodeRefs.get(0);
|
||||
FileInfo duplicateFileInfo = toFileInfo(duplicateNodeRef);
|
||||
throw new FileExistsException(duplicateFileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,18 +274,10 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
List<NodeRef> nodeRefs = luceneSearch(contextNodeRef, true, true);
|
||||
// convert the noderefs
|
||||
List<FileInfo> results = toFileInfo(nodeRefs);
|
||||
// done
|
||||
@@ -282,18 +290,10 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
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);
|
||||
List<NodeRef> nodeRefs = luceneSearch(contextNodeRef, false, true);
|
||||
// convert the noderefs
|
||||
List<FileInfo> results = toFileInfo(nodeRefs);
|
||||
// done
|
||||
@@ -306,18 +306,10 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
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);
|
||||
List<NodeRef> nodeRefs = luceneSearch(contextNodeRef, true, false);
|
||||
// convert the noderefs
|
||||
List<FileInfo> results = toFileInfo(nodeRefs);
|
||||
// done
|
||||
@@ -338,6 +330,7 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
return search(contextNodeRef, namePattern, true, true, includeSubFolders);
|
||||
}
|
||||
|
||||
private static final String LUCENE_MULTI_CHAR_WILDCARD = "*";
|
||||
/**
|
||||
* Full search with all options
|
||||
*/
|
||||
@@ -348,50 +341,9 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
boolean folderSearch,
|
||||
boolean includeSubFolders)
|
||||
{
|
||||
// shortcut if the search is requesting nothing
|
||||
if (!fileSearch && !folderSearch)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// get the raw nodeRefs
|
||||
List<NodeRef> nodeRefs = searchInternal(contextNodeRef, namePattern, fileSearch, folderSearch, includeSubFolders);
|
||||
|
||||
// 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();
|
||||
@@ -420,6 +372,133 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a full search, but doesn't translate the node references into
|
||||
* file info objects. This allows {@link #checkExists(NodeRef, String)} to
|
||||
* bypass the retrieval of node properties.
|
||||
*/
|
||||
public List<NodeRef> searchInternal(
|
||||
NodeRef contextNodeRef,
|
||||
String namePattern,
|
||||
boolean fileSearch,
|
||||
boolean folderSearch,
|
||||
boolean includeSubFolders)
|
||||
{
|
||||
// shortcut if the search is requesting nothing
|
||||
if (!fileSearch && !folderSearch)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (namePattern == null)
|
||||
{
|
||||
namePattern = LUCENE_MULTI_CHAR_WILDCARD; // default to wildcard
|
||||
}
|
||||
// now check if we can use Lucene to handle this query
|
||||
boolean useLucene = false;
|
||||
boolean anyName = namePattern.equals(LUCENE_MULTI_CHAR_WILDCARD);
|
||||
if (!includeSubFolders && anyName)
|
||||
{
|
||||
// Lucene only handles any name or exact name
|
||||
useLucene = true;
|
||||
}
|
||||
|
||||
List<NodeRef> nodeRefs = null;
|
||||
if (!useLucene) // go with the XPath queries
|
||||
{
|
||||
// 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
|
||||
nodeRefs = searchService.selectNodes(
|
||||
contextNodeRef,
|
||||
query,
|
||||
params,
|
||||
namespaceService,
|
||||
false);
|
||||
}
|
||||
else // go with Lucene queries
|
||||
{
|
||||
nodeRefs = luceneSearch(contextNodeRef, folderSearch, fileSearch);
|
||||
}
|
||||
// done
|
||||
return nodeRefs;
|
||||
}
|
||||
|
||||
private List<NodeRef> luceneSearch(NodeRef contextNodeRef, boolean folders, boolean files)
|
||||
{
|
||||
SearchParameters params = new SearchParameters();
|
||||
params.setLanguage(SearchService.LANGUAGE_LUCENE);
|
||||
params.addStore(contextNodeRef.getStoreRef());
|
||||
// set the parent parameter
|
||||
QueryParameterDefinition parentParamDef = new QueryParameterDefImpl(
|
||||
PARAM_QNAME_PARENT,
|
||||
dataTypeNodeRef,
|
||||
true,
|
||||
contextNodeRef.toString());
|
||||
params.addQueryParameterDefinition(parentParamDef);
|
||||
if (folders && files) // search for both files and folders
|
||||
{
|
||||
params.setQuery(LUCENE_QUERY_SHALLOW_ALL);
|
||||
}
|
||||
else if (folders) // search for folders only
|
||||
{
|
||||
params.setQuery(LUCENE_QUERY_SHALLOW_FOLDERS);
|
||||
}
|
||||
else if (files) // search for files only
|
||||
{
|
||||
params.setQuery(LUCENE_QUERY_SHALLOW_FILES);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Must search for either files or folders or both");
|
||||
}
|
||||
ResultSet rs = searchService.query(params);
|
||||
int length = rs.length();
|
||||
List<NodeRef> nodeRefs = new ArrayList<NodeRef>(length);
|
||||
try
|
||||
{
|
||||
for (ResultSetRow row : rs)
|
||||
{
|
||||
nodeRefs.add(row.getNodeRef());
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
rs.close();
|
||||
}
|
||||
// done
|
||||
return nodeRefs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #move(NodeRef, NodeRef, String)
|
||||
@@ -467,10 +546,10 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
targetParentRef = assocRef.getParentRef();
|
||||
}
|
||||
|
||||
// there is nothing to do if both the name and parent folder haven't changed
|
||||
boolean checkExists = true;
|
||||
if (targetParentRef.equals(assocRef.getParentRef()))
|
||||
{
|
||||
// there is nothing to do if both the name and parent folder haven't changed
|
||||
if (newName.equals(beforeFileInfo.getName()))
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
@@ -484,17 +563,15 @@ public class FileFolderServiceImpl implements FileFolderService
|
||||
}
|
||||
else if (newName.equalsIgnoreCase(beforeFileInfo.getName()))
|
||||
{
|
||||
// name has only changed case so don't bother with exists check
|
||||
checkExists = false;
|
||||
}
|
||||
}
|
||||
|
||||
// check for existing file or folder (if name has changed)
|
||||
// check for existing file or folder
|
||||
if (checkExists)
|
||||
{
|
||||
checkExists(targetParentRef, newName);
|
||||
}
|
||||
|
||||
|
||||
QName qname = QName.createQName(
|
||||
NamespaceService.CONTENT_MODEL_1_0_URI,
|
||||
|
Reference in New Issue
Block a user