aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2014-04-03 17:52:05 +0200
committerJulien Lancelot <julien.lancelot@sonarsource.com>2014-04-03 17:52:32 +0200
commitfcb07c6af06f952f5c241470ffaef47b6d5df8ed (patch)
tree73fe1861970e4ff015b20d8e9039e05cb4041251
parentac849445803cfb26d9a7bf298fc4320ae941bd2f (diff)
downloadsonarqube-fcb07c6af06f952f5c241470ffaef47b6d5df8ed.tar.gz
sonarqube-fcb07c6af06f952f5c241470ffaef47b6d5df8ed.zip
Create a new DebtModel API on batch side
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/DebtDecorator.java2
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/DebtDecoratorTest.java4
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java64
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java17
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java30
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java36
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java12
-rw-r--r--sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java51
-rw-r--r--sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModel.java47
-rw-r--r--sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModelTest.java64
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtCharacteristic.java37
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtModel.java58
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/internal/DefaultDebtCharacteristic.java120
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/internal/DefaultDebtModel.java93
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rule.java4
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRule.java8
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewRule.java6
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/server/debt/DebtCharacteristic.java11
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/server/debt/DebtModel.java5
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/server/debt/internal/DefaultDebtCharacteristic.java9
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/Characteristic.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/TechnicalDebtModel.java5
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/debt/internal/DefaultDebtModelTest.java88
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/RulesBuilderTest.java8
25 files changed, 593 insertions, 190 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/DebtDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/DebtDecorator.java
index d948742da26..2caf164d9c2 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/DebtDecorator.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/technicaldebt/DebtDecorator.java
@@ -121,7 +121,7 @@ public final class DebtDecorator implements Decorator {
if (debt != null) {
Rule rule = rules.find(ruleKey);
if (rule != null) {
- String characteristicKey = rule.debtCharacteristic();
+ String characteristicKey = rule.debtSubCharacteristic();
if (characteristicKey != null) {
Characteristic characteristic = model.characteristicByKey(characteristicKey);
if (characteristic != null) {
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/DebtDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/DebtDecoratorTest.java
index aff369faab5..2aac5804446 100644
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/DebtDecoratorTest.java
+++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/technicaldebt/DebtDecoratorTest.java
@@ -98,8 +98,8 @@ public class DebtDecoratorTest {
public void before() throws Exception {
when(perspectives.as(Issuable.class, resource)).thenReturn(issuable);
RulesBuilder rulesBuilder = new RulesBuilder();
- rulesBuilder.add(ruleKey1).setName("rule1").setDebtCharacteristic("MEMORY_EFFICIENCY");
- rulesBuilder.add(ruleKey2).setName("rule2").setDebtCharacteristic("MODULARITY");
+ rulesBuilder.add(ruleKey1).setName("rule1").setDebtSubCharacteristic("MEMORY_EFFICIENCY");
+ rulesBuilder.add(ruleKey2).setName("rule2").setDebtSubCharacteristic("MODULARITY");
rules = rulesBuilder.build();
when(ruleFinder.findByKey(ruleKey1)).thenReturn(org.sonar.api.rules.Rule.create(ruleKey1.repository(), ruleKey1.rule()));
diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java b/sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java
index be7d9895cc2..a00b9f909f5 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java
@@ -20,28 +20,30 @@
package org.sonar.batch.debt;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
import org.picocontainer.injectors.ProviderAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+import org.sonar.api.batch.debt.DebtModel;
+import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
+import org.sonar.api.batch.debt.internal.DefaultDebtModel;
import org.sonar.api.utils.TimeProfiler;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
-import java.util.List;
-import java.util.Map;
+import javax.annotation.Nullable;
-import static com.google.common.collect.Maps.newHashMap;
+import java.util.List;
public class DebtModelProvider extends ProviderAdapter {
private static final Logger LOG = LoggerFactory.getLogger(DebtModelProvider.class);
- private TechnicalDebtModel model;
+ private DebtModel model;
- public TechnicalDebtModel provide(CharacteristicDao dao) {
+ public DebtModel provide(CharacteristicDao dao) {
if (model == null) {
TimeProfiler profiler = new TimeProfiler(LOG).start("Loading technical debt model");
model = load(dao);
@@ -50,33 +52,37 @@ public class DebtModelProvider extends ProviderAdapter {
return model;
}
- private TechnicalDebtModel load(CharacteristicDao dao) {
- DefaultTechnicalDebtModel debtModel = new DefaultTechnicalDebtModel();
- List<CharacteristicDto> dtos = dao.selectEnabledCharacteristics();
- Map<Integer, DefaultCharacteristic> characteristicsById = newHashMap();
+ private DebtModel load(CharacteristicDao dao) {
+ DefaultDebtModel debtModel = new DefaultDebtModel();
- addRootCharacteristics(debtModel, dtos, characteristicsById);
- addCharacteristics(dtos, characteristicsById);
+ List<CharacteristicDto> allCharacteristics = dao.selectEnabledCharacteristics();
+ for (CharacteristicDto dto : allCharacteristics) {
+ Integer parentId = dto.getParentId();
+ if (parentId == null) {
+ debtModel.addCharacteristic(toDebtCharacteristic(dto));
+ } else {
+ debtModel.addSubCharacteristic(toDebtCharacteristic(dto), characteristicById(parentId, allCharacteristics).getKey());
+ }
+ }
return debtModel;
}
- private void addRootCharacteristics(DefaultTechnicalDebtModel model, List<CharacteristicDto> dtos, Map<Integer, DefaultCharacteristic> characteristicsById) {
- for (CharacteristicDto dto : dtos) {
- if (dto.getParentId() == null) {
- DefaultCharacteristic rootCharacteristic = dto.toCharacteristic(null);
- model.addRootCharacteristic(rootCharacteristic);
- characteristicsById.put(dto.getId(), rootCharacteristic);
+ private static CharacteristicDto characteristicById(final int id, List<CharacteristicDto> allCharacteristics) {
+ return Iterables.find(allCharacteristics, new Predicate<CharacteristicDto>() {
+ @Override
+ public boolean apply(@Nullable CharacteristicDto input) {
+ return input != null && id == input.getId();
}
- }
+ });
}
- private void addCharacteristics(List<CharacteristicDto> dtos, Map<Integer, DefaultCharacteristic> characteristicsById) {
- for (CharacteristicDto dto : dtos) {
- if (dto.getParentId() != null) {
- DefaultCharacteristic parent = characteristicsById.get(dto.getParentId());
- DefaultCharacteristic characteristic = dto.toCharacteristic(parent);
- characteristicsById.put(dto.getId(), characteristic);
- }
- }
+ private static DebtCharacteristic toDebtCharacteristic(CharacteristicDto characteristic) {
+ return new DefaultDebtCharacteristic()
+ .setId(characteristic.getId())
+ .setKey(characteristic.getKey())
+ .setName(characteristic.getName())
+ .setOrder(characteristic.getOrder())
+ .setParentId(characteristic.getParentId());
}
+
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java b/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
index 1e6bb240720..5eaa0726038 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
@@ -108,7 +108,7 @@ public class ModuleIssues {
issue.setSeverity(activeRule.severity());
}
DebtRemediationFunction function = rule.debtRemediationFunction();
- if (rule.debtCharacteristic() != null && function != null) {
+ if (rule.debtSubCharacteristic() != null && function != null) {
issue.setDebt(calculateDebt(function, issue.effortToFix(), rule.key()));
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java b/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java
index 1cbf9b1aa5b..ef479b27f00 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java
@@ -25,14 +25,15 @@ import com.google.common.collect.ListMultimap;
import org.picocontainer.injectors.ProviderAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+import org.sonar.api.batch.debt.DebtModel;
+import org.sonar.api.batch.debt.internal.DefaultDebtModel;
import org.sonar.api.batch.rule.DebtRemediationFunction;
import org.sonar.api.batch.rule.Rules;
import org.sonar.api.batch.rule.internal.NewRule;
import org.sonar.api.batch.rule.internal.RulesBuilder;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.technicaldebt.batch.Characteristic;
-import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
import org.sonar.api.utils.Durations;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.core.rule.RuleDao;
@@ -52,16 +53,16 @@ public class RulesProvider extends ProviderAdapter {
private Rules singleton = null;
- public Rules provide(RuleDao ruleDao, TechnicalDebtModel debtModel, Durations durations) {
+ public Rules provide(RuleDao ruleDao, DebtModel debtModel, Durations durations) {
if (singleton == null) {
TimeProfiler profiler = new TimeProfiler(LOG).start("Loading rules");
- singleton = load(ruleDao, debtModel, durations);
+ singleton = load(ruleDao, (DefaultDebtModel) debtModel, durations);
profiler.stop();
}
return singleton;
}
- private Rules load(RuleDao ruleDao, TechnicalDebtModel debtModel, Durations durations) {
+ private Rules load(RuleDao ruleDao, DefaultDebtModel debtModel, Durations durations) {
RulesBuilder rulesBuilder = new RulesBuilder();
List<RuleParamDto> ruleParamDtos = ruleDao.selectParameters();
@@ -80,7 +81,7 @@ public class RulesProvider extends ProviderAdapter {
// TODO should we set metadata ?
if (hasCharacteristic(ruleDto)) {
- newRule.setDebtCharacteristic(effectiveCharacteristic(ruleDto, ruleKey, debtModel).key());
+ newRule.setDebtSubCharacteristic(effectiveCharacteristic(ruleDto, ruleKey, debtModel).key());
newRule.setDebtRemediationFunction(effectiveFunction(ruleDto, ruleKey, durations));
}
@@ -92,11 +93,11 @@ public class RulesProvider extends ProviderAdapter {
return rulesBuilder.build();
}
- private Characteristic effectiveCharacteristic(RuleDto ruleDto, RuleKey ruleKey, TechnicalDebtModel debtModel) {
+ private DebtCharacteristic effectiveCharacteristic(RuleDto ruleDto, RuleKey ruleKey, DefaultDebtModel debtModel) {
Integer subCharacteristicId = ruleDto.getSubCharacteristicId();
Integer defaultSubCharacteristicId = ruleDto.getDefaultSubCharacteristicId();
Integer effectiveSubCharacteristicId = subCharacteristicId != null ? subCharacteristicId : defaultSubCharacteristicId;
- Characteristic subCharacteristic = debtModel.characteristicById(effectiveSubCharacteristicId);
+ DebtCharacteristic subCharacteristic = debtModel.characteristicById(effectiveSubCharacteristicId);
if (subCharacteristic == null) {
throw new IllegalStateException(String.format("Sub characteristic id '%s' on rule '%s' has not been found", effectiveSubCharacteristicId, ruleKey));
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
index b610b00338b..dee73ecd6c7 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/scan/ProjectScanContainer.java
@@ -35,34 +35,12 @@ import org.sonar.batch.DefaultFileLinesContextFactory;
import org.sonar.batch.DefaultResourceCreationLock;
import org.sonar.batch.ProjectConfigurator;
import org.sonar.batch.ProjectTree;
-import org.sonar.batch.bootstrap.BootstrapSettings;
-import org.sonar.batch.bootstrap.ExtensionInstaller;
-import org.sonar.batch.bootstrap.ExtensionMatcher;
-import org.sonar.batch.bootstrap.ExtensionUtils;
-import org.sonar.batch.bootstrap.MetricProvider;
+import org.sonar.batch.bootstrap.*;
import org.sonar.batch.components.PeriodsDefinition;
import org.sonar.batch.debt.DebtModelProvider;
import org.sonar.batch.debt.IssueChangelogDebtCalculator;
-import org.sonar.batch.index.Caches;
-import org.sonar.batch.index.ComponentDataCache;
-import org.sonar.batch.index.ComponentDataPersister;
-import org.sonar.batch.index.DefaultIndex;
-import org.sonar.batch.index.DefaultPersistenceManager;
-import org.sonar.batch.index.DefaultResourcePersister;
-import org.sonar.batch.index.DependencyPersister;
-import org.sonar.batch.index.EventPersister;
-import org.sonar.batch.index.LinkPersister;
-import org.sonar.batch.index.MeasurePersister;
-import org.sonar.batch.index.MemoryOptimizer;
-import org.sonar.batch.index.ResourceCache;
-import org.sonar.batch.index.ResourceKeyMigration;
-import org.sonar.batch.index.SnapshotCache;
-import org.sonar.batch.index.SourcePersister;
-import org.sonar.batch.issue.DefaultProjectIssues;
-import org.sonar.batch.issue.DeprecatedViolations;
-import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.issue.IssuePersister;
-import org.sonar.batch.issue.ScanIssueStorage;
+import org.sonar.batch.index.*;
+import org.sonar.batch.issue.*;
import org.sonar.batch.phases.GraphPersister;
import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
import org.sonar.batch.rule.RulesProvider;
@@ -77,6 +55,7 @@ import org.sonar.core.issue.IssueUpdater;
import org.sonar.core.issue.workflow.FunctionExecutor;
import org.sonar.core.issue.workflow.IssueWorkflow;
import org.sonar.core.notification.DefaultNotificationManager;
+import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
import org.sonar.core.test.TestPlanBuilder;
import org.sonar.core.test.TestPlanPerspectiveLoader;
import org.sonar.core.test.TestableBuilder;
@@ -180,6 +159,7 @@ public class ProjectScanContainer extends ComponentContainer {
SymbolizableBuilder.class,
// technical debt
+ DefaultTechnicalDebtModel.class,
new DebtModelProvider(),
// rules
diff --git a/sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java
index 66bf2768902..a61e4e18063 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelProviderTest.java
@@ -25,8 +25,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+import org.sonar.api.batch.debt.DebtModel;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
@@ -42,18 +42,18 @@ public class DebtModelProviderTest {
DebtModelProvider provider;
-
@Before
public void before() {
provider = new DebtModelProvider();
}
@Test
- public void find_all() throws Exception {
+ public void provide_model() throws Exception {
CharacteristicDto rootCharacteristicDto = new CharacteristicDto()
.setId(1)
.setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
+ .setName("Memory use")
+ .setOrder(1);
CharacteristicDto characteristicDto = new CharacteristicDto()
.setId(2)
@@ -63,21 +63,19 @@ public class DebtModelProviderTest {
when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(rootCharacteristicDto, characteristicDto));
- DefaultTechnicalDebtModel result = (DefaultTechnicalDebtModel) provider.provide(dao);
- assertThat(result.rootCharacteristics()).hasSize(1);
+ DebtModel result = provider.provide(dao);
+ assertThat(result.characteristics()).hasSize(1);
- DefaultCharacteristic rootCharacteristic = result.characteristicByKey("MEMORY_EFFICIENCY");
- assertThat(rootCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(rootCharacteristic.name()).isEqualTo("Memory use");
- assertThat(rootCharacteristic.parent()).isNull();
- assertThat(rootCharacteristic.children()).hasSize(1);
- assertThat(rootCharacteristic.children().get(0).key()).isEqualTo("EFFICIENCY");
+ DebtCharacteristic characteristic = result.characteristicByKey("MEMORY_EFFICIENCY");
+ assertThat(characteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(characteristic.name()).isEqualTo("Memory use");
+ assertThat(characteristic.isSub()).isFalse();
+ assertThat(characteristic.order()).isEqualTo(1);
- DefaultCharacteristic characteristic = result.characteristicByKey("EFFICIENCY");
- assertThat(characteristic.key()).isEqualTo("EFFICIENCY");
- assertThat(characteristic.name()).isEqualTo("Efficiency");
- assertThat(characteristic.parent().key()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(characteristic.children()).isEmpty();
+ DebtCharacteristic subCharacteristic = result.characteristicByKey("EFFICIENCY");
+ assertThat(subCharacteristic.key()).isEqualTo("EFFICIENCY");
+ assertThat(subCharacteristic.name()).isEqualTo("Efficiency");
+ assertThat(subCharacteristic.isSub()).isTrue();
+ assertThat(subCharacteristic.order()).isNull();
}
-
}
diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
index 5a5f8ef282d..6be76b5d95d 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
@@ -47,9 +47,7 @@ import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class ModuleIssuesTest {
@@ -252,7 +250,7 @@ public class ModuleIssuesTest {
public void set_debt_with_linear_function() throws Exception {
ruleBuilder.add(SQUID_RULE_KEY)
.setName(SQUID_RULE_NAME)
- .setDebtCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
.setDebtRemediationFunction(DebtRemediationFunction.createLinear(Duration.create(10L)));
activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
initModuleIssues();
@@ -278,7 +276,7 @@ public class ModuleIssuesTest {
public void set_debt_with_linear_with_offset_function() throws Exception {
ruleBuilder.add(SQUID_RULE_KEY)
.setName(SQUID_RULE_NAME)
- .setDebtCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
.setDebtRemediationFunction(DebtRemediationFunction.createLinearWithOffset(Duration.create(10L), Duration.create(25L)));
activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
initModuleIssues();
@@ -304,7 +302,7 @@ public class ModuleIssuesTest {
public void set_debt_with_constant_issue_function() throws Exception {
ruleBuilder.add(SQUID_RULE_KEY)
.setName(SQUID_RULE_NAME)
- .setDebtCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
.setDebtRemediationFunction(DebtRemediationFunction.createConstantPerIssue(Duration.create(10L)));
activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
initModuleIssues();
@@ -330,7 +328,7 @@ public class ModuleIssuesTest {
public void fail_to_set_debt_with_constant_issue_function_when_effort_to_fix_is_set() throws Exception {
ruleBuilder.add(SQUID_RULE_KEY)
.setName(SQUID_RULE_NAME)
- .setDebtCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
.setDebtRemediationFunction(DebtRemediationFunction.createConstantPerIssue(Duration.create(25L)));
activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
initModuleIssues();
diff --git a/sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java b/sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java
index ffcab662476..5ec693d2bc1 100644
--- a/sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java
+++ b/sonar-batch/src/test/java/org/sonar/batch/rule/RulesProviderTest.java
@@ -25,6 +25,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
+import org.sonar.api.batch.debt.internal.DefaultDebtModel;
import org.sonar.api.batch.rule.DebtRemediationFunction;
import org.sonar.api.batch.rule.Rule;
import org.sonar.api.batch.rule.RuleParam;
@@ -32,12 +34,10 @@ import org.sonar.api.batch.rule.Rules;
import org.sonar.api.config.Settings;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.rule.RuleDao;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
@@ -50,29 +50,34 @@ public class RulesProviderTest extends AbstractDaoTestCase {
RuleDao ruleDao;
- DefaultTechnicalDebtModel debtModel;
+ DefaultDebtModel debtModel;
RulesProvider provider;
@Before
public void setUp() throws Exception {
- debtModel = new DefaultTechnicalDebtModel();
- debtModel.addRootCharacteristic(new DefaultCharacteristic()
- .setId(101)
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParent(new DefaultCharacteristic()
+ debtModel = new DefaultDebtModel()
+ .addCharacteristic(new DefaultDebtCharacteristic()
.setId(100)
.setKey("MEMORY_EFFICIENCY")
- .setName("Memory use")));
- debtModel.addRootCharacteristic(new DefaultCharacteristic()
- .setId(103)
- .setKey("PORTABILITY")
- .setName("Portability")
- .setParent(new DefaultCharacteristic()
+ .setName("Memory use")
+ .setOrder(1))
+ .addCharacteristic(new DefaultDebtCharacteristic()
+ .setId(101)
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParentId(100));
+ debtModel
+ .addCharacteristic(new DefaultDebtCharacteristic()
.setId(102)
.setKey("COMPILER_RELATED_PORTABILITY")
- .setName("Compiler")));
+ .setName("Compiler")
+ .setOrder(1))
+ .addCharacteristic(new DefaultDebtCharacteristic()
+ .setId(103)
+ .setKey("PORTABILITY")
+ .setName("Portability")
+ .setParentId(102));
durations = new Durations(new Settings().setProperty("sonar.technicalDebt.hoursInDay", 8), null);
ruleDao = new RuleDao(getMyBatis());
@@ -111,7 +116,7 @@ public class RulesProviderTest extends AbstractDaoTestCase {
Rules rules = provider.provide(ruleDao, debtModel, durations);
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isEqualTo("EFFICIENCY");
+ assertThat(rule.debtSubCharacteristic()).isEqualTo("EFFICIENCY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinearWithOffset(Duration.decode("5d", 8), Duration.decode("10h", 8)));
}
@@ -122,7 +127,7 @@ public class RulesProviderTest extends AbstractDaoTestCase {
Rules rules = provider.provide(ruleDao, debtModel, durations);
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isEqualTo("PORTABILITY");
+ assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
}
@@ -134,7 +139,7 @@ public class RulesProviderTest extends AbstractDaoTestCase {
// As both default columns and user columns on debt are set, user debt columns should be used
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isEqualTo("PORTABILITY");
+ assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
}
@@ -146,7 +151,7 @@ public class RulesProviderTest extends AbstractDaoTestCase {
// As both default columns and user columns on debt are set, user debt columns should be used
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isEqualTo("PORTABILITY");
+ assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
}
@@ -158,7 +163,7 @@ public class RulesProviderTest extends AbstractDaoTestCase {
// As both default columns and user columns on debt are set, user debt columns should be used
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isEqualTo("PORTABILITY");
+ assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
}
@@ -169,7 +174,7 @@ public class RulesProviderTest extends AbstractDaoTestCase {
Rules rules = provider.provide(ruleDao, debtModel, durations);
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isNull();
+ assertThat(rule.debtSubCharacteristic()).isNull();
assertThat(rule.debtRemediationFunction()).isNull();
}
@@ -180,7 +185,7 @@ public class RulesProviderTest extends AbstractDaoTestCase {
Rules rules = provider.provide(ruleDao, debtModel, durations);
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isNull();
+ assertThat(rule.debtSubCharacteristic()).isNull();
assertThat(rule.debtRemediationFunction()).isNull();
}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModel.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModel.java
index c5d58b984d4..8e82b618bdd 100644
--- a/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModel.java
+++ b/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModel.java
@@ -22,14 +22,17 @@ package org.sonar.core.technicaldebt;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+import org.sonar.api.batch.debt.DebtModel;
+import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -37,19 +40,14 @@ import static com.google.common.collect.Lists.newArrayList;
public class DefaultTechnicalDebtModel implements TechnicalDebtModel {
- private Collection<DefaultCharacteristic> rootCharacteristics;
+ private final DebtModel model;
- public DefaultTechnicalDebtModel() {
- rootCharacteristics = newArrayList();
- }
-
- public DefaultTechnicalDebtModel addRootCharacteristic(DefaultCharacteristic characteristic) {
- rootCharacteristics.add(characteristic);
- return this;
+ public DefaultTechnicalDebtModel(DebtModel model) {
+ this.model = model;
}
public List<DefaultCharacteristic> rootCharacteristics() {
- return newArrayList(Iterables.filter(rootCharacteristics, new Predicate<DefaultCharacteristic>() {
+ return newArrayList(Iterables.filter(characteristics(), new Predicate<DefaultCharacteristic>() {
@Override
public boolean apply(DefaultCharacteristic input) {
return input.isRoot();
@@ -68,7 +66,7 @@ public class DefaultTechnicalDebtModel implements TechnicalDebtModel {
}
@CheckForNull
- public DefaultCharacteristic characteristicById(final Integer id){
+ public DefaultCharacteristic characteristicById(final Integer id) {
return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
@Override
public boolean apply(DefaultCharacteristic input) {
@@ -83,16 +81,17 @@ public class DefaultTechnicalDebtModel implements TechnicalDebtModel {
}
@CheckForNull
- public DefaultRequirement requirementsById(final Integer id){
+ public DefaultRequirement requirementsById(final Integer id) {
return null;
}
public List<DefaultCharacteristic> characteristics() {
List<DefaultCharacteristic> flatCharacteristics = newArrayList();
- for (DefaultCharacteristic rootCharacteristic : rootCharacteristics) {
- flatCharacteristics.add(rootCharacteristic);
- for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
- flatCharacteristics.add(characteristic);
+ for (DebtCharacteristic characteristic : model.characteristics()) {
+ DefaultCharacteristic root = toDefaultCharacteristic((DefaultDebtCharacteristic) characteristic, null);
+ flatCharacteristics.add(root);
+ for (DebtCharacteristic subCharacteristic : model.subCharacteristics(characteristic.key())) {
+ flatCharacteristics.add(toDefaultCharacteristic((DefaultDebtCharacteristic) subCharacteristic, root));
}
}
return flatCharacteristics;
@@ -102,8 +101,20 @@ public class DefaultTechnicalDebtModel implements TechnicalDebtModel {
return Collections.emptyList();
}
- public boolean isEmpty(){
- return rootCharacteristics.isEmpty();
+ public boolean isEmpty() {
+ return model.allCharacteristics().isEmpty();
+ }
+
+ private static DefaultCharacteristic toDefaultCharacteristic(DefaultDebtCharacteristic debtCharacteristic, @Nullable DefaultCharacteristic parentCharacteristic) {
+ return new DefaultCharacteristic()
+ .setId(debtCharacteristic.id())
+ .setKey(debtCharacteristic.key())
+ .setName(debtCharacteristic.name())
+ .setOrder(debtCharacteristic.order())
+ .setParent(parentCharacteristic)
+ .setRoot(parentCharacteristic)
+ .setCreatedAt(debtCharacteristic.createdAt())
+ .setUpdatedAt(debtCharacteristic.updatedAt());
}
}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModelTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModelTest.java
index 6bde3927995..a22036ed58e 100644
--- a/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModelTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModelTest.java
@@ -22,6 +22,8 @@ package org.sonar.core.technicaldebt;
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
+import org.sonar.api.batch.debt.internal.DefaultDebtModel;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
@@ -33,48 +35,54 @@ public class DefaultTechnicalDebtModelTest {
@Before
public void setUp() throws Exception {
- sqaleModel = new DefaultTechnicalDebtModel();
+ DefaultDebtModel debtModel = new DefaultDebtModel();
+ debtModel.addCharacteristic(
+ new DefaultDebtCharacteristic().setId(1)
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use")
+ .setOrder(1)
+ );
+ debtModel.addSubCharacteristic(
+ new DefaultDebtCharacteristic().setId(2)
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParentId(1),
+ "MEMORY_EFFICIENCY"
+ );
+ sqaleModel = new DefaultTechnicalDebtModel(debtModel);
}
@Test
- public void get_root_characteristics() throws Exception {
- DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
- .setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
-
- new DefaultCharacteristic()
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParent(rootCharacteristic);
-
- sqaleModel.addRootCharacteristic(rootCharacteristic);
-
+ public void get_characteristics() throws Exception {
assertThat(sqaleModel.rootCharacteristics()).hasSize(1);
+
DefaultCharacteristic resultRootCharacteristic = sqaleModel.rootCharacteristics().get(0);
- assertThat(resultRootCharacteristic).isEqualTo(rootCharacteristic);
+ assertThat(resultRootCharacteristic.id()).isEqualTo(1);
+ assertThat(resultRootCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(resultRootCharacteristic.name()).isEqualTo("Memory use");
+ assertThat(resultRootCharacteristic.order()).isEqualTo(1);
+ assertThat(resultRootCharacteristic.children()).hasSize(1);
+ assertThat(resultRootCharacteristic.parent()).isNull();
+ assertThat(resultRootCharacteristic.root()).isNull();
}
@Test
public void get_characteristic_by_key() throws Exception {
- DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
- .setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
-
- DefaultCharacteristic characteristic = new DefaultCharacteristic()
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParent(rootCharacteristic);
-
- sqaleModel.addRootCharacteristic(rootCharacteristic);
-
- assertThat(sqaleModel.characteristicByKey("MEMORY_EFFICIENCY")).isEqualTo(rootCharacteristic);
- assertThat(sqaleModel.characteristicByKey("EFFICIENCY")).isEqualTo(characteristic);
- assertThat(sqaleModel.characteristicByKey("EFFICIENCY").parent()).isEqualTo(rootCharacteristic);
+ assertThat(sqaleModel.characteristicByKey("MEMORY_EFFICIENCY")).isNotNull();
+ assertThat(sqaleModel.characteristicByKey("EFFICIENCY")).isNotNull();
+ assertThat(sqaleModel.characteristicByKey("EFFICIENCY").parent()).isNotNull();
assertThat(sqaleModel.characteristicByKey("UNKNOWN")).isNull();
}
@Test
+ public void characteristic_by_id() throws Exception {
+ assertThat(sqaleModel.characteristicById(1)).isNotNull();
+ assertThat(sqaleModel.characteristicById(2)).isNotNull();
+ assertThat(sqaleModel.characteristicById(123)).isNull();
+ }
+
+ @Test
public void get_requirement_by_rule_key_always_return_null() throws Exception {
assertThat(sqaleModel.requirementsByRule(RuleKey.of("checkstyle", "Regexp"))).isNull();
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtCharacteristic.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtCharacteristic.java
new file mode 100644
index 00000000000..01a3a97fe29
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtCharacteristic.java
@@ -0,0 +1,37 @@
+/*
+ * 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.api.batch.debt;
+
+import javax.annotation.CheckForNull;
+
+/**
+ * @since 4.3
+ */
+public interface DebtCharacteristic {
+ String key();
+
+ String name();
+
+ @CheckForNull
+ Integer order();
+
+ boolean isSub();
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtModel.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtModel.java
new file mode 100644
index 00000000000..b5aa6691f4b
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/DebtModel.java
@@ -0,0 +1,58 @@
+/*
+ * 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.api.batch.debt;
+
+import javax.annotation.CheckForNull;
+
+import java.util.List;
+
+/**
+ * This class can be used to retrieve characteristics or sub-characteristics from the technical debt model during analysis.
+ *
+ * Unfortunately, this class cannot be used to set characteristic on {@link org.sonar.api.measures.Measure},
+ * because the Measure API still uses deprecated {@link org.sonar.api.technicaldebt.batch.Characteristic}.
+ *
+ * @since 4.3
+ */
+public interface DebtModel {
+
+ /**
+ * Return only characteristics
+ */
+ List<DebtCharacteristic> characteristics();
+
+ /**
+ * Return sub-characteristics of a characteristic
+ */
+ List<DebtCharacteristic> subCharacteristics(String characteristicKey);
+
+ /**
+ * Return characteristics and sub-characteristics
+ */
+ List<DebtCharacteristic> allCharacteristics();
+
+ /**
+ * Return a characteristic or a sub-characteristic by a key
+ */
+ @CheckForNull
+ DebtCharacteristic characteristicByKey(String key);
+
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/internal/DefaultDebtCharacteristic.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/internal/DefaultDebtCharacteristic.java
new file mode 100644
index 00000000000..bea0f94cce6
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/internal/DefaultDebtCharacteristic.java
@@ -0,0 +1,120 @@
+/*
+ * 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.api.batch.debt.internal;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.util.Date;
+
+public class DefaultDebtCharacteristic implements DebtCharacteristic {
+
+ private Integer id;
+ private String key;
+ private String name;
+ private Integer order;
+ private Integer parentId;
+ private Date createdAt;
+ private Date updatedAt;
+
+ public Integer id() {
+ return id;
+ }
+
+ public DefaultDebtCharacteristic setId(Integer id) {
+ this.id = id;
+ return this;
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ public DefaultDebtCharacteristic setKey(String key) {
+ this.key = key;
+ return this;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ public DefaultDebtCharacteristic setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @Override
+ @CheckForNull
+ public Integer order() {
+ return order;
+ }
+
+ public DefaultDebtCharacteristic setOrder(@Nullable Integer order) {
+ this.order = order;
+ return this;
+ }
+
+ @CheckForNull
+ public Integer parentId() {
+ return parentId;
+ }
+
+ public DefaultDebtCharacteristic setParentId(@Nullable Integer parentId) {
+ this.parentId = parentId;
+ return this;
+ }
+
+ public Date createdAt() {
+ return createdAt;
+ }
+
+ public DefaultDebtCharacteristic setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ @CheckForNull
+ public Date updatedAt() {
+ return updatedAt;
+ }
+
+ public DefaultDebtCharacteristic setUpdatedAt(@Nullable Date updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+
+ @Override
+ public boolean isSub(){
+ return parentId != null;
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/internal/DefaultDebtModel.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/internal/DefaultDebtModel.java
new file mode 100644
index 00000000000..853412ac236
--- /dev/null
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/internal/DefaultDebtModel.java
@@ -0,0 +1,93 @@
+/*
+ * 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.api.batch.debt.internal;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+import org.sonar.api.batch.debt.DebtModel;
+
+import javax.annotation.CheckForNull;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class DefaultDebtModel implements DebtModel {
+
+ /**
+ * Sub-characteristics list can be retrieved with the characteristic key
+ * Characteristics list can be retrieved by with the null key
+ */
+ private Multimap<String, DebtCharacteristic> characteristicsByKey;
+
+ public DefaultDebtModel() {
+ characteristicsByKey = ArrayListMultimap.create();
+ }
+
+ public DefaultDebtModel addCharacteristic(DebtCharacteristic characteristic) {
+ characteristicsByKey.put(null, characteristic);
+ return this;
+ }
+
+ public DefaultDebtModel addSubCharacteristic(DebtCharacteristic subCharacteristic, String characteristicKey) {
+ characteristicsByKey.put(characteristicKey, subCharacteristic);
+ return this;
+ }
+
+ @Override
+ public List<DebtCharacteristic> characteristics() {
+ return newArrayList(characteristicsByKey.get(null));
+ }
+
+ @Override
+ public List<DebtCharacteristic> subCharacteristics(String characteristicKey) {
+ return newArrayList(characteristicsByKey.get(characteristicKey));
+ }
+
+ @Override
+ public List<DebtCharacteristic> allCharacteristics() {
+ return newArrayList(characteristicsByKey.values());
+ }
+
+ @Override
+ @CheckForNull
+ public DebtCharacteristic characteristicByKey(final String key) {
+ return Iterables.find(characteristicsByKey.values(), new Predicate<DebtCharacteristic>() {
+ @Override
+ public boolean apply(DebtCharacteristic input) {
+ return key.equals(input.key());
+ }
+ }, null);
+ }
+
+ @CheckForNull
+ public DebtCharacteristic characteristicById(final int id) {
+ return Iterables.find(characteristicsByKey.values(), new Predicate<DebtCharacteristic>() {
+ @Override
+ public boolean apply(DebtCharacteristic input) {
+ return id == ((DefaultDebtCharacteristic) input).id();
+ }
+ }, null);
+ }
+}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rule.java
index f87317dfdab..475d8e7b600 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rule.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/Rule.java
@@ -53,12 +53,12 @@ public interface Rule {
RuleStatus status();
/**
- * Characteristic key.
+ * Sub characteristic key.
*
* @since 4.3
*/
@CheckForNull
- String debtCharacteristic();
+ String debtSubCharacteristic();
/**
* Remediation function : can by Linear (with a coefficient), Linear with offset (with a coefficient and an offset) or Constant per issue (with an offset)
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRule.java
index 5b2db0d27b9..cd93c077d60 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRule.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/DefaultRule.java
@@ -37,7 +37,7 @@ public class DefaultRule implements Rule {
private final RuleKey key;
private final Integer id;
- private final String name, severity, description, metadata, debtCharacteristic;
+ private final String name, severity, description, metadata, debtSubCharacteristic;
private final RuleStatus status;
private final DebtRemediationFunction debtRemediationFunction;
@@ -51,7 +51,7 @@ public class DefaultRule implements Rule {
this.description = newRule.description;
this.metadata = newRule.metadata;
this.status = newRule.status;
- this.debtCharacteristic = newRule.debtCharacteristic;
+ this.debtSubCharacteristic = newRule.debtSubCharacteristic;
this.debtRemediationFunction = newRule.debtRemediationFunction;
ImmutableMap.Builder<String, RuleParam> builder = ImmutableMap.builder();
@@ -97,8 +97,8 @@ public class DefaultRule implements Rule {
}
@Override
- public String debtCharacteristic() {
- return debtCharacteristic;
+ public String debtSubCharacteristic() {
+ return debtSubCharacteristic;
}
@Override
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewRule.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewRule.java
index c3506ff1b50..c921a41ecc4 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewRule.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewRule.java
@@ -37,7 +37,7 @@ public class NewRule {
final RuleKey key;
Integer id;
- String name, description, severity = DEFAULT_SEVERITY, metadata, debtCharacteristic;
+ String name, description, severity = DEFAULT_SEVERITY, metadata, debtSubCharacteristic;
DebtRemediationFunction debtRemediationFunction;
RuleStatus status = RuleStatus.defaultStatus();
Map<String, NewRuleParam> params = new HashMap<String, NewRuleParam>();
@@ -76,8 +76,8 @@ public class NewRule {
return this;
}
- public NewRule setDebtCharacteristic(@Nullable String c) {
- this.debtCharacteristic = c;
+ public NewRule setDebtSubCharacteristic(@Nullable String c) {
+ this.debtSubCharacteristic = c;
return this;
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/DebtCharacteristic.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/DebtCharacteristic.java
index 81d704ced4a..c8e428213a0 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/DebtCharacteristic.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/DebtCharacteristic.java
@@ -22,13 +22,10 @@ package org.sonar.api.server.debt;
import javax.annotation.CheckForNull;
-import java.util.Date;
-
/**
* @since 4.3
*/
public interface DebtCharacteristic {
- Integer id();
String key();
@@ -37,11 +34,5 @@ public interface DebtCharacteristic {
@CheckForNull
Integer order();
- @CheckForNull
- Integer parentId();
-
- Date createdAt();
-
- @CheckForNull
- Date updatedAt();
+ boolean isSub();
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/DebtModel.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/DebtModel.java
index cfc8f323cba..b2d668fa239 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/DebtModel.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/DebtModel.java
@@ -39,6 +39,9 @@ public interface DebtModel extends ServerComponent {
*/
List<DebtCharacteristic> characteristics();
- DebtCharacteristic characteristicById(int id);
+ /**
+ * Return a characteristic or a sub-characteristic by its key
+ */
+ DebtCharacteristic characteristicByKey(String key);
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/internal/DefaultDebtCharacteristic.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/internal/DefaultDebtCharacteristic.java
index d9df13d4d76..9852e6c7cc1 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/internal/DefaultDebtCharacteristic.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/debt/internal/DefaultDebtCharacteristic.java
@@ -42,7 +42,6 @@ public class DefaultDebtCharacteristic implements DebtCharacteristic {
private Date createdAt;
private Date updatedAt;
- @Override
public Integer id() {
return id;
}
@@ -83,7 +82,6 @@ public class DefaultDebtCharacteristic implements DebtCharacteristic {
return this;
}
- @Override
@CheckForNull
public Integer parentId() {
return parentId;
@@ -94,7 +92,6 @@ public class DefaultDebtCharacteristic implements DebtCharacteristic {
return this;
}
- @Override
public Date createdAt() {
return createdAt;
}
@@ -104,7 +101,6 @@ public class DefaultDebtCharacteristic implements DebtCharacteristic {
return this;
}
- @Override
@CheckForNull
public Date updatedAt() {
return updatedAt;
@@ -116,6 +112,11 @@ public class DefaultDebtCharacteristic implements DebtCharacteristic {
}
@Override
+ public boolean isSub(){
+ return parentId != null;
+ }
+
+ @Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/Characteristic.java b/sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/Characteristic.java
index 27287a14498..fadad455575 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/Characteristic.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/Characteristic.java
@@ -27,7 +27,9 @@ import java.util.List;
/**
* @since 4.1
+ * @deprecated since 4.3
*/
+@Deprecated
public interface Characteristic {
Integer id();
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/TechnicalDebtModel.java b/sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/TechnicalDebtModel.java
index a18212ec83e..33eb7e48a76 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/TechnicalDebtModel.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/technicaldebt/batch/TechnicalDebtModel.java
@@ -20,6 +20,7 @@
package org.sonar.api.technicaldebt.batch;
+import org.sonar.api.BatchComponent;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
@@ -30,8 +31,10 @@ import java.util.List;
/**
* @since 4.1
* Used by Views plugin
+ * @deprecated since 4.3
*/
-public interface TechnicalDebtModel {
+@Deprecated
+public interface TechnicalDebtModel extends BatchComponent {
@CheckForNull
Characteristic characteristicById(Integer id);
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/debt/internal/DefaultDebtModelTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/debt/internal/DefaultDebtModelTest.java
new file mode 100644
index 00000000000..561cb5ed3ae
--- /dev/null
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/debt/internal/DefaultDebtModelTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.api.batch.debt.internal;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class DefaultDebtModelTest {
+
+ private DefaultDebtModel debtModel;
+
+ @Before
+ public void setUp() throws Exception {
+ debtModel = new DefaultDebtModel()
+ .addCharacteristic(
+ new DefaultDebtCharacteristic().setId(1)
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use")
+ .setOrder(1)
+ )
+ .addSubCharacteristic(
+ new DefaultDebtCharacteristic().setId(2)
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParentId(1),
+ "MEMORY_EFFICIENCY"
+ );
+ }
+
+ @Test
+ public void all_characteristics() throws Exception {
+ assertThat(debtModel.allCharacteristics()).hasSize(2);
+ }
+
+ @Test
+ public void characteristics() throws Exception {
+ assertThat(debtModel.characteristics()).hasSize(1);
+ }
+
+ @Test
+ public void sub_characteristics() throws Exception {
+ assertThat(debtModel.subCharacteristics("MEMORY_EFFICIENCY")).hasSize(1);
+ }
+
+ @Test
+ public void characteristic_by_id() throws Exception {
+ DefaultDebtCharacteristic debtCharacteristic = (DefaultDebtCharacteristic) debtModel.characteristicById(1);
+ assertThat(debtCharacteristic).isNotNull();
+ assertThat(debtCharacteristic.id()).isEqualTo(1);
+ assertThat(debtCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(debtCharacteristic.name()).isEqualTo("Memory use");
+ assertThat(debtCharacteristic.order()).isEqualTo(1);
+ assertThat(debtCharacteristic.parentId()).isNull();
+ assertThat(debtCharacteristic.isSub()).isFalse();
+ }
+
+ @Test
+ public void characteristic_by_key() throws Exception {
+ DefaultDebtCharacteristic debtCharacteristic = (DefaultDebtCharacteristic) debtModel.characteristicByKey("EFFICIENCY");
+ assertThat(debtCharacteristic).isNotNull();
+ assertThat(debtCharacteristic.id()).isEqualTo(2);
+ assertThat(debtCharacteristic.key()).isEqualTo("EFFICIENCY");
+ assertThat(debtCharacteristic.name()).isEqualTo("Efficiency");
+ assertThat(debtCharacteristic.order()).isNull();
+ assertThat(debtCharacteristic.parentId()).isEqualTo(1);
+ assertThat(debtCharacteristic.isSub()).isTrue();
+ }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/RulesBuilderTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/RulesBuilderTest.java
index e569d4e1db1..074fe58aef7 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/RulesBuilderTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/RulesBuilderTest.java
@@ -48,7 +48,7 @@ public class RulesBuilderTest {
newSquid1.setMetadata("foo=bar");
newSquid1.setSeverity(Severity.CRITICAL);
newSquid1.setStatus(RuleStatus.BETA);
- newSquid1.setDebtCharacteristic("COMPILER");
+ newSquid1.setDebtSubCharacteristic("COMPILER");
newSquid1.setDebtRemediationFunction(DebtRemediationFunction.create(DebtRemediationFunction.Type.LINEAR_OFFSET, Duration.create(10), Duration.create(60)));
newSquid1.addParam("min");
newSquid1.addParam("max").setDescription("Maximum");
@@ -71,11 +71,11 @@ public class RulesBuilderTest {
assertThat(squid1.metadata()).isEqualTo("foo=bar");
assertThat(squid1.status()).isEqualTo(RuleStatus.BETA);
assertThat(squid1.severity()).isEqualTo(Severity.CRITICAL);
- assertThat(squid1.debtCharacteristic()).isEqualTo("COMPILER");
+ assertThat(squid1.debtSubCharacteristic()).isEqualTo("COMPILER");
assertThat(squid1.debtRemediationFunction().type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
assertThat(squid1.debtRemediationFunction().coefficient()).isEqualTo(Duration.create(10));
assertThat(squid1.debtRemediationFunction().offset()).isEqualTo(Duration.create(60));
- assertThat(squid1.debtCharacteristic()).isEqualTo("COMPILER");
+ assertThat(squid1.debtSubCharacteristic()).isEqualTo("COMPILER");
assertThat(squid1.params()).hasSize(2);
assertThat(squid1.param("min").key()).isEqualTo("min");
assertThat(squid1.param("min").description()).isNull();
@@ -89,7 +89,7 @@ public class RulesBuilderTest {
assertThat(squid2.metadata()).isNull();
assertThat(squid2.status()).isEqualTo(RuleStatus.defaultStatus());
assertThat(squid2.severity()).isEqualTo(Severity.defaultSeverity());
- assertThat(squid2.debtCharacteristic()).isNull();
+ assertThat(squid2.debtSubCharacteristic()).isNull();
assertThat(squid2.debtRemediationFunction()).isNull();
assertThat(squid2.params()).isEmpty();
}