diff --git a/source/java/org/alfresco/rest/api/Nodes.java b/source/java/org/alfresco/rest/api/Nodes.java index 64661e5845..990e9edf9c 100644 --- a/source/java/org/alfresco/rest/api/Nodes.java +++ b/source/java/org/alfresco/rest/api/Nodes.java @@ -287,4 +287,5 @@ public interface Nodes String PARAM_VERSION_COMMENT = "comment"; String PARAM_ISPRIMARY = "isPrimary"; + String PARAM_ASSOC_TYPE = "assocType"; } diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java index 58d8554933..3484ba57f1 100644 --- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -129,6 +129,8 @@ import org.alfresco.service.cmr.version.VersionService; import org.alfresco.service.cmr.version.VersionType; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; +import org.alfresco.service.namespace.QNamePattern; +import org.alfresco.service.namespace.RegexQNamePattern; import org.alfresco.util.Pair; import org.alfresco.util.PropertyCheck; import org.apache.commons.lang.StringUtils; @@ -347,7 +349,7 @@ public class NodesImpl implements Nodes // list children filtering (via where clause) private final static Set LIST_FOLDER_CHILDREN_EQUALS_QUERY_PROPERTIES = - new HashSet<>(Arrays.asList(new String[] {PARAM_ISFOLDER, PARAM_ISFILE, PARAM_NODETYPE, PARAM_ISPRIMARY})); + new HashSet<>(Arrays.asList(new String[] {PARAM_ISFOLDER, PARAM_ISFILE, PARAM_NODETYPE, PARAM_ISPRIMARY, PARAM_ASSOC_TYPE})); /* * Validates that node exists. @@ -1163,18 +1165,13 @@ public class NodesImpl implements Nodes final NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, path); - // check that resolved node is a folder - if (!nodeMatches(parentNodeRef, Collections.singleton(ContentModel.TYPE_FOLDER), null, false)) - { - throw new InvalidArgumentException("NodeId of folder is expected: " + parentNodeRef.getId()); - } - final List includeParam = parameters.getInclude(); // filters Boolean includeFolders = null; Boolean includeFiles = null; Boolean isPrimary = null; + QName assocTypeQNameParam = null; QName filterNodeTypeQName = null; // note: for files/folders, include subtypes by default (unless filtering by a specific nodeType - see below) @@ -1190,6 +1187,12 @@ public class NodesImpl implements Nodes isPrimary = propertyWalker.getProperty(PARAM_ISPRIMARY, WhereClauseParser.EQUALS, Boolean.class); + String assocTypeQNameStr = propertyWalker.getProperty(PARAM_ASSOC_TYPE, WhereClauseParser.EQUALS, String.class); + if (assocTypeQNameStr != null) + { + assocTypeQNameParam = getAssocType(assocTypeQNameStr); + } + Boolean isFolder = propertyWalker.getProperty(PARAM_ISFOLDER, WhereClauseParser.EQUALS, Boolean.class); Boolean isFile = propertyWalker.getProperty(PARAM_ISFILE, WhereClauseParser.EQUALS, Boolean.class); @@ -1302,7 +1305,10 @@ public class NodesImpl implements Nodes Set searchTypeQNames = pair.getFirst(); Set ignoreAspectQNames = pair.getSecond(); - pagingResults = fileFolderService.list(parentNodeRef, searchTypeQNames, ignoreAspectQNames, sortProps, filterProps, pagingRequest); + Set assocTypeQNames = buildAssocTypes(assocTypeQNameParam); + + // call GetChildrenCannedQuery (via FileFolderService) + pagingResults = fileFolderService.list(parentNodeRef, assocTypeQNames, searchTypeQNames, ignoreAspectQNames, sortProps, filterProps, pagingRequest); final Map mapUserInfo = new HashMap<>(10); @@ -1359,6 +1365,34 @@ public class NodesImpl implements Nodes return new Pair<>(filterNodeTypeQName, filterIncludeSubTypes); } + protected Set buildAssocTypes(QName assocTypeQName) + { + Set assocTypeQNames = null; + if (assocTypeQName != null) + { + 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 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; + } + protected Pair, Set> buildSearchTypesAndIgnoreAspects(QName nodeTypeQName, boolean includeSubTypes, Set ignoreQNameTypes, Boolean includeFiles, Boolean includeFolders) { Set searchTypeQNames = new HashSet<>(100); @@ -1570,8 +1604,14 @@ public class NodesImpl implements Nodes String relativePath = nodeInfo.getRelativePath(); parentNodeRef = getOrCreatePath(parentNodeRef, relativePath); + QName assocTypeQName = ContentModel.ASSOC_CONTAINS; + if ((nodeInfo.getAssociation() != null) && (nodeInfo.getAssociation().getAssocType() != null)) + { + assocTypeQName = getAssocType(nodeInfo.getAssociation().getAssocType()); + } + // Create the node - NodeRef nodeRef = createNodeImpl(parentNodeRef, nodeName, nodeTypeQName, props); + NodeRef nodeRef = createNodeImpl(parentNodeRef, nodeName, nodeTypeQName, props, assocTypeQName); List aspectNames = nodeInfo.getAspectNames(); if (aspectNames != null) @@ -1734,7 +1774,7 @@ public class NodesImpl implements Nodes } - private NodeRef createNodeImpl(NodeRef parentNodeRef, String nodeName, QName nodeTypeQName, Map props) + private NodeRef createNodeImpl(NodeRef parentNodeRef, String nodeName, QName nodeTypeQName, Map props, QName assocTypeQName) { NodeRef newNode = null; if (props == null) @@ -1748,7 +1788,7 @@ public class NodesImpl implements Nodes QName assocQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(nodeName)); try { - newNode = nodeService.createNode(parentNodeRef, ContentModel.ASSOC_CONTAINS, assocQName, nodeTypeQName, props).getChildRef(); + newNode = nodeService.createNode(parentNodeRef, assocTypeQName, assocQName, nodeTypeQName, props).getChildRef(); } catch (DuplicateChildNodeNameException dcne) { @@ -2413,6 +2453,8 @@ public class NodesImpl implements Nodes // if requested, make (get or create) path parentNodeRef = getOrCreatePath(parentNodeRef, relativePath); + QName assocTypeQName = ContentModel.ASSOC_CONTAINS; + try { // Map the given properties, if any. @@ -2424,7 +2466,7 @@ public class NodesImpl implements Nodes /* * Existing file handling */ - NodeRef existingFile = nodeService.getChildByName(parentNodeRef, ContentModel.ASSOC_CONTAINS, fileName); + NodeRef existingFile = nodeService.getChildByName(parentNodeRef, assocTypeQName, fileName); if (existingFile != null) { // File already exists, decide what to do @@ -2449,7 +2491,7 @@ public class NodesImpl implements Nodes } // Create a new file. - final Node fileNode = createNewFile(parentNodeRef, fileName, nodeTypeQName, content, properties, parameters); + Node fileNode = createNewFile(parentNodeRef, fileName, nodeTypeQName, content, properties, assocTypeQName, parameters); // RA-1052 try @@ -2501,13 +2543,13 @@ public class NodesImpl implements Nodes } } - private Node createNewFile(NodeRef parentNodeRef, String fileName, QName nodeType, Content content, Map props, Parameters params) + private Node createNewFile(NodeRef parentNodeRef, String fileName, QName nodeType, Content content, Map props, QName assocTypeQName, Parameters params) { if (nodeType == null) { nodeType = ContentModel.TYPE_CONTENT; } - NodeRef newFile = createNodeImpl(parentNodeRef, fileName, nodeType, props); + NodeRef newFile = createNodeImpl(parentNodeRef, fileName, nodeType, props, assocTypeQName); // Write content write(newFile, content); diff --git a/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java b/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java index 7ab1dd6b84..ca189a7737 100644 --- a/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java +++ b/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java @@ -58,13 +58,11 @@ import java.util.Set; */ public class AbstractNodeRelation implements InitializingBean { - public final static String PARAM_ASSOC_TYPE = "assocType"; - // excluded namespaces (assoc types) protected static final List EXCLUDED_NS = Arrays.asList(NamespaceService.SYSTEM_MODEL_1_0_URI); private final static Set WHERE_PARAMS_ASSOC_TYPE = - new HashSet<>(Arrays.asList(new String[] {PARAM_ASSOC_TYPE})); + new HashSet<>(Arrays.asList(new String[] {Nodes.PARAM_ASSOC_TYPE})); protected ServiceRegistry sr; protected NodeService nodeService; @@ -110,7 +108,7 @@ public class AbstractNodeRelation implements InitializingBean MapBasedQueryWalker propertyWalker = new MapBasedQueryWalker(WHERE_PARAMS_ASSOC_TYPE, null); QueryHelper.walk(q, propertyWalker); - String assocTypeQNameStr = propertyWalker.getProperty(PARAM_ASSOC_TYPE, WhereClauseParser.EQUALS, String.class); + String assocTypeQNameStr = propertyWalker.getProperty(Nodes.PARAM_ASSOC_TYPE, WhereClauseParser.EQUALS, String.class); if (assocTypeQNameStr != null) { assocTypeQNamePattern = nodes.getAssocType(assocTypeQNameStr); diff --git a/source/java/org/alfresco/rest/api/nodes/NodeParentsRelation.java b/source/java/org/alfresco/rest/api/nodes/NodeParentsRelation.java index 1ffd4d3940..e34eb6b671 100644 --- a/source/java/org/alfresco/rest/api/nodes/NodeParentsRelation.java +++ b/source/java/org/alfresco/rest/api/nodes/NodeParentsRelation.java @@ -47,10 +47,8 @@ import java.util.Set; @RelationshipResource(name = "parents", entityResource = NodesEntityResource.class, title = "Node Parents") public class NodeParentsRelation extends AbstractNodeRelation implements RelationshipResourceAction.Read { - public final static String PARAM_IS_PRIMARY = Nodes.PARAM_ISPRIMARY; - private final static Set WHERE_PARAMS_PARENTS = - new HashSet<>(Arrays.asList(new String[] {PARAM_ASSOC_TYPE, PARAM_IS_PRIMARY})); + new HashSet<>(Arrays.asList(new String[] {Nodes.PARAM_ASSOC_TYPE, Nodes.PARAM_ISPRIMARY})); /** * List child node's parent(s) based on (parent ->) child associations. @@ -74,9 +72,9 @@ public class NodeParentsRelation extends AbstractNodeRelation implements Relatio MapBasedQueryWalker propertyWalker = new MapBasedQueryWalker(WHERE_PARAMS_PARENTS, null); QueryHelper.walk(q, propertyWalker); - isPrimary = propertyWalker.getProperty(PARAM_IS_PRIMARY, WhereClauseParser.EQUALS, Boolean.class); + isPrimary = propertyWalker.getProperty(Nodes.PARAM_ISPRIMARY, WhereClauseParser.EQUALS, Boolean.class); - String assocTypeQNameStr = propertyWalker.getProperty(PARAM_ASSOC_TYPE, WhereClauseParser.EQUALS, String.class); + String assocTypeQNameStr = propertyWalker.getProperty(Nodes.PARAM_ASSOC_TYPE, WhereClauseParser.EQUALS, String.class); if (assocTypeQNameStr != null) { assocTypeQNameParam = nodes.getAssocType(assocTypeQNameStr); diff --git a/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java b/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java index b41e31750d..c76fc29dc6 100644 --- a/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java +++ b/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java @@ -18,6 +18,7 @@ */ package org.alfresco.rest.api.nodes; +import org.alfresco.rest.api.Nodes; import org.alfresco.rest.api.model.AssocChild; import org.alfresco.rest.api.model.Node; import org.alfresco.rest.framework.WebApiDescription; @@ -94,7 +95,7 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen NodeRef parentNodeRef = nodes.validateNode(parentNodeId); NodeRef childNodeRef = nodes.validateNode(childNodeId); - String assocTypeStr = parameters.getParameter(PARAM_ASSOC_TYPE); + String assocTypeStr = parameters.getParameter(Nodes.PARAM_ASSOC_TYPE); QName assocTypeQName = nodes.getAssocType(assocTypeStr, false); List assocRefs = nodeService.getChildAssocs(parentNodeRef); diff --git a/source/java/org/alfresco/rest/api/nodes/NodeTargetsRelation.java b/source/java/org/alfresco/rest/api/nodes/NodeTargetsRelation.java index 12cf3fd807..f187f3b122 100644 --- a/source/java/org/alfresco/rest/api/nodes/NodeTargetsRelation.java +++ b/source/java/org/alfresco/rest/api/nodes/NodeTargetsRelation.java @@ -18,6 +18,7 @@ */ package org.alfresco.rest.api.nodes; +import org.alfresco.rest.api.Nodes; import org.alfresco.rest.api.model.AssocTarget; import org.alfresco.rest.api.model.Node; import org.alfresco.rest.framework.WebApiDescription; @@ -79,7 +80,7 @@ public class NodeTargetsRelation extends AbstractNodeRelation implements NodeRef srcNodeRef = nodes.validateNode(sourceNodeId); NodeRef tgtNodeRef = nodes.validateNode(targetNodeId); - String assocTypeStr = parameters.getParameter(PARAM_ASSOC_TYPE); + String assocTypeStr = parameters.getParameter(Nodes.PARAM_ASSOC_TYPE); QNamePattern assocTypeQName = nodes.getAssocType(assocTypeStr, false); if (assocTypeQName == null)