From 4626491b61aa5fa33d39e5c0cf8ece638d68dd45 Mon Sep 17 00:00:00 2001 From: Teryk Bellahsene Date: Wed, 27 May 2015 17:44:53 +0200 Subject: [PATCH] refactoring - drop SearchRequestHandler --- .../sonar/server/issue/IssueQueryService.java | 6 +- .../sonar/server/rule/ws/SearchAction.java | 167 +++++++++++--- .../sonar/server/search/ws/SearchOptions.java | 1 - .../search/ws/SearchRequestHandler.java | 203 ------------------ 4 files changed, 144 insertions(+), 233 deletions(-) delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/search/ws/SearchRequestHandler.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java index 0c9d33b7f95..8fc90b871d3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueQueryService.java @@ -45,7 +45,7 @@ import org.sonar.core.persistence.DbSession; import org.sonar.server.component.ComponentService; import org.sonar.server.db.DbClient; import org.sonar.server.issue.filter.IssueFilterParameters; -import org.sonar.server.search.ws.SearchRequestHandler; +import org.sonar.server.rule.ws.SearchAction; import org.sonar.server.user.UserSession; import org.sonar.server.util.RubyUtils; @@ -196,10 +196,10 @@ public class IssueQueryService { request.paramAsStrings(IssueFilterParameters.FILE_UUIDS), request.paramAsStrings(IssueFilterParameters.AUTHORS)); - String sort = request.param(SearchRequestHandler.PARAM_SORT); + String sort = request.param(SearchAction.PARAM_SORT); if (!Strings.isNullOrEmpty(sort)) { builder.sort(sort); - builder.asc(request.paramAsBoolean(SearchRequestHandler.PARAM_ASCENDING)); + builder.asc(request.paramAsBoolean(SearchAction.PARAM_ASCENDING)); } return builder.build(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java index 4cf9dafb973..2ee7424a24c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/SearchAction.java @@ -22,11 +22,23 @@ package org.sonar.server.rule.ws; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import com.google.common.io.Resources; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; import org.sonar.api.rule.RuleStatus; import org.sonar.api.rule.Severity; import org.sonar.api.server.debt.DebtCharacteristic; import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.text.JsonWriter; import org.sonar.core.qualityprofile.db.QualityProfileDto; @@ -41,18 +53,13 @@ import org.sonar.server.search.QueryContext; import org.sonar.server.search.Result; import org.sonar.server.search.ws.SearchOptions; import org.sonar.server.search.ws.SearchRequestHandler; - -import javax.annotation.CheckForNull; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; import org.sonar.server.user.UserSession; /** * @since 4.4 */ -public class SearchAction extends SearchRequestHandler implements RulesWsAction { +public class SearchAction implements RulesWsAction, org.sonar.api.server.ws.RequestHandler { + public static final String ACTION = "search"; public static final String PARAM_REPOSITORIES = "repositories"; public static final String PARAM_KEY = "rule_key"; @@ -69,22 +76,76 @@ public class SearchAction extends SearchRequestHandler implemen public static final String PARAM_ACTIVE_SEVERITIES = "active_severities"; public static final String PARAM_IS_TEMPLATE = "is_template"; public static final String PARAM_TEMPLATE_KEY = "template_key"; - public static final String SEARCH_ACTION = "search"; + + public static final String PARAM_PAGE = "p"; + public static final String PARAM_PAGE_SIZE = "ps"; + public static final String PARAM_FIELDS = "f"; + public static final String PARAM_SORT = "s"; + public static final String PARAM_ASCENDING = "asc"; + public static final String PARAM_FACETS = "facets"; private static final Collection DEFAULT_FACETS = ImmutableSet.of(PARAM_LANGUAGES, PARAM_REPOSITORIES, "tags"); private final RuleService ruleService; private final ActiveRuleCompleter activeRuleCompleter; private final RuleMapping mapping; + private final UserSession userSession; public SearchAction(RuleService service, ActiveRuleCompleter activeRuleCompleter, RuleMapping mapping, UserSession userSession) { - super(SEARCH_ACTION, userSession); + this.userSession = userSession; this.ruleService = service; this.activeRuleCompleter = activeRuleCompleter; this.mapping = mapping; } @Override + public void define(WebService.NewController controller) { + WebService.NewAction action = controller.createAction(ACTION) + .addPagingParams(100) + .setHandler(this); + + Collection possibleFacets = possibleFacets(); + WebService.NewParam paramFacets = action.createParam(PARAM_FACETS) + .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.") + .setPossibleValues(possibleFacets); + if (possibleFacets != null && possibleFacets.size() > 1) { + Iterator it = possibleFacets.iterator(); + paramFacets.setExampleValue(String.format("%s,%s", it.next(), it.next())); + } + + Collection possibleFields = possibleFields(); + WebService.NewParam paramFields = action.createParam(PARAM_FIELDS) + .setDescription("Comma-separated list of the fields to be returned in response. All the fields are returned by default.") + .setPossibleValues(possibleFields); + if (possibleFields != null && possibleFields.size() > 1) { + Iterator it = possibleFields.iterator(); + paramFields.setExampleValue(String.format("%s,%s", it.next(), it.next())); + } + + this.doDefinition(action); + } + + @Override + public void handle(Request request, Response response) throws Exception { + QueryContext context = getQueryContext(request); + RuleQuery query = doQuery(request); + Result result = doSearch(query, context); + + JsonWriter json = response.newJsonWriter().beginObject(); + writeStatistics(json, result, context); + doContextResponse(request, result, json); + if (context.isFacet()) { + writeFacets(request, context, result, json); + } + json.endObject().close(); + } + + protected void writeStatistics(JsonWriter json, Result searchResult, QueryContext context) { + json.prop("total", searchResult.getTotal()); + json.prop(SearchAction.PARAM_PAGE, context.getPage()); + json.prop(SearchAction.PARAM_PAGE_SIZE, context.getLimit()); + } + protected void doDefinition(WebService.NewAction action) { action.setDescription("Search for a collection of relevant rules matching a specified query") .setResponseExample(Resources.getResource(getClass(), "example-search.json")) @@ -95,10 +156,9 @@ public class SearchAction extends SearchRequestHandler implemen defineRuleSearchParameters(action); } - @Override @CheckForNull protected Collection possibleFacets() { - return Arrays.asList(new String[] { + return Arrays.asList( RuleIndex.FACET_LANGUAGES, RuleIndex.FACET_REPOSITORIES, RuleIndex.FACET_TAGS, @@ -107,7 +167,7 @@ public class SearchAction extends SearchRequestHandler implemen RuleIndex.FACET_ACTIVE_SEVERITIES, RuleIndex.FACET_STATUSES, RuleIndex.FACET_OLD_DEFAULT - }); + ); } /** @@ -254,10 +314,9 @@ public class SearchAction extends SearchRequestHandler implemen json.endArray(); } - @Override protected QueryContext getQueryContext(Request request) { // TODO Get rid of this horrible hack: fields on request are not the same as fields for ES search ! 1/2 - QueryContext context = super.getQueryContext(request); + QueryContext context = loadCommonContext(request); QueryContext searchQueryContext = mapping.newQueryOptions(SearchOptions.create(request)) .setLimit(context.getLimit()) .setOffset(context.getOffset()) @@ -270,12 +329,25 @@ public class SearchAction extends SearchRequestHandler implemen return searchQueryContext; } - @Override + private QueryContext loadCommonContext(Request request) { + int pageSize = request.mandatoryParamAsInt(SearchAction.PARAM_PAGE_SIZE); + QueryContext context = new QueryContext(userSession).addFieldsToReturn(request.paramAsStrings(SearchAction.PARAM_FIELDS)); + List facets = request.paramAsStrings(SearchAction.PARAM_FACETS); + if (facets != null) { + context.addFacets(facets); + } + if (pageSize < 1) { + context.setPage(request.mandatoryParamAsInt(SearchAction.PARAM_PAGE), 0).setMaxLimit(); + } else { + context.setPage(request.mandatoryParamAsInt(SearchAction.PARAM_PAGE), pageSize); + } + return context; + } + protected Result doSearch(RuleQuery query, QueryContext context) { return ruleService.search(query, context); } - @Override protected RuleQuery doQuery(Request request) { RuleQuery plainQuery = createRuleQuery(ruleService.newRuleQuery(), request); @@ -290,26 +362,21 @@ public class SearchAction extends SearchRequestHandler implemen return plainQuery; } - @Override - protected void doContextResponse(Request request, QueryContext context, Result result, JsonWriter json) { + protected void doContextResponse(Request request, Result result, JsonWriter json) { // TODO Get rid of this horrible hack: fields on request are not the same as fields for ES search ! 2/2 - QueryContext contextForResponse = super.getQueryContext(request); + QueryContext contextForResponse = loadCommonContext(request); writeRules(result, json, contextForResponse); if (contextForResponse.getFieldsToReturn().contains("actives")) { activeRuleCompleter.completeSearch(doQuery(request), result.getHits(), json); } } - @Override protected Collection possibleFields() { - Builder builder = ImmutableList.builder(); - if (mapping != null) { - builder.addAll(mapping.supportedFields()); - } + Builder builder = ImmutableList.builder(); + builder.addAll(mapping.supportedFields()); return builder.add("actives").build(); } - @Override protected void writeFacets(Request request, QueryContext context, Result results, JsonWriter json) { addMandatoryFacetValues(results, RuleIndex.FACET_DEBT_CHARACTERISTICS, request.paramAsStrings(PARAM_DEBT_CHARACTERISTICS)); addMandatoryFacetValues(results, RuleIndex.FACET_LANGUAGES, request.paramAsStrings(PARAM_LANGUAGES)); @@ -321,7 +388,25 @@ public class SearchAction extends SearchRequestHandler implemen mergeNoneAndEmptyBucketOnCharacteristics(results); - super.writeFacets(request, context, results, json); + json.name("facets").beginArray(); + for (String facetName : context.facets()) { + json.beginObject(); + json.prop("property", facetName); + json.name("values").beginArray(); + if (results.getFacets().containsKey(facetName)) { + Set itemsFromFacets = Sets.newHashSet(); + for (FacetValue facetValue : results.getFacets().get(facetName)) { + itemsFromFacets.add(facetValue.getKey()); + json.beginObject(); + json.prop("val", facetValue.getKey()); + json.prop("count", facetValue.getValue()); + json.endObject(); + } + addZeroFacetsForSelectedItems(request, facetName, itemsFromFacets, json); + } + json.endArray().endObject(); + } + json.endArray(); } protected void mergeNoneAndEmptyBucketOnCharacteristics(Result results) { @@ -345,4 +430,34 @@ public class SearchAction extends SearchRequestHandler implemen characValues.add(mergedNoneValue); } } + + private void addZeroFacetsForSelectedItems(Request request, String facetName, Set itemsFromFacets, JsonWriter json) { + List requestParams = request.paramAsStrings(facetName); + if (requestParams != null) { + for (String param : requestParams) { + if (!itemsFromFacets.contains(param)) { + json.beginObject(); + json.prop("val", param); + json.prop("count", 0); + json.endObject(); + } + } + } + } + + protected void addMandatoryFacetValues(Result results, String facetName, @Nullable List mandatoryValues) { + Collection facetValues = results.getFacetValues(facetName); + if (facetValues != null) { + Map valuesByItem = Maps.newHashMap(); + for (FacetValue value : facetValues) { + valuesByItem.put(value.getKey(), value.getValue()); + } + List valuesToAdd = mandatoryValues == null ? Lists.newArrayList() : mandatoryValues; + for (String item : valuesToAdd) { + if (!valuesByItem.containsKey(item)) { + facetValues.add(new FacetValue(item, 0)); + } + } + } + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/ws/SearchOptions.java b/server/sonar-server/src/main/java/org/sonar/server/search/ws/SearchOptions.java index 858116c2504..e162db5d59b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/search/ws/SearchOptions.java +++ b/server/sonar-server/src/main/java/org/sonar/server/search/ws/SearchOptions.java @@ -35,7 +35,6 @@ import java.util.List; /** * Generic options for search web services * - * TODO {@link org.sonar.server.search.ws.SearchRequestHandler} should be used instead */ public class SearchOptions { diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/ws/SearchRequestHandler.java b/server/sonar-server/src/main/java/org/sonar/server/search/ws/SearchRequestHandler.java deleted file mode 100644 index 5481a4b2e55..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/search/ws/SearchRequestHandler.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube 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. - * - * SonarQube 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.search.ws; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.RequestHandler; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.server.search.FacetValue; -import org.sonar.server.search.QueryContext; -import org.sonar.server.search.Result; - -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; - -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.sonar.server.user.UserSession; - -public abstract class SearchRequestHandler implements RequestHandler { - - public static final String PARAM_PAGE = "p"; - public static final String PARAM_PAGE_SIZE = "ps"; - public static final String PARAM_FIELDS = "f"; - public static final String PARAM_SORT = "s"; - public static final String PARAM_ASCENDING = "asc"; - - public static final String PARAM_FACETS = "facets"; - - private final String actionName; - protected final UserSession userSession; - - protected SearchRequestHandler(String actionName, UserSession userSession) { - this.actionName = actionName; - this.userSession = userSession; - } - - protected abstract Result doSearch(QUERY query, QueryContext context); - - protected abstract QUERY doQuery(Request request); - - protected abstract void doContextResponse(Request request, QueryContext context, Result result, JsonWriter json); - - protected abstract void doDefinition(WebService.NewAction action); - - @CheckForNull - protected abstract Collection possibleFields(); - - @CheckForNull - protected abstract Collection possibleFacets(); - - public final void define(WebService.NewController controller) { - WebService.NewAction action = controller.createAction(this.actionName) - .setHandler(this); - - action - .createParam(PARAM_PAGE) - .setDeprecatedKey("pageIndex") - .setDescription("1-based page number") - .setExampleValue("42") - .setDefaultValue("1"); - - action - .createParam(PARAM_PAGE_SIZE) - .setDeprecatedKey("pageSize") - .setDescription(String.format("Page size (-1 return up to %s).", QueryContext.MAX_LIMIT)) - .setExampleValue("20") - .setDefaultValue("100"); - - Collection possibleFacets = possibleFacets(); - WebService.NewParam paramFacets = action.createParam(PARAM_FACETS) - .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.") - .setPossibleValues(possibleFacets); - if (possibleFacets != null && possibleFacets.size() > 1) { - Iterator it = possibleFacets.iterator(); - paramFacets.setExampleValue(String.format("%s,%s", it.next(), it.next())); - } - - Collection possibleFields = possibleFields(); - WebService.NewParam paramFields = action.createParam(PARAM_FIELDS) - .setDescription("Comma-separated list of the fields to be returned in response. All the fields are returned by default.") - .setPossibleValues(possibleFields); - if (possibleFields != null && possibleFields.size() > 1) { - Iterator it = possibleFields.iterator(); - paramFields.setExampleValue(String.format("%s,%s", it.next(), it.next())); - } - - this.doDefinition(action); - } - - @Override - public final void handle(Request request, Response response) throws Exception { - QueryContext context = getQueryContext(request); - QUERY query = doQuery(request); - Result result = doSearch(query, context); - - JsonWriter json = response.newJsonWriter().beginObject(); - this.writeStatistics(json, result, context); - doContextResponse(request, context, result, json); - if (context.isFacet()) { - writeFacets(request, context, result, json); - } - json.endObject().close(); - } - - protected QueryContext getQueryContext(Request request) { - int pageSize = request.mandatoryParamAsInt(PARAM_PAGE_SIZE); - QueryContext queryContext = new QueryContext(userSession).addFieldsToReturn(request.paramAsStrings(PARAM_FIELDS)); - List facets = request.paramAsStrings(PARAM_FACETS); - if(facets != null) { - queryContext.addFacets(facets); - } - if (pageSize < 1) { - queryContext.setPage(request.mandatoryParamAsInt(PARAM_PAGE), 0).setMaxLimit(); - } else { - queryContext.setPage(request.mandatoryParamAsInt(PARAM_PAGE), pageSize); - } - return queryContext; - } - - protected void writeStatistics(JsonWriter json, Result searchResult, QueryContext context) { - json.prop("total", searchResult.getTotal()); - json.prop(PARAM_PAGE, context.getPage()); - json.prop(PARAM_PAGE_SIZE, context.getLimit()); - } - - protected void writeFacets(Request request, QueryContext context, Result results, JsonWriter json) { - json.name("facets").beginArray(); - for (String facetName: context.facets()) { - json.beginObject(); - json.prop("property", facetName); - json.name("values").beginArray(); - if (results.getFacets().containsKey(facetName)) { - Set itemsFromFacets = Sets.newHashSet(); - for (FacetValue facetValue : results.getFacets().get(facetName)) { - itemsFromFacets.add(facetValue.getKey()); - json.beginObject(); - json.prop("val", facetValue.getKey()); - json.prop("count", facetValue.getValue()); - json.endObject(); - } - addZeroFacetsForSelectedItems(request, facetName, itemsFromFacets, json); - } - json.endArray().endObject(); - } - json.endArray(); - } - - private void addZeroFacetsForSelectedItems(Request request, String facetName, Set itemsFromFacets, JsonWriter json) { - List requestParams = request.paramAsStrings(facetName); - if (requestParams != null) { - for (String param: requestParams) { - if (!itemsFromFacets.contains(param)) { - json.beginObject(); - json.prop("val", param); - json.prop("count", 0); - json.endObject(); - } - } - } - } - - protected void addMandatoryFacetValues(Result results, String facetName, @Nullable List mandatoryValues) { - Collection facetValues = results.getFacetValues(facetName); - if (facetValues != null) { - Map valuesByItem = Maps.newHashMap(); - for (FacetValue value : facetValues) { - valuesByItem.put(value.getKey(), value.getValue()); - } - List valuesToAdd = mandatoryValues == null ? Lists.newArrayList() : mandatoryValues; - for (String item : valuesToAdd) { - if (!valuesByItem.containsKey(item)) { - facetValues.add(new FacetValue(item, 0)); - } - } - } - } - -} -- 2.39.5