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.server.debt.internal;
021
022import com.google.common.base.MoreObjects;
023import javax.annotation.CheckForNull;
024import javax.annotation.Nullable;
025import org.apache.commons.lang.StringUtils;
026import org.apache.commons.lang.builder.EqualsBuilder;
027import org.sonar.api.server.debt.DebtRemediationFunction;
028import org.sonar.api.utils.Duration;
029
030import static com.google.common.base.Preconditions.checkArgument;
031
032public class DefaultDebtRemediationFunction implements DebtRemediationFunction {
033
034  private static final int HOURS_IN_DAY = 24;
035
036  private final Type type;
037  private final String gapMultiplier;
038  private final String baseEffort;
039
040  public DefaultDebtRemediationFunction(@Nullable Type type, @Nullable String gapMultiplier, @Nullable String baseEffort) {
041    this.type = type;
042    this.gapMultiplier = sanitizeValue("gap multiplier", gapMultiplier);
043    this.baseEffort = sanitizeValue("base effort", baseEffort);
044    validate();
045  }
046
047  @CheckForNull
048  private static String sanitizeValue(String label, @Nullable String s) {
049    if (StringUtils.isNotBlank(s)) {
050      try {
051        Duration duration = Duration.decode(s, HOURS_IN_DAY);
052        return duration.encode(HOURS_IN_DAY);
053      } catch (Exception e) {
054        throw new IllegalArgumentException(String.format("Invalid %s: %s (%s)", label, s, e.getMessage()), e);
055      }
056    }
057    return null;
058  }
059
060  @Override
061  public Type type() {
062    return type;
063  }
064
065  /**
066   * @deprecated since 5.5, replaced by {@link #gapMultiplier}
067   */
068  @Override
069  @CheckForNull
070  @Deprecated
071  public String coefficient() {
072    return gapMultiplier();
073  }
074
075
076  @Override
077  @CheckForNull
078  public String gapMultiplier() {
079    return gapMultiplier;
080  }
081
082  /**
083   * @deprecated since 5.5, replaced by {@link #baseEffort}
084   */
085  @Override
086  @CheckForNull
087  @Deprecated
088  public String offset() {
089    return baseEffort();
090  }
091
092  @Override
093  public String baseEffort() {
094    return baseEffort;
095  }
096
097
098  private void validate() {
099    checkArgument(type != null, "Remediation function type cannot be null");
100    switch (type) {
101      case LINEAR:
102        checkArgument(this.gapMultiplier != null && this.baseEffort == null, "Linear functions must only have a non empty gap multiplier");
103        break;
104      case LINEAR_OFFSET:
105        checkArgument(this.gapMultiplier != null && this.baseEffort != null, "Linear with offset functions must have both non null gap multiplier and base effort");
106        break;
107      case CONSTANT_ISSUE:
108        checkArgument(this.gapMultiplier == null && this.baseEffort != null, "Constant/issue functions must only have a non empty base effort");
109        break;
110      default:
111        throw new IllegalArgumentException(String.format("Unknown type on %s", this));
112    }
113  }
114
115  @Override
116  public boolean equals(Object o) {
117    if (!(o instanceof DefaultDebtRemediationFunction)) {
118      return false;
119    }
120    if (this == o) {
121      return true;
122    }
123    DefaultDebtRemediationFunction other = (DefaultDebtRemediationFunction) o;
124    return new EqualsBuilder()
125      .append(gapMultiplier, other.gapMultiplier())
126      .append(baseEffort, other.baseEffort())
127      .append(type, other.type())
128      .isEquals();
129  }
130
131  @Override
132  public int hashCode() {
133    int result = type.hashCode();
134    result = 31 * result + (gapMultiplier != null ? gapMultiplier.hashCode() : 0);
135    result = 31 * result + (baseEffort != null ? baseEffort.hashCode() : 0);
136    return result;
137  }
138
139  
140  @Override
141  public String toString() {
142    return MoreObjects.toStringHelper(DebtRemediationFunction.class)
143      .add("type", type)
144      .add("gap multiplier", gapMultiplier)
145      .add("base effort", baseEffort)
146      .toString();
147  }
148}