From 478ed2baaeecebcd3ae98dbb3051c63456ebbb62 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Wed, 11 May 2016 12:07:07 +0000 Subject: [PATCH] Merged HEAD (5.2) to 5.2.N (5.2.1) 126548 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2) 124180 jvonka: RA-896: Fix filter by "where=(isFile=false and isFolder=false)" - when listing node children - will list cmobject, including sub-types (except cm:folder & cm:content, including sub-types) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126894 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../org/alfresco/rest/api/impl/NodesImpl.java | 93 +++++++++--- .../alfresco/rest/api/tests/NodeApiTest.java | 142 +++++++++++++++++- 2 files changed, 215 insertions(+), 20 deletions(-) diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java index b8f28ee086..75cde374be 100644 --- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -1042,8 +1042,8 @@ public class NodesImpl implements Nodes final List includeParam = parameters.getInclude(); - boolean includeFolders = true; - boolean includeFiles = true; + Boolean includeFolders = null; + Boolean includeFiles = null; QName filterNodeTypeQName = null; @@ -1061,20 +1061,14 @@ public class NodesImpl implements Nodes Boolean isFolder = propertyWalker.getProperty(PARAM_ISFOLDER, WhereClauseParser.EQUALS, Boolean.class); Boolean isFile = propertyWalker.getProperty(PARAM_ISFILE, WhereClauseParser.EQUALS, Boolean.class); - if ((isFolder != null) && (isFile != null)) + if (isFolder != null) { - includeFiles = isFile; includeFolders = isFolder; } - else if (isFolder != null) - { - includeFiles = !isFolder; - includeFolders = isFolder; - } - else if (isFile != null) + + if (isFile != null) { includeFiles = isFile; - includeFolders = !isFile; } String nodeTypeStr = propertyWalker.getProperty(PARAM_NODETYPE, WhereClauseParser.EQUALS, String.class); @@ -1119,14 +1113,14 @@ public class NodesImpl implements Nodes PagingRequest pagingRequest = Util.getPagingRequest(paging); final PagingResults pagingResults; - if ((filterNodeTypeQName != null) || (includeFolders && includeFiles)) + if ((filterNodeTypeQName != null) || (Boolean.FALSE.equals(includeFiles) && Boolean.FALSE.equals(includeFolders))) { if (filterNodeTypeQName == null) { filterNodeTypeQName = ContentModel.TYPE_CMOBJECT; } - Pair, Set> pair = buildSearchTypesAndIgnoreAspects(filterNodeTypeQName, filterIncludeSubTypes, ignoreQNames); + Pair, Set> pair = buildSearchTypesAndIgnoreAspects(filterNodeTypeQName, filterIncludeSubTypes, ignoreQNames, includeFiles, includeFolders); Set searchTypeQNames = pair.getFirst(); Set ignoreAspectQNames = pair.getSecond(); @@ -1134,7 +1128,20 @@ public class NodesImpl implements Nodes } else { - // files *or* folders only + // files and/or folders only + if ((includeFiles == null) && (includeFolders == null)) + { + // no filtering + includeFiles = true; + includeFolders = true; + } + else + { + // some filtering + includeFiles = (includeFiles != null ? includeFiles : false); + includeFolders = (includeFolders != null ? includeFolders : false); + } + pagingResults = fileFolderService.list(parentNodeRef, includeFiles, includeFolders, ignoreQNames, sortProps, pagingRequest); } @@ -1193,27 +1200,75 @@ public class NodesImpl implements Nodes return new Pair<>(filterNodeTypeQName, filterIncludeSubTypes); } - protected Pair, Set> buildSearchTypesAndIgnoreAspects(QName filterNodeTypeQName, boolean filterIncludeSubTypes, Set ignoreQNameTypes) + protected Pair, Set> buildSearchTypesAndIgnoreAspects(QName nodeTypeQName, boolean includeSubTypes, Set ignoreQNameTypes, Boolean includeFiles, Boolean includeFolders) { Set searchTypeQNames = new HashSet(100); Set ignoreAspectQNames = null; // Build a list of (sub-)types - if (filterIncludeSubTypes) + if (includeSubTypes) { - Collection qnames = dictionaryService.getSubTypes(filterNodeTypeQName, true); + Collection qnames = dictionaryService.getSubTypes(nodeTypeQName, true); searchTypeQNames.addAll(qnames); } - searchTypeQNames.add(filterNodeTypeQName); + searchTypeQNames.add(nodeTypeQName); // Remove 'system' folders - if (filterIncludeSubTypes) + if (includeSubTypes) { Collection qnames = dictionaryService.getSubTypes(ContentModel.TYPE_SYSTEM_FOLDER, true); searchTypeQNames.removeAll(qnames); } searchTypeQNames.remove(ContentModel.TYPE_SYSTEM_FOLDER); + if (includeFiles != null) + { + if (includeFiles) + { + if (! dictionaryService.isSubClass(ContentModel.TYPE_CONTENT, nodeTypeQName)) + { + throw new InvalidArgumentException("Cannot filter for isFile since not sub-type of: "+nodeTypeQName); + } + + if (includeSubTypes) + { + Collection qnames = dictionaryService.getSubTypes(ContentModel.TYPE_CONTENT, true); + searchTypeQNames.addAll(qnames); + } + searchTypeQNames.add(ContentModel.TYPE_CONTENT); + } + else + { + Collection qnames = dictionaryService.getSubTypes(ContentModel.TYPE_CONTENT, true); + searchTypeQNames.removeAll(qnames); + searchTypeQNames.remove(ContentModel.TYPE_CONTENT); + } + } + + if (includeFolders != null) + { + if (includeFolders) + { + if (! dictionaryService.isSubClass(ContentModel.TYPE_FOLDER, nodeTypeQName)) + { + throw new InvalidArgumentException("Cannot filter for isFolder since not sub-type of: "+nodeTypeQName); + } + + if (includeSubTypes) + { + Collection qnames = dictionaryService.getSubTypes(ContentModel.TYPE_FOLDER, true); + searchTypeQNames.addAll(qnames); + } + searchTypeQNames.add(ContentModel.TYPE_FOLDER); + } + else + { + Collection qnames = dictionaryService.getSubTypes(ContentModel.TYPE_FOLDER, true); + searchTypeQNames.removeAll(qnames); + searchTypeQNames.remove(ContentModel.TYPE_FOLDER); + } + } + if (ignoreQNameTypes != null) { Set ignoreQNamesNotSearchTypes = new HashSet(ignoreQNameTypes); diff --git a/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java b/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java index cd26072f3d..4575573aad 100644 --- a/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java @@ -1646,7 +1646,147 @@ public class NodeApiTest extends AbstractBaseApiTest post(getNodeChildrenUrl(myNodeId), user1, RestApiUtil.toJsonAsStringNonNull(n), 409); } - // TODO test custom type with properties (sub-type of cm:cmobject) + // TODO test custom types with properties (sub-type of cm:cmobject) + + @Test + public void testListChildrenIsFileIsFolderFilter() throws Exception + { + String myNodeId = getMyNodeId(user1); + String myChildrenUrl = getNodeChildrenUrl(myNodeId); + + long timeNow = System.currentTimeMillis(); + + int folderCnt = 2; + int fileCnt = 3; + int objCnt = 4; + + // create some folders + List folderIds = new ArrayList<>(folderCnt); + + for (int i = 1; i <= folderCnt; i++) + { + folderIds.add(createFolder(user1, myNodeId, "folder "+i+" "+timeNow).getId()); + } + + // create some files + List fileIds = new ArrayList<>(fileCnt); + for (int i = 1; i <= fileCnt; i++) + { + fileIds.add(createTextFile(user1, myNodeId, "file "+i+" "+timeNow, "The quick brown fox jumps over the lazy dog "+i).getId()); + } + + // create some nodes (cmobject) + List objIds = new ArrayList<>(objCnt); + for (int i = 1; i <= objCnt; i++) + { + Node obj = new Node(); + obj.setName("obj "+i+" "+timeNow); + obj.setNodeType("cm:cmobject"); + + // create node/object + HttpResponse response = post(myChildrenUrl, user1, toJsonAsStringNonNull(obj), 201); + Node nodeResp = RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Node.class); + objIds.add(nodeResp.getId()); + } + + List allIds = new ArrayList<>(objCnt+folderCnt+fileCnt); + allIds.addAll(folderIds); + allIds.addAll(fileIds); + allIds.addAll(objIds); + + List folderAndFileIds = new ArrayList<>(folderCnt+fileCnt); + folderAndFileIds.addAll(folderIds); + folderAndFileIds.addAll(fileIds); + + Paging paging = getPaging(0, Integer.MAX_VALUE); + + // filtering, via where clause - folders + + Map params = new HashMap<>(); + params.put("where", "(nodeType='cm:folder')"); + + HttpResponse response = getAll(myChildrenUrl, user1, paging, params, 200); + List nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + checkNodeIds(nodes, folderIds); + + params = new HashMap<>(); + params.put("where", "(isFolder=true)"); + + response = getAll(myChildrenUrl, user1, paging, params, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + checkNodeIds(nodes, folderIds); + + params = new HashMap<>(); + params.put("where", "(isFolder=true AND isFile=false)"); + + response = getAll(myChildrenUrl, user1, paging, params, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + checkNodeIds(nodes, folderIds); + + // filtering, via where clause - files + + params = new HashMap<>(); + params.put("where", "(nodeType='cm:content')"); + + response = getAll(myChildrenUrl, user1, paging, params, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + checkNodeIds(nodes, fileIds); + + params = new HashMap<>(); + params.put("where", "(isFile=true)"); + + response = getAll(myChildrenUrl, user1, paging, params, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + checkNodeIds(nodes, fileIds); + + params = new HashMap<>(); + params.put("where", "(isFile=true AND isFolder=false)"); + + response = getAll(myChildrenUrl, user1, paging, params, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + checkNodeIds(nodes, fileIds); + + // filtering, via where clause - files and folders + + params = new HashMap<>(); + params.put("where", "(isFile=true AND isFolder=true)"); + + response = getAll(myChildrenUrl, user1, paging, params, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + checkNodeIds(nodes, folderAndFileIds); + + // filtering, via where clause - non-folders / non-files + + params = new HashMap<>(); + params.put("where", "(nodeType='cm:cmobject')"); + + response = getAll(myChildrenUrl, user1, paging, params, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + checkNodeIds(nodes, objIds); + + params = new HashMap<>(); + params.put("where", "(nodeType='cm:cmobject INCLUDESUBTYPES')"); + + response = getAll(myChildrenUrl, user1, paging, params, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + checkNodeIds(nodes, allIds); + + params = new HashMap<>(); + params.put("where", "(isFile=false AND isFolder=false)"); + + response = getAll(myChildrenUrl, user1, paging, params, 200); + nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); + checkNodeIds(nodes, objIds); + } + + private void checkNodeIds(List nodes, List nodeIds) + { + assertEquals(nodeIds.size(), nodes.size()); + for (Node node : nodes) + { + assertTrue(nodeIds.contains(node.getId())); + } + } // note: app:folderlink & app:filelink both extend cm:link (which in turn extends cm:cmobject) // (see applicationModel.xml / contentModel.xml)