All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.db.issue.IssueDto Maven / Gradle / Ivy

There is a newer version: 6.3.1
Show newest version
/*
 * SonarQube
 * Copyright (C) 2009-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program 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.
 *
 * This program 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.db.issue;

import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.InvalidProtocolBufferException;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.sonar.api.resources.Project;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.core.issue.DefaultIssue;
import org.sonar.core.util.Uuids;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.protobuf.DbIssues;
import org.sonar.db.rule.RuleDto;

import static com.google.common.base.Preconditions.checkArgument;
import static org.sonar.api.utils.DateUtils.dateToLong;
import static org.sonar.api.utils.DateUtils.longToDate;

public final class IssueDto implements Serializable {

  private static final char TAGS_SEPARATOR = ',';
  private static final Joiner TAGS_JOINER = Joiner.on(TAGS_SEPARATOR).skipNulls();
  private static final Splitter TAGS_SPLITTER = Splitter.on(',').trimResults().omitEmptyStrings();

  private Long id;
  private int type;
  private String kee;
  private String componentUuid;
  private String projectUuid;
  private Integer ruleId;
  private String severity;
  private boolean manualSeverity;
  private String message;
  private Integer line;
  private Double gap;
  private Long effort;
  private String status;
  private String resolution;
  private String checksum;
  private String assignee;
  private String authorLogin;
  private String issueAttributes;
  private byte[] locations;
  private long createdAt;
  private long updatedAt;

  // functional dates stored as Long
  private Long issueCreationDate;
  private Long issueUpdateDate;
  private Long issueCloseDate;

  /**
   * Temporary date used only during scan
   */
  private Long selectedAt;

  // joins
  private String ruleKey;
  private String ruleRepo;
  private String language;
  private String componentKey;
  private String moduleUuid;
  private String moduleUuidPath;
  private String projectKey;
  private String filePath;
  private String tags;

  /**
   * On batch side, component keys and uuid are useless
   */
  public static IssueDto toDtoForComputationInsert(DefaultIssue issue, int ruleId, long now) {
    return new IssueDto()
      .setKee(issue.key())
      .setType(issue.type())
      .setLine(issue.line())
      .setLocations((DbIssues.Locations) issue.getLocations())
      .setMessage(issue.message())
      .setGap(issue.gap())
      .setEffort(issue.effortInMinutes())
      .setResolution(issue.resolution())
      .setStatus(issue.status())
      .setSeverity(issue.severity())
      .setManualSeverity(issue.manualSeverity())
      .setChecksum(issue.checksum())
      .setAssignee(issue.assignee())
      .setRuleId(ruleId)
      .setRuleKey(issue.ruleKey().repository(), issue.ruleKey().rule())
      .setTags(issue.tags())
      .setComponentUuid(issue.componentUuid())
      .setComponentKey(issue.componentKey())
      .setModuleUuid(issue.moduleUuid())
      .setModuleUuidPath(issue.moduleUuidPath())
      .setComponentUuid(issue.componentUuid())
      .setProjectUuid(issue.projectUuid())
      .setProjectKey(issue.projectKey())
      .setIssueAttributes(KeyValueFormat.format(issue.attributes()))
      .setAuthorLogin(issue.authorLogin())
      .setIssueCreationDate(issue.creationDate())
      .setIssueCloseDate(issue.closeDate())
      .setIssueUpdateDate(issue.updateDate())
      .setSelectedAt(issue.selectedAt())

      // technical dates
      .setCreatedAt(now)
      .setUpdatedAt(now);
  }

  /**
   * On server side, we need component keys and uuid
   */
  public static IssueDto toDtoForServerInsert(DefaultIssue issue, ComponentDto component, ComponentDto project, int ruleId, long now) {
    return toDtoForComputationInsert(issue, ruleId, now)
      .setComponent(component)
      .setProject(project);
  }

  public static IssueDto toDtoForUpdate(DefaultIssue issue, long now) {
    // Invariant fields, like key and rule, can't be updated
    return new IssueDto()
      .setKee(issue.key())
      .setType(issue.type())
      .setLine(issue.line())
      .setLocations((DbIssues.Locations) issue.getLocations())
      .setMessage(issue.message())
      .setGap(issue.gap())
      .setEffort(issue.effortInMinutes())
      .setResolution(issue.resolution())
      .setStatus(issue.status())
      .setSeverity(issue.severity())
      .setChecksum(issue.checksum())
      .setManualSeverity(issue.manualSeverity())
      .setAssignee(issue.assignee())
      .setIssueAttributes(KeyValueFormat.format(issue.attributes()))
      .setAuthorLogin(issue.authorLogin())
      .setRuleKey(issue.ruleKey().repository(), issue.ruleKey().rule())
      .setTags(issue.tags())
      .setComponentUuid(issue.componentUuid())
      .setComponentKey(issue.componentKey())
      .setModuleUuid(issue.moduleUuid())
      .setModuleUuidPath(issue.moduleUuidPath())
      .setProjectUuid(issue.projectUuid())
      .setProjectKey(issue.projectKey())
      .setIssueCreationDate(issue.creationDate())
      .setIssueCloseDate(issue.closeDate())
      .setIssueUpdateDate(issue.updateDate())
      .setSelectedAt(issue.selectedAt())

      // technical date
      .setUpdatedAt(now);
  }

  public static IssueDto createFor(Project project, RuleDto rule) {
    return new IssueDto()
      .setProjectUuid(project.getUuid())
      .setRuleId(rule.getId())
      .setKee(Uuids.create());
  }

  public String getKey() {
    return getKee();
  }

  public Long getId() {
    return id;
  }

  public IssueDto setId(@Nullable Long id) {
    this.id = id;
    return this;
  }

  public String getKee() {
    return kee;
  }

  public IssueDto setKee(String s) {
    this.kee = s;
    return this;
  }

  public IssueDto setComponent(ComponentDto component) {
    this.componentKey = component.getKey();
    this.componentUuid = component.uuid();
    this.moduleUuid = component.moduleUuid();
    this.moduleUuidPath = component.moduleUuidPath();
    this.filePath = component.path();
    return this;
  }

  public IssueDto setProject(ComponentDto project) {
    this.projectKey = project.getKey();
    this.projectUuid = project.uuid();
    return this;
  }

  public Integer getRuleId() {
    return ruleId;
  }

  /**
   * please use setRule(RuleDto rule)
   */
  public IssueDto setRuleId(Integer ruleId) {
    this.ruleId = ruleId;
    return this;
  }

  @CheckForNull
  public String getSeverity() {
    return severity;
  }

  public IssueDto setSeverity(@Nullable String s) {
    checkArgument(s == null || s.length() <= 10, "Value is too long for issue severity: %s", s);
    this.severity = s;
    return this;
  }

  public boolean isManualSeverity() {
    return manualSeverity;
  }

  public IssueDto setManualSeverity(boolean manualSeverity) {
    this.manualSeverity = manualSeverity;
    return this;
  }

  @CheckForNull
  public String getMessage() {
    return message;
  }

  public IssueDto setMessage(@Nullable String s) {
    checkArgument(s == null || s.length() <= 4000, "Value is too long for issue message: %s", s);
    this.message = s;
    return this;
  }

  @CheckForNull
  public Integer getLine() {
    return line;
  }

  public IssueDto setLine(@Nullable Integer i) {
    checkArgument(i == null || i >= 0, "Value of issue line must be positive: %d", i);
    this.line = i;
    return this;
  }

  @CheckForNull
  public Double getGap() {
    return gap;
  }

  public IssueDto setGap(@Nullable Double d) {
    checkArgument(d == null || d >= 0, "Value of issue gap must be positive: %d", d);
    this.gap = d;
    return this;
  }

  @CheckForNull
  public Long getEffort() {
    return effort;
  }

  public IssueDto setEffort(@Nullable Long l) {
    checkArgument(l == null || l >= 0, "Value of issue effort must be positive: %d", l);
    this.effort = l;
    return this;
  }

  public String getStatus() {
    return status;
  }

  public IssueDto setStatus(@Nullable String s) {
    checkArgument(s == null || s.length() <= 20, "Value is too long for issue status: %s", s);
    this.status = s;
    return this;
  }

  @CheckForNull
  public String getResolution() {
    return resolution;
  }

  public IssueDto setResolution(@Nullable String s) {
    checkArgument(s == null || s.length() <= 20, "Value is too long for issue resolution: %s", s);
    this.resolution = s;
    return this;
  }

  @CheckForNull
  public String getChecksum() {
    return checksum;
  }

  public IssueDto setChecksum(@Nullable String s) {
    checkArgument(s == null || s.length() <= 1000, "Value is too long for issue checksum: %s", s);
    this.checksum = s;
    return this;
  }

  @CheckForNull
  public String getAssignee() {
    return assignee;
  }

  public IssueDto setAssignee(@Nullable String s) {
    checkArgument(s == null || s.length() <= 255, "Value is too long for issue assignee: %s", s);
    this.assignee = s;
    return this;
  }

  @CheckForNull
  public String getAuthorLogin() {
    return authorLogin;
  }

  public IssueDto setAuthorLogin(@Nullable String s) {
    checkArgument(s == null || s.length() <= 255, "Value is too long for issue author login: %s", s);
    this.authorLogin = s;
    return this;
  }

  @CheckForNull
  public String getIssueAttributes() {
    return issueAttributes;
  }

  public IssueDto setIssueAttributes(@Nullable String s) {
    checkArgument(s == null || s.length() <= 4000, "Value is too long for issue attributes: %s", s);
    this.issueAttributes = s;
    return this;
  }

  /**
   * Technical date
   */
  public long getCreatedAt() {
    return createdAt;
  }

  public IssueDto setCreatedAt(long createdAt) {
    this.createdAt = createdAt;
    return this;
  }

  /**
   * Technical date
   */
  public long getUpdatedAt() {
    return updatedAt;
  }

  public IssueDto setUpdatedAt(long updatedAt) {
    this.updatedAt = updatedAt;
    return this;
  }

  public Long getIssueCreationTime() {
    return issueCreationDate;
  }

  public IssueDto setIssueCreationTime(Long time) {
    this.issueCreationDate = time;
    return this;
  }

  public Date getIssueCreationDate() {
    return longToDate(issueCreationDate);
  }

  public IssueDto setIssueCreationDate(@Nullable Date d) {
    this.issueCreationDate = dateToLong(d);
    return this;
  }

  public Long getIssueUpdateTime() {
    return issueUpdateDate;
  }

  public IssueDto setIssueUpdateTime(Long time) {
    this.issueUpdateDate = time;
    return this;
  }

  public Date getIssueUpdateDate() {
    return longToDate(issueUpdateDate);
  }

  public IssueDto setIssueUpdateDate(@Nullable Date d) {
    this.issueUpdateDate = dateToLong(d);
    return this;
  }

  public Long getIssueCloseTime() {
    return issueCloseDate;
  }

  public IssueDto setIssueCloseTime(Long time) {
    this.issueCloseDate = time;
    return this;
  }

  public Date getIssueCloseDate() {
    return longToDate(issueCloseDate);
  }

  public IssueDto setIssueCloseDate(@Nullable Date d) {
    this.issueCloseDate = dateToLong(d);
    return this;
  }

  public String getRule() {
    return ruleKey;
  }

  public IssueDto setRule(RuleDto rule) {
    Preconditions.checkNotNull(rule.getId(), "Rule must be persisted.");
    this.ruleId = rule.getId();
    this.ruleKey = rule.getRuleKey();
    this.ruleRepo = rule.getRepositoryKey();
    this.language = rule.getLanguage();
    return this;
  }

  public String getRuleRepo() {
    return ruleRepo;
  }

  public RuleKey getRuleKey() {
    return RuleKey.of(ruleRepo, ruleKey);
  }

  public String getLanguage() {
    return language;
  }

  /**
   * Should only be used to persist in E/S
   * 

* Please use {@link #setRule(RuleDto)} instead */ public IssueDto setLanguage(String language) { this.language = language; return this; } public String getComponentKey() { return componentKey; } /** * Should only be used to persist in E/S *

* Please use {@link #setComponent(ComponentDto)} instead */ public IssueDto setComponentKey(String componentKey) { this.componentKey = componentKey; return this; } /** * Can be null on Views or Devs */ @CheckForNull public String getComponentUuid() { return componentUuid; } /** * Should only be used to persist in E/S *

* Please use {@link #setComponent(ComponentDto)} instead */ public IssueDto setComponentUuid(@Nullable String s) { checkArgument(s == null || s.length() <= 50, "Value is too long for column ISSUES.COMPONENT_UUID: %s", s); this.componentUuid = s; return this; } @CheckForNull public String getModuleUuid() { return moduleUuid; } /** * Should only be used to persist in E/S *

* Please use {@link #setComponent(ComponentDto)} instead */ public IssueDto setModuleUuid(@Nullable String moduleUuid) { this.moduleUuid = moduleUuid; return this; } @CheckForNull public String getModuleUuidPath() { return moduleUuidPath; } /** * Should only be used to persist in E/S *

* Please use {@link #setComponent(ComponentDto)} instead */ public IssueDto setModuleUuidPath(@Nullable String moduleUuidPath) { this.moduleUuidPath = moduleUuidPath; return this; } /** * Used by the issue tracking mechanism, but it should used the component uuid instead */ public String getProjectKey() { return projectKey; } /** * Should only be used to persist in E/S *

* Please use {@link #setProject(ComponentDto)} instead */ public IssueDto setProjectKey(String projectKey) { this.projectKey = projectKey; return this; } /** * Can be null on Views or Devs */ @CheckForNull public String getProjectUuid() { return projectUuid; } /** * Should only be used to persist in E/S *

* Please use {@link #setProject(ComponentDto)} instead */ public IssueDto setProjectUuid(@Nullable String s) { checkArgument(s == null || s.length() <= 50, "Value is too long for column ISSUES.PROJECT_UUID: %s", s); this.projectUuid = s; return this; } @CheckForNull public Long getSelectedAt() { return selectedAt; } public IssueDto setSelectedAt(@Nullable Long d) { this.selectedAt = d; return this; } /** * Should only be used to persist in E/S *

* Please use {@link #setRule(RuleDto)} instead */ public IssueDto setRuleKey(String repo, String rule) { this.ruleRepo = repo; this.ruleKey = rule; return this; } /** * Should only be used to persist in E/S *

* Please use {@link #setProject(ComponentDto)} instead */ public String getFilePath() { return filePath; } /** * Should only be used to persist in E/S *

* Please use {@link #setProject(ComponentDto)} instead */ public IssueDto setFilePath(String filePath) { this.filePath = filePath; return this; } public Set getTags() { return ImmutableSet.copyOf(TAGS_SPLITTER.split(tags == null ? "" : tags)); } public IssueDto setTags(@Nullable Collection tags) { if (tags == null || tags.isEmpty()) { setTagsString(null); } else { setTagsString(TAGS_JOINER.join(tags)); } return this; } public IssueDto setTagsString(@Nullable String s) { checkArgument(s == null || s.length() <= 4000, "Value is too long for column ISSUES.TAGS: %s", s); this.tags = s; return this; } public String getTagsString() { return tags; } @CheckForNull public byte[] getLocations() { return locations; } @CheckForNull public DbIssues.Locations parseLocations() { if (locations != null) { try { return DbIssues.Locations.parseFrom(locations); } catch (InvalidProtocolBufferException e) { throw new IllegalStateException(String.format("Fail to read ISSUES.LOCATIONS [KEE=%s]", kee), e); } } return null; } public IssueDto setLocations(@Nullable byte[] locations) { this.locations = locations; return this; } public IssueDto setLocations(@Nullable DbIssues.Locations locations) { if (locations == null) { this.locations = null; } else { this.locations = locations.toByteArray(); } return this; } public int getType() { return type; } public IssueDto setType(int type) { this.type = type; return this; } public IssueDto setType(RuleType type) { this.type = type.getDbConstant(); return this; } @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); } public DefaultIssue toDefaultIssue() { DefaultIssue issue = new DefaultIssue(); issue.setKey(kee); issue.setType(RuleType.valueOf(type)); issue.setStatus(status); issue.setResolution(resolution); issue.setMessage(message); issue.setGap(gap); issue.setEffort(effort != null ? Duration.create(effort) : null); issue.setLine(line); issue.setChecksum(checksum); issue.setSeverity(severity); issue.setAssignee(assignee); issue.setAttributes(KeyValueFormat.parse(Objects.firstNonNull(issueAttributes, ""))); issue.setComponentKey(componentKey); issue.setComponentUuid(componentUuid); issue.setModuleUuid(moduleUuid); issue.setModuleUuidPath(moduleUuidPath); issue.setProjectUuid(projectUuid); issue.setProjectKey(projectKey); issue.setManualSeverity(manualSeverity); issue.setRuleKey(getRuleKey()); issue.setTags(getTags()); issue.setLanguage(language); issue.setAuthorLogin(authorLogin); issue.setNew(false); issue.setCreationDate(longToDate(issueCreationDate)); issue.setCloseDate(longToDate(issueCloseDate)); issue.setUpdateDate(longToDate(issueUpdateDate)); issue.setSelectedAt(selectedAt); issue.setLocations(parseLocations()); return issue; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy