Java tutorial
/* * 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.issue.ws; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import org.sonar.api.component.Component; import org.sonar.api.i18n.I18n; import org.sonar.api.issue.*; import org.sonar.api.issue.action.Action; import org.sonar.api.issue.internal.DefaultIssue; import org.sonar.api.issue.internal.FieldDiffs; import org.sonar.api.server.debt.DebtCharacteristic; import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic; 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.user.User; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.Duration; import org.sonar.api.utils.Durations; import org.sonar.api.utils.text.JsonWriter; import org.sonar.api.web.UserRole; import org.sonar.core.component.ComponentDto; import org.sonar.core.issue.workflow.Transition; import org.sonar.markdown.Markdown; import org.sonar.server.debt.DebtModelService; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.issue.ActionService; import org.sonar.server.issue.IssueChangelog; import org.sonar.server.issue.IssueChangelogService; import org.sonar.server.issue.IssueService; import org.sonar.server.user.UserSession; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import java.util.Arrays; import java.util.Date; import java.util.List; import static com.google.common.collect.Lists.newArrayList; public class IssueShowWsHandler implements RequestHandler { private final IssueFinder issueFinder; private final IssueService issueService; private final IssueChangelogService issueChangelogService; private final ActionService actionService; private final DebtModelService debtModel; private final I18n i18n; private final Durations durations; public IssueShowWsHandler(IssueFinder issueFinder, IssueService issueService, IssueChangelogService issueChangelogService, ActionService actionService, DebtModelService debtModel, I18n i18n, Durations durations) { this.issueFinder = issueFinder; this.issueService = issueService; this.issueChangelogService = issueChangelogService; this.actionService = actionService; this.debtModel = debtModel; this.i18n = i18n; this.durations = durations; } @Override public void handle(Request request, Response response) { String issueKey = request.mandatoryParam("key"); IssueQueryResult queryResult = issueFinder .find(IssueQuery.builder().issueKeys(Arrays.asList(issueKey)).build()); if (queryResult.issues().size() != 1) { throw new NotFoundException("Issue not found: " + issueKey); } DefaultIssue issue = (DefaultIssue) queryResult.first(); JsonWriter json = response.newJsonWriter(); json.beginObject().name("issue").beginObject(); writeIssue(queryResult, issue, json); writeTransitions(issue, json); writeActions(issue, json); writeComments(queryResult, issue, json); writeChangelog(issue, json); json.endObject().endObject().close(); } private void writeIssue(IssueQueryResult result, DefaultIssue issue, JsonWriter json) { String actionPlanKey = issue.actionPlanKey(); ActionPlan actionPlan = result.actionPlan(issue); Duration debt = issue.debt(); Date updateDate = issue.updateDate(); Date closeDate = issue.closeDate(); json.prop("key", issue.key()).prop("rule", issue.ruleKey().toString()) .prop("ruleName", result.rule(issue).getName()).prop("line", issue.line()) .prop("message", issue.message()).prop("resolution", issue.resolution()) .prop("status", issue.status()).prop("severity", issue.severity()) .prop("author", issue.authorLogin()).prop("actionPlan", actionPlanKey) .prop("actionPlanName", actionPlan != null ? actionPlan.name() : null) .prop("debt", debt != null ? durations.format(UserSession.get().locale(), debt, Durations.DurationFormat.SHORT) : null) .prop("creationDate", DateUtils.formatDateTime(issue.creationDate())) .prop("fCreationDate", formatDate(issue.creationDate())) .prop("updateDate", updateDate != null ? DateUtils.formatDateTime(updateDate) : null) .prop("fUpdateDate", formatDate(updateDate)).prop("fUpdateAge", formatAgeDate(updateDate)) .prop("closeDate", closeDate != null ? DateUtils.formatDateTime(closeDate) : null) .prop("fCloseDate", formatDate(issue.closeDate())); addComponents(result, issue, json); addUserWithLabel(result, issue.assignee(), "assignee", json); addUserWithLabel(result, issue.reporter(), "reporter", json); addCharacteristics(result, issue, json); } private void addComponents(IssueQueryResult result, DefaultIssue issue, JsonWriter json) { // component, module and project can be null if they were removed ComponentDto component = (ComponentDto) result.component(issue); ComponentDto subProject = (ComponentDto) getSubProject(result, component); ComponentDto project = (ComponentDto) geProject(result, component); String projectName = project != null ? project.longName() != null ? project.longName() : project.name() : null; // Do not display sub project long name if sub project and project are the same boolean shoudDisplaySubProjectLongName = subProject != null && project != null && !subProject.getId().equals(project.getId()); String subProjectName = shoudDisplaySubProjectLongName ? subProject.longName() != null ? subProject.longName() : subProject.name() : null; json.prop("component", issue.componentKey()) .prop("componentLongName", component != null ? component.longName() : null) .prop("componentQualifier", component != null ? component.qualifier() : null) .prop("project", issue.projectKey()).prop("projectName", projectName) // Do not display sub project long name if sub project and project are the same .prop("subProjectName", subProjectName); } /** * Can be null on project or on removed component */ @CheckForNull private Component getSubProject(IssueQueryResult result, @Nullable final ComponentDto component) { if (component != null) { return Iterables.find(result.components(), new Predicate<Component>() { @Override public boolean apply(Component input) { Long groupId = component.subProjectId(); return groupId != null && groupId.equals(((ComponentDto) input).getId()); } }, null); } return null; } /** * Can be null on removed component */ @CheckForNull private Component geProject(IssueQueryResult result, @Nullable final ComponentDto component) { if (component != null) { return Iterables.find(result.components(), new Predicate<Component>() { @Override public boolean apply(Component input) { return component.projectId().equals(((ComponentDto) input).getId()); } }, null); } return null; } private void addCharacteristics(IssueQueryResult result, DefaultIssue issue, JsonWriter json) { Integer subCharacteristicId = result.rule(issue).getCharacteristicId() != null ? result.rule(issue).getCharacteristicId() : result.rule(issue).getDefaultCharacteristicId(); DebtCharacteristic subCharacteristic = characteristicById(subCharacteristicId); if (subCharacteristic != null) { json.prop("subCharacteristic", subCharacteristic.name()); DebtCharacteristic characteristic = characteristicById( ((DefaultDebtCharacteristic) subCharacteristic).parentId()); json.prop("characteristic", characteristic != null ? characteristic.name() : null); } } @CheckForNull private DebtCharacteristic characteristicById(@Nullable Integer id) { if (id != null) { return debtModel.characteristicById(id); } return null; } private void writeTransitions(Issue issue, JsonWriter json) { json.name("transitions").beginArray(); if (UserSession.get().isLoggedIn()) { List<Transition> transitions = issueService.listTransitions(issue, UserSession.get()); for (Transition transition : transitions) { json.value(transition.key()); } } json.endArray(); } private void writeActions(DefaultIssue issue, JsonWriter json) { json.name("actions").beginArray(); for (String action : actions(issue)) { json.value(action); } json.endArray(); } // TODO all available actions should be returned by ActionService or another service private List<String> actions(DefaultIssue issue) { List<String> actions = newArrayList(); String login = UserSession.get().login(); if (login != null) { actions.add("comment"); if (issue.resolution() == null) { actions.add("assign"); if (!login.equals(issue.assignee())) { actions.add("assign_to_me"); } actions.add("plan"); String projectKey = issue.projectKey(); if (projectKey != null && UserSession.get().hasProjectPermission(UserRole.ISSUE_ADMIN, projectKey)) { actions.add("set_severity"); } for (Action action : actionService.listAvailableActions(issue)) { actions.add(action.key()); } } } return actions; } private void writeComments(IssueQueryResult queryResult, Issue issue, JsonWriter json) { json.name("comments").beginArray(); String login = UserSession.get().login(); for (IssueComment comment : issue.comments()) { String userLogin = comment.userLogin(); User user = userLogin != null ? queryResult.user(userLogin) : null; json.beginObject().prop("key", comment.key()).prop("userName", user != null ? user.name() : null) .prop("raw", comment.markdownText()) .prop("html", Markdown.convertToHtml(comment.markdownText())) .prop("createdAt", DateUtils.formatDateTime(comment.createdAt())) .prop("fCreatedAge", formatAgeDate(comment.createdAt())) .prop("updatable", login != null && login.equals(userLogin)).endObject(); } json.endArray(); } private void writeChangelog(Issue issue, JsonWriter json) { json.name("changelog").beginArray().beginObject() .prop("creationDate", DateUtils.formatDateTime(issue.creationDate())) .prop("fCreationDate", formatDate(issue.creationDate())).name("diffs").beginArray() .value(i18n.message(UserSession.get().locale(), "created", null)).endArray().endObject(); IssueChangelog changelog = issueChangelogService.changelog(issue); for (FieldDiffs diffs : changelog.changes()) { User user = changelog.user(diffs); json.beginObject().prop("userName", user != null ? user.name() : null) .prop("creationDate", DateUtils.formatDateTime(diffs.creationDate())) .prop("fCreationDate", formatDate(diffs.creationDate())); json.name("diffs").beginArray(); List<String> diffsFormatted = issueChangelogService.formatDiffs(diffs); for (String diff : diffsFormatted) { json.value(diff); } json.endArray(); json.endObject(); } json.endArray(); } private void addUserWithLabel(IssueQueryResult result, @Nullable String value, String field, JsonWriter json) { if (value != null) { User user = result.user(value); json.prop(field, value).prop(field + "Name", user != null ? user.name() : null); } } @CheckForNull private String formatDate(@Nullable Date date) { if (date != null) { return i18n.formatDateTime(UserSession.get().locale(), date); } return null; } @CheckForNull private String formatAgeDate(@Nullable Date date) { if (date != null) { return i18n.ageFromNow(UserSession.get().locale(), date); } return null; } }