diff --git a/control-base/src/main/java/fi/nls/oskari/control/data/GetSearchResultHandler.java b/control-base/src/main/java/fi/nls/oskari/control/data/GetSearchResultHandler.java index 6ff9eb1444..cc25ef7b3c 100755 --- a/control-base/src/main/java/fi/nls/oskari/control/data/GetSearchResultHandler.java +++ b/control-base/src/main/java/fi/nls/oskari/control/data/GetSearchResultHandler.java @@ -9,10 +9,15 @@ import fi.nls.oskari.control.ActionHandler; import fi.nls.oskari.control.ActionParameters; import fi.nls.oskari.control.ActionParamsException; +import fi.nls.oskari.util.ConversionHelper; +import fi.nls.oskari.util.JSONHelper; import fi.nls.oskari.util.PropertyUtil; import fi.nls.oskari.util.ResponseHelper; +import org.json.JSONObject; +import java.util.Collections; import java.util.Locale; +import java.util.Map; @OskariActionRoute("GetSearchResult") public class GetSearchResultHandler extends ActionHandler { @@ -51,7 +56,18 @@ public void handleAction(final ActionParameters params) throws ActionException { // default to configuration String[] channelIds = channels; final String channelParam = params.getHttpParam(PARAM_CHANNELIDS_KEY, "").trim(); - + Map options = getOptions(params.getHttpParam("options")); + options.forEach((key, value) -> { + if (key.equals("limit")) { + if (value instanceof String) { + sc.setMaxResults(ConversionHelper.getInt((String)value, -1)); + } else if (value instanceof Number) { + sc.setMaxResults(((Number) value).intValue()); + } + } else { + sc.addParam(key, value); + } + }); // if channels defined in request, use channels from request if(!channelParam.isEmpty()) { channelIds = channelParam.split("\\s*,\\s*"); @@ -70,4 +86,12 @@ public void handleAction(final ActionParameters params) throws ActionException { ResponseHelper.writeResponse(params, SearchWorker.doSearch(sc)); } } + + private Map getOptions(String json) { + if (json == null) { + return Collections.emptyMap(); + } + JSONObject tmp = JSONHelper.createJSONObject(json); + return JSONHelper.getObjectAsMap(tmp); + } } diff --git a/service-search/src/main/java/fi/mml/portti/service/search/SearchCriteria.java b/service-search/src/main/java/fi/mml/portti/service/search/SearchCriteria.java index 533537e11a..5eb9e06fa7 100755 --- a/service-search/src/main/java/fi/mml/portti/service/search/SearchCriteria.java +++ b/service-search/src/main/java/fi/mml/portti/service/search/SearchCriteria.java @@ -1,5 +1,6 @@ package fi.mml.portti.service.search; +import fi.nls.oskari.SearchWorker; import fi.nls.oskari.domain.User; import fi.nls.oskari.service.ServiceException; import fi.nls.oskari.service.UserService; @@ -147,7 +148,7 @@ public int getMaxResults() { } public void setMaxResults(int maxResults) { - this.maxResults = maxResults; + this.maxResults = SearchWorker.getMaxResults(maxResults); } public List getChannels() { diff --git a/service-search/src/main/java/fi/mml/portti/service/search/SearchService.java b/service-search/src/main/java/fi/mml/portti/service/search/SearchService.java index 749b2cb63f..c24790e6f0 100755 --- a/service-search/src/main/java/fi/mml/portti/service/search/SearchService.java +++ b/service-search/src/main/java/fi/mml/portti/service/search/SearchService.java @@ -8,39 +8,59 @@ import java.util.Map; - /** * Interface to service that searches all the channels. */ public abstract class SearchService extends OskariComponent { - private int maxCount = -1; - - @Override - public void init() { - super.init(); - } - - /** - * Makes a search with given criteria - * - * @param searchCriteria - * @return Query - */ - public abstract Query doSearch(SearchCriteria searchCriteria); - public abstract JSONObject doSearchAutocomplete(SearchCriteria searchCriteria); - public abstract void addChannel(String channelId, SearchableChannel searchableChannel); + private int maxCount = -1; + private int hardLimit = -1; + + @Override + public void init() { + super.init(); + } + + /** + * Makes a search with given criteria + * + * @param searchCriteria + * @return Query + */ + public abstract Query doSearch(SearchCriteria searchCriteria); + public abstract JSONObject doSearchAutocomplete(SearchCriteria searchCriteria); + public abstract void addChannel(String channelId, SearchableChannel searchableChannel); public abstract Map getAvailableChannels(); - /** - * Returns a generic maximum results instruction for search functions. - * SearchChannels/implementations may opt to use this to - * @return maxCount - Search results max count + /** + * Returns a generic maximum results instruction for search functions. + * SearchChannels/implementations may opt to use this to + * Can be configured with search.max.results property. + * Defaults to 100. + * @return maxCount - Search results max count + */ + public int getMaxResultsCount() { + if (maxCount == -1) { + maxCount = ConversionHelper.getInt(PropertyUtil.getOptional("search.max.results"), 100); + } + if (hardLimit > 0 && maxCount > hardLimit) { + // sanity-check limit can't be bigger than hard limit if it has been configured + maxCount = hardLimit; + } + return maxCount; + } + + /** + * Returns instance limit for maximum results instruction for search functions. + * SearchChannels/implementations may opt to use this to. + * Can be configured with search.max.results.hardlimit property. + * Defaults to 10x max count. + * @return hard limit for search results. Client can't ask more than this */ - public int getMaxResultsCount() { - if (maxCount == -1) { - maxCount = ConversionHelper.getInt(PropertyUtil.getOptional("search.max.results"), 100); - } - return maxCount; - } + public int getMaxResultsHardLimit() { + if (hardLimit == -1) { + hardLimit = ConversionHelper.getInt(PropertyUtil.getOptional("search.max.results.hardlimit"), getMaxResultsCount() * 10); + } + return hardLimit; + } } diff --git a/service-search/src/main/java/fi/nls/oskari/SearchWorker.java b/service-search/src/main/java/fi/nls/oskari/SearchWorker.java index 46a9a3a81d..0b523de321 100755 --- a/service-search/src/main/java/fi/nls/oskari/SearchWorker.java +++ b/service-search/src/main/java/fi/nls/oskari/SearchWorker.java @@ -52,16 +52,22 @@ public static String checkLegalSearch(String searchString) { } /** + * Returns the maximum amount of search results that should be queried. + * If requested is negative value, returns configured max results count. + * Requested count is checked against result hard limit which might be lower than the client requests * Returns the parameter value if it's not -1 or more than the maximum result count. * @param requested * @return maximum value of results or requested, which ever is smaller. */ public static int getMaxResults(int requested) { + int hardLimit = searchService.getMaxResultsHardLimit(); int maximum = searchService.getMaxResultsCount(); - if(requested != -1 && requested < maximum) { - return requested; + if (requested < 0) { + return maximum; + } else if (hardLimit > 0 && requested > hardLimit) { + return hardLimit; } - return maximum; + return requested; } /** @@ -71,7 +77,7 @@ public static int getMaxResults(int requested) { * @return result - Search results */ public static JSONObject doSearch(final SearchCriteria sc) { - + Query query = searchService.doSearch(sc); int maxResults = getMaxResults(sc.getMaxResults()); List items = query.getSortedResults(maxResults + 1);