001/*
002 * SonarQube
003 * Copyright (C) 2009-2017 SonarSource SA
004 * mailto:info AT sonarsource DOT com
005 *
006 * This program is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019 */
020package org.sonar.api.batch.sensor.issue.internal;
021
022import com.google.common.base.Preconditions;
023import com.google.common.collect.ImmutableList;
024import java.util.ArrayList;
025import java.util.Arrays;
026import java.util.List;
027import javax.annotation.Nullable;
028import org.sonar.api.batch.rule.Severity;
029import org.sonar.api.batch.sensor.internal.DefaultStorable;
030import org.sonar.api.batch.sensor.internal.SensorStorage;
031import org.sonar.api.batch.sensor.issue.Issue;
032import org.sonar.api.batch.sensor.issue.IssueLocation;
033import org.sonar.api.batch.sensor.issue.NewIssue;
034import org.sonar.api.batch.sensor.issue.NewIssueLocation;
035import org.sonar.api.rule.RuleKey;
036
037import static java.lang.String.format;
038import static java.util.stream.Collectors.toList;
039
040public class DefaultIssue extends DefaultStorable implements Issue, NewIssue {
041
042  private RuleKey ruleKey;
043  private Double gap;
044  private Severity overriddenSeverity;
045  private IssueLocation primaryLocation;
046  private List<List<IssueLocation>> flows = new ArrayList<>();
047
048  public DefaultIssue() {
049    super(null);
050  }
051
052  public DefaultIssue(SensorStorage storage) {
053    super(storage);
054  }
055
056  @Override
057  public DefaultIssue forRule(RuleKey ruleKey) {
058    this.ruleKey = ruleKey;
059    return this;
060  }
061
062  @Override
063  public DefaultIssue effortToFix(@Nullable Double effortToFix) {
064    return gap(effortToFix);
065  }
066
067  @Override
068  public DefaultIssue gap(@Nullable Double gap) {
069    Preconditions.checkArgument(gap == null || gap >= 0, format("Gap must be greater than or equal 0 (got %s)", gap));
070    this.gap = gap;
071    return this;
072  }
073
074  @Override
075  public DefaultIssue overrideSeverity(@Nullable Severity severity) {
076    this.overriddenSeverity = severity;
077    return this;
078  }
079
080  @Override
081  public NewIssueLocation newLocation() {
082    return new DefaultIssueLocation();
083  }
084
085  @Override
086  public DefaultIssue at(NewIssueLocation primaryLocation) {
087    Preconditions.checkArgument(primaryLocation != null, "Cannot use a location that is null");
088    Preconditions.checkState(this.primaryLocation == null, "at() already called");
089    this.primaryLocation = (DefaultIssueLocation) primaryLocation;
090    Preconditions.checkArgument(this.primaryLocation.inputComponent() != null, "Cannot use a location with no input component");
091    return this;
092  }
093
094  @Override
095  public NewIssue addLocation(NewIssueLocation secondaryLocation) {
096    flows.add(Arrays.asList((IssueLocation) secondaryLocation));
097    return this;
098  }
099
100  @Override
101  public DefaultIssue addFlow(Iterable<NewIssueLocation> locations) {
102    List<IssueLocation> flowAsList = new ArrayList<>();
103    for (NewIssueLocation issueLocation : locations) {
104      flowAsList.add((DefaultIssueLocation) issueLocation);
105    }
106    flows.add(flowAsList);
107    return this;
108  }
109
110  @Override
111  public RuleKey ruleKey() {
112    return this.ruleKey;
113  }
114
115  @Override
116  public Severity overriddenSeverity() {
117    return this.overriddenSeverity;
118  }
119
120  @Override
121  public Double gap() {
122    return this.gap;
123  }
124
125  @Override
126  public Double effortToFix() {
127    return this.gap;
128  }
129
130  @Override
131  public IssueLocation primaryLocation() {
132    return primaryLocation;
133  }
134
135  @Override
136  public List<Flow> flows() {
137    return this.flows.stream()
138      .<Flow>map(l -> () -> ImmutableList.copyOf(l))
139      .collect(toList());
140  }
141
142  @Override
143  public void doSave() {
144    Preconditions.checkNotNull(this.ruleKey, "ruleKey is mandatory on issue");
145    Preconditions.checkState(primaryLocation != null, "Primary location is mandatory on every issue");
146    storage.store(this);
147  }
148
149}