[MNT-25404] Query Performance - High performance cost in retrieving nodes/node properties for large result sets

- pre-commit changes
This commit is contained in:
Jared Ottley
2025-11-02 18:44:09 -07:00
parent 8bc7937e98
commit d9ff7ef1d0
4 changed files with 406 additions and 461 deletions

View File

@@ -46,6 +46,7 @@ public interface DeletedNodes
{
/**
* Lists deleted nodes using a ArchivedNodesCannedQuery
*
* @param parameters
* @return Collection of deleted Nodes
*/
@@ -53,9 +54,11 @@ public interface DeletedNodes
/**
* Gets a single deleted node by id.
*
* @param originalId
* @param parameters
* @param fullnode Should we return the full representation of the minimal one?
* @param fullnode
* Should we return the full representation of the minimal one?
* @param mapUserInfo
* @return a deleted node
*/
@@ -86,6 +89,7 @@ public interface DeletedNodes
/**
* Permanently delete the node.
*
* @param archivedId
*/
void purgeArchivedNode(String archivedId);
@@ -118,9 +122,12 @@ public interface DeletedNodes
/**
* Gets a presigned URL to directly access content.
*
* @param archivedId The node id for which to obtain the direct access {@code URL}
* @param renditionId The rendition id for which to obtain the direct access {@code URL}
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}, {@code true} by default.
* @param archivedId
* The node id for which to obtain the direct access {@code URL}
* @param renditionId
* The rendition id for which to obtain the direct access {@code URL}
* @param attachment
* {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}, {@code true} by default.
* @return A direct access {@code URL} object for the content.
*/
default DirectAccessUrl requestContentDirectUrl(String archivedId, String renditionId, boolean attachment)
@@ -131,10 +138,14 @@ public interface DeletedNodes
/**
* Gets a presigned URL to directly access content.
*
* @param archivedId The node id for which to obtain the direct access {@code URL}
* @param renditionId The rendition id for which to obtain the direct access {@code URL}
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}, {@code true} by default.
* @param validFor The time at which the direct access {@code URL} will expire.
* @param archivedId
* The node id for which to obtain the direct access {@code URL}
* @param renditionId
* The rendition id for which to obtain the direct access {@code URL}
* @param attachment
* {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}, {@code true} by default.
* @param validFor
* The time at which the direct access {@code URL} will expire.
* @return A direct access {@code URL} object for the content.
*/
DirectAccessUrl requestContentDirectUrl(String archivedId, String renditionId, boolean attachment, Long validFor);

View File

@@ -31,6 +31,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.extensions.webscripts.servlet.FormData;
import org.alfresco.rest.api.model.AssocChild;
import org.alfresco.rest.api.model.AssocTarget;
import org.alfresco.rest.api.model.Document;
@@ -48,7 +50,6 @@ import org.alfresco.service.cmr.repository.DirectAccessUrl;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.springframework.extensions.webscripts.servlet.FormData;
/**
* File Folder (Nodes) API
@@ -63,7 +64,8 @@ public interface Nodes
/**
* Get the node representation for the given node.
*
* @param nodeId String
* @param nodeId
* String
* @return Node
*/
Node getNode(String nodeId);
@@ -71,7 +73,8 @@ public interface Nodes
/**
* Get the document representation for the given node.
*
* @param nodeRef NodeRef
* @param nodeRef
* NodeRef
* @return Document
*/
Document getDocument(NodeRef nodeRef);
@@ -79,7 +82,8 @@ public interface Nodes
/**
* Get the folder representation for the given node.
*
* @param nodeRef NodeRef
* @param nodeRef
* NodeRef
* @return Folder
*/
Folder getFolder(NodeRef nodeRef);
@@ -87,10 +91,10 @@ public interface Nodes
/**
* Get the folder or document representation (as appropriate) for the given node.
*
* @param nodeId String nodeId or well-known alias, eg. "-root-" or "-my-"
* @param parameters the {@link Parameters} object to get the parameters passed into the request
* including:
* - incPrimaryParent
* @param nodeId
* String nodeId or well-known alias, eg. "-root-" or "-my-"
* @param parameters
* the {@link Parameters} object to get the parameters passed into the request including: - incPrimaryParent
* @return
*/
Node getFolderOrDocument(String nodeId, Parameters parameters);
@@ -102,7 +106,8 @@ public interface Nodes
/**
* Get the folder or document representation (as appropriate) for the given node.
*
* @param nodeRef A real Node
* @param nodeRef
* A real Node
* @param parentNodeRef
* @param nodeTypeQName
* @param includeParam
@@ -121,14 +126,14 @@ public interface Nodes
* @return
*/
List<Node> getFoldersOrDocuments(List<NodeRef> nodeRefs, List<String> includeParam, Map<String, UserInfo> mapUserInfo);
/**
* Get list of children of a parent folder.
*
* @param parentFolderNodeId String id of parent folder node or well-known alias, eg. "-root-" or "-my-"
* @param parameters the {@link Parameters} object to get the parameters passed into the request
* including:
* - filter, sort & paging params (where, orderBy, skipCount, maxItems)
* - incFiles, incFolders (both true by default)
* @param parentFolderNodeId
* String id of parent folder node or well-known alias, eg. "-root-" or "-my-"
* @param parameters
* the {@link Parameters} object to get the parameters passed into the request including: - filter, sort & paging params (where, orderBy, skipCount, maxItems) - incFiles, incFolders (both true by default)
* @return a paged list of {@code org.alfresco.rest.api.model.Node} objects
*/
CollectionWithPagingInfo<Node> listChildren(String parentFolderNodeId, Parameters parameters);
@@ -136,9 +141,10 @@ public interface Nodes
/**
* Delete the given node. Note: will cascade delete for a folder.
*
* @param nodeId String id of node (folder or document)
* @param parameters the {@link Parameters} object to get the parameters passed into the request
* - permanent (default false)
* @param nodeId
* String id of node (folder or document)
* @param parameters
* the {@link Parameters} object to get the parameters passed into the request - permanent (default false)
*/
void deleteNode(String nodeId, Parameters parameters);
@@ -178,7 +184,8 @@ public interface Nodes
*
* @param fileNodeId
* @param parameters
* @param recordActivity true, if an activity post is required.
* @param recordActivity
* true, if an activity post is required.
* @return
*/
BinaryResource getContent(String fileNodeId, Parameters parameters, boolean recordActivity);
@@ -186,9 +193,11 @@ public interface Nodes
/**
* Download file content.
*
* @param nodeRef the content nodeRef
* @param nodeRef
* the content nodeRef
* @param parameters
* @param recordActivity true, if an activity post is required.
* @param recordActivity
* true, if an activity post is required.
* @return
*/
BinaryResource getContent(NodeRef nodeRef, Parameters parameters, boolean recordActivity);
@@ -209,18 +218,24 @@ public interface Nodes
/**
* Uploads file content and meta-data into the repository.
*
* @param parentFolderNodeId String id of parent folder node or well-known alias, eg. "-root-" or "-my-"
* @param formData the {@link FormData}
* @param parameters the {@link Parameters} object to get the parameters passed into the request
* @param parentFolderNodeId
* String id of parent folder node or well-known alias, eg. "-root-" or "-my-"
* @param formData
* the {@link FormData}
* @param parameters
* the {@link Parameters} object to get the parameters passed into the request
* @return {@code Node} if successful
*/
Node upload(String parentFolderNodeId, FormData formData, Parameters parameters);
NodeRef validateNode(StoreRef storeRef, String nodeId);
List<NodeRef> validateNodes(StoreRef storeRef, List<String> nodeIds);
NodeRef validateNode(String nodeId);
NodeRef validateNode(NodeRef nodeRef);
NodeRef validateOrLookupNode(String nodeId, String path);
boolean nodeMatches(NodeRef nodeRef, Set<QName> expectedTypes, Set<QName> excludedTypes);
@@ -228,9 +243,12 @@ public interface Nodes
/**
* Determines whether the type of the given nodeRef is a sub-class of another class or not.
*
* @param nodeRef source nodeRef
* @param ofClassQName the class to test against
* @param validateNodeRef whether to validate the given source node or not
* @param nodeRef
* source nodeRef
* @param ofClassQName
* the class to test against
* @param validateNodeRef
* whether to validate the given source node or not
* @return true if the type of the given nodeRef is a sub-class of another class, otherwise false
*/
boolean isSubClass(NodeRef nodeRef, QName ofClassQName, boolean validateNodeRef);
@@ -238,7 +256,8 @@ public interface Nodes
/**
* Helper to create a QName from either a fully qualified or short-name QName string
*
* @param qnameStr Fully qualified or short-name QName string
* @param qnameStr
* Fully qualified or short-name QName string
* @return QName
*/
QName createQName(String qnameStr);
@@ -265,6 +284,7 @@ public interface Nodes
/**
* Lock a node
*
* @param nodeId
* @param lockInfo
* @param parameters
@@ -274,6 +294,7 @@ public interface Nodes
/**
* Unlock a node
*
* @param nodeId
* @param parameters
* @return
@@ -282,8 +303,11 @@ public interface Nodes
/**
* Gets a presigned URL to directly access content.
* @param nodeId The node id for which to obtain the direct access {@code URL}
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}.
*
* @param nodeId
* The node id for which to obtain the direct access {@code URL}
* @param attachment
* {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}.
* @return A direct access {@code URL} object for the content.
*/
default DirectAccessUrl requestContentDirectUrl(String nodeId, boolean attachment)
@@ -293,8 +317,11 @@ public interface Nodes
/**
* Gets a presigned URL to directly access content.
* @param nodeRef The node reference for which to obtain the direct access {@code URL}
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}.
*
* @param nodeRef
* The node reference for which to obtain the direct access {@code URL}
* @param attachment
* {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}.
* @return A direct access {@code URL} object for the content.
*/
default DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment)
@@ -304,9 +331,13 @@ public interface Nodes
/**
* Gets a presigned URL to directly access content.
* @param nodeId The node id for which to obtain the direct access {@code URL}
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}.
* @param validFor The time at which the direct access {@code URL} will expire.
*
* @param nodeId
* The node id for which to obtain the direct access {@code URL}
* @param attachment
* {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}.
* @param validFor
* The time at which the direct access {@code URL} will expire.
* @return A direct access {@code URL} object for the content.
*/
default DirectAccessUrl requestContentDirectUrl(String nodeId, boolean attachment, Long validFor)
@@ -316,17 +347,19 @@ public interface Nodes
/**
* Gets a presigned URL to directly access content.
* @param nodeRef The node reference for which to obtain the direct access {@code URL}
* @param attachment {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}.
* @param validFor The time at which the direct access {@code URL} will expire.
*
* @param nodeRef
* The node reference for which to obtain the direct access {@code URL}
* @param attachment
* {@code true} if an attachment {@code URL} is requested, {@code false} for an embedded {@code URL}.
* @param validFor
* The time at which the direct access {@code URL} will expire.
* @return A direct access {@code URL} object for the content.
*/
DirectAccessUrl requestContentDirectUrl(NodeRef nodeRef, boolean attachment, Long validFor);
/**
* Convert from node properties (map of QName to Serializable) retrieved from
* the respository to a map of String to Object that can be formatted/expressed
* as required by the API JSON response for get nodes, get person etc.
* Convert from node properties (map of QName to Serializable) retrieved from the respository to a map of String to Object that can be formatted/expressed as required by the API JSON response for get nodes, get person etc.
* <p>
* Returns null if there are no properties to return, rather than an empty map.
*
@@ -340,8 +373,7 @@ public interface Nodes
Map<String, Object> mapFromNodeProperties(Map<QName, Serializable> nodeProps, List<String> selectParam, Map<String, UserInfo> mapUserInfo, List<String> excludedNS, List<QName> excludedProps);
/**
* Map from the JSON API format of properties (String to Object) to
* the typical node properties map used by the repository (QName to Serializable).
* Map from the JSON API format of properties (String to Object) to the typical node properties map used by the repository (QName to Serializable).
*
* @param props
* @return
@@ -351,15 +383,16 @@ public interface Nodes
/**
* Returns the path to the given nodeRef {@code nodeRefIn} or the archived nodeRef {@code archivedParentAssoc}.
*
* @param nodeRefIn the NodeRef
* @param archivedParentAssoc the ChildAssociationRef of the archived NodeRef
* @param nodeRefIn
* the NodeRef
* @param archivedParentAssoc
* the ChildAssociationRef of the archived NodeRef
* @return the path to the given node
*/
PathInfo lookupPathInfo(NodeRef nodeRefIn, ChildAssociationRef archivedParentAssoc);
/**
* Map from a String representation of aspect names to a set
* of QName objects, as used by the repository.
* Map from a String representation of aspect names to a set of QName objects, as used by the repository.
*
* @param aspectNames
* @return
@@ -367,9 +400,7 @@ public interface Nodes
Set<QName> mapToNodeAspects(List<String> aspectNames);
/**
* Map from aspects (Set of QName) retrieved from the repository to a
* map List of String required that can be formatted/expressed as required
* by the API JSON response for get nodes, get person etc.
* Map from aspects (Set of QName) retrieved from the repository to a map List of String required that can be formatted/expressed as required by the API JSON response for get nodes, get person etc.
* <p>
* Returns null if there are no aspect names to return, rather than an empty list.
*
@@ -381,8 +412,7 @@ public interface Nodes
List<String> mapFromNodeAspects(Set<QName> nodeAspects, List<String> excludedNS, List<QName> excludedAspects);
/**
* Add aspects to the specified NodeRef. Aspects that appear in the exclusions list
* will be ignored.
* Add aspects to the specified NodeRef. Aspects that appear in the exclusions list will be ignored.
*
* @param nodeRef
* @param aspectNames
@@ -391,8 +421,7 @@ public interface Nodes
void addCustomAspects(NodeRef nodeRef, List<String> aspectNames, List<QName> exclusions);
/**
* Update aspects for the specified NodeRef. An empty list will result in
* aspects being <strong>removed</strong>.
* Update aspects for the specified NodeRef. An empty list will result in aspects being <strong>removed</strong>.
*
* @param nodeRef
* @param aspectNames
@@ -404,7 +433,6 @@ public interface Nodes
void validateProperties(Map<String, Object> properties, List<String> excludedNS, List<QName> excludedProperties);
/**
* API Constants - query parameters, etc
*/
@@ -456,4 +484,3 @@ public interface Nodes
String PARAM_ISPRIMARY = "isPrimary";
String PARAM_ASSOC_TYPE = "assocType";
}

View File

@@ -102,12 +102,14 @@ public class DeletedNodesImpl implements DeletedNodes, RecognizedParamsExtractor
/**
* Sets archived information on the Node
*
* @param aNode
* @param mapUserInfo
*/
private void mapArchiveInfo(Node aNode, Map<String, UserInfo> mapUserInfo)
{
if (mapUserInfo == null) {
if (mapUserInfo == null)
{
mapUserInfo = new HashMap<>();
}
Map<QName, Serializable> nodeProps = nodeService.getProperties(aNode.getNodeRef());
@@ -196,7 +198,8 @@ public class DeletedNodesImpl implements DeletedNodes, RecognizedParamsExtractor
foundNode = nodes.getFolderOrDocument(archivedNodeRef, null, null, parameters.getInclude(), mapUserInfo);
}
if (foundNode != null) mapArchiveInfo(foundNode,null);
if (foundNode != null)
mapArchiveInfo(foundNode, null);
return foundNode;
}

View File

@@ -47,6 +47,13 @@ import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.extensions.surf.util.Content;
import org.springframework.extensions.webscripts.servlet.FormData;
import org.alfresco.model.ApplicationModel;
import org.alfresco.model.ContentModel;
import org.alfresco.model.QuickShareModel;
@@ -164,21 +171,13 @@ import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.alfresco.util.PropertyCheck;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.extensions.surf.util.Content;
import org.springframework.extensions.webscripts.servlet.FormData;
/**
* Centralises access to file/folder/node services and maps between representations.
*
* Note:
* This class was originally used for returning some basic node info when listing Favourites.
* Note: This class was originally used for returning some basic node info when listing Favourites.
*
* It has now been re-purposed and extended to implement the new Nodes (RESTful) API for
* managing files & folders, as well as custom node types.
* It has now been re-purposed and extended to implement the new Nodes (RESTful) API for managing files & folders, as well as custom node types.
*
* @author steveglover
* @author janv
@@ -319,7 +318,8 @@ public class NodesImpl implements Nodes
this.defaultIgnoreTypesAndAspects = ignoreTypesAndAspects;
}
public void setPersonLookupProperties(Set<String> personLookupProperties) {
public void setPersonLookupProperties(Set<String> personLookupProperties)
{
this.defaultPersonLookupProperties = personLookupProperties;
}
@@ -377,14 +377,11 @@ public class NodesImpl implements Nodes
}
// list children filtering (via where clause)
private final static Set<String> LIST_FOLDER_CHILDREN_EQUALS_QUERY_PROPERTIES =
new HashSet<>(Arrays.asList(new String[] {PARAM_ISFOLDER, PARAM_ISFILE, PARAM_NODETYPE, PARAM_ISPRIMARY, PARAM_ASSOC_TYPE}));
private final static Set<String> LIST_FOLDER_CHILDREN_EQUALS_QUERY_PROPERTIES = new HashSet<>(Arrays.asList(new String[]{PARAM_ISFOLDER, PARAM_ISFILE, PARAM_NODETYPE, PARAM_ISPRIMARY, PARAM_ASSOC_TYPE}));
/*
* Validates that node exists.
/* Validates that node exists.
*
* Note: assumes workspace://SpacesStore
*/
* Note: assumes workspace://SpacesStore */
@Override
public NodeRef validateNode(String nodeId)
{
@@ -466,9 +463,7 @@ public class NodesImpl implements Nodes
return nodes;
}
/*
* Check that nodes exists and matches given expected/excluded type(s).
*/
/* Check that nodes exists and matches given expected/excluded type(s). */
@Override
public boolean nodeMatches(NodeRef nodeRef, Set<QName> expectedTypes, Set<QName> excludedTypes)
{
@@ -744,19 +739,7 @@ public class NodesImpl implements Nodes
if (!pathElements.isEmpty() && checkForCompanyHome)
{
/*
if (nodeService.getRootNode(parentNodeRef.getStoreRef()).equals(parentNodeRef))
{
// special case
NodeRef chNodeRef = repositoryHelper.getCompanyHome();
String chName = (String) nodeService.getProperty(chNodeRef, ContentModel.PROP_NAME);
if (chName.equals(pathElements.get(0)))
{
pathElements = pathElements.subList(1, pathElements.size());
parentNodeRef = chNodeRef;
}
}
*/
/* if (nodeService.getRootNode(parentNodeRef.getStoreRef()).equals(parentNodeRef)) { // special case NodeRef chNodeRef = repositoryHelper.getCompanyHome(); String chName = (String) nodeService.getProperty(chNodeRef, ContentModel.PROP_NAME); if (chName.equals(pathElements.get(0))) { pathElements = pathElements.subList(1, pathElements.size()); parentNodeRef = chNodeRef; } } */
}
FileInfo fileInfo = null;
@@ -813,8 +796,7 @@ public class NodesImpl implements Nodes
final NodeRef contextNodeRef = currentParentRef;
// does it exist?
// Navigation should not check permissions
NodeRef nodeRef = AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
{
NodeRef nodeRef = AuthenticationUtil.runAs(new RunAsWork<NodeRef>() {
@Override
public NodeRef doWork() throws Exception
{
@@ -996,7 +978,6 @@ public class NodesImpl implements Nodes
mapPermsToOps.put(PermissionService.WRITE, OP_UPDATE);
mapPermsToOps.put(PermissionService.CHANGE_PERMISSIONS, OP_UPDATE_PERMISSIONS);
List<String> allowableOperations = new ArrayList<>(3);
for (Entry<String, String> kv : mapPermsToOps.entrySet())
{
@@ -1039,7 +1020,8 @@ public class NodesImpl implements Nodes
if (accessPerm.isSetDirectly())
{
setDirectlyPerms.add(nodePerm);
} else
}
else
{
inheritedPerms.add(nodePerm);
}
@@ -1109,7 +1091,6 @@ public class NodesImpl implements Nodes
return node;
}
@Override
public List<Node> getFoldersOrDocuments(final List<NodeRef> nodeRefs, List<String> includeParam, Map<String, UserInfo> mapUserInfo)
{
@@ -1610,8 +1591,7 @@ public class NodesImpl implements Nodes
final Map<String, UserInfo> mapUserInfo = new HashMap<>(10);
final List<FileInfo> page = pagingResults.getPage();
List<Node> nodes = new AbstractList<Node>()
{
List<Node> nodes = new AbstractList<Node>() {
@Override
public Node get(int index)
{
@@ -1689,12 +1669,12 @@ public class NodesImpl implements Nodes
}
/**
* <p>Returns a List of filter properties specified by request parameters.</p>
* <p>
* Returns a List of filter properties specified by request parameters.
* </p>
*
* @param parameters The {@link Parameters} object to get the parameters passed into the request
* including:
* - filter, sort & paging params (where, orderBy, skipCount, maxItems)
* - incFiles, incFolders (both true by default)
* @param parameters
* The {@link Parameters} object to get the parameters passed into the request including: - filter, sort & paging params (where, orderBy, skipCount, maxItems) - incFiles, incFolders (both true by default)
* @return The list of {@link FilterProp}. Can be null.
*/
protected List<FilterProp> getListChildrenFilterProps(final Parameters parameters)
@@ -1718,14 +1698,13 @@ public class NodesImpl implements Nodes
}
/**
* <p>Returns a List of sort properties specified by the "sorting" request parameter.</p>
* <p>
* Returns a List of sort properties specified by the "sorting" request parameter.
* </p>
*
* @param parameters The {@link Parameters} object to get the parameters passed into the request
* including:
* - filter, sort & paging params (where, orderBy, skipCount, maxItems)
* - incFiles, incFolders (both true by default)
* @return The list of <code>Pair&lt;QName, Boolean&gt;</code> sort properties. If no sort parameters are
* found defaults to {@link #getListChildrenSortPropsDefault() getListChildrenSortPropsDefault}.
* @param parameters
* The {@link Parameters} object to get the parameters passed into the request including: - filter, sort & paging params (where, orderBy, skipCount, maxItems) - incFiles, incFolders (both true by default)
* @return The list of <code>Pair&lt;QName, Boolean&gt;</code> sort properties. If no sort parameters are found defaults to {@link #getListChildrenSortPropsDefault() getListChildrenSortPropsDefault}.
*/
protected List<Pair<QName, Boolean>> getListChildrenSortProps(final Parameters parameters)
{
@@ -1762,8 +1741,7 @@ public class NodesImpl implements Nodes
* Returns the default sort order.
* </p>
*
* @return The list of <code>Pair&lt;QName, Boolean&gt;</code> sort
* properties.
* @return The list of <code>Pair&lt;QName, Boolean&gt;</code> sort properties.
*/
protected List<Pair<QName, Boolean>> getListChildrenSortPropsDefault()
{
@@ -1803,24 +1781,9 @@ public class NodesImpl implements Nodes
{
assocTypeQNames = Collections.singleton(assocTypeQName);
}
/*
// TODO review - this works, but reduces from ~100 to ~96 (OOTB)
// maybe we could post filter (rather than join) - examples: sys:children, sys:lost_found, sys:archivedLink, sys:archiveUserLink
else
{
Collection<QName> qnames = dictionaryService.getAllAssociations();
assocTypeQNames = new HashSet<>(qnames.size());
// remove system assoc types
for (QName qname : qnames)
{
if ((!EXCLUDED_NS.contains(qname.getNamespaceURI())))
{
assocTypeQNames.add(qname);
}
}
}
*/
/* // TODO review - this works, but reduces from ~100 to ~96 (OOTB) // maybe we could post filter (rather than join) - examples: sys:children, sys:lost_found, sys:archivedLink, sys:archiveUserLink else { Collection<QName> qnames = dictionaryService.getAllAssociations(); assocTypeQNames = new HashSet<>(qnames.size());
*
* // remove system assoc types for (QName qname : qnames) { if ((!EXCLUDED_NS.contains(qname.getNamespaceURI()))) { assocTypeQNames.add(qname); } } } */
return assocTypeQNames;
}
@@ -2083,19 +2046,9 @@ public class NodesImpl implements Nodes
validateCmObject(nodeTypeQName);
}
/* RA-834: commented-out since not currently applicable for empty file
List<ThumbnailDefinition> thumbnailDefs = null;
String renditionsParam = parameters.getParameter(PARAM_RENDITIONS);
if (renditionsParam != null)
{
if (!isContent)
{
throw new InvalidArgumentException("Renditions ['"+renditionsParam+"'] only apply to content types: "+parentNodeRef.getId()+","+nodeName);
}
thumbnailDefs = getThumbnailDefs(renditionsParam);
}
*/
/* RA-834: commented-out since not currently applicable for empty file List<ThumbnailDefinition> thumbnailDefs = null; String renditionsParam = parameters.getParameter(PARAM_RENDITIONS); if (renditionsParam != null) { if (!isContent) { throw new InvalidArgumentException("Renditions ['"+renditionsParam+"'] only apply to content types: "+parentNodeRef.getId()+","+nodeName); }
*
* thumbnailDefs = getThumbnailDefs(renditionsParam); } */
Map<QName, Serializable> props = new HashMap<>(1);
@@ -2180,9 +2133,7 @@ public class NodesImpl implements Nodes
Node newNode = getFolderOrDocument(nodeRef.getId(), parameters);
/* RA-834: commented-out since not currently applicable for empty file
requestRenditions(thumbnailDefs, newNode); // note: noop for folder
*/
/* RA-834: commented-out since not currently applicable for empty file requestRenditions(thumbnailDefs, newNode); // note: noop for folder */
return newNode;
}
@@ -2330,7 +2281,6 @@ public class NodesImpl implements Nodes
return assocType;
}
private NodeRef createNodeImpl(NodeRef parentNodeRef, String nodeName, QName nodeTypeQName, Map<QName, Serializable> props, QName assocTypeQName)
{
NodeRef newNode = null;
@@ -2359,16 +2309,16 @@ public class NodesImpl implements Nodes
}
/**
* Posts activities based on the activity_type.
* If the method is called with aSync=true then a TransactionListener is used post the activity
* afterCommit. Otherwise the activity posting is done synchronously.
* Posts activities based on the activity_type. If the method is called with aSync=true then a TransactionListener is used post the activity afterCommit. Otherwise the activity posting is done synchronously.
*
* @param activity_type
* @param activityInfo
* @param aSync
*/
protected void postActivity(Activity_Type activity_type, ActivityInfo activityInfo, boolean aSync)
{
if (activityInfo == null) return; //Nothing to do.
if (activityInfo == null)
return; // Nothing to do.
String activityType = determineActivityType(activity_type, activityInfo.getFileInfo().isFolder());
if (activityType != null)
@@ -2394,8 +2344,7 @@ public class NodesImpl implements Nodes
protected ActivityInfo getActivityInfo(NodeRef parentNodeRef, NodeRef nodeRef)
{
// runAs system, eg. user may not have permission see one or more parents (irrespective of whether in a site context of not)
SiteInfo siteInfo = AuthenticationUtil.runAs(new RunAsWork<SiteInfo>()
{
SiteInfo siteInfo = AuthenticationUtil.runAs(new RunAsWork<SiteInfo>() {
@Override
public SiteInfo doWork() throws Exception
{
@@ -2436,10 +2385,12 @@ public class NodesImpl implements Nodes
case ADDED:
return isFolder ? ActivityType.FOLDER_ADDED : ActivityType.FILE_ADDED;
case UPDATED:
if (!isFolder) return ActivityType.FILE_UPDATED;
if (!isFolder)
return ActivityType.FILE_UPDATED;
break;
case DOWNLOADED:
if (!isFolder) return ActivityPoster.DOWNLOADED;
if (!isFolder)
return ActivityPoster.DOWNLOADED;
break;
}
return null;
@@ -2473,10 +2424,8 @@ public class NodesImpl implements Nodes
}
}
/**
* Check for special case: additional node validation (pending common lower-level service support)
* for blacklist of system nodes that should not be deleted or locked, eg. Company Home, Sites, Data Dictionary
* Check for special case: additional node validation (pending common lower-level service support) for blacklist of system nodes that should not be deleted or locked, eg. Company Home, Sites, Data Dictionary
*
* @param nodeRef
* @param type
@@ -2536,8 +2485,7 @@ public class NodesImpl implements Nodes
@Override
public Node updateNode(String nodeId, Node nodeInfo, Parameters parameters)
{
retryingTransactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
retryingTransactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>() {
@Override
public Void execute() throws Throwable
{
@@ -2549,8 +2497,7 @@ public class NodesImpl implements Nodes
}
}, false, true);
return retryingTransactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Node>()
{
return retryingTransactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Node>() {
@Override
public Node execute() throws Throwable
{
@@ -3124,7 +3071,8 @@ public class NodesImpl implements Nodes
{
// quick/weak guess based on file extension
writer.setMimetype(mimeType);
} else
}
else
{
// stronger guess based on file stream
writer.guessMimetype(fileName);
@@ -3140,14 +3088,16 @@ public class NodesImpl implements Nodes
try
{
is.reset();
} catch (IOException ioe)
}
catch (IOException ioe)
{
if (logger.isWarnEnabled())
{
logger.warn("Failed to reset stream after trying to guess encoding: " + ioe.getMessage());
}
}
} else
}
else
{
is = stream;
}
@@ -3359,9 +3309,7 @@ public class NodesImpl implements Nodes
properties = mapToNodeProperties(qnameStrProps);
}
/*
* Existing file handling
*/
/* Existing file handling */
NodeRef existingFile = nodeService.getChildByName(parentNodeRef, assocTypeQName, fileName);
if (existingFile != null)
{
@@ -3413,11 +3361,7 @@ public class NodesImpl implements Nodes
throw new PermissionDeniedException(ade.getMessage());
}
/*
* NOTE: Do not clean formData temp files to allow for retries. It's
* possible for a temp file to remain if max retry attempts are
* made, but this is rare, so leave to usual temp file cleanup.
*/
/* NOTE: Do not clean formData temp files to allow for retries. It's possible for a temp file to remain if max retry attempts are made, but this is rare, so leave to usual temp file cleanup. */
}
private NodeRef createNewFile(NodeRef parentNodeRef, String fileName, QName nodeType, Content content, Map<QName, Serializable> props, QName assocTypeQName, Parameters params,
@@ -3557,11 +3501,12 @@ public class NodesImpl implements Nodes
}
/**
* Creates a unique file name, if the upload component was configured to
* find a new unique name for clashing filenames.
* Creates a unique file name, if the upload component was configured to find a new unique name for clashing filenames.
*
* @param parentNodeRef the parent node
* @param fileName the original fileName
* @param parentNodeRef
* the parent node
* @param fileName
* the original fileName
* @return a new file name
*/
private String findUniqueName(NodeRef parentNodeRef, String fileName)
@@ -3599,7 +3544,8 @@ public class NodesImpl implements Nodes
/**
* Helper to create a QName from either a fully qualified or short-name QName string
*
* @param qnameStr Fully qualified or short-name QName string
* @param qnameStr
* Fully qualified or short-name QName string
* @return QName
*/
public QName createQName(String qnameStr)
@@ -3631,7 +3577,8 @@ public class NodesImpl implements Nodes
/**
* Helper to create a QName from either a fully qualified or short-name QName string
*
* @param qnameStrList list of fully qualified or short-name QName string
* @param qnameStrList
* list of fully qualified or short-name QName string
* @param excludedProps
* @return a list of {@code QName} objects
*/
@@ -3729,6 +3676,7 @@ public class NodesImpl implements Nodes
/**
* Checks if same permission is sent more than once
*
* @param locallySetPermissions
* @return
*/
@@ -3823,63 +3771,19 @@ public class NodesImpl implements Nodes
/**
* @author Jamal Kaabi-Mofrad
*/
/*
private static class ContentInfoWrapper implements BasicContentInfo
{
private String mimeType;
private String encoding;
public String getEncoding()
{
return encoding;
}
public String getMimeType()
{
return mimeType;
}
ContentInfoWrapper(BasicContentInfo basicContentInfo)
{
if (basicContentInfo != null)
{
this.mimeType = basicContentInfo.getMimeType();
this.encoding = basicContentInfo.getEncoding();
}
}
ContentInfoWrapper(ContentInfo contentInfo)
{
if (contentInfo != null)
{
this.mimeType = contentInfo.getMimeType();
this.encoding = contentInfo.getEncoding();
}
}
ContentInfoWrapper(Content content)
{
if (content != null && StringUtils.isNotEmpty(content.getMimetype()))
{
try
{
// TODO I think it makes sense to push contentType parsing into org.springframework.extensions.webscripts.servlet.FormData
MediaType media = MediaType.parseMediaType(content.getMimetype());
this.mimeType = media.getType() + '/' + media.getSubtype();
if (media.getCharSet() != null)
{
this.encoding = media.getCharSet().name();
}
}
catch (InvalidMediaTypeException ime)
{
throw new InvalidArgumentException(ime.getMessage());
}
}
}
}
*/
/* private static class ContentInfoWrapper implements BasicContentInfo { private String mimeType; private String encoding;
*
* public String getEncoding() { return encoding; }
*
* public String getMimeType() { return mimeType; }
*
* ContentInfoWrapper(BasicContentInfo basicContentInfo) { if (basicContentInfo != null) { this.mimeType = basicContentInfo.getMimeType(); this.encoding = basicContentInfo.getEncoding(); } }
*
* ContentInfoWrapper(ContentInfo contentInfo) { if (contentInfo != null) { this.mimeType = contentInfo.getMimeType(); this.encoding = contentInfo.getEncoding(); } }
*
* ContentInfoWrapper(Content content) { if (content != null && StringUtils.isNotEmpty(content.getMimetype())) { try { // TODO I think it makes sense to push contentType parsing into org.springframework.extensions.webscripts.servlet.FormData MediaType media = MediaType.parseMediaType(content.getMimetype()); this.mimeType = media.getType() + '/' + media.getSubtype();
*
* if (media.getCharSet() != null) { this.encoding = media.getCharSet().name(); } } catch (InvalidMediaTypeException ime) { throw new InvalidArgumentException(ime.getMessage()); } } } } */
protected NodeService getNodeService()
{