diff --git a/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java b/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java index 7266d8696b..24f352b12f 100644 --- a/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java +++ b/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java @@ -28,6 +28,7 @@ package org.alfresco.rest.api.search.impl; import org.alfresco.rest.api.search.model.Query; import org.alfresco.rest.api.search.model.SearchQuery; +import org.alfresco.rest.api.search.model.SortDef; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.resource.content.BasicContentInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; @@ -38,6 +39,7 @@ import org.alfresco.service.cmr.search.LimitBy; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.rest.api.model.Node; +import org.alfresco.service.cmr.search.SearchParameters.SortDefinition; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.util.ParameterCheck; import org.apache.commons.lang.NotImplementedException; @@ -81,6 +83,7 @@ public class SearchMapper fromQuery(sp, searchQuery.getQuery()); fromPaging(sp, searchQuery.getPaging()); + fromSort(sp, searchQuery.getSort()); validateInclude(searchQuery.getInclude()); return sp; @@ -123,7 +126,6 @@ public class SearchMapper } sp.setQuery(q.getQuery()); sp.setSearchTerm(q.getUserQuery()); - } public void fromPaging(SearchParameters sp, Paging paging) @@ -136,6 +138,25 @@ public class SearchMapper } } + public void fromSort(SearchParameters sp, List sort) + { + if (sort != null && !sort.isEmpty()) + { + for (SortDef sortDef:sort) + { + + try + { + sp.addSort(sortDef.toDefinition()); + } + catch (IllegalArgumentException e) + { + throw new InvalidArgumentException(InvalidArgumentException.DEFAULT_MESSAGE_ID, new Object[] { sortDef.getType() }); + } + } + } + } + public void validateInclude(List includes) { if (includes != null && !includes.isEmpty()) diff --git a/source/java/org/alfresco/rest/api/search/model/SearchQuery.java b/source/java/org/alfresco/rest/api/search/model/SearchQuery.java index eb52441c23..5f4b0a9fc1 100644 --- a/source/java/org/alfresco/rest/api/search/model/SearchQuery.java +++ b/source/java/org/alfresco/rest/api/search/model/SearchQuery.java @@ -42,17 +42,20 @@ public class SearchQuery private final Query query; private final Paging paging; private final List include; + private final List sort; - public static final SearchQuery EMPTY = new SearchQuery(null, null, null); + public static final SearchQuery EMPTY = new SearchQuery(null, null, null, null); @JsonCreator public SearchQuery(@JsonProperty("query") Query query, @JsonProperty("paging") Paging paging, - @JsonProperty("include") List include) + @JsonProperty("include") List include, + @JsonProperty("sort") List sort) { this.query = query; this.paging = paging; this.include = include; + this.sort = sort; } public Query getQuery() @@ -69,4 +72,8 @@ public class SearchQuery { return include; } + public List getSort() + { + return sort; + } } diff --git a/source/java/org/alfresco/rest/api/search/model/SortDef.java b/source/java/org/alfresco/rest/api/search/model/SortDef.java new file mode 100644 index 0000000000..92be2ba976 --- /dev/null +++ b/source/java/org/alfresco/rest/api/search/model/SortDef.java @@ -0,0 +1,73 @@ +/*- + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.api.search.model; + +import org.alfresco.service.cmr.search.SearchParameters; +import org.alfresco.service.cmr.search.SearchParameters.SortDefinition; +import org.alfresco.service.cmr.search.SearchParameters.SortDefinition.SortType; +import org.codehaus.jackson.annotate.JsonCreator; +import org.codehaus.jackson.annotate.JsonProperty; + +/** + * This is a copy of the SortDefinition class found in data-model. Due to the use of a very old version + * of Jackson it is necessary to duplicate this class rather than reuse it. + * + * @author Gethin James + */ +public class SortDef +{ + + String type; + String field; + boolean ascending; + + @JsonCreator + public SortDef(@JsonProperty("type") String type, + @JsonProperty("field") String field, + @JsonProperty("ascending") boolean ascending) + { + this.type = type; + this.field = field; + this.ascending = ascending; + } + + public String getType() + { + return type; + } + + /** + * You are allowed to create an instance of this class that has an invalid sortType + * but this method will validate the definition is correct and return it. + * + * @return SortDefinition + */ + public SortDefinition toDefinition() + { + return new SortDefinition(SortType.valueOf(type), field, ascending); + } + +} diff --git a/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java b/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java index faed46955e..8e98d09a60 100644 --- a/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java +++ b/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java @@ -32,9 +32,11 @@ import static junit.framework.TestCase.fail; import static org.alfresco.service.cmr.search.SearchService.LANGUAGE_CMIS_ALFRESCO; import static org.alfresco.service.cmr.search.SearchService.LANGUAGE_FTS_ALFRESCO; import static org.alfresco.service.cmr.search.SearchService.LANGUAGE_LUCENE; +import static org.junit.Assert.assertNull; import org.alfresco.rest.api.search.impl.SearchMapper; import org.alfresco.rest.api.search.model.Query; import org.alfresco.rest.api.search.model.SearchQuery; +import org.alfresco.rest.api.search.model.SortDef; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.resource.parameters.Paging; import org.alfresco.service.cmr.repository.StoreRef; @@ -52,6 +54,7 @@ public class SearchMapperTests { static SearchMapper searchMapper = new SearchMapper(); + static SerializerTestHelper helper = new SerializerTestHelper(); @Test(expected = IllegalArgumentException.class) public void testMandatory() throws Exception @@ -68,6 +71,9 @@ public class SearchMapperTests //Test defaults assertEquals("There should be only 1 default store", 1,searchParameters.getStores().size()); assertEquals("workspaces store is the default", StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, searchParameters.getStores().get(0)); + + searchParameters = searchMapper.toSearchParameters(helper.searchQueryFromJson()); + assertNotNull(searchParameters); } @Test @@ -137,6 +143,45 @@ public class SearchMapperTests assertEquals(searchParameters.getSkipCount(),paging.getSkipCount()); } + + @Test + public void fromSort() throws Exception + { + SearchParameters searchParameters = new SearchParameters(); + //Doesn't error + searchMapper.fromSort(searchParameters, null); + + try + { + searchMapper.fromSort(searchParameters, Arrays.asList(new SortDef("wrongenum", null, false))); + fail(); + } + catch (InvalidArgumentException iae) + { + //wrongenum is illegal + assertNotNull(iae); + } + + searchMapper.fromSort(searchParameters, Arrays.asList(new SortDef("FIELD", "my", true), new SortDef("SCORE", null, false))); + assertEquals(2 , searchParameters.getSortDefinitions().size()); + searchParameters.getSortDefinitions().forEach(sortDefinition -> + { + switch (sortDefinition.getSortType()) + { + case FIELD: + assertEquals("my", sortDefinition.getField()); + assertEquals(true, sortDefinition.isAscending()); + break; + case SCORE: + assertNull(sortDefinition.getField()); + assertEquals(false, sortDefinition.isAscending()); + break; + default: + fail("Invalid sortDefinition"); + } + }); + } + @Test public void validateInclude() throws Exception { @@ -171,7 +216,7 @@ public class SearchMapperTests private SearchQuery minimalQuery() { Query query = new Query("cmis", "foo", ""); - SearchQuery sq = new SearchQuery(query,null, null); + SearchQuery sq = new SearchQuery(query,null, null, null); return sq; } } diff --git a/source/test-java/org/alfresco/rest/api/search/SearchQuerySerializerTests.java b/source/test-java/org/alfresco/rest/api/search/SearchQuerySerializerTests.java index 7db01b25b8..6ea09485a0 100644 --- a/source/test-java/org/alfresco/rest/api/search/SearchQuerySerializerTests.java +++ b/source/test-java/org/alfresco/rest/api/search/SearchQuerySerializerTests.java @@ -48,43 +48,30 @@ import java.io.StringReader; * * @author Gethin James */ -public class SearchQuerySerializerTests implements RequestReader +public class SearchQuerySerializerTests { - static JacksonHelper jsonHelper = null; + + private static SerializerTestHelper helper; @BeforeClass public static void setupTests() throws Exception { - jsonHelper = new JacksonHelper(); - RestJsonModule module = new RestJsonModule(); - jsonHelper.setModule(module); - jsonHelper.afterPropertiesSet(); + helper = new SerializerTestHelper(); } @Test public void testDeserializeQuery() throws IOException { - String json = "{ \"query\": {\"query\": \"g*\",\"userQuery\": \"great\",\"language\": \"bob\"}, " - + "\"paging\": {\"maxItems\": \"99\",\"skipCount\": \"4\"}, \"include\": [\"bob\", \"hope\"]}"; - SearchQuery searchQuery = extractFromJson(json); + SearchQuery searchQuery = helper.searchQueryFromJson(); assertEquals(SearchQuery.class, searchQuery.getClass()); - assertEquals("bob", searchQuery.getQuery().getLanguage()); + assertEquals("afts", searchQuery.getQuery().getLanguage()); assertEquals("g*", searchQuery.getQuery().getQuery()); assertEquals("great", searchQuery.getQuery().getUserQuery()); assertEquals(99, searchQuery.getPaging().getMaxItems()); assertEquals(4, searchQuery.getPaging().getSkipCount()); assertEquals(2, searchQuery.getInclude().size()); - assertTrue(searchQuery.getInclude().contains("bob")); - assertTrue(searchQuery.getInclude().contains("hope")); - } - - private SearchQuery extractFromJson(String json) throws IOException - { - Content content = mock(Content.class); - when(content.getReader()).thenReturn(new StringReader(json)); - WebScriptRequest request = mock(WebScriptRequest.class); - when(request.getContent()).thenReturn(content); - return extractJsonContent(request, jsonHelper, SearchQuery.class); + assertTrue(searchQuery.getInclude().contains("aspectNames")); + assertTrue(searchQuery.getInclude().contains("properties")); } } diff --git a/source/test-java/org/alfresco/rest/api/search/SerializerTestHelper.java b/source/test-java/org/alfresco/rest/api/search/SerializerTestHelper.java new file mode 100644 index 0000000000..e4a08912cc --- /dev/null +++ b/source/test-java/org/alfresco/rest/api/search/SerializerTestHelper.java @@ -0,0 +1,84 @@ +/*- + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.api.search; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import org.alfresco.rest.api.search.model.SearchQuery; +import org.alfresco.rest.framework.jacksonextensions.JacksonHelper; +import org.alfresco.rest.framework.jacksonextensions.RestJsonModule; +import org.alfresco.rest.framework.tools.RequestReader; +import org.junit.BeforeClass; +import org.springframework.extensions.surf.util.Content; +import org.springframework.extensions.webscripts.WebScriptRequest; + +import java.io.IOException; +import java.io.StringReader; + +/** + * Sets up an parses a valid JSON request. + * + * @author Gethin James + */ +public class SerializerTestHelper implements RequestReader +{ + + JacksonHelper jsonHelper = null; + + public static final String JSON = "{ \"query\": {\"query\": \"g*\",\"userQuery\": \"great\",\"language\": \"afts\"}, " + + "\"paging\": {\"maxItems\": \"99\",\"skipCount\": \"4\"}," + + "\"sort\": {\"type\": \"FIELD\",\"field\": \"king\",\"ascending\": \"true\"}," + + "\"include\": [\"aspectNames\", \"properties\"]}"; + + public SerializerTestHelper() + { + this.jsonHelper = new JacksonHelper(); + RestJsonModule module = new RestJsonModule(); + jsonHelper.setModule(module); + try + { + jsonHelper.afterPropertiesSet(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + private SearchQuery extractFromJson(String json) throws IOException + { + Content content = mock(Content.class); + when(content.getReader()).thenReturn(new StringReader(json)); + WebScriptRequest request = mock(WebScriptRequest.class); + when(request.getContent()).thenReturn(content); + return extractJsonContent(request, jsonHelper, SearchQuery.class); + } + + public SearchQuery searchQueryFromJson() throws IOException + { + return extractFromJson(JSON); + } +}