You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AppAction.java 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. * SonarQube, open source software quality management tool.
  3. * Copyright (C) 2008-2014 SonarSource
  4. * mailto:contact AT sonarsource DOT com
  5. *
  6. * SonarQube is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * SonarQube is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.server.component.ws;
  21. import java.util.List;
  22. import java.util.Map;
  23. import javax.annotation.CheckForNull;
  24. import javax.annotation.Nullable;
  25. import org.apache.commons.lang.BooleanUtils;
  26. import org.sonar.api.i18n.I18n;
  27. import org.sonar.api.measures.CoreMetrics;
  28. import org.sonar.api.measures.Metric;
  29. import org.sonar.api.server.ws.Request;
  30. import org.sonar.api.server.ws.RequestHandler;
  31. import org.sonar.api.server.ws.Response;
  32. import org.sonar.api.server.ws.WebService;
  33. import org.sonar.api.utils.Durations;
  34. import org.sonar.api.utils.text.JsonWriter;
  35. import org.sonar.api.web.UserRole;
  36. import org.sonar.db.component.ComponentDto;
  37. import org.sonar.db.measure.MeasureDto;
  38. import org.sonar.db.DbSession;
  39. import org.sonar.db.MyBatis;
  40. import org.sonar.db.property.PropertyDto;
  41. import org.sonar.db.property.PropertyQuery;
  42. import org.sonar.server.db.DbClient;
  43. import org.sonar.server.exceptions.NotFoundException;
  44. import org.sonar.server.user.UserSession;
  45. import static com.google.common.collect.Lists.newArrayList;
  46. import static com.google.common.collect.Maps.newHashMap;
  47. public class AppAction implements RequestHandler {
  48. private static final String PARAM_UUID = "uuid";
  49. private static final String PARAM_PERIOD = "period";
  50. private static final List<String> METRIC_KEYS = newArrayList(CoreMetrics.LINES_KEY, CoreMetrics.VIOLATIONS_KEY,
  51. CoreMetrics.COVERAGE_KEY, CoreMetrics.IT_COVERAGE_KEY, CoreMetrics.OVERALL_COVERAGE_KEY,
  52. CoreMetrics.DUPLICATED_LINES_DENSITY_KEY, CoreMetrics.TESTS_KEY,
  53. CoreMetrics.TECHNICAL_DEBT_KEY, CoreMetrics.SQALE_RATING_KEY, CoreMetrics.SQALE_DEBT_RATIO_KEY);
  54. private final DbClient dbClient;
  55. private final Durations durations;
  56. private final I18n i18n;
  57. private final UserSession userSession;
  58. public AppAction(DbClient dbClient, Durations durations, I18n i18n, UserSession userSession) {
  59. this.dbClient = dbClient;
  60. this.durations = durations;
  61. this.i18n = i18n;
  62. this.userSession = userSession;
  63. }
  64. void define(WebService.NewController controller) {
  65. WebService.NewAction action = controller.createAction("app")
  66. .setDescription("Coverage data required for rendering the component viewer")
  67. .setSince("4.4")
  68. .setInternal(true)
  69. .setHandler(this);
  70. action
  71. .createParam(PARAM_UUID)
  72. .setRequired(true)
  73. .setDescription("Component UUID")
  74. .setExampleValue("d6d9e1e5-5e13-44fa-ab82-3ec29efa8935");
  75. action
  76. .createParam(PARAM_PERIOD)
  77. .setDescription("Period index in order to get differential measures")
  78. .setPossibleValues(1, 2, 3, 4, 5);
  79. }
  80. @Override
  81. public void handle(Request request, Response response) {
  82. String componentUuid = request.mandatoryParam(PARAM_UUID);
  83. JsonWriter json = response.newJsonWriter();
  84. json.beginObject();
  85. DbSession session = dbClient.openSession(false);
  86. try {
  87. ComponentDto component = dbClient.componentDao().selectNullableByUuid(session, componentUuid);
  88. if (component == null) {
  89. throw new NotFoundException(String.format("Component '%s' does not exist", componentUuid));
  90. }
  91. userSession.checkComponentPermission(UserRole.USER, component.getKey());
  92. Map<String, MeasureDto> measuresByMetricKey = measuresByMetricKey(component, session);
  93. appendComponent(json, component, userSession, session);
  94. appendPermissions(json, component, userSession);
  95. appendMeasures(json, measuresByMetricKey);
  96. } finally {
  97. MyBatis.closeQuietly(session);
  98. }
  99. json.endObject();
  100. json.close();
  101. }
  102. private void appendComponent(JsonWriter json, ComponentDto component, UserSession userSession, DbSession session) {
  103. List<PropertyDto> propertyDtos = dbClient.propertiesDao().selectByQuery(PropertyQuery.builder()
  104. .setKey("favourite")
  105. .setComponentId(component.getId())
  106. .setUserId(userSession.getUserId())
  107. .build(),
  108. session
  109. );
  110. boolean isFavourite = propertyDtos.size() == 1;
  111. json.prop("key", component.key());
  112. json.prop("uuid", component.uuid());
  113. json.prop("path", component.path());
  114. json.prop("name", component.name());
  115. json.prop("longName", component.longName());
  116. json.prop("q", component.qualifier());
  117. ComponentDto parentProject = nullableComponentById(component.parentProjectId(), session);
  118. ComponentDto project = dbClient.componentDao().selectByUuid(session, component.projectUuid());
  119. // Do not display parent project if parent project and project are the same
  120. boolean displayParentProject = parentProject != null && !parentProject.getId().equals(project.getId());
  121. json.prop("subProject", displayParentProject ? parentProject.key() : null);
  122. json.prop("subProjectName", displayParentProject ? parentProject.longName() : null);
  123. json.prop("project", project.key());
  124. json.prop("projectName", project.longName());
  125. json.prop("fav", isFavourite);
  126. }
  127. private static void appendPermissions(JsonWriter json, ComponentDto component, UserSession userSession) {
  128. boolean hasBrowsePermission = userSession.hasComponentPermission(UserRole.USER, component.key());
  129. json.prop("canMarkAsFavourite", userSession.isLoggedIn() && hasBrowsePermission);
  130. json.prop("canCreateManualIssue", userSession.isLoggedIn() && hasBrowsePermission);
  131. }
  132. private void appendMeasures(JsonWriter json, Map<String, MeasureDto> measuresByMetricKey) {
  133. json.name("measures").beginObject();
  134. json.prop("lines", formatMeasure(measuresByMetricKey.get(CoreMetrics.LINES_KEY)));
  135. json.prop("coverage", formatMeasure(coverageMeasure(measuresByMetricKey)));
  136. json.prop("duplicationDensity", formatMeasure(measuresByMetricKey.get(CoreMetrics.DUPLICATED_LINES_DENSITY_KEY)));
  137. json.prop("issues", formatMeasure(measuresByMetricKey.get(CoreMetrics.VIOLATIONS_KEY)));
  138. json.prop("tests", formatMeasure(measuresByMetricKey.get(CoreMetrics.TESTS_KEY)));
  139. json.prop("debt", formatMeasure(measuresByMetricKey.get(CoreMetrics.TECHNICAL_DEBT_KEY)));
  140. json.prop("sqaleRating", formatMeasure(measuresByMetricKey.get(CoreMetrics.SQALE_RATING_KEY)));
  141. json.prop("debtRatio", formatMeasure(measuresByMetricKey.get(CoreMetrics.SQALE_DEBT_RATIO_KEY)));
  142. json.endObject();
  143. }
  144. private static MeasureDto coverageMeasure(Map<String, MeasureDto> measuresByMetricKey) {
  145. MeasureDto overallCoverage = measuresByMetricKey.get(CoreMetrics.OVERALL_COVERAGE_KEY);
  146. MeasureDto itCoverage = measuresByMetricKey.get(CoreMetrics.IT_COVERAGE_KEY);
  147. MeasureDto utCoverage = measuresByMetricKey.get(CoreMetrics.COVERAGE_KEY);
  148. if (overallCoverage != null) {
  149. return overallCoverage;
  150. } else if (utCoverage != null) {
  151. return utCoverage;
  152. } else {
  153. return itCoverage;
  154. }
  155. }
  156. private Map<String, MeasureDto> measuresByMetricKey(ComponentDto component, DbSession session) {
  157. Map<String, MeasureDto> measuresByMetricKey = newHashMap();
  158. String fileKey = component.getKey();
  159. for (MeasureDto measureDto : dbClient.measureDao().findByComponentKeyAndMetricKeys(session, fileKey, METRIC_KEYS)) {
  160. measuresByMetricKey.put(measureDto.getMetricKey(), measureDto);
  161. }
  162. return measuresByMetricKey;
  163. }
  164. @CheckForNull
  165. private ComponentDto nullableComponentById(@Nullable Long componentId, DbSession session) {
  166. if (componentId != null) {
  167. return dbClient.componentDao().selectById(componentId, session);
  168. }
  169. return null;
  170. }
  171. @CheckForNull
  172. private String formatMeasure(@Nullable MeasureDto measure) {
  173. if (measure == null) {
  174. return null;
  175. }
  176. Metric metric = CoreMetrics.getMetric(measure.getMetricKey());
  177. Metric.ValueType metricType = metric.getType();
  178. Double value = getDoubleValue(measure, metric);
  179. String data = measure.getData();
  180. if (value != null) {
  181. switch (metricType) {
  182. case FLOAT:
  183. return i18n.formatDouble(userSession.locale(), value);
  184. case INT:
  185. return i18n.formatInteger(userSession.locale(), value.intValue());
  186. case PERCENT:
  187. return i18n.formatDouble(userSession.locale(), value) + "%";
  188. case WORK_DUR:
  189. return durations.format(userSession.locale(), durations.create(value.longValue()), Durations.DurationFormat.SHORT);
  190. }
  191. }
  192. if ((metricType.equals(Metric.ValueType.STRING) || metricType.equals(Metric.ValueType.RATING)) && data != null) {
  193. return data;
  194. }
  195. return null;
  196. }
  197. @CheckForNull
  198. private static Double getDoubleValue(MeasureDto measure, Metric metric){
  199. Double value = measure.getValue();
  200. if (BooleanUtils.isTrue(metric.isOptimizedBestValue()) && value == null) {
  201. value = metric.getBestValue();
  202. }
  203. return value;
  204. }
  205. }