diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java index d6266e78a1..a2ca870fdb 100644 --- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -249,7 +249,8 @@ public class NodesImpl implements Nodes private final static String PARAM_ISFOLDER = "isFolder"; private final static String PARAM_ISCONTENT = "isContent"; - private final static String PARAM_SUBTYPES = "subTypes"; + + private final static String PARAM_INCLUDE_SUBTYPES = "INCLUDESUBTYPES"; private final static String PARAM_NAME = "name"; private final static String PARAM_CREATEDAT = "createdAt"; @@ -280,7 +281,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_ISCONTENT, PARAM_NODETYPE, PARAM_SUBTYPES})); + new HashSet<>(Arrays.asList(new String[] {PARAM_ISFOLDER, PARAM_ISCONTENT, PARAM_NODETYPE})); /* * Validates that node exists. @@ -955,24 +956,9 @@ public class NodesImpl implements Nodes String nodeTypeStr = propertyWalker.getProperty(PARAM_NODETYPE, WhereClauseParser.EQUALS, String.class); if ((nodeTypeStr != null) && (! nodeTypeStr.isEmpty())) { - filterIncludeSubTypes = false; // default nodeType filtering is without subTypes (unless subTypes = true) - - filterNodeTypeQName = createQName(nodeTypeStr); - if (dictionaryService.getType(filterNodeTypeQName) == null) - { - throw new InvalidArgumentException("Unknown filter nodeType: "+nodeTypeStr); - } - } - - // optionally used with nodeType filter (default is *not* to include sub-types) - Boolean subTypes = propertyWalker.getProperty(PARAM_SUBTYPES, WhereClauseParser.EQUALS, Boolean.class); - if (subTypes != null) - { - if (nodeTypeStr == null) - { - throw new InvalidArgumentException("Expected nodeType and subTypes (not just subTypes) filter: "+parentNodeRef.getId()); - } - filterIncludeSubTypes = subTypes; + Pair pair = parseNodeTypeFilter(nodeTypeStr); + filterNodeTypeQName = pair.getFirst(); + filterIncludeSubTypes = pair.getSecond(); } } @@ -1052,6 +1038,30 @@ public class NodesImpl implements Nodes return CollectionWithPagingInfo.asPaged(paging, nodes, pagingResults.hasMoreItems(), pagingResults.getTotalResultCount().getFirst()); } + private Pair parseNodeTypeFilter(String nodeTypeStr) + { + boolean filterIncludeSubTypes = false; // default nodeType filtering is without subTypes (unless nodeType value is suffixed with ' INCLUDESUBTYPES') + + int idx = nodeTypeStr.lastIndexOf(' '); + if (idx > 0) + { + String suffix = nodeTypeStr.substring(idx); + if (suffix.equalsIgnoreCase(" "+PARAM_INCLUDE_SUBTYPES)) + { + filterIncludeSubTypes = true; + nodeTypeStr = nodeTypeStr.substring(0, idx); + } + } + + QName filterNodeTypeQName = createQName(nodeTypeStr); + if (dictionaryService.getType(filterNodeTypeQName) == null) + { + throw new InvalidArgumentException("Unknown filter nodeType: "+nodeTypeStr); + } + + return new Pair<>(filterNodeTypeQName, filterIncludeSubTypes); + } + protected Pair, Set> buildSearchTypesAndIgnoreAspects(QName filterNodeTypeQName, boolean filterIncludeSubTypes, Set ignoreQNameTypes) { Set searchTypeQNames = new HashSet(100); 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 fd126d5374..334e5a25da 100644 --- a/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/NodeApiTest.java @@ -1484,7 +1484,7 @@ public class NodeApiTest extends AbstractBaseApiTest n1.expected(nodeResp); - // filtering, via where clause (nodeType + subTypes) + // filtering, via where clause (nodeType + optionally including sub-types) // note: subtle issue - in order to filter by "cm:link" the qname must have been created in the DB (in a write txn) // otherwise query will not match a missing qname (hmm). Workaround here by forcing the create of an explicit "cm:link". @@ -1505,11 +1505,23 @@ public class NodeApiTest extends AbstractBaseApiTest response = getAll(getChildrenUrl(f2Id), user1, paging, params, 200); List nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class); - assertEquals(1, nodes.size()); + // filter by including sub-types - note: includesubtypes is case-insensitive + params = new HashMap<>(); - params.put("where", "(nodeType='cm:link' and subTypes=true)"); + params.put("where", "(nodeType='cm:link INCLUDESUBTYPES')"); + + paging = getPaging(0, Integer.MAX_VALUE); + + response = getAll(getChildrenUrl(f2Id), user1, paging, params, 200); + nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class); + assertEquals(3, nodes.size()); + assertTrue(linkIds.contains(nodes.get(0).getId())); + assertTrue(linkIds.contains(nodes.get(1).getId())); + + params = new HashMap<>(); + params.put("where", "(nodeType='cm:link includeSubTypes')"); paging = getPaging(0, Integer.MAX_VALUE); @@ -1549,6 +1561,15 @@ public class NodeApiTest extends AbstractBaseApiTest params = new HashMap<>(); params.put("where", "(nodeType='my:unknown'"); getAll(getChildrenUrl(f2Id), user1, paging, params, 400); + + // -ver test - invalid node type localname format and suffix is not ' includesubtypes' + params = new HashMap<>(); + params.put("where", "(nodeType='cm:link ')"); + getAll(getChildrenUrl(f2Id), user1, paging, params, 400); + + params = new HashMap<>(); + params.put("where", "(nodeType='cm:link blah')"); + getAll(getChildrenUrl(f2Id), user1, paging, params, 400); }