]> source.dussan.org Git - sonarqube.git/commitdiff
Renamed package to org.sonar.core.technicaldebt to debt And removed technical word...
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 7 Mar 2014 12:56:18 +0000 (13:56 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 7 Mar 2014 12:56:44 +0000 (13:56 +0100)
130 files changed:
sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelLoader.java
sonar-batch/src/test/java/org/sonar/batch/debt/DebtModelLoaderTest.java
sonar-core/src/main/java/org/sonar/core/debt/CharacteristicsDebtModelSynchronizer.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/CharacteristicsDebtModelXMLImporter.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/DebtModelPluginRepository.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/DefaultTechnicalDebtManager.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/DefaultTechnicalDebtModel.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/RulesDebtModelXMLImporter.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/TechnicalDebtModelSynchronizer.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/TechnicalDebtRuleCache.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/TechnicalDebtXMLImporter.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/db/CharacteristicDao.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/db/CharacteristicDto.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/db/CharacteristicMapper.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/db/package-info.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/debt/package-info.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/DaoUtils.java
sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
sonar-core/src/main/java/org/sonar/core/technicaldebt/CharacteristicsXMLImporter.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/DebtCharacteristicsSynchronizer.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManager.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModel.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/RuleDebtXMLImporter.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtModelRepository.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtModelSynchronizer.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtRuleCache.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporter.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/db/CharacteristicDao.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/db/CharacteristicDto.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/db/CharacteristicMapper.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/db/package-info.java [deleted file]
sonar-core/src/main/java/org/sonar/core/technicaldebt/package-info.java [deleted file]
sonar-core/src/main/resources/org/sonar/core/debt/db/CharacteristicMapper.xml [new file with mode: 0644]
sonar-core/src/main/resources/org/sonar/core/technicaldebt/db/CharacteristicMapper.xml [deleted file]
sonar-core/src/test/java/org/sonar/core/debt/CharacteristicsDebtModelSynchronizerTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/debt/CharacteristicsDebtModelXMLImporterTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/debt/DebtModelPluginRepositoryTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/debt/DefaultTechnicalDebtManagerTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/debt/DefaultTechnicalDebtModelTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/debt/RulesDebtModelXMLImporterTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/debt/TechnicalDebtModelSynchronizerTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/debt/TechnicalDebtRuleCacheTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/debt/TechnicalDebtXMLImporterTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/debt/db/CharacteristicDaoTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/debt/db/CharacteristicDtoTest.java [new file with mode: 0644]
sonar-core/src/test/java/org/sonar/core/technicaldebt/CharacteristicsXMLImporterTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/technicaldebt/DebtCharacteristicsSynchronizerTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManagerTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtModelTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/technicaldebt/RuleDebtXMLImporterTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtModelSynchronizerTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtRuleCacheTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/technicaldebt/db/CharacteristicDaoTest.java [deleted file]
sonar-core/src/test/java/org/sonar/core/technicaldebt/db/CharacteristicDtoTest.java [deleted file]
sonar-core/src/test/resources/org/sonar/core/debt/CharacteristicsDebtModelXMLImporterTest/import_badly_formatted_xml.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/CharacteristicsDebtModelXMLImporterTest/import_characteristics.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/convert_deprecated_linear_with_threshold_function_by_linear_function.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/ignore_deprecated_constant_per_file_function.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/ignore_invalid_value.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/ignore_rule_on_root_characteristics.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_badly_formatted_xml.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_constant_issue.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_linear.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_linear_with_offset.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_rules.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/replace_mn_by_min.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/use_default_unit_when_no_unit.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtModelRepositoryTest/csharp-model.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtModelRepositoryTest/java-model.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/ignore_requirement_on_root_characteristics.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/import_characteristics.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_badly-formatted.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_constant_per_file.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_linear_with_threshold.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear_with_offset.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldLogWarningIfRuleNotFound.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldRejectXML_with_invalid_value.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/use_default_unit_when_no_unit.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/disable-result.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/disable.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/insert_characteristic-result.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/insert_requirement-result.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/select_enabled_root_characteristics.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/select_enabled_root_characteristics_order_by_characteristic_order.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/shared.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_characteristic-result.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_characteristic.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_requirement-result.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_requirement.xml [new file with mode: 0644]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/CharacteristicsXMLImporterTest/import_badly_formatted_xml.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/CharacteristicsXMLImporterTest/import_characteristics.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest/csharp-model.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest/java-model.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/ignore_requirement_on_root_characteristics.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/import_characteristics.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_badly-formatted.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_constant_per_file.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_linear_with_threshold.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear_with_offset.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldLogWarningIfRuleNotFound.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldRejectXML_with_invalid_value.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/use_default_unit_when_no_unit.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/disable-result.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/disable.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/insert_characteristic-result.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/insert_requirement-result.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/select_enabled_root_characteristics.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/select_enabled_root_characteristics_order_by_characteristic_order.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/shared.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_characteristic-result.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_characteristic.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_requirement-result.xml [deleted file]
sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_requirement.xml [deleted file]
sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java
sonar-server/src/main/java/org/sonar/server/platform/Platform.java
sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRuleDefinitions.java
sonar-server/src/main/java/org/sonar/server/rule/RuleRegistration.java
sonar-server/src/main/java/org/sonar/server/startup/RegisterDebtCharacteristicModel.java
sonar-server/src/main/java/org/sonar/server/startup/RegisterTechnicalDebtModel.java
sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java
sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java
sonar-server/src/test/java/org/sonar/server/rule/DeprecatedRuleDefinitionsTest.java
sonar-server/src/test/java/org/sonar/server/rule/RuleRegistrationTest.java
sonar-server/src/test/java/org/sonar/server/startup/RegisterDebtCharacteristicModelTest.java
sonar-server/src/test/java/org/sonar/server/startup/RegisterTechnicalDebtModelTest.java
sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java

index 1cbf38d6835b210b7b44a3e20ccb2df523d235a2..9d770500e3cd493a4f195018f1f123c2b8ae5c6c 100644 (file)
@@ -27,9 +27,9 @@ import org.sonar.api.rules.RuleFinder;
 import org.sonar.api.rules.RuleQuery;
 import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
 import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import org.sonar.core.debt.DefaultTechnicalDebtModel;
+import org.sonar.core.debt.db.CharacteristicDao;
+import org.sonar.core.debt.db.CharacteristicDto;
 
 import java.util.Collection;
 import java.util.List;
index 2de08c8f77ad1ca416e53b5e26f1c0111e2d7f2f..1d2ce77018fb25b4e5ce893d421b682ee9c67325 100644 (file)
@@ -32,9 +32,9 @@ import org.sonar.api.rules.RuleQuery;
 import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
 import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
 import org.sonar.api.utils.internal.WorkDuration;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import org.sonar.core.debt.DefaultTechnicalDebtModel;
+import org.sonar.core.debt.db.CharacteristicDao;
+import org.sonar.core.debt.db.CharacteristicDto;
 
 import static com.google.common.collect.Lists.newArrayList;
 import static org.fest.assertions.Assertions.assertThat;
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/CharacteristicsDebtModelSynchronizer.java b/sonar-core/src/main/java/org/sonar/core/debt/CharacteristicsDebtModelSynchronizer.java
new file mode 100644 (file)
index 0000000..6a702d6
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.ibatis.session.SqlSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.debt.db.CharacteristicDao;
+import org.sonar.core.debt.db.CharacteristicDto;
+import org.sonar.core.persistence.MyBatis;
+
+import java.io.Reader;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class CharacteristicsDebtModelSynchronizer implements ServerExtension {
+
+  private static final Logger LOG = LoggerFactory.getLogger(CharacteristicsDebtModelSynchronizer.class);
+
+  private final MyBatis mybatis;
+  private final CharacteristicDao dao;
+  private final DebtModelPluginRepository languageModelFinder;
+  private final CharacteristicsDebtModelXMLImporter importer;
+
+  public CharacteristicsDebtModelSynchronizer(MyBatis mybatis, CharacteristicDao dao, DebtModelPluginRepository modelRepository, CharacteristicsDebtModelXMLImporter importer) {
+    this.mybatis = mybatis;
+    this.dao = dao;
+    this.languageModelFinder = modelRepository;
+    this.importer = importer;
+  }
+
+  public List<CharacteristicDto> synchronize(ValidationMessages messages) {
+    SqlSession session = mybatis.openSession();
+
+    List<CharacteristicDto> model = newArrayList();
+    try {
+      model = synchronize(messages, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+    return model;
+  }
+
+  public List<CharacteristicDto> synchronize(ValidationMessages messages, SqlSession session) {
+    DefaultTechnicalDebtModel defaultModel = loadModelFromXml(DebtModelPluginRepository.DEFAULT_MODEL, messages);
+    List<CharacteristicDto> model = loadOrCreateModelFromDb(defaultModel, session);
+    messages.log(LOG);
+    return model;
+  }
+
+  private List<CharacteristicDto> loadOrCreateModelFromDb(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
+    List<CharacteristicDto> characteristicDtos = loadModel();
+    if (characteristicDtos.isEmpty()) {
+      return createTechnicalDebtModel(defaultModel, session);
+    }
+    return characteristicDtos;
+  }
+
+  private List<CharacteristicDto> loadModel() {
+    return dao.selectEnabledCharacteristics();
+  }
+
+  private List<CharacteristicDto> createTechnicalDebtModel(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
+    List<CharacteristicDto> characteristics = newArrayList();
+    for (DefaultCharacteristic rootCharacteristic : defaultModel.rootCharacteristics()) {
+      CharacteristicDto rootCharacteristicDto = CharacteristicDto.toDto(rootCharacteristic, null);
+      dao.insert(rootCharacteristicDto, session);
+      characteristics.add(rootCharacteristicDto);
+      for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
+        CharacteristicDto characteristicDto = CharacteristicDto.toDto(characteristic, rootCharacteristicDto.getId());
+        dao.insert(characteristicDto, session);
+        characteristics.add(characteristicDto);
+      }
+    }
+    return characteristics;
+  }
+
+  public DefaultTechnicalDebtModel loadModelFromXml(String pluginKey, ValidationMessages messages) {
+    Reader xmlFileReader = null;
+    try {
+      xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
+      return importer.importXML(xmlFileReader, messages);
+    } finally {
+      IOUtils.closeQuietly(xmlFileReader);
+    }
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/CharacteristicsDebtModelXMLImporter.java b/sonar-core/src/main/java/org/sonar/core/debt/CharacteristicsDebtModelXMLImporter.java
new file mode 100644 (file)
index 0000000..3437140
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import org.apache.commons.lang.StringUtils;
+import org.codehaus.stax2.XMLInputFactory2;
+import org.codehaus.staxmate.SMInputFactory;
+import org.codehaus.staxmate.in.SMHierarchicCursor;
+import org.codehaus.staxmate.in.SMInputCursor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.utils.ValidationMessages;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Reader;
+import java.io.StringReader;
+
+public class CharacteristicsDebtModelXMLImporter implements ServerExtension {
+
+  private static final Logger LOG = LoggerFactory.getLogger(CharacteristicsDebtModelXMLImporter.class);
+
+  public static final String CHARACTERISTIC = "chc";
+  public static final String CHARACTERISTIC_KEY = "key";
+  public static final String CHARACTERISTIC_NAME = "name";
+
+  public DefaultTechnicalDebtModel importXML(String xml, ValidationMessages messages) {
+    return importXML(new StringReader(xml), messages);
+  }
+
+  public DefaultTechnicalDebtModel importXML(Reader xml, ValidationMessages messages) {
+    DefaultTechnicalDebtModel model = new DefaultTechnicalDebtModel();
+    try {
+      SMInputFactory inputFactory = initStax();
+      SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
+
+      // advance to <sqale>
+      cursor.advance();
+      SMInputCursor chcCursor = cursor.childElementCursor(CHARACTERISTIC);
+
+      while (chcCursor.getNext() != null) {
+        processCharacteristic(model, null, chcCursor, messages);
+      }
+
+      cursor.getStreamReader().closeCompletely();
+
+    } catch (XMLStreamException e) {
+      LOG.error("XML is not valid", e);
+      messages.addErrorText("XML is not valid: " + e.getMessage());
+    }
+    return model;
+  }
+
+  private SMInputFactory initStax() {
+    XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
+    xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
+    xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
+    xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+    xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
+    return new SMInputFactory(xmlFactory);
+  }
+
+  private DefaultCharacteristic processCharacteristic(DefaultTechnicalDebtModel model, DefaultCharacteristic parent, SMInputCursor chcCursor,
+                                                      ValidationMessages messages) throws XMLStreamException {
+    DefaultCharacteristic characteristic = new DefaultCharacteristic();
+    SMInputCursor cursor = chcCursor.childElementCursor();
+    while (cursor.getNext() != null) {
+      String node = cursor.getLocalName();
+      if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
+        characteristic.setKey(cursor.collectDescendantText().trim());
+        // Attached to parent only if a key is existing, otherwise characteristic with empty key can be added.
+        characteristic.setParent(parent);
+
+      } else if (StringUtils.equals(node, CHARACTERISTIC_NAME)) {
+        characteristic.setName(cursor.collectDescendantText().trim(), false);
+
+        // <chc> can contain characteristics or requirements
+      } else if (StringUtils.equals(node, CHARACTERISTIC)) {
+        processCharacteristic(model, characteristic, cursor, messages);
+
+      }
+    }
+
+    if (StringUtils.isNotBlank(characteristic.key()) && characteristic.isRoot()) {
+      characteristic.setOrder(model.rootCharacteristics().size() + 1);
+      model.addRootCharacteristic(characteristic);
+      return characteristic;
+    }
+    return null;
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/DebtModelPluginRepository.java b/sonar-core/src/main/java/org/sonar/core/debt/DebtModelPluginRepository.java
new file mode 100644 (file)
index 0000000..ca4de29
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+import org.picocontainer.Startable;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.platform.PluginMetadata;
+import org.sonar.api.platform.PluginRepository;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+/**
+ * <p>This class is used to find which technical debt model XML files exist in the Sonar instance.</p>
+ * <p>
+ * Those XML files are provided by language plugins that embed their own contribution to the definition of the Technical debt model.
+ * They must be located in the classpath of those language plugins, more specifically in the "com.sonar.sqale" package, and
+ * they must be named "<pluginKey>-model.xml".
+ * </p>
+ */
+public class DebtModelPluginRepository implements ServerExtension, Startable {
+
+  public static final String DEFAULT_MODEL = "technical-debt";
+
+  private static final String XML_FILE_SUFFIX = "-model.xml";
+  private static final String XML_FILE_PREFIX = "com/sonar/sqale/";
+
+  private String xmlFilePrefix;
+
+  private PluginRepository pluginRepository;
+  private Map<String, ClassLoader> contributingPluginKeyToClassLoader;
+
+  public DebtModelPluginRepository(PluginRepository pluginRepository) {
+    this.pluginRepository = pluginRepository;
+    this.xmlFilePrefix = XML_FILE_PREFIX;
+  }
+
+  @VisibleForTesting
+  DebtModelPluginRepository(PluginRepository pluginRepository, String xmlFilePrefix) {
+    this.pluginRepository = pluginRepository;
+    this.xmlFilePrefix = xmlFilePrefix;
+  }
+
+  @VisibleForTesting
+  DebtModelPluginRepository(Map<String, ClassLoader> contributingPluginKeyToClassLoader, String xmlFilePrefix) {
+    this.contributingPluginKeyToClassLoader = contributingPluginKeyToClassLoader;
+    this.xmlFilePrefix = xmlFilePrefix;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void start() {
+    findAvailableXMLFiles();
+  }
+
+  protected void findAvailableXMLFiles() {
+    if (contributingPluginKeyToClassLoader == null) {
+      contributingPluginKeyToClassLoader = Maps.newTreeMap();
+      // Add default model
+      contributingPluginKeyToClassLoader.put(DEFAULT_MODEL, getClass().getClassLoader());
+      for (PluginMetadata metadata : pluginRepository.getMetadata()) {
+        String pluginKey = metadata.getKey();
+        ClassLoader classLoader = pluginRepository.getPlugin(pluginKey).getClass().getClassLoader();
+        if (classLoader.getResource(getXMLFilePath(pluginKey)) != null) {
+          contributingPluginKeyToClassLoader.put(pluginKey, classLoader);
+        }
+      }
+    }
+    contributingPluginKeyToClassLoader = Collections.unmodifiableMap(contributingPluginKeyToClassLoader);
+  }
+
+  @VisibleForTesting
+  String getXMLFilePath(String model) {
+    return xmlFilePrefix + model + XML_FILE_SUFFIX;
+  }
+
+  /**
+   * Returns the list of plugins that can contribute to the technical debt model.
+   *
+   * @return the list of plugin keys
+   */
+  public Collection<String> getContributingPluginList() {
+    return newArrayList(contributingPluginKeyToClassLoader.keySet());
+  }
+
+  /**
+   * Creates a new {@link java.io.Reader} for the XML file that contains the model contributed by the given plugin.
+   *
+   * @param pluginKey the key of the plugin that contributes the XML file
+   * @return the reader, that must be closed once its use is finished.
+   */
+  public Reader createReaderForXMLFile(String pluginKey) {
+    ClassLoader classLoader = contributingPluginKeyToClassLoader.get(pluginKey);
+    String xmlFilePath = getXMLFilePath(pluginKey);
+    return new InputStreamReader(classLoader.getResourceAsStream(xmlFilePath));
+  }
+
+  @VisibleForTesting
+  Map<String, ClassLoader> getContributingPluginKeyToClassLoader(){
+    return contributingPluginKeyToClassLoader;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void stop() {
+    // Nothing to do
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/DefaultTechnicalDebtManager.java b/sonar-core/src/main/java/org/sonar/core/debt/DefaultTechnicalDebtManager.java
new file mode 100644 (file)
index 0000000..eb9fe92
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.technicaldebt.server.Characteristic;
+import org.sonar.api.technicaldebt.server.TechnicalDebtManager;
+import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic;
+import org.sonar.core.debt.db.CharacteristicDao;
+import org.sonar.core.debt.db.CharacteristicDto;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+/**
+ * TODO This class should be replaced or created by a TechnicalDebtManagerBuilder
+ */
+public class DefaultTechnicalDebtManager implements TechnicalDebtManager {
+
+  private final CharacteristicDao dao;
+  private final RuleFinder ruleFinder;
+
+  public DefaultTechnicalDebtManager(CharacteristicDao dao, RuleFinder ruleFinder) {
+    this.dao = dao;
+    this.ruleFinder = ruleFinder;
+  }
+
+  public List<Characteristic> findRootCharacteristics() {
+    List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
+    List<Characteristic> characteristics = newArrayList();
+    for (CharacteristicDto dto : dtos) {
+      characteristics.add(toCharacteristic(dto, null));
+    }
+    return characteristics;
+  }
+
+  @CheckForNull
+  public Characteristic findCharacteristicById(Integer id) {
+    CharacteristicDto dto = dao.selectById(id);
+    if (dto != null) {
+      return toCharacteristic(dto, null);
+    }
+    return null;
+  }
+
+  @CheckForNull
+  public Characteristic findRequirementByRuleId(int ruleId) {
+    CharacteristicDto requirementDto = dao.selectByRuleId(ruleId);
+    if (requirementDto != null) {
+      Rule rule = ruleFinder.findById(ruleId);
+      if (rule == null) {
+        throw new IllegalArgumentException(String.format("Rule with id '%s' do not exists.", ruleId));
+      }
+      return toCharacteristic(requirementDto, RuleKey.of(rule.getRepositoryKey(), rule.getKey()));
+    }
+    return null;
+  }
+
+  @CheckForNull
+  public Characteristic findRequirementByRule(Rule rule) {
+    CharacteristicDto requirementDto = dao.selectByRuleId(rule.getId());
+    if (requirementDto != null) {
+      return toCharacteristic(requirementDto, RuleKey.of(rule.getRepositoryKey(), rule.getKey()));
+    }
+    return null;
+  }
+
+  private static Characteristic toCharacteristic(CharacteristicDto dto, @Nullable RuleKey ruleKey) {
+    Double factorValue = dto.getFactorValue();
+    Double offsetValue = dto.getOffsetValue();
+    return new DefaultCharacteristic()
+      .setId(dto.getId())
+      .setKey(dto.getKey())
+      .setName(dto.getName())
+      .setOrder(dto.getOrder())
+      .setParentId(dto.getParentId())
+      .setRootId(dto.getRootId())
+      .setRuleKey(ruleKey)
+      .setFunction(dto.getFunction())
+      .setFactorValue(factorValue != null ? factorValue.intValue() : null)
+      .setFactorUnit(DefaultCharacteristic.toUnit(dto.getFactorUnit()))
+      .setOffsetValue(offsetValue != null ? offsetValue.intValue() : null)
+      .setOffsetUnit(DefaultCharacteristic.toUnit(dto.getOffsetUnit()));
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/DefaultTechnicalDebtModel.java b/sonar-core/src/main/java/org/sonar/core/debt/DefaultTechnicalDebtModel.java
new file mode 100644 (file)
index 0000000..4cb950d
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+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 java.util.Collection;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class DefaultTechnicalDebtModel implements TechnicalDebtModel {
+
+  private Collection<DefaultCharacteristic> rootCharacteristics;
+
+  public DefaultTechnicalDebtModel() {
+    rootCharacteristics = newArrayList();
+  }
+
+  public DefaultTechnicalDebtModel addRootCharacteristic(DefaultCharacteristic characteristic) {
+    rootCharacteristics.add(characteristic);
+    return this;
+  }
+
+  public List<DefaultCharacteristic> rootCharacteristics() {
+    return newArrayList(Iterables.filter(rootCharacteristics, new Predicate<DefaultCharacteristic>() {
+      @Override
+      public boolean apply(DefaultCharacteristic input) {
+        return input.isRoot();
+      }
+    }));
+  }
+
+  @CheckForNull
+  public DefaultCharacteristic characteristicByKey(final String key) {
+    return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
+      @Override
+      public boolean apply(DefaultCharacteristic input) {
+        return input.key().equals(key);
+      }
+    }, null);
+  }
+
+  @CheckForNull
+  public DefaultCharacteristic characteristicById(final Integer id){
+    return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
+      @Override
+      public boolean apply(DefaultCharacteristic input) {
+        return input.id().equals(id);
+      }
+    }, null);
+  }
+
+  @CheckForNull
+  public DefaultRequirement requirementsByRule(final RuleKey ruleKey) {
+    return Iterables.find(requirements(), new Predicate<DefaultRequirement>() {
+      @Override
+      public boolean apply(DefaultRequirement input) {
+        return input.ruleKey().equals(ruleKey);
+      }
+    }, null);
+  }
+
+  @CheckForNull
+  public DefaultRequirement requirementsById(final Integer id){
+    return Iterables.find(requirements(), new Predicate<DefaultRequirement>() {
+      @Override
+      public boolean apply(DefaultRequirement input) {
+        return input.id().equals(id);
+      }
+    }, null);
+  }
+
+  public List<DefaultCharacteristic> characteristics() {
+    List<DefaultCharacteristic> flatCharacteristics = newArrayList();
+    for (DefaultCharacteristic rootCharacteristic : rootCharacteristics) {
+      flatCharacteristics.add(rootCharacteristic);
+      for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
+        flatCharacteristics.add(characteristic);
+      }
+    }
+    return flatCharacteristics;
+  }
+
+  public List<DefaultRequirement> requirements() {
+    List<DefaultRequirement> allRequirements = newArrayList();
+    for (DefaultCharacteristic characteristic : characteristics()) {
+      for (DefaultRequirement requirement : characteristic.requirements()) {
+        allRequirements.add(requirement);
+      }
+    }
+    return allRequirements;
+  }
+
+  public boolean isEmpty(){
+    return rootCharacteristics.isEmpty();
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/RulesDebtModelXMLImporter.java b/sonar-core/src/main/java/org/sonar/core/debt/RulesDebtModelXMLImporter.java
new file mode 100644 (file)
index 0000000..927e375
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.NumberUtils;
+import org.codehaus.stax2.XMLInputFactory2;
+import org.codehaus.staxmate.SMInputFactory;
+import org.codehaus.staxmate.in.SMHierarchicCursor;
+import org.codehaus.staxmate.in.SMInputCursor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.rule.RemediationFunction;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class RulesDebtModelXMLImporter implements ServerExtension {
+
+  private static final Logger LOG = LoggerFactory.getLogger(RulesDebtModelXMLImporter.class);
+
+  public static final String CHARACTERISTIC = "chc";
+  public static final String CHARACTERISTIC_KEY = "key";
+  public static final String PROPERTY = "prop";
+
+  public static final String PROPERTY_KEY = "key";
+  public static final String PROPERTY_VALUE = "val";
+  public static final String PROPERTY_TEXT_VALUE = "txt";
+
+  public static final String REPOSITORY_KEY = "rule-repo";
+  public static final String RULE_KEY = "rule-key";
+
+  public static final String PROPERTY_FUNCTION = "remediationFunction";
+  public static final String PROPERTY_FACTOR = "remediationFactor";
+  public static final String PROPERTY_OFFSET = "offset";
+
+  public List<RuleDebt> importXML(String xml) {
+    return importXML(new StringReader(xml));
+  }
+
+  public List<RuleDebt> importXML(Reader xml) {
+    List<RuleDebt> ruleDebts = newArrayList();
+    try {
+      SMInputFactory inputFactory = initStax();
+      SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
+
+      // advance to <sqale>
+      cursor.advance();
+      SMInputCursor rootCursor = cursor.childElementCursor(CHARACTERISTIC);
+      while (rootCursor.getNext() != null) {
+        processCharacteristic(ruleDebts, null, null, rootCursor);
+      }
+
+      cursor.getStreamReader().closeCompletely();
+    } catch (XMLStreamException e) {
+      LOG.error("XML is not valid", e);
+    }
+
+    return ruleDebts;
+  }
+
+  private SMInputFactory initStax() {
+    XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
+    xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
+    xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
+    xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+    xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
+    return new SMInputFactory(xmlFactory);
+  }
+
+  private void processCharacteristic(List<RuleDebt> ruleDebts, @Nullable String rootKey, @Nullable String parentKey, SMInputCursor chcCursor) throws XMLStreamException {
+    String currentCharacteristicKey = null;
+    SMInputCursor cursor = chcCursor.childElementCursor();
+    while (cursor.getNext() != null) {
+      String node = cursor.getLocalName();
+      if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
+        currentCharacteristicKey = cursor.collectDescendantText().trim();
+      } else if (StringUtils.equals(node, CHARACTERISTIC)) {
+        processCharacteristic(ruleDebts, parentKey, currentCharacteristicKey, cursor);
+      } else if (StringUtils.equals(node, REPOSITORY_KEY)) {
+        RuleDebt ruleDebt = processRule(cursor);
+        if (ruleDebt != null) {
+          if (rootKey != null) {
+            ruleDebt.characteristicKey = parentKey;
+            ruleDebts.add(ruleDebt);
+          } else {
+            LOG.warn("Rule '" + ruleDebt.ruleKey + "' is ignored because it's defined directly under a root characteristic.");
+          }
+        }
+      }
+    }
+  }
+
+  private RuleDebt processRule(SMInputCursor cursor)
+    throws XMLStreamException {
+
+    RuleDebt ruleDebt = new RuleDebt();
+    String ruleRepositoryKey = cursor.collectDescendantText().trim();
+    String ruleKey = null;
+    Properties properties = new Properties();
+    while (cursor.getNext() != null) {
+      String node = cursor.getLocalName();
+      if (StringUtils.equals(node, PROPERTY)) {
+        properties.add(processProperty(cursor));
+      } else if (StringUtils.equals(node, RULE_KEY)) {
+        ruleKey = cursor.collectDescendantText().trim();
+      }
+    }
+    if (StringUtils.isNotBlank(ruleRepositoryKey) && StringUtils.isNotBlank(ruleKey)) {
+      ruleDebt.ruleKey = RuleKey.of(ruleRepositoryKey, ruleKey);
+    } else {
+      return null;
+    }
+    return processFunctionsOnRequirement(ruleDebt, properties);
+  }
+
+  private Property processProperty(SMInputCursor cursor) throws XMLStreamException {
+    SMInputCursor c = cursor.childElementCursor();
+    String key = null;
+    int value = 0;
+    String textValue = null;
+    while (c.getNext() != null) {
+      String node = c.getLocalName();
+      if (StringUtils.equals(node, PROPERTY_KEY)) {
+        key = c.collectDescendantText().trim();
+
+      } else if (StringUtils.equals(node, PROPERTY_VALUE)) {
+        String s = c.collectDescendantText().trim();
+        try {
+          Double valueDouble = NumberUtils.createDouble(s);
+          value = valueDouble.intValue();
+        } catch (NumberFormatException ex) {
+          LOG.error(String.format("Cannot import value '%s' for field %s - Expected a numeric value instead", s, key));
+        }
+      } else if (StringUtils.equals(node, PROPERTY_TEXT_VALUE)) {
+        textValue = c.collectDescendantText().trim();
+      }
+    }
+    return new Property(key, value, textValue);
+  }
+
+  @CheckForNull
+  private RuleDebt processFunctionsOnRequirement(RuleDebt requirement, Properties properties) {
+    Property function = properties.function();
+    Property factor = properties.factor();
+    Property offset = properties.offset();
+
+    if (function != null) {
+      // Init with default values
+      requirement.factor = "0" + Duration.DAY;
+      requirement.offset = "0" + Duration.DAY;
+
+      String functionKey = function.getTextValue();
+      if ("linear_threshold".equals(functionKey)) {
+        function.setTextValue(RemediationFunction.LINEAR.name().toLowerCase());
+        offset.setValue(0);
+        offset.setTextValue(Duration.DAY);
+        LOG.warn(String.format("Linear with threshold function is no longer used, remediation function of '%s' is replaced by linear.", requirement.ruleKey));
+      } else if ("constant_resource".equals(functionKey)) {
+        LOG.warn(String.format("Constant/file function is no longer used, technical debt definitions on '%s' are ignored.", requirement.ruleKey));
+        return null;
+      }
+
+      requirement.function = RemediationFunction.valueOf(function.getTextValue().toUpperCase());
+      if (factor != null) {
+        requirement.factor = Integer.toString(factor.getValue());
+        requirement.factor += !Strings.isNullOrEmpty(factor.getTextValue()) ? factor.getTextValue() : Duration.DAY;
+      }
+      if (offset != null) {
+        requirement.offset = Integer.toString(offset.getValue());
+        requirement.offset += !Strings.isNullOrEmpty(offset.getTextValue()) ? offset.getTextValue() : Duration.DAY;
+      }
+      return requirement;
+    }
+    return null;
+  }
+
+  private static class Properties {
+    List<Property> properties;
+
+    public Properties() {
+      this.properties = newArrayList();
+    }
+
+    public Properties add(Property property) {
+      this.properties.add(property);
+      return this;
+    }
+
+    public Property function() {
+      return find(PROPERTY_FUNCTION);
+    }
+
+    public Property factor() {
+      return find(PROPERTY_FACTOR);
+    }
+
+    public Property offset() {
+      return find(PROPERTY_OFFSET);
+    }
+
+    private Property find(final String key) {
+      return Iterables.find(properties, new Predicate<Property>() {
+        @Override
+        public boolean apply(Property input) {
+          return input.getKey().equals(key);
+        }
+      }, null);
+    }
+  }
+
+  private static class Property {
+    String key;
+    int value;
+    String textValue;
+
+    private Property(String key, int value, String textValue) {
+      this.key = key;
+      this.value = value;
+      this.textValue = textValue;
+    }
+
+    private Property setValue(int value) {
+      this.value = value;
+      return this;
+    }
+
+    private Property setTextValue(String textValue) {
+      this.textValue = textValue;
+      return this;
+    }
+
+    private String getKey() {
+      return key;
+    }
+
+    private int getValue() {
+      return value;
+    }
+
+    private String getTextValue() {
+      return "mn".equals(textValue) ? Duration.MINUTE : textValue;
+    }
+  }
+
+  public static class RuleDebt {
+    private RuleKey ruleKey;
+    private String characteristicKey;
+    private RemediationFunction function;
+    private String factor;
+    private String offset;
+
+    public RuleKey ruleKey() {
+      return ruleKey;
+    }
+
+    public RuleDebt setRuleKey(RuleKey ruleKey) {
+      this.ruleKey = ruleKey;
+      return this;
+    }
+
+    public String characteristicKey() {
+      return characteristicKey;
+    }
+
+    public RuleDebt setCharacteristicKey(String characteristicKey) {
+      this.characteristicKey = characteristicKey;
+      return this;
+    }
+
+    public RemediationFunction function() {
+      return function;
+    }
+
+    public RuleDebt setFunction(RemediationFunction function) {
+      this.function = function;
+      return this;
+    }
+
+    public String factor() {
+      return factor;
+    }
+
+    public RuleDebt setFactor(String factor) {
+      this.factor = factor;
+      return this;
+    }
+
+    public String offset() {
+      return offset;
+    }
+
+    public RuleDebt setOffset(String offset) {
+      this.offset = offset;
+      return this;
+    }
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/TechnicalDebtModelSynchronizer.java b/sonar-core/src/main/java/org/sonar/core/debt/TechnicalDebtModelSynchronizer.java
new file mode 100644 (file)
index 0000000..a58032f
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import org.apache.commons.io.IOUtils;
+import org.apache.ibatis.session.SqlSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.debt.db.CharacteristicDao;
+import org.sonar.core.debt.db.CharacteristicDto;
+import org.sonar.core.persistence.MyBatis;
+
+import java.io.Reader;
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class TechnicalDebtModelSynchronizer implements ServerExtension {
+
+  private static final Logger LOG = LoggerFactory.getLogger(TechnicalDebtModelSynchronizer.class);
+
+  private final MyBatis mybatis;
+  private final CharacteristicDao dao;
+  private final DebtModelPluginRepository languageModelFinder;
+  private final TechnicalDebtXMLImporter importer;
+
+  public TechnicalDebtModelSynchronizer(MyBatis mybatis, CharacteristicDao dao,
+                                        DebtModelPluginRepository modelRepository, TechnicalDebtXMLImporter importer) {
+    this.mybatis = mybatis;
+    this.dao = dao;
+    this.languageModelFinder = modelRepository;
+    this.importer = importer;
+  }
+
+  public List<CharacteristicDto> synchronize(ValidationMessages messages, TechnicalDebtRuleCache rulesCache) {
+    SqlSession session = mybatis.openSession();
+
+    List<CharacteristicDto> model = newArrayList();
+    try {
+      model = synchronize(messages, rulesCache, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+    return model;
+  }
+
+  public List<CharacteristicDto> synchronize(ValidationMessages messages, TechnicalDebtRuleCache rulesCache, SqlSession session) {
+    DefaultTechnicalDebtModel defaultModel = loadModelFromXml(DebtModelPluginRepository.DEFAULT_MODEL, messages, rulesCache);
+    List<CharacteristicDto> model = loadOrCreateModelFromDb(defaultModel, session);
+    disableRequirementsOnRemovedRules(model, rulesCache, session);
+    mergePlugins(model, defaultModel, messages, rulesCache, session);
+    messages.log(LOG);
+
+    return model;
+  }
+
+  private List<CharacteristicDto> loadOrCreateModelFromDb(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
+    List<CharacteristicDto> characteristicDtos = loadModel();
+    if (characteristicDtos.isEmpty()) {
+      return createTechnicalDebtModel(defaultModel, session);
+    }
+    return characteristicDtos;
+  }
+
+  private List<CharacteristicDto> loadModel() {
+    return dao.selectEnabledCharacteristics();
+  }
+
+  private List<CharacteristicDto> createTechnicalDebtModel(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
+    List<CharacteristicDto> characteristics = newArrayList();
+    for (DefaultCharacteristic rootCharacteristic : defaultModel.rootCharacteristics()) {
+      CharacteristicDto rootCharacteristicDto = CharacteristicDto.toDto(rootCharacteristic, null);
+      dao.insert(rootCharacteristicDto, session);
+      characteristics.add(rootCharacteristicDto);
+      for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
+        CharacteristicDto characteristicDto = CharacteristicDto.toDto(characteristic, rootCharacteristicDto.getId());
+        dao.insert(characteristicDto, session);
+        characteristics.add(characteristicDto);
+      }
+    }
+    return characteristics;
+  }
+
+  private void mergePlugins(List<CharacteristicDto> existingModel, DefaultTechnicalDebtModel defaultModel, ValidationMessages messages, TechnicalDebtRuleCache rulesCache,
+                            SqlSession session) {
+    for (String pluginKey : getContributingPluginListWithoutSqale()) {
+      DefaultTechnicalDebtModel pluginModel = loadModelFromXml(pluginKey, messages, rulesCache);
+      checkPluginDoNotAddNewCharacteristic(pluginModel, defaultModel);
+      mergePlugin(pluginModel, existingModel, messages, rulesCache, session);
+    }
+  }
+
+  private void mergePlugin(DefaultTechnicalDebtModel pluginModel, List<CharacteristicDto> existingModel, ValidationMessages messages, TechnicalDebtRuleCache rulesCache,
+                           SqlSession session) {
+    if (!messages.hasErrors()) {
+      for (DefaultRequirement pluginRequirement : pluginModel.requirements()) {
+        Rule rule = rulesCache.getByRuleKey(pluginRequirement.ruleKey());
+        if (!isRequirementExists(existingModel, rule)) {
+          CharacteristicDto characteristicDto = findCharacteristic(existingModel, pluginRequirement.characteristic().key());
+          Integer rootId = characteristicDto.getRootId();
+          if (rootId == null) {
+            throw new IllegalArgumentException("Requirement on rule '" + pluginRequirement.ruleKey() + "' should not be linked on a root characteristic.");
+          }
+          CharacteristicDto requirementDto = CharacteristicDto.toDto(pluginRequirement, characteristicDto.getId(), rootId, rule.getId());
+          dao.insert(requirementDto, session);
+        }
+      }
+    }
+  }
+
+  public DefaultTechnicalDebtModel loadModelFromXml(String pluginKey, ValidationMessages messages, TechnicalDebtRuleCache rulesCache) {
+    Reader xmlFileReader = null;
+    try {
+      xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
+      return importer.importXML(xmlFileReader, messages, rulesCache);
+    } finally {
+      IOUtils.closeQuietly(xmlFileReader);
+    }
+  }
+
+  private void checkPluginDoNotAddNewCharacteristic(DefaultTechnicalDebtModel pluginModel, DefaultTechnicalDebtModel defaultModel) {
+    List<DefaultCharacteristic> characteristics = defaultModel.characteristics();
+    for (DefaultCharacteristic characteristic : pluginModel.characteristics()) {
+      if (!characteristics.contains(characteristic)) {
+        throw new IllegalArgumentException("The characteristic : " + characteristic.key() + " cannot be used as it's not available in default characteristics.");
+      }
+    }
+  }
+
+  private void disableRequirementsOnRemovedRules(List<CharacteristicDto> existingModel, TechnicalDebtRuleCache rulesCache, SqlSession session) {
+    for (CharacteristicDto characteristicDto : existingModel) {
+      Integer ruleId = characteristicDto.getRuleId();
+      if (ruleId != null && !rulesCache.exists(ruleId)) {
+        dao.disable(characteristicDto.getId(), session);
+      }
+    }
+  }
+
+  private Collection<String> getContributingPluginListWithoutSqale() {
+    Collection<String> pluginList = newArrayList(languageModelFinder.getContributingPluginList());
+    pluginList.remove(DebtModelPluginRepository.DEFAULT_MODEL);
+    return pluginList;
+  }
+
+  private CharacteristicDto findCharacteristic(List<CharacteristicDto> existingModel, final String key) {
+    return Iterables.find(existingModel, new Predicate<CharacteristicDto>() {
+      @Override
+      public boolean apply(CharacteristicDto input) {
+        String characteristicKey = input.getKey();
+        return input.getRuleId() == null && characteristicKey != null && characteristicKey.equals(key);
+      }
+    });
+  }
+
+  private boolean isRequirementExists(List<CharacteristicDto> existingModel, final Rule rule) {
+    return Iterables.any(existingModel, new Predicate<CharacteristicDto>() {
+      @Override
+      public boolean apply(CharacteristicDto input) {
+        Integer ruleId = input.getRuleId();
+        return ruleId != null && ruleId.equals(rule.getId());
+      }
+    });
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/TechnicalDebtRuleCache.java b/sonar-core/src/main/java/org/sonar/core/debt/TechnicalDebtRuleCache.java
new file mode 100644 (file)
index 0000000..92b1f07
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.collect.Maps;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RuleQuery;
+
+import javax.annotation.CheckForNull;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class TechnicalDebtRuleCache {
+
+  private final RuleFinder ruleFinder;
+
+  private Map<String, Map<String, Rule>> cachedRules;
+  private Map<Integer, Rule> cachedRulesId;
+
+  public TechnicalDebtRuleCache(RuleFinder ruleFinder) {
+    this.ruleFinder = ruleFinder;
+  }
+
+  @CheckForNull
+  public Rule getByRuleKey(RuleKey ruleKey) {
+    initRules();
+    return lookUpRuleInCache(ruleKey.repository(), ruleKey.rule());
+  }
+
+  @CheckForNull
+  public Rule getByRuleId(Integer ruleId) {
+    initRules();
+    return cachedRulesId.get(ruleId);
+  }
+
+  public boolean exists(Integer ruleId) {
+    initRules();
+    return getByRuleId(ruleId) != null;
+  }
+
+  public boolean exists(RuleKey ruleKey) {
+    return getByRuleKey(ruleKey) != null;
+  }
+
+  private void initRules(){
+    if(cachedRules == null) {
+      loadRules();
+    }
+  }
+
+  private void loadRules() {
+    cachedRules = Maps.newHashMap();
+    cachedRulesId = Maps.newHashMap();
+    Collection<Rule> rules = ruleFinder.findAll(RuleQuery.create());
+    for (Rule rule : rules) {
+      if(!cachedRules.containsKey(rule.getRepositoryKey())) {
+        cachedRules.put(rule.getRepositoryKey(), new HashMap<String, Rule>());
+      }
+      Map<String, Rule> cachedRepository = cachedRules.get(rule.getRepositoryKey());
+      if(!cachedRepository.containsKey(rule.getKey())) {
+        cachedRepository.put(rule.getKey(), rule);
+        cachedRulesId.put(rule.getId(), rule);
+      }
+    }
+  }
+
+  @CheckForNull
+  private Rule lookUpRuleInCache(String repository, String ruleKey) {
+    Map<String, Rule> cachedRepository = cachedRules.get(repository);
+    if(cachedRepository != null) {
+      return cachedRepository.get(ruleKey);
+    }
+    return null;
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/TechnicalDebtXMLImporter.java b/sonar-core/src/main/java/org/sonar/core/debt/TechnicalDebtXMLImporter.java
new file mode 100644 (file)
index 0000000..6c46bf9
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.NumberUtils;
+import org.codehaus.stax2.XMLInputFactory2;
+import org.codehaus.staxmate.SMInputFactory;
+import org.codehaus.staxmate.in.SMHierarchicCursor;
+import org.codehaus.staxmate.in.SMInputCursor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.api.utils.internal.WorkDuration;
+import org.sonar.core.debt.db.CharacteristicDto;
+
+import javax.annotation.CheckForNull;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class TechnicalDebtXMLImporter implements ServerExtension {
+
+  private static final Logger LOG = LoggerFactory.getLogger(TechnicalDebtXMLImporter.class);
+
+  public static final String CHARACTERISTIC = "chc";
+  public static final String CHARACTERISTIC_KEY = "key";
+  public static final String CHARACTERISTIC_NAME = "name";
+  public static final String PROPERTY = "prop";
+
+  public static final String PROPERTY_KEY = "key";
+  public static final String PROPERTY_VALUE = "val";
+  public static final String PROPERTY_TEXT_VALUE = "txt";
+
+  public static final String REPOSITORY_KEY = "rule-repo";
+  public static final String RULE_KEY = "rule-key";
+
+  public static final String PROPERTY_FUNCTION = "remediationFunction";
+  public static final String PROPERTY_FACTOR = "remediationFactor";
+  public static final String PROPERTY_OFFSET = "offset";
+
+  public DefaultTechnicalDebtModel importXML(String xml, ValidationMessages messages, TechnicalDebtRuleCache technicalDebtRuleCache) {
+    return importXML(new StringReader(xml), messages, technicalDebtRuleCache);
+  }
+
+  public DefaultTechnicalDebtModel importXML(Reader xml, ValidationMessages messages, TechnicalDebtRuleCache repositoryCache) {
+    DefaultTechnicalDebtModel model = new DefaultTechnicalDebtModel();
+    try {
+      SMInputFactory inputFactory = initStax();
+      SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
+
+      // advance to <sqale>
+      cursor.advance();
+      SMInputCursor chcCursor = cursor.childElementCursor(CHARACTERISTIC);
+
+      while (chcCursor.getNext() != null) {
+        processCharacteristic(model, null, chcCursor, messages, repositoryCache);
+      }
+
+      cursor.getStreamReader().closeCompletely();
+
+    } catch (XMLStreamException e) {
+      LOG.error("XML is not valid", e);
+      messages.addErrorText("XML is not valid: " + e.getMessage());
+    }
+    return model;
+  }
+
+  private SMInputFactory initStax() {
+    XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
+    xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
+    xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
+    xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+    xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
+    return new SMInputFactory(xmlFactory);
+  }
+
+  private DefaultCharacteristic processCharacteristic(DefaultTechnicalDebtModel model, DefaultCharacteristic parent, SMInputCursor chcCursor, ValidationMessages messages,
+                                                      TechnicalDebtRuleCache technicalDebtRuleCache) throws XMLStreamException {
+    DefaultCharacteristic characteristic = new DefaultCharacteristic();
+    SMInputCursor cursor = chcCursor.childElementCursor();
+    while (cursor.getNext() != null) {
+      String node = cursor.getLocalName();
+      if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
+        characteristic.setKey(cursor.collectDescendantText().trim());
+        // Attached to parent only if a key is existing, otherwise characteristic with empty key can be added.
+        characteristic.setParent(parent);
+
+      } else if (StringUtils.equals(node, CHARACTERISTIC_NAME)) {
+        characteristic.setName(cursor.collectDescendantText().trim(), false);
+
+        // <chc> can contain characteristics or requirements
+      } else if (StringUtils.equals(node, CHARACTERISTIC)) {
+        processCharacteristic(model, characteristic, cursor, messages, technicalDebtRuleCache);
+
+      } else if (StringUtils.equals(node, REPOSITORY_KEY)) {
+        DefaultRequirement requirement = processRequirement(cursor, messages, technicalDebtRuleCache);
+        if (requirement != null) {
+          addRequirement(requirement, parent, messages);
+        }
+      }
+    }
+
+    if (StringUtils.isNotBlank(characteristic.key()) && characteristic.isRoot()) {
+      characteristic.setOrder(model.rootCharacteristics().size() + 1);
+      model.addRootCharacteristic(characteristic);
+      return characteristic;
+    }
+    return null;
+  }
+
+  private void addRequirement(DefaultRequirement requirement, DefaultCharacteristic parent, ValidationMessages messages) {
+    DefaultCharacteristic root = parent.parent();
+    if (root == null) {
+      messages.addWarningText("Requirement '" + requirement.ruleKey() + "' is ignored because it's defined directly under a root characteristic.");
+    } else {
+      requirement.setCharacteristic(parent);
+      requirement.setRootCharacteristic(root);
+    }
+  }
+
+  private DefaultRequirement processRequirement(SMInputCursor cursor, ValidationMessages messages, TechnicalDebtRuleCache technicalDebtRuleCache)
+    throws XMLStreamException {
+
+    DefaultRequirement requirement = new DefaultRequirement();
+    String ruleRepositoryKey = cursor.collectDescendantText().trim();
+    String ruleKey = null;
+    Properties properties = new Properties();
+    while (cursor.getNext() != null) {
+      String node = cursor.getLocalName();
+      if (StringUtils.equals(node, PROPERTY)) {
+        properties.add(processProperty(cursor, messages));
+      } else if (StringUtils.equals(node, RULE_KEY)) {
+        ruleKey = cursor.collectDescendantText().trim();
+      }
+    }
+    fillRule(requirement, ruleRepositoryKey, ruleKey, messages, technicalDebtRuleCache);
+    if (requirement.ruleKey() == null) {
+      return null;
+    }
+    return processFunctionsOnRequirement(requirement, properties, messages);
+  }
+
+  private void fillRule(DefaultRequirement requirement, String ruleRepositoryKey, String ruleKey, ValidationMessages messages,
+                        TechnicalDebtRuleCache technicalDebtRuleCache) {
+    if (StringUtils.isNotBlank(ruleRepositoryKey) && StringUtils.isNotBlank(ruleKey)) {
+      Rule rule = technicalDebtRuleCache.getByRuleKey(RuleKey.of(ruleRepositoryKey, ruleKey));
+      if (rule != null) {
+        requirement.setRuleKey(RuleKey.of(ruleRepositoryKey, ruleKey));
+      } else {
+        messages.addWarningText("Rule not found: [repository=" + ruleRepositoryKey + ", key=" + ruleKey + "]");
+      }
+    }
+  }
+
+  private Property processProperty(SMInputCursor cursor, ValidationMessages messages) throws XMLStreamException {
+    SMInputCursor c = cursor.childElementCursor();
+    String key = null;
+    int value = 0;
+    String textValue = null;
+    while (c.getNext() != null) {
+      String node = c.getLocalName();
+      if (StringUtils.equals(node, PROPERTY_KEY)) {
+        key = c.collectDescendantText().trim();
+
+      } else if (StringUtils.equals(node, PROPERTY_VALUE)) {
+        String s = c.collectDescendantText().trim();
+        try {
+          // The value is still a double for the moment
+          Double valueDouble = NumberUtils.createDouble(s);
+          value = valueDouble.intValue();
+        } catch (NumberFormatException ex) {
+          messages.addErrorText(String.format("Cannot import value '%s' for field %s - Expected a numeric value instead", s, key));
+        }
+      } else if (StringUtils.equals(node, PROPERTY_TEXT_VALUE)) {
+        textValue = c.collectDescendantText().trim();
+      }
+    }
+    return new Property(key, value, textValue);
+  }
+
+  @CheckForNull
+  private DefaultRequirement processFunctionsOnRequirement(DefaultRequirement requirement, Properties properties, ValidationMessages messages) {
+    Property function = properties.function();
+    Property factor = properties.factor();
+    Property offset = properties.offset();
+
+    if (function != null) {
+      // Requirements should always have values, so we init it with default values
+      requirement.setFactorValue(0);
+      requirement.setFactorUnit(WorkDuration.UNIT.DAYS);
+      requirement.setOffsetValue(0);
+      requirement.setOffsetUnit(WorkDuration.UNIT.DAYS);
+
+      String functionKey = function.getTextValue();
+      if ("linear_threshold".equals(functionKey)) {
+        function.setTextValue(DefaultRequirement.FUNCTION_LINEAR);
+        offset.setValue(0);
+        offset.setTextValue(CharacteristicDto.DAYS);
+        messages.addWarningText(String.format("Linear with threshold function is no longer used, function of the requirement '%s' is replaced by linear.", requirement.ruleKey()));
+      } else if ("constant_resource".equals(functionKey)) {
+        messages.addWarningText(String.format("Constant/file function is no longer used, requirements '%s' are ignored.", requirement.ruleKey()));
+        return null;
+      }
+
+      requirement.setFunction(function.getTextValue());
+      if (factor != null) {
+        requirement.setFactorValue(factor.getValue());
+        if (!Strings.isNullOrEmpty(factor.getTextValue())) {
+          requirement.setFactorUnit(DefaultRequirement.toUnit(factor.getTextValue()));
+        }
+      }
+      if (offset != null) {
+        requirement.setOffsetValue(offset.getValue());
+        if (!Strings.isNullOrEmpty(offset.getTextValue())) {
+          requirement.setOffsetUnit(DefaultRequirement.toUnit(offset.getTextValue()));
+        }
+      }
+      return requirement;
+    }
+    return null;
+  }
+
+  private static class Properties {
+    List<Property> properties;
+
+    public Properties() {
+      this.properties = newArrayList();
+    }
+
+    public Properties add(Property property) {
+      this.properties.add(property);
+      return this;
+    }
+
+    public Property function() {
+      return find(PROPERTY_FUNCTION);
+    }
+
+    public Property factor() {
+      return find(PROPERTY_FACTOR);
+    }
+
+    public Property offset() {
+      return find(PROPERTY_OFFSET);
+    }
+
+    private Property find(final String key) {
+      return Iterables.find(properties, new Predicate<Property>() {
+        @Override
+        public boolean apply(Property input) {
+          return input.getKey().equals(key);
+        }
+      }, null);
+    }
+
+  }
+
+  private static class Property {
+    String key;
+    int value;
+    String textValue;
+
+    private Property(String key, int value, String textValue) {
+      this.key = key;
+      this.value = value;
+      this.textValue = textValue;
+    }
+
+    private Property setValue(int value) {
+      this.value = value;
+      return this;
+    }
+
+    private Property setTextValue(String textValue) {
+      this.textValue = textValue;
+      return this;
+    }
+
+    private String getKey() {
+      return key;
+    }
+
+    private int getValue() {
+      return value;
+    }
+
+    private String getTextValue() {
+      return textValue;
+    }
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/db/CharacteristicDao.java b/sonar-core/src/main/java/org/sonar/core/debt/db/CharacteristicDao.java
new file mode 100644 (file)
index 0000000..9232876
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt.db;
+
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.persistence.MyBatis;
+
+import javax.annotation.CheckForNull;
+
+import java.util.List;
+
+public class CharacteristicDao implements BatchComponent, ServerComponent {
+
+  private final MyBatis mybatis;
+
+  public CharacteristicDao(MyBatis mybatis) {
+    this.mybatis = mybatis;
+  }
+
+  /**
+   * @return enabled root characteristics, characteristics and requirements
+   *
+   * @deprecated since 4.3
+   */
+  @Deprecated
+  public List<CharacteristicDto> selectEnabledCharacteristics() {
+    SqlSession session = mybatis.openSession();
+    try {
+      return session.getMapper(CharacteristicMapper.class).selectEnabledCharacteristics();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  /**
+   * @return enabled root characteristics, and characteristics
+   *
+   */
+  public List<CharacteristicDto> selectCharacteristics() {
+    SqlSession session = mybatis.openSession();
+    try {
+      return selectCharacteristics(session);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public List<CharacteristicDto> selectCharacteristics(SqlSession session) {
+    return session.getMapper(CharacteristicMapper.class).selectCharacteristics();
+  }
+
+  /**
+   * @return only enabled root characteristics, order by order
+   */
+  public List<CharacteristicDto> selectEnabledRootCharacteristics() {
+    SqlSession session = mybatis.openSession();
+    CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
+    try {
+      return mapper.selectEnabledRootCharacteristics();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  @CheckForNull
+  public CharacteristicDto selectByKey(String key) {
+    SqlSession session = mybatis.openSession();
+    CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
+    try {
+      return mapper.selectByKey(key);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  @CheckForNull
+  public CharacteristicDto selectById(int id) {
+    SqlSession session = mybatis.openSession();
+    CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
+    try {
+      return mapper.selectById(id);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  @CheckForNull
+  public CharacteristicDto selectByRuleId(Integer ruleId) {
+    SqlSession session = mybatis.openSession();
+    CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
+    try {
+      return mapper.selectByRuleId(ruleId);
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public void insert(CharacteristicDto dto, SqlSession session) {
+    session.getMapper(CharacteristicMapper.class).insert(dto);
+  }
+
+  public void insert(CharacteristicDto dto) {
+    SqlSession session = mybatis.openSession();
+    try {
+      insert(dto, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public void update(CharacteristicDto dto, SqlSession session) {
+    session.getMapper(CharacteristicMapper.class).update(dto);
+  }
+
+  public void update(CharacteristicDto dto) {
+    SqlSession session = mybatis.openSession();
+    try {
+      update(dto, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  public void disable(Integer id, SqlSession session) {
+    session.getMapper(CharacteristicMapper.class).disable(id);
+  }
+
+  public void disable(Integer id) {
+    SqlSession session = mybatis.openSession();
+    try {
+      disable(id, session);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/db/CharacteristicDto.java b/sonar-core/src/main/java/org/sonar/core/debt/db/CharacteristicDto.java
new file mode 100644 (file)
index 0000000..23eb8a2
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt.db;
+
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.internal.WorkDuration;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class CharacteristicDto implements Serializable {
+
+  public static final String DAYS = "d";
+  public static final String MINUTES = "mn";
+  public static final String HOURS = "h";
+
+  private Integer id;
+  private String kee;
+  private String name;
+  private Integer parentId;
+  private Integer rootId;
+  private Integer characteristicOrder;
+  private Integer ruleId;
+  private String functionKey;
+  private Double factorValue;
+  private String factorUnit;
+  private Double offsetValue;
+  private String offsetUnit;
+  private Date createdAt;
+  private Date updatedAt;
+  private boolean enabled;
+
+  public Integer getId() {
+    return id;
+  }
+
+  public CharacteristicDto setId(Integer id) {
+    this.id = id;
+    return this;
+  }
+
+  @CheckForNull
+  public String getKey() {
+    return kee;
+  }
+
+  public CharacteristicDto setKey(@Nullable String s) {
+    this.kee = s;
+    return this;
+  }
+
+  @CheckForNull
+  public String getName() {
+    return name;
+  }
+
+  public CharacteristicDto setName(@Nullable String s) {
+    this.name = s;
+    return this;
+  }
+
+  @CheckForNull
+  public Integer getParentId() {
+    return parentId;
+  }
+
+  public CharacteristicDto setParentId(@Nullable Integer i) {
+    this.parentId = i;
+    return this;
+  }
+
+  @CheckForNull
+  public Integer getRootId() {
+    return rootId;
+  }
+
+  public CharacteristicDto setRootId(@Nullable Integer rootId) {
+    this.rootId = rootId;
+    return this;
+  }
+
+  @CheckForNull
+  public Integer getOrder() {
+    return characteristicOrder;
+  }
+
+  public CharacteristicDto setOrder(@Nullable Integer i) {
+    this.characteristicOrder = i;
+    return this;
+  }
+
+  @CheckForNull
+  public Integer getRuleId() {
+    return ruleId;
+  }
+
+  public CharacteristicDto setRuleId(@Nullable Integer ruleId) {
+    this.ruleId = ruleId;
+    return this;
+  }
+
+  @CheckForNull
+  public String getFunction() {
+    return functionKey;
+  }
+
+  public CharacteristicDto setFunction(@Nullable String function) {
+    this.functionKey = function;
+    return this;
+  }
+
+  @CheckForNull
+  public Double getFactorValue() {
+    return factorValue;
+  }
+
+  public CharacteristicDto setFactorValue(Double factor) {
+    this.factorValue = factor;
+    return this;
+  }
+
+  @CheckForNull
+  public String getFactorUnit() {
+    return factorUnit;
+  }
+
+  public CharacteristicDto setFactorUnit(@Nullable String factorUnit) {
+    this.factorUnit = factorUnit;
+    return this;
+  }
+
+  @CheckForNull
+  public Double getOffsetValue() {
+    return offsetValue;
+  }
+
+  public CharacteristicDto setOffsetValue(@Nullable Double offset) {
+    this.offsetValue = offset;
+    return this;
+  }
+
+  @CheckForNull
+  public String getOffsetUnit() {
+    return offsetUnit;
+  }
+
+  public CharacteristicDto setOffsetUnit(@Nullable String offsetUnit) {
+    this.offsetUnit = offsetUnit;
+    return this;
+  }
+
+  public Date getCreatedAt() {
+    return createdAt;
+  }
+
+  public CharacteristicDto setCreatedAt(Date createdAt) {
+    this.createdAt = createdAt;
+    return this;
+  }
+
+  @CheckForNull
+  public Date getUpdatedAt() {
+    return updatedAt;
+  }
+
+  public CharacteristicDto setUpdatedAt(@Nullable Date updatedAt) {
+    this.updatedAt = updatedAt;
+    return this;
+  }
+
+  public boolean isEnabled() {
+    return enabled;
+  }
+
+  public CharacteristicDto setEnabled(boolean enabled) {
+    this.enabled = enabled;
+    return this;
+  }
+
+  public DefaultCharacteristic toCharacteristic(@Nullable DefaultCharacteristic parent) {
+    return new DefaultCharacteristic()
+      .setId(id)
+      .setKey(kee)
+      .setName(name)
+      .setOrder(characteristicOrder)
+      .setParent(parent)
+      .setRoot(parent)
+      .setCreatedAt(createdAt)
+      .setUpdatedAt(updatedAt);
+  }
+
+  public static CharacteristicDto toDto(DefaultCharacteristic characteristic, @Nullable Integer parentId) {
+    return new CharacteristicDto()
+      .setKey(characteristic.key())
+      .setName(characteristic.name())
+      .setOrder(characteristic.order())
+      .setParentId(parentId)
+      .setRootId(parentId)
+      .setEnabled(true)
+      .setCreatedAt(characteristic.createdAt())
+      .setUpdatedAt(characteristic.updatedAt());
+  }
+
+  public DefaultRequirement toRequirement(RuleKey ruleKey, DefaultCharacteristic characteristic, DefaultCharacteristic rootCharacteristic) {
+    return new DefaultRequirement()
+      .setId(id)
+      .setRuleKey(ruleKey)
+      .setCharacteristic(characteristic)
+      .setRootCharacteristic(rootCharacteristic)
+      .setFunction(functionKey)
+      .setFactorValue(factorValue.intValue())
+      .setFactorUnit(toUnit(factorUnit))
+      .setOffsetValue(offsetValue.intValue())
+      .setOffsetUnit(toUnit(offsetUnit))
+      .setCreatedAt(createdAt)
+      .setUpdatedAt(updatedAt);
+  }
+
+  public static CharacteristicDto toDto(DefaultRequirement requirement, Integer characteristicId, Integer rootCharacteristicId, Integer ruleId) {
+    return new CharacteristicDto()
+      .setRuleId(ruleId)
+      .setParentId(characteristicId)
+      .setRootId(rootCharacteristicId)
+      .setFunction(requirement.function())
+      .setFactorValue((double) requirement.factorValue())
+      .setFactorUnit(fromUnit(requirement.factorUnit()))
+      .setOffsetValue((double) requirement.offsetValue())
+      .setOffsetUnit(fromUnit(requirement.offsetUnit()))
+      .setEnabled(true)
+      .setCreatedAt(requirement.createdAt())
+      .setUpdatedAt(requirement.updatedAt());
+  }
+
+  private static WorkDuration.UNIT toUnit(@Nullable String requirementUnit) {
+    if (requirementUnit != null) {
+      if (DAYS.equals(requirementUnit)) {
+        return WorkDuration.UNIT.DAYS;
+      } else if (HOURS.equals(requirementUnit)) {
+        return WorkDuration.UNIT.HOURS;
+      } else if (MINUTES.equals(requirementUnit)) {
+        return WorkDuration.UNIT.MINUTES;
+      }
+      throw new IllegalStateException("Invalid unit : " + requirementUnit);
+    }
+    return null;
+  }
+
+  private static String fromUnit(@Nullable WorkDuration.UNIT unit) {
+    if (unit != null) {
+      if (WorkDuration.UNIT.DAYS.equals(unit)) {
+        return DAYS;
+      } else if (WorkDuration.UNIT.HOURS.equals(unit)) {
+        return HOURS;
+      } else if (WorkDuration.UNIT.MINUTES.equals(unit)) {
+        return MINUTES;
+      }
+      throw new IllegalStateException("Invalid unit : " + unit);
+    }
+    return null;
+  }
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/db/CharacteristicMapper.java b/sonar-core/src/main/java/org/sonar/core/debt/db/CharacteristicMapper.java
new file mode 100644 (file)
index 0000000..1e5243b
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt.db;
+
+import java.util.List;
+
+public interface CharacteristicMapper {
+
+  List<CharacteristicDto> selectEnabledCharacteristics();
+
+  List<CharacteristicDto> selectCharacteristics();
+
+  List<CharacteristicDto> selectEnabledRootCharacteristics();
+
+  CharacteristicDto selectByKey(String key);
+
+  CharacteristicDto selectById(int id);
+
+  CharacteristicDto selectByRuleId(Integer ruleId);
+
+  void insert(CharacteristicDto characteristic);
+
+  int update(CharacteristicDto characteristic);
+
+  int disable(Integer id);
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/db/package-info.java b/sonar-core/src/main/java/org/sonar/core/debt/db/package-info.java
new file mode 100644 (file)
index 0000000..b003c97
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.core.debt.db;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-core/src/main/java/org/sonar/core/debt/package-info.java b/sonar-core/src/main/java/org/sonar/core/debt/package-info.java
new file mode 100644 (file)
index 0000000..46a651d
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.core.debt;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index 05628a72ed0385b91f10c0f98642d1d2718035c6..5beafe71e24c70eada6ccf426f74768157f1c5a0 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.core.persistence;
 import com.google.common.collect.ImmutableList;
 import org.sonar.core.dashboard.ActiveDashboardDao;
 import org.sonar.core.dashboard.DashboardDao;
+import org.sonar.core.debt.db.CharacteristicDao;
 import org.sonar.core.duplication.DuplicationDao;
 import org.sonar.core.graph.jdbc.GraphDao;
 import org.sonar.core.issue.db.*;
@@ -41,7 +42,6 @@ import org.sonar.core.rule.RuleDao;
 import org.sonar.core.rule.RuleTagDao;
 import org.sonar.core.source.db.SnapshotDataDao;
 import org.sonar.core.source.db.SnapshotSourceDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
 import org.sonar.core.template.LoadedTemplateDao;
 import org.sonar.core.user.*;
 
index 8325bd831cd5fcc05fe703a35a7a00fe0f635ca3..f1fd87442c5879942d971db0423e62038ef1cb08 100644 (file)
@@ -36,6 +36,8 @@ import org.sonar.core.component.ComponentDto;
 import org.sonar.core.component.db.ComponentMapper;
 import org.sonar.core.config.Logback;
 import org.sonar.core.dashboard.*;
+import org.sonar.core.debt.db.CharacteristicDto;
+import org.sonar.core.debt.db.CharacteristicMapper;
 import org.sonar.core.dependency.DependencyDto;
 import org.sonar.core.dependency.DependencyMapper;
 import org.sonar.core.dependency.ResourceSnapshotDto;
@@ -63,8 +65,6 @@ import org.sonar.core.rule.*;
 import org.sonar.core.source.db.SnapshotDataDto;
 import org.sonar.core.source.db.SnapshotDataMapper;
 import org.sonar.core.source.db.SnapshotSourceMapper;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-import org.sonar.core.technicaldebt.db.CharacteristicMapper;
 import org.sonar.core.template.LoadedTemplateDto;
 import org.sonar.core.template.LoadedTemplateMapper;
 import org.sonar.core.user.*;
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/CharacteristicsXMLImporter.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/CharacteristicsXMLImporter.java
deleted file mode 100644 (file)
index b04c9b7..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import org.apache.commons.lang.StringUtils;
-import org.codehaus.stax2.XMLInputFactory2;
-import org.codehaus.staxmate.SMInputFactory;
-import org.codehaus.staxmate.in.SMHierarchicCursor;
-import org.codehaus.staxmate.in.SMInputCursor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.utils.ValidationMessages;
-
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-
-import java.io.Reader;
-import java.io.StringReader;
-
-public class CharacteristicsXMLImporter implements ServerExtension {
-
-  private static final Logger LOG = LoggerFactory.getLogger(CharacteristicsXMLImporter.class);
-
-  public static final String CHARACTERISTIC = "chc";
-  public static final String CHARACTERISTIC_KEY = "key";
-  public static final String CHARACTERISTIC_NAME = "name";
-
-  public DefaultTechnicalDebtModel importXML(String xml, ValidationMessages messages) {
-    return importXML(new StringReader(xml), messages);
-  }
-
-  public DefaultTechnicalDebtModel importXML(Reader xml, ValidationMessages messages) {
-    DefaultTechnicalDebtModel model = new DefaultTechnicalDebtModel();
-    try {
-      SMInputFactory inputFactory = initStax();
-      SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
-
-      // advance to <sqale>
-      cursor.advance();
-      SMInputCursor chcCursor = cursor.childElementCursor(CHARACTERISTIC);
-
-      while (chcCursor.getNext() != null) {
-        processCharacteristic(model, null, chcCursor, messages);
-      }
-
-      cursor.getStreamReader().closeCompletely();
-
-    } catch (XMLStreamException e) {
-      LOG.error("XML is not valid", e);
-      messages.addErrorText("XML is not valid: " + e.getMessage());
-    }
-    return model;
-  }
-
-  private SMInputFactory initStax() {
-    XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
-    xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
-    xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
-    xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
-    xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
-    return new SMInputFactory(xmlFactory);
-  }
-
-  private DefaultCharacteristic processCharacteristic(DefaultTechnicalDebtModel model, DefaultCharacteristic parent, SMInputCursor chcCursor,
-                                                      ValidationMessages messages) throws XMLStreamException {
-    DefaultCharacteristic characteristic = new DefaultCharacteristic();
-    SMInputCursor cursor = chcCursor.childElementCursor();
-    while (cursor.getNext() != null) {
-      String node = cursor.getLocalName();
-      if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
-        characteristic.setKey(cursor.collectDescendantText().trim());
-        // Attached to parent only if a key is existing, otherwise characteristic with empty key can be added.
-        characteristic.setParent(parent);
-
-      } else if (StringUtils.equals(node, CHARACTERISTIC_NAME)) {
-        characteristic.setName(cursor.collectDescendantText().trim(), false);
-
-        // <chc> can contain characteristics or requirements
-      } else if (StringUtils.equals(node, CHARACTERISTIC)) {
-        processCharacteristic(model, characteristic, cursor, messages);
-
-      }
-    }
-
-    if (StringUtils.isNotBlank(characteristic.key()) && characteristic.isRoot()) {
-      characteristic.setOrder(model.rootCharacteristics().size() + 1);
-      model.addRootCharacteristic(characteristic);
-      return characteristic;
-    }
-    return null;
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/DebtCharacteristicsSynchronizer.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/DebtCharacteristicsSynchronizer.java
deleted file mode 100644 (file)
index 8e8d95a..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.ibatis.session.SqlSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-
-import java.io.Reader;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class DebtCharacteristicsSynchronizer implements ServerExtension {
-
-  private static final Logger LOG = LoggerFactory.getLogger(DebtCharacteristicsSynchronizer.class);
-
-  private final MyBatis mybatis;
-  private final CharacteristicDao dao;
-  private final TechnicalDebtModelRepository languageModelFinder;
-  private final CharacteristicsXMLImporter importer;
-
-  public DebtCharacteristicsSynchronizer(MyBatis mybatis, CharacteristicDao dao, TechnicalDebtModelRepository modelRepository, CharacteristicsXMLImporter importer) {
-    this.mybatis = mybatis;
-    this.dao = dao;
-    this.languageModelFinder = modelRepository;
-    this.importer = importer;
-  }
-
-  public List<CharacteristicDto> synchronize(ValidationMessages messages) {
-    SqlSession session = mybatis.openSession();
-
-    List<CharacteristicDto> model = newArrayList();
-    try {
-      model = synchronize(messages, session);
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-    return model;
-  }
-
-  public List<CharacteristicDto> synchronize(ValidationMessages messages, SqlSession session) {
-    DefaultTechnicalDebtModel defaultModel = loadModelFromXml(TechnicalDebtModelRepository.DEFAULT_MODEL, messages);
-    List<CharacteristicDto> model = loadOrCreateModelFromDb(defaultModel, session);
-    messages.log(LOG);
-    return model;
-  }
-
-  private List<CharacteristicDto> loadOrCreateModelFromDb(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
-    List<CharacteristicDto> characteristicDtos = loadModel();
-    if (characteristicDtos.isEmpty()) {
-      return createTechnicalDebtModel(defaultModel, session);
-    }
-    return characteristicDtos;
-  }
-
-  private List<CharacteristicDto> loadModel() {
-    return dao.selectEnabledCharacteristics();
-  }
-
-  private List<CharacteristicDto> createTechnicalDebtModel(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
-    List<CharacteristicDto> characteristics = newArrayList();
-    for (DefaultCharacteristic rootCharacteristic : defaultModel.rootCharacteristics()) {
-      CharacteristicDto rootCharacteristicDto = CharacteristicDto.toDto(rootCharacteristic, null);
-      dao.insert(rootCharacteristicDto, session);
-      characteristics.add(rootCharacteristicDto);
-      for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
-        CharacteristicDto characteristicDto = CharacteristicDto.toDto(characteristic, rootCharacteristicDto.getId());
-        dao.insert(characteristicDto, session);
-        characteristics.add(characteristicDto);
-      }
-    }
-    return characteristics;
-  }
-
-  public DefaultTechnicalDebtModel loadModelFromXml(String pluginKey, ValidationMessages messages) {
-    Reader xmlFileReader = null;
-    try {
-      xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
-      return importer.importXML(xmlFileReader, messages);
-    } finally {
-      IOUtils.closeQuietly(xmlFileReader);
-    }
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManager.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManager.java
deleted file mode 100644 (file)
index 823064f..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.technicaldebt.server.Characteristic;
-import org.sonar.api.technicaldebt.server.TechnicalDebtManager;
-import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-/**
- * TODO This class should be replaced or created by a TechnicalDebtManagerBuilder
- */
-public class DefaultTechnicalDebtManager implements TechnicalDebtManager {
-
-  private final CharacteristicDao dao;
-  private final RuleFinder ruleFinder;
-
-  public DefaultTechnicalDebtManager(CharacteristicDao dao, RuleFinder ruleFinder) {
-    this.dao = dao;
-    this.ruleFinder = ruleFinder;
-  }
-
-  public List<Characteristic> findRootCharacteristics() {
-    List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
-    List<Characteristic> characteristics = newArrayList();
-    for (CharacteristicDto dto : dtos) {
-      characteristics.add(toCharacteristic(dto, null));
-    }
-    return characteristics;
-  }
-
-  @CheckForNull
-  public Characteristic findCharacteristicById(Integer id) {
-    CharacteristicDto dto = dao.selectById(id);
-    if (dto != null) {
-      return toCharacteristic(dto, null);
-    }
-    return null;
-  }
-
-  @CheckForNull
-  public Characteristic findRequirementByRuleId(int ruleId) {
-    CharacteristicDto requirementDto = dao.selectByRuleId(ruleId);
-    if (requirementDto != null) {
-      Rule rule = ruleFinder.findById(ruleId);
-      if (rule == null) {
-        throw new IllegalArgumentException(String.format("Rule with id '%s' do not exists.", ruleId));
-      }
-      return toCharacteristic(requirementDto, RuleKey.of(rule.getRepositoryKey(), rule.getKey()));
-    }
-    return null;
-  }
-
-  @CheckForNull
-  public Characteristic findRequirementByRule(Rule rule) {
-    CharacteristicDto requirementDto = dao.selectByRuleId(rule.getId());
-    if (requirementDto != null) {
-      return toCharacteristic(requirementDto, RuleKey.of(rule.getRepositoryKey(), rule.getKey()));
-    }
-    return null;
-  }
-
-  private static Characteristic toCharacteristic(CharacteristicDto dto, @Nullable RuleKey ruleKey) {
-    Double factorValue = dto.getFactorValue();
-    Double offsetValue = dto.getOffsetValue();
-    return new DefaultCharacteristic()
-      .setId(dto.getId())
-      .setKey(dto.getKey())
-      .setName(dto.getName())
-      .setOrder(dto.getOrder())
-      .setParentId(dto.getParentId())
-      .setRootId(dto.getRootId())
-      .setRuleKey(ruleKey)
-      .setFunction(dto.getFunction())
-      .setFactorValue(factorValue != null ? factorValue.intValue() : null)
-      .setFactorUnit(DefaultCharacteristic.toUnit(dto.getFactorUnit()))
-      .setOffsetValue(offsetValue != null ? offsetValue.intValue() : null)
-      .setOffsetUnit(DefaultCharacteristic.toUnit(dto.getOffsetUnit()));
-  }
-
-}
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
deleted file mode 100644 (file)
index 6c9c50d..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-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 java.util.Collection;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class DefaultTechnicalDebtModel implements TechnicalDebtModel {
-
-  private Collection<DefaultCharacteristic> rootCharacteristics;
-
-  public DefaultTechnicalDebtModel() {
-    rootCharacteristics = newArrayList();
-  }
-
-  public DefaultTechnicalDebtModel addRootCharacteristic(DefaultCharacteristic characteristic) {
-    rootCharacteristics.add(characteristic);
-    return this;
-  }
-
-  public List<DefaultCharacteristic> rootCharacteristics() {
-    return newArrayList(Iterables.filter(rootCharacteristics, new Predicate<DefaultCharacteristic>() {
-      @Override
-      public boolean apply(DefaultCharacteristic input) {
-        return input.isRoot();
-      }
-    }));
-  }
-
-  @CheckForNull
-  public DefaultCharacteristic characteristicByKey(final String key) {
-    return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
-      @Override
-      public boolean apply(DefaultCharacteristic input) {
-        return input.key().equals(key);
-      }
-    }, null);
-  }
-
-  @CheckForNull
-  public DefaultCharacteristic characteristicById(final Integer id){
-    return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
-      @Override
-      public boolean apply(DefaultCharacteristic input) {
-        return input.id().equals(id);
-      }
-    }, null);
-  }
-
-  @CheckForNull
-  public DefaultRequirement requirementsByRule(final RuleKey ruleKey) {
-    return Iterables.find(requirements(), new Predicate<DefaultRequirement>() {
-      @Override
-      public boolean apply(DefaultRequirement input) {
-        return input.ruleKey().equals(ruleKey);
-      }
-    }, null);
-  }
-
-  @CheckForNull
-  public DefaultRequirement requirementsById(final Integer id){
-    return Iterables.find(requirements(), new Predicate<DefaultRequirement>() {
-      @Override
-      public boolean apply(DefaultRequirement input) {
-        return input.id().equals(id);
-      }
-    }, null);
-  }
-
-  public List<DefaultCharacteristic> characteristics() {
-    List<DefaultCharacteristic> flatCharacteristics = newArrayList();
-    for (DefaultCharacteristic rootCharacteristic : rootCharacteristics) {
-      flatCharacteristics.add(rootCharacteristic);
-      for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
-        flatCharacteristics.add(characteristic);
-      }
-    }
-    return flatCharacteristics;
-  }
-
-  public List<DefaultRequirement> requirements() {
-    List<DefaultRequirement> allRequirements = newArrayList();
-    for (DefaultCharacteristic characteristic : characteristics()) {
-      for (DefaultRequirement requirement : characteristic.requirements()) {
-        allRequirements.add(requirement);
-      }
-    }
-    return allRequirements;
-  }
-
-  public boolean isEmpty(){
-    return rootCharacteristics.isEmpty();
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/RuleDebtXMLImporter.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/RuleDebtXMLImporter.java
deleted file mode 100644 (file)
index 8608558..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
-import com.google.common.collect.Iterables;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.math.NumberUtils;
-import org.codehaus.stax2.XMLInputFactory2;
-import org.codehaus.staxmate.SMInputFactory;
-import org.codehaus.staxmate.in.SMHierarchicCursor;
-import org.codehaus.staxmate.in.SMInputCursor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.rule.RemediationFunction;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.Duration;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class RuleDebtXMLImporter implements ServerExtension {
-
-  private static final Logger LOG = LoggerFactory.getLogger(RuleDebtXMLImporter.class);
-
-  public static final String CHARACTERISTIC = "chc";
-  public static final String CHARACTERISTIC_KEY = "key";
-  public static final String PROPERTY = "prop";
-
-  public static final String PROPERTY_KEY = "key";
-  public static final String PROPERTY_VALUE = "val";
-  public static final String PROPERTY_TEXT_VALUE = "txt";
-
-  public static final String REPOSITORY_KEY = "rule-repo";
-  public static final String RULE_KEY = "rule-key";
-
-  public static final String PROPERTY_FUNCTION = "remediationFunction";
-  public static final String PROPERTY_FACTOR = "remediationFactor";
-  public static final String PROPERTY_OFFSET = "offset";
-
-  public List<RuleDebt> importXML(String xml) {
-    return importXML(new StringReader(xml));
-  }
-
-  public List<RuleDebt> importXML(Reader xml) {
-    List<RuleDebt> ruleDebts = newArrayList();
-    try {
-      SMInputFactory inputFactory = initStax();
-      SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
-
-      // advance to <sqale>
-      cursor.advance();
-      SMInputCursor rootCursor = cursor.childElementCursor(CHARACTERISTIC);
-      while (rootCursor.getNext() != null) {
-        processCharacteristic(ruleDebts, null, null, rootCursor);
-      }
-
-      cursor.getStreamReader().closeCompletely();
-    } catch (XMLStreamException e) {
-      LOG.error("XML is not valid", e);
-    }
-
-    return ruleDebts;
-  }
-
-  private SMInputFactory initStax() {
-    XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
-    xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
-    xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
-    xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
-    xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
-    return new SMInputFactory(xmlFactory);
-  }
-
-  private void processCharacteristic(List<RuleDebt> ruleDebts, @Nullable String rootKey, @Nullable String parentKey, SMInputCursor chcCursor) throws XMLStreamException {
-    String currentCharacteristicKey = null;
-    SMInputCursor cursor = chcCursor.childElementCursor();
-    while (cursor.getNext() != null) {
-      String node = cursor.getLocalName();
-      if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
-        currentCharacteristicKey = cursor.collectDescendantText().trim();
-      } else if (StringUtils.equals(node, CHARACTERISTIC)) {
-        processCharacteristic(ruleDebts, parentKey, currentCharacteristicKey, cursor);
-      } else if (StringUtils.equals(node, REPOSITORY_KEY)) {
-        RuleDebt ruleDebt = processRequirement(cursor);
-        if (ruleDebt != null) {
-          if (rootKey != null) {
-            ruleDebt.characteristicKey = parentKey;
-            ruleDebts.add(ruleDebt);
-          } else {
-            LOG.warn("Rule '" + ruleDebt.ruleKey + "' is ignored because it's defined directly under a root characteristic.");
-          }
-        }
-      }
-    }
-  }
-
-  private RuleDebt processRequirement(SMInputCursor cursor)
-    throws XMLStreamException {
-
-    RuleDebt ruleDebt = new RuleDebt();
-    String ruleRepositoryKey = cursor.collectDescendantText().trim();
-    String ruleKey = null;
-    Properties properties = new Properties();
-    while (cursor.getNext() != null) {
-      String node = cursor.getLocalName();
-      if (StringUtils.equals(node, PROPERTY)) {
-        properties.add(processProperty(cursor));
-      } else if (StringUtils.equals(node, RULE_KEY)) {
-        ruleKey = cursor.collectDescendantText().trim();
-      }
-    }
-    if (StringUtils.isNotBlank(ruleRepositoryKey) && StringUtils.isNotBlank(ruleKey)) {
-      ruleDebt.ruleKey = RuleKey.of(ruleRepositoryKey, ruleKey);
-    } else {
-      return null;
-    }
-    return processFunctionsOnRequirement(ruleDebt, properties);
-  }
-
-  private Property processProperty(SMInputCursor cursor) throws XMLStreamException {
-    SMInputCursor c = cursor.childElementCursor();
-    String key = null;
-    int value = 0;
-    String textValue = null;
-    while (c.getNext() != null) {
-      String node = c.getLocalName();
-      if (StringUtils.equals(node, PROPERTY_KEY)) {
-        key = c.collectDescendantText().trim();
-
-      } else if (StringUtils.equals(node, PROPERTY_VALUE)) {
-        String s = c.collectDescendantText().trim();
-        try {
-          Double valueDouble = NumberUtils.createDouble(s);
-          value = valueDouble.intValue();
-        } catch (NumberFormatException ex) {
-          LOG.error(String.format("Cannot import value '%s' for field %s - Expected a numeric value instead", s, key));
-        }
-      } else if (StringUtils.equals(node, PROPERTY_TEXT_VALUE)) {
-        textValue = c.collectDescendantText().trim();
-      }
-    }
-    return new Property(key, value, textValue);
-  }
-
-  @CheckForNull
-  private RuleDebt processFunctionsOnRequirement(RuleDebt requirement, Properties properties) {
-    Property function = properties.function();
-    Property factor = properties.factor();
-    Property offset = properties.offset();
-
-    if (function != null) {
-      // Init with default values
-      requirement.factor = "0" + Duration.DAY;
-      requirement.offset = "0" + Duration.DAY;
-
-      String functionKey = function.getTextValue();
-      if ("linear_threshold".equals(functionKey)) {
-        function.setTextValue(RemediationFunction.LINEAR.name().toLowerCase());
-        offset.setValue(0);
-        offset.setTextValue(Duration.DAY);
-        LOG.warn(String.format("Linear with threshold function is no longer used, remediation function of '%s' is replaced by linear.", requirement.ruleKey));
-      } else if ("constant_resource".equals(functionKey)) {
-        LOG.warn(String.format("Constant/file function is no longer used, technical debt definitions on '%s' are ignored.", requirement.ruleKey));
-        return null;
-      }
-
-      requirement.function = RemediationFunction.valueOf(function.getTextValue().toUpperCase());
-      if (factor != null) {
-        requirement.factor = Integer.toString(factor.getValue());
-        requirement.factor += !Strings.isNullOrEmpty(factor.getTextValue()) ? factor.getTextValue() : Duration.DAY;
-      }
-      if (offset != null) {
-        requirement.offset = Integer.toString(offset.getValue());
-        requirement.offset += !Strings.isNullOrEmpty(offset.getTextValue()) ? offset.getTextValue() : Duration.DAY;
-      }
-      return requirement;
-    }
-    return null;
-  }
-
-  private static class Properties {
-    List<Property> properties;
-
-    public Properties() {
-      this.properties = newArrayList();
-    }
-
-    public Properties add(Property property) {
-      this.properties.add(property);
-      return this;
-    }
-
-    public Property function() {
-      return find(PROPERTY_FUNCTION);
-    }
-
-    public Property factor() {
-      return find(PROPERTY_FACTOR);
-    }
-
-    public Property offset() {
-      return find(PROPERTY_OFFSET);
-    }
-
-    private Property find(final String key) {
-      return Iterables.find(properties, new Predicate<Property>() {
-        @Override
-        public boolean apply(Property input) {
-          return input.getKey().equals(key);
-        }
-      }, null);
-    }
-  }
-
-  private static class Property {
-    String key;
-    int value;
-    String textValue;
-
-    private Property(String key, int value, String textValue) {
-      this.key = key;
-      this.value = value;
-      this.textValue = textValue;
-    }
-
-    private Property setValue(int value) {
-      this.value = value;
-      return this;
-    }
-
-    private Property setTextValue(String textValue) {
-      this.textValue = textValue;
-      return this;
-    }
-
-    private String getKey() {
-      return key;
-    }
-
-    private int getValue() {
-      return value;
-    }
-
-    private String getTextValue() {
-      return "mn".equals(textValue) ? Duration.MINUTE : textValue;
-    }
-  }
-
-  public static class RuleDebt {
-    private RuleKey ruleKey;
-    private String characteristicKey;
-    private RemediationFunction function;
-    private String factor;
-    private String offset;
-
-    public RuleKey ruleKey() {
-      return ruleKey;
-    }
-
-    public RuleDebt setRuleKey(RuleKey ruleKey) {
-      this.ruleKey = ruleKey;
-      return this;
-    }
-
-    public String characteristicKey() {
-      return characteristicKey;
-    }
-
-    public RuleDebt setCharacteristicKey(String characteristicKey) {
-      this.characteristicKey = characteristicKey;
-      return this;
-    }
-
-    public RemediationFunction function() {
-      return function;
-    }
-
-    public RuleDebt setFunction(RemediationFunction function) {
-      this.function = function;
-      return this;
-    }
-
-    public String factor() {
-      return factor;
-    }
-
-    public RuleDebt setFactor(String factor) {
-      this.factor = factor;
-      return this;
-    }
-
-    public String offset() {
-      return offset;
-    }
-
-    public RuleDebt setOffset(String offset) {
-      this.offset = offset;
-      return this;
-    }
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtModelRepository.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtModelRepository.java
deleted file mode 100644 (file)
index d103004..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Maps;
-import org.picocontainer.Startable;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
-
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-/**
- * <p>This class is used to find which technical debt model XML files exist in the Sonar instance.</p>
- * <p>
- * Those XML files are provided by language plugins that embed their own contribution to the definition of the Technical debt model.
- * They must be located in the classpath of those language plugins, more specifically in the "com.sonar.sqale" package, and
- * they must be named "<pluginKey>-model.xml".
- * </p>
- */
-public class TechnicalDebtModelRepository implements ServerExtension, Startable {
-
-  public static final String DEFAULT_MODEL = "technical-debt";
-
-  private static final String XML_FILE_SUFFIX = "-model.xml";
-  private static final String XML_FILE_PREFIX = "com/sonar/sqale/";
-
-  private String xmlFilePrefix;
-
-  private PluginRepository pluginRepository;
-  private Map<String, ClassLoader> contributingPluginKeyToClassLoader;
-
-  public TechnicalDebtModelRepository(PluginRepository pluginRepository) {
-    this.pluginRepository = pluginRepository;
-    this.xmlFilePrefix = XML_FILE_PREFIX;
-  }
-
-  @VisibleForTesting
-  TechnicalDebtModelRepository(PluginRepository pluginRepository, String xmlFilePrefix) {
-    this.pluginRepository = pluginRepository;
-    this.xmlFilePrefix = xmlFilePrefix;
-  }
-
-  @VisibleForTesting
-  TechnicalDebtModelRepository(Map<String, ClassLoader> contributingPluginKeyToClassLoader, String xmlFilePrefix) {
-    this.contributingPluginKeyToClassLoader = contributingPluginKeyToClassLoader;
-    this.xmlFilePrefix = xmlFilePrefix;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public void start() {
-    findAvailableXMLFiles();
-  }
-
-  protected void findAvailableXMLFiles() {
-    if (contributingPluginKeyToClassLoader == null) {
-      contributingPluginKeyToClassLoader = Maps.newTreeMap();
-      // Add default model
-      contributingPluginKeyToClassLoader.put(DEFAULT_MODEL, getClass().getClassLoader());
-      for (PluginMetadata metadata : pluginRepository.getMetadata()) {
-        String pluginKey = metadata.getKey();
-        ClassLoader classLoader = pluginRepository.getPlugin(pluginKey).getClass().getClassLoader();
-        if (classLoader.getResource(getXMLFilePath(pluginKey)) != null) {
-          contributingPluginKeyToClassLoader.put(pluginKey, classLoader);
-        }
-      }
-    }
-    contributingPluginKeyToClassLoader = Collections.unmodifiableMap(contributingPluginKeyToClassLoader);
-  }
-
-  @VisibleForTesting
-  String getXMLFilePath(String model) {
-    return xmlFilePrefix + model + XML_FILE_SUFFIX;
-  }
-
-  /**
-   * Returns the list of plugins that can contribute to the technical debt model.
-   *
-   * @return the list of plugin keys
-   */
-  public Collection<String> getContributingPluginList() {
-    return newArrayList(contributingPluginKeyToClassLoader.keySet());
-  }
-
-  /**
-   * Creates a new {@link java.io.Reader} for the XML file that contains the model contributed by the given plugin.
-   *
-   * @param pluginKey the key of the plugin that contributes the XML file
-   * @return the reader, that must be closed once its use is finished.
-   */
-  public Reader createReaderForXMLFile(String pluginKey) {
-    ClassLoader classLoader = contributingPluginKeyToClassLoader.get(pluginKey);
-    String xmlFilePath = getXMLFilePath(pluginKey);
-    return new InputStreamReader(classLoader.getResourceAsStream(xmlFilePath));
-  }
-
-  @VisibleForTesting
-  Map<String, ClassLoader> getContributingPluginKeyToClassLoader(){
-    return contributingPluginKeyToClassLoader;
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public void stop() {
-    // Nothing to do
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtModelSynchronizer.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtModelSynchronizer.java
deleted file mode 100644 (file)
index d553c22..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import org.apache.commons.io.IOUtils;
-import org.apache.ibatis.session.SqlSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-
-import java.io.Reader;
-import java.util.Collection;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class TechnicalDebtModelSynchronizer implements ServerExtension {
-
-  private static final Logger LOG = LoggerFactory.getLogger(TechnicalDebtModelSynchronizer.class);
-
-  private final MyBatis mybatis;
-  private final CharacteristicDao dao;
-  private final TechnicalDebtModelRepository languageModelFinder;
-  private final TechnicalDebtXMLImporter importer;
-
-  public TechnicalDebtModelSynchronizer(MyBatis mybatis, CharacteristicDao dao,
-                                        TechnicalDebtModelRepository modelRepository, TechnicalDebtXMLImporter importer) {
-    this.mybatis = mybatis;
-    this.dao = dao;
-    this.languageModelFinder = modelRepository;
-    this.importer = importer;
-  }
-
-  public List<CharacteristicDto> synchronize(ValidationMessages messages, TechnicalDebtRuleCache rulesCache) {
-    SqlSession session = mybatis.openSession();
-
-    List<CharacteristicDto> model = newArrayList();
-    try {
-      model = synchronize(messages, rulesCache, session);
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-    return model;
-  }
-
-  public List<CharacteristicDto> synchronize(ValidationMessages messages, TechnicalDebtRuleCache rulesCache, SqlSession session) {
-    DefaultTechnicalDebtModel defaultModel = loadModelFromXml(TechnicalDebtModelRepository.DEFAULT_MODEL, messages, rulesCache);
-    List<CharacteristicDto> model = loadOrCreateModelFromDb(defaultModel, session);
-    disableRequirementsOnRemovedRules(model, rulesCache, session);
-    mergePlugins(model, defaultModel, messages, rulesCache, session);
-    messages.log(LOG);
-
-    return model;
-  }
-
-  private List<CharacteristicDto> loadOrCreateModelFromDb(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
-    List<CharacteristicDto> characteristicDtos = loadModel();
-    if (characteristicDtos.isEmpty()) {
-      return createTechnicalDebtModel(defaultModel, session);
-    }
-    return characteristicDtos;
-  }
-
-  private List<CharacteristicDto> loadModel() {
-    return dao.selectEnabledCharacteristics();
-  }
-
-  private List<CharacteristicDto> createTechnicalDebtModel(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
-    List<CharacteristicDto> characteristics = newArrayList();
-    for (DefaultCharacteristic rootCharacteristic : defaultModel.rootCharacteristics()) {
-      CharacteristicDto rootCharacteristicDto = CharacteristicDto.toDto(rootCharacteristic, null);
-      dao.insert(rootCharacteristicDto, session);
-      characteristics.add(rootCharacteristicDto);
-      for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
-        CharacteristicDto characteristicDto = CharacteristicDto.toDto(characteristic, rootCharacteristicDto.getId());
-        dao.insert(characteristicDto, session);
-        characteristics.add(characteristicDto);
-      }
-    }
-    return characteristics;
-  }
-
-  private void mergePlugins(List<CharacteristicDto> existingModel, DefaultTechnicalDebtModel defaultModel, ValidationMessages messages, TechnicalDebtRuleCache rulesCache,
-                            SqlSession session) {
-    for (String pluginKey : getContributingPluginListWithoutSqale()) {
-      DefaultTechnicalDebtModel pluginModel = loadModelFromXml(pluginKey, messages, rulesCache);
-      checkPluginDoNotAddNewCharacteristic(pluginModel, defaultModel);
-      mergePlugin(pluginModel, existingModel, messages, rulesCache, session);
-    }
-  }
-
-  private void mergePlugin(DefaultTechnicalDebtModel pluginModel, List<CharacteristicDto> existingModel, ValidationMessages messages, TechnicalDebtRuleCache rulesCache,
-                           SqlSession session) {
-    if (!messages.hasErrors()) {
-      for (DefaultRequirement pluginRequirement : pluginModel.requirements()) {
-        Rule rule = rulesCache.getByRuleKey(pluginRequirement.ruleKey());
-        if (!isRequirementExists(existingModel, rule)) {
-          CharacteristicDto characteristicDto = findCharacteristic(existingModel, pluginRequirement.characteristic().key());
-          Integer rootId = characteristicDto.getRootId();
-          if (rootId == null) {
-            throw new IllegalArgumentException("Requirement on rule '" + pluginRequirement.ruleKey() + "' should not be linked on a root characteristic.");
-          }
-          CharacteristicDto requirementDto = CharacteristicDto.toDto(pluginRequirement, characteristicDto.getId(), rootId, rule.getId());
-          dao.insert(requirementDto, session);
-        }
-      }
-    }
-  }
-
-  public DefaultTechnicalDebtModel loadModelFromXml(String pluginKey, ValidationMessages messages, TechnicalDebtRuleCache rulesCache) {
-    Reader xmlFileReader = null;
-    try {
-      xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
-      return importer.importXML(xmlFileReader, messages, rulesCache);
-    } finally {
-      IOUtils.closeQuietly(xmlFileReader);
-    }
-  }
-
-  private void checkPluginDoNotAddNewCharacteristic(DefaultTechnicalDebtModel pluginModel, DefaultTechnicalDebtModel defaultModel) {
-    List<DefaultCharacteristic> characteristics = defaultModel.characteristics();
-    for (DefaultCharacteristic characteristic : pluginModel.characteristics()) {
-      if (!characteristics.contains(characteristic)) {
-        throw new IllegalArgumentException("The characteristic : " + characteristic.key() + " cannot be used as it's not available in default characteristics.");
-      }
-    }
-  }
-
-  private void disableRequirementsOnRemovedRules(List<CharacteristicDto> existingModel, TechnicalDebtRuleCache rulesCache, SqlSession session) {
-    for (CharacteristicDto characteristicDto : existingModel) {
-      Integer ruleId = characteristicDto.getRuleId();
-      if (ruleId != null && !rulesCache.exists(ruleId)) {
-        dao.disable(characteristicDto.getId(), session);
-      }
-    }
-  }
-
-  private Collection<String> getContributingPluginListWithoutSqale() {
-    Collection<String> pluginList = newArrayList(languageModelFinder.getContributingPluginList());
-    pluginList.remove(TechnicalDebtModelRepository.DEFAULT_MODEL);
-    return pluginList;
-  }
-
-  private CharacteristicDto findCharacteristic(List<CharacteristicDto> existingModel, final String key) {
-    return Iterables.find(existingModel, new Predicate<CharacteristicDto>() {
-      @Override
-      public boolean apply(CharacteristicDto input) {
-        String characteristicKey = input.getKey();
-        return input.getRuleId() == null && characteristicKey != null && characteristicKey.equals(key);
-      }
-    });
-  }
-
-  private boolean isRequirementExists(List<CharacteristicDto> existingModel, final Rule rule) {
-    return Iterables.any(existingModel, new Predicate<CharacteristicDto>() {
-      @Override
-      public boolean apply(CharacteristicDto input) {
-        Integer ruleId = input.getRuleId();
-        return ruleId != null && ruleId.equals(rule.getId());
-      }
-    });
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtRuleCache.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtRuleCache.java
deleted file mode 100644 (file)
index d5a098a..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.collect.Maps;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.rules.RuleQuery;
-
-import javax.annotation.CheckForNull;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-public class TechnicalDebtRuleCache {
-
-  private final RuleFinder ruleFinder;
-
-  private Map<String, Map<String, Rule>> cachedRules;
-  private Map<Integer, Rule> cachedRulesId;
-
-  public TechnicalDebtRuleCache(RuleFinder ruleFinder) {
-    this.ruleFinder = ruleFinder;
-  }
-
-  @CheckForNull
-  public Rule getByRuleKey(RuleKey ruleKey) {
-    initRules();
-    return lookUpRuleInCache(ruleKey.repository(), ruleKey.rule());
-  }
-
-  @CheckForNull
-  public Rule getByRuleId(Integer ruleId) {
-    initRules();
-    return cachedRulesId.get(ruleId);
-  }
-
-  public boolean exists(Integer ruleId) {
-    initRules();
-    return getByRuleId(ruleId) != null;
-  }
-
-  public boolean exists(RuleKey ruleKey) {
-    return getByRuleKey(ruleKey) != null;
-  }
-
-  private void initRules(){
-    if(cachedRules == null) {
-      loadRules();
-    }
-  }
-
-  private void loadRules() {
-    cachedRules = Maps.newHashMap();
-    cachedRulesId = Maps.newHashMap();
-    Collection<Rule> rules = ruleFinder.findAll(RuleQuery.create());
-    for (Rule rule : rules) {
-      if(!cachedRules.containsKey(rule.getRepositoryKey())) {
-        cachedRules.put(rule.getRepositoryKey(), new HashMap<String, Rule>());
-      }
-      Map<String, Rule> cachedRepository = cachedRules.get(rule.getRepositoryKey());
-      if(!cachedRepository.containsKey(rule.getKey())) {
-        cachedRepository.put(rule.getKey(), rule);
-        cachedRulesId.put(rule.getId(), rule);
-      }
-    }
-  }
-
-  @CheckForNull
-  private Rule lookUpRuleInCache(String repository, String ruleKey) {
-    Map<String, Rule> cachedRepository = cachedRules.get(repository);
-    if(cachedRepository != null) {
-      return cachedRepository.get(ruleKey);
-    }
-    return null;
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporter.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporter.java
deleted file mode 100644 (file)
index 12c307d..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
-import com.google.common.collect.Iterables;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.math.NumberUtils;
-import org.codehaus.stax2.XMLInputFactory2;
-import org.codehaus.staxmate.SMInputFactory;
-import org.codehaus.staxmate.in.SMHierarchicCursor;
-import org.codehaus.staxmate.in.SMInputCursor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.api.utils.internal.WorkDuration;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-
-import javax.annotation.CheckForNull;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class TechnicalDebtXMLImporter implements ServerExtension {
-
-  private static final Logger LOG = LoggerFactory.getLogger(TechnicalDebtXMLImporter.class);
-
-  public static final String CHARACTERISTIC = "chc";
-  public static final String CHARACTERISTIC_KEY = "key";
-  public static final String CHARACTERISTIC_NAME = "name";
-  public static final String PROPERTY = "prop";
-
-  public static final String PROPERTY_KEY = "key";
-  public static final String PROPERTY_VALUE = "val";
-  public static final String PROPERTY_TEXT_VALUE = "txt";
-
-  public static final String REPOSITORY_KEY = "rule-repo";
-  public static final String RULE_KEY = "rule-key";
-
-  public static final String PROPERTY_FUNCTION = "remediationFunction";
-  public static final String PROPERTY_FACTOR = "remediationFactor";
-  public static final String PROPERTY_OFFSET = "offset";
-
-  public DefaultTechnicalDebtModel importXML(String xml, ValidationMessages messages, TechnicalDebtRuleCache technicalDebtRuleCache) {
-    return importXML(new StringReader(xml), messages, technicalDebtRuleCache);
-  }
-
-  public DefaultTechnicalDebtModel importXML(Reader xml, ValidationMessages messages, TechnicalDebtRuleCache repositoryCache) {
-    DefaultTechnicalDebtModel model = new DefaultTechnicalDebtModel();
-    try {
-      SMInputFactory inputFactory = initStax();
-      SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
-
-      // advance to <sqale>
-      cursor.advance();
-      SMInputCursor chcCursor = cursor.childElementCursor(CHARACTERISTIC);
-
-      while (chcCursor.getNext() != null) {
-        processCharacteristic(model, null, chcCursor, messages, repositoryCache);
-      }
-
-      cursor.getStreamReader().closeCompletely();
-
-    } catch (XMLStreamException e) {
-      LOG.error("XML is not valid", e);
-      messages.addErrorText("XML is not valid: " + e.getMessage());
-    }
-    return model;
-  }
-
-  private SMInputFactory initStax() {
-    XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
-    xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
-    xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
-    xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
-    xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
-    return new SMInputFactory(xmlFactory);
-  }
-
-  private DefaultCharacteristic processCharacteristic(DefaultTechnicalDebtModel model, DefaultCharacteristic parent, SMInputCursor chcCursor, ValidationMessages messages,
-                                                      TechnicalDebtRuleCache technicalDebtRuleCache) throws XMLStreamException {
-    DefaultCharacteristic characteristic = new DefaultCharacteristic();
-    SMInputCursor cursor = chcCursor.childElementCursor();
-    while (cursor.getNext() != null) {
-      String node = cursor.getLocalName();
-      if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
-        characteristic.setKey(cursor.collectDescendantText().trim());
-        // Attached to parent only if a key is existing, otherwise characteristic with empty key can be added.
-        characteristic.setParent(parent);
-
-      } else if (StringUtils.equals(node, CHARACTERISTIC_NAME)) {
-        characteristic.setName(cursor.collectDescendantText().trim(), false);
-
-        // <chc> can contain characteristics or requirements
-      } else if (StringUtils.equals(node, CHARACTERISTIC)) {
-        processCharacteristic(model, characteristic, cursor, messages, technicalDebtRuleCache);
-
-      } else if (StringUtils.equals(node, REPOSITORY_KEY)) {
-        DefaultRequirement requirement = processRequirement(cursor, messages, technicalDebtRuleCache);
-        if (requirement != null) {
-          addRequirement(requirement, parent, messages);
-        }
-      }
-    }
-
-    if (StringUtils.isNotBlank(characteristic.key()) && characteristic.isRoot()) {
-      characteristic.setOrder(model.rootCharacteristics().size() + 1);
-      model.addRootCharacteristic(characteristic);
-      return characteristic;
-    }
-    return null;
-  }
-
-  private void addRequirement(DefaultRequirement requirement, DefaultCharacteristic parent, ValidationMessages messages) {
-    DefaultCharacteristic root = parent.parent();
-    if (root == null) {
-      messages.addWarningText("Requirement '" + requirement.ruleKey() + "' is ignored because it's defined directly under a root characteristic.");
-    } else {
-      requirement.setCharacteristic(parent);
-      requirement.setRootCharacteristic(root);
-    }
-  }
-
-  private DefaultRequirement processRequirement(SMInputCursor cursor, ValidationMessages messages, TechnicalDebtRuleCache technicalDebtRuleCache)
-    throws XMLStreamException {
-
-    DefaultRequirement requirement = new DefaultRequirement();
-    String ruleRepositoryKey = cursor.collectDescendantText().trim();
-    String ruleKey = null;
-    Properties properties = new Properties();
-    while (cursor.getNext() != null) {
-      String node = cursor.getLocalName();
-      if (StringUtils.equals(node, PROPERTY)) {
-        properties.add(processProperty(cursor, messages));
-      } else if (StringUtils.equals(node, RULE_KEY)) {
-        ruleKey = cursor.collectDescendantText().trim();
-      }
-    }
-    fillRule(requirement, ruleRepositoryKey, ruleKey, messages, technicalDebtRuleCache);
-    if (requirement.ruleKey() == null) {
-      return null;
-    }
-    return processFunctionsOnRequirement(requirement, properties, messages);
-  }
-
-  private void fillRule(DefaultRequirement requirement, String ruleRepositoryKey, String ruleKey, ValidationMessages messages,
-                        TechnicalDebtRuleCache technicalDebtRuleCache) {
-    if (StringUtils.isNotBlank(ruleRepositoryKey) && StringUtils.isNotBlank(ruleKey)) {
-      Rule rule = technicalDebtRuleCache.getByRuleKey(RuleKey.of(ruleRepositoryKey, ruleKey));
-      if (rule != null) {
-        requirement.setRuleKey(RuleKey.of(ruleRepositoryKey, ruleKey));
-      } else {
-        messages.addWarningText("Rule not found: [repository=" + ruleRepositoryKey + ", key=" + ruleKey + "]");
-      }
-    }
-  }
-
-  private Property processProperty(SMInputCursor cursor, ValidationMessages messages) throws XMLStreamException {
-    SMInputCursor c = cursor.childElementCursor();
-    String key = null;
-    int value = 0;
-    String textValue = null;
-    while (c.getNext() != null) {
-      String node = c.getLocalName();
-      if (StringUtils.equals(node, PROPERTY_KEY)) {
-        key = c.collectDescendantText().trim();
-
-      } else if (StringUtils.equals(node, PROPERTY_VALUE)) {
-        String s = c.collectDescendantText().trim();
-        try {
-          // The value is still a double for the moment
-          Double valueDouble = NumberUtils.createDouble(s);
-          value = valueDouble.intValue();
-        } catch (NumberFormatException ex) {
-          messages.addErrorText(String.format("Cannot import value '%s' for field %s - Expected a numeric value instead", s, key));
-        }
-      } else if (StringUtils.equals(node, PROPERTY_TEXT_VALUE)) {
-        textValue = c.collectDescendantText().trim();
-      }
-    }
-    return new Property(key, value, textValue);
-  }
-
-  @CheckForNull
-  private DefaultRequirement processFunctionsOnRequirement(DefaultRequirement requirement, Properties properties, ValidationMessages messages) {
-    Property function = properties.function();
-    Property factor = properties.factor();
-    Property offset = properties.offset();
-
-    if (function != null) {
-      // Requirements should always have values, so we init it with default values
-      requirement.setFactorValue(0);
-      requirement.setFactorUnit(WorkDuration.UNIT.DAYS);
-      requirement.setOffsetValue(0);
-      requirement.setOffsetUnit(WorkDuration.UNIT.DAYS);
-
-      String functionKey = function.getTextValue();
-      if ("linear_threshold".equals(functionKey)) {
-        function.setTextValue(DefaultRequirement.FUNCTION_LINEAR);
-        offset.setValue(0);
-        offset.setTextValue(CharacteristicDto.DAYS);
-        messages.addWarningText(String.format("Linear with threshold function is no longer used, function of the requirement '%s' is replaced by linear.", requirement.ruleKey()));
-      } else if ("constant_resource".equals(functionKey)) {
-        messages.addWarningText(String.format("Constant/file function is no longer used, requirements '%s' are ignored.", requirement.ruleKey()));
-        return null;
-      }
-
-      requirement.setFunction(function.getTextValue());
-      if (factor != null) {
-        requirement.setFactorValue(factor.getValue());
-        if (!Strings.isNullOrEmpty(factor.getTextValue())) {
-          requirement.setFactorUnit(DefaultRequirement.toUnit(factor.getTextValue()));
-        }
-      }
-      if (offset != null) {
-        requirement.setOffsetValue(offset.getValue());
-        if (!Strings.isNullOrEmpty(offset.getTextValue())) {
-          requirement.setOffsetUnit(DefaultRequirement.toUnit(offset.getTextValue()));
-        }
-      }
-      return requirement;
-    }
-    return null;
-  }
-
-  private static class Properties {
-    List<Property> properties;
-
-    public Properties() {
-      this.properties = newArrayList();
-    }
-
-    public Properties add(Property property) {
-      this.properties.add(property);
-      return this;
-    }
-
-    public Property function() {
-      return find(PROPERTY_FUNCTION);
-    }
-
-    public Property factor() {
-      return find(PROPERTY_FACTOR);
-    }
-
-    public Property offset() {
-      return find(PROPERTY_OFFSET);
-    }
-
-    private Property find(final String key) {
-      return Iterables.find(properties, new Predicate<Property>() {
-        @Override
-        public boolean apply(Property input) {
-          return input.getKey().equals(key);
-        }
-      }, null);
-    }
-
-  }
-
-  private static class Property {
-    String key;
-    int value;
-    String textValue;
-
-    private Property(String key, int value, String textValue) {
-      this.key = key;
-      this.value = value;
-      this.textValue = textValue;
-    }
-
-    private Property setValue(int value) {
-      this.value = value;
-      return this;
-    }
-
-    private Property setTextValue(String textValue) {
-      this.textValue = textValue;
-      return this;
-    }
-
-    private String getKey() {
-      return key;
-    }
-
-    private int getValue() {
-      return value;
-    }
-
-    private String getTextValue() {
-      return textValue;
-    }
-  }
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/db/CharacteristicDao.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/db/CharacteristicDao.java
deleted file mode 100644 (file)
index 6e6ff49..0000000
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt.db;
-
-import org.apache.ibatis.session.SqlSession;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.ServerComponent;
-import org.sonar.core.persistence.MyBatis;
-
-import javax.annotation.CheckForNull;
-
-import java.util.List;
-
-public class CharacteristicDao implements BatchComponent, ServerComponent {
-
-  private final MyBatis mybatis;
-
-  public CharacteristicDao(MyBatis mybatis) {
-    this.mybatis = mybatis;
-  }
-
-  /**
-   * @return enabled root characteristics, characteristics and requirements
-   *
-   * @deprecated since 4.3
-   */
-  @Deprecated
-  public List<CharacteristicDto> selectEnabledCharacteristics() {
-    SqlSession session = mybatis.openSession();
-    try {
-      return session.getMapper(CharacteristicMapper.class).selectEnabledCharacteristics();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  /**
-   * @return enabled root characteristics, and characteristics
-   *
-   */
-  public List<CharacteristicDto> selectCharacteristics() {
-    SqlSession session = mybatis.openSession();
-    try {
-      return selectCharacteristics(session);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  public List<CharacteristicDto> selectCharacteristics(SqlSession session) {
-    return session.getMapper(CharacteristicMapper.class).selectCharacteristics();
-  }
-
-  /**
-   * @return only enabled root characteristics, order by order
-   */
-  public List<CharacteristicDto> selectEnabledRootCharacteristics() {
-    SqlSession session = mybatis.openSession();
-    CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
-    try {
-      return mapper.selectEnabledRootCharacteristics();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  @CheckForNull
-  public CharacteristicDto selectByKey(String key) {
-    SqlSession session = mybatis.openSession();
-    CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
-    try {
-      return mapper.selectByKey(key);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  @CheckForNull
-  public CharacteristicDto selectById(int id) {
-    SqlSession session = mybatis.openSession();
-    CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
-    try {
-      return mapper.selectById(id);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  @CheckForNull
-  public CharacteristicDto selectByRuleId(Integer ruleId) {
-    SqlSession session = mybatis.openSession();
-    CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
-    try {
-      return mapper.selectByRuleId(ruleId);
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  public void insert(CharacteristicDto dto, SqlSession session) {
-    session.getMapper(CharacteristicMapper.class).insert(dto);
-  }
-
-  public void insert(CharacteristicDto dto) {
-    SqlSession session = mybatis.openSession();
-    try {
-      insert(dto, session);
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  public void update(CharacteristicDto dto, SqlSession session) {
-    session.getMapper(CharacteristicMapper.class).update(dto);
-  }
-
-  public void update(CharacteristicDto dto) {
-    SqlSession session = mybatis.openSession();
-    try {
-      update(dto, session);
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-  public void disable(Integer id, SqlSession session) {
-    session.getMapper(CharacteristicMapper.class).disable(id);
-  }
-
-  public void disable(Integer id) {
-    SqlSession session = mybatis.openSession();
-    try {
-      disable(id, session);
-      session.commit();
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/db/CharacteristicDto.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/db/CharacteristicDto.java
deleted file mode 100644 (file)
index 18a1bb9..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt.db;
-
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.internal.WorkDuration;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.io.Serializable;
-import java.util.Date;
-
-public class CharacteristicDto implements Serializable {
-
-  public static final String DAYS = "d";
-  public static final String MINUTES = "mn";
-  public static final String HOURS = "h";
-
-  private Integer id;
-  private String kee;
-  private String name;
-  private Integer parentId;
-  private Integer rootId;
-  private Integer characteristicOrder;
-  private Integer ruleId;
-  private String functionKey;
-  private Double factorValue;
-  private String factorUnit;
-  private Double offsetValue;
-  private String offsetUnit;
-  private Date createdAt;
-  private Date updatedAt;
-  private boolean enabled;
-
-  public Integer getId() {
-    return id;
-  }
-
-  public CharacteristicDto setId(Integer id) {
-    this.id = id;
-    return this;
-  }
-
-  @CheckForNull
-  public String getKey() {
-    return kee;
-  }
-
-  public CharacteristicDto setKey(@Nullable String s) {
-    this.kee = s;
-    return this;
-  }
-
-  @CheckForNull
-  public String getName() {
-    return name;
-  }
-
-  public CharacteristicDto setName(@Nullable String s) {
-    this.name = s;
-    return this;
-  }
-
-  @CheckForNull
-  public Integer getParentId() {
-    return parentId;
-  }
-
-  public CharacteristicDto setParentId(@Nullable Integer i) {
-    this.parentId = i;
-    return this;
-  }
-
-  @CheckForNull
-  public Integer getRootId() {
-    return rootId;
-  }
-
-  public CharacteristicDto setRootId(@Nullable Integer rootId) {
-    this.rootId = rootId;
-    return this;
-  }
-
-  @CheckForNull
-  public Integer getOrder() {
-    return characteristicOrder;
-  }
-
-  public CharacteristicDto setOrder(@Nullable Integer i) {
-    this.characteristicOrder = i;
-    return this;
-  }
-
-  @CheckForNull
-  public Integer getRuleId() {
-    return ruleId;
-  }
-
-  public CharacteristicDto setRuleId(@Nullable Integer ruleId) {
-    this.ruleId = ruleId;
-    return this;
-  }
-
-  @CheckForNull
-  public String getFunction() {
-    return functionKey;
-  }
-
-  public CharacteristicDto setFunction(@Nullable String function) {
-    this.functionKey = function;
-    return this;
-  }
-
-  @CheckForNull
-  public Double getFactorValue() {
-    return factorValue;
-  }
-
-  public CharacteristicDto setFactorValue(Double factor) {
-    this.factorValue = factor;
-    return this;
-  }
-
-  @CheckForNull
-  public String getFactorUnit() {
-    return factorUnit;
-  }
-
-  public CharacteristicDto setFactorUnit(@Nullable String factorUnit) {
-    this.factorUnit = factorUnit;
-    return this;
-  }
-
-  @CheckForNull
-  public Double getOffsetValue() {
-    return offsetValue;
-  }
-
-  public CharacteristicDto setOffsetValue(@Nullable Double offset) {
-    this.offsetValue = offset;
-    return this;
-  }
-
-  @CheckForNull
-  public String getOffsetUnit() {
-    return offsetUnit;
-  }
-
-  public CharacteristicDto setOffsetUnit(@Nullable String offsetUnit) {
-    this.offsetUnit = offsetUnit;
-    return this;
-  }
-
-  public Date getCreatedAt() {
-    return createdAt;
-  }
-
-  public CharacteristicDto setCreatedAt(Date createdAt) {
-    this.createdAt = createdAt;
-    return this;
-  }
-
-  @CheckForNull
-  public Date getUpdatedAt() {
-    return updatedAt;
-  }
-
-  public CharacteristicDto setUpdatedAt(@Nullable Date updatedAt) {
-    this.updatedAt = updatedAt;
-    return this;
-  }
-
-  public boolean isEnabled() {
-    return enabled;
-  }
-
-  public CharacteristicDto setEnabled(boolean enabled) {
-    this.enabled = enabled;
-    return this;
-  }
-
-  public DefaultCharacteristic toCharacteristic(@Nullable DefaultCharacteristic parent) {
-    return new DefaultCharacteristic()
-      .setId(id)
-      .setKey(kee)
-      .setName(name)
-      .setOrder(characteristicOrder)
-      .setParent(parent)
-      .setRoot(parent)
-      .setCreatedAt(createdAt)
-      .setUpdatedAt(updatedAt);
-  }
-
-  public static CharacteristicDto toDto(DefaultCharacteristic characteristic, @Nullable Integer parentId) {
-    return new CharacteristicDto()
-      .setKey(characteristic.key())
-      .setName(characteristic.name())
-      .setOrder(characteristic.order())
-      .setParentId(parentId)
-      .setRootId(parentId)
-      .setEnabled(true)
-      .setCreatedAt(characteristic.createdAt())
-      .setUpdatedAt(characteristic.updatedAt());
-  }
-
-  public DefaultRequirement toRequirement(RuleKey ruleKey, DefaultCharacteristic characteristic, DefaultCharacteristic rootCharacteristic) {
-    return new DefaultRequirement()
-      .setId(id)
-      .setRuleKey(ruleKey)
-      .setCharacteristic(characteristic)
-      .setRootCharacteristic(rootCharacteristic)
-      .setFunction(functionKey)
-      .setFactorValue(factorValue.intValue())
-      .setFactorUnit(toUnit(factorUnit))
-      .setOffsetValue(offsetValue.intValue())
-      .setOffsetUnit(toUnit(offsetUnit))
-      .setCreatedAt(createdAt)
-      .setUpdatedAt(updatedAt);
-  }
-
-  public static CharacteristicDto toDto(DefaultRequirement requirement, Integer characteristicId, Integer rootCharacteristicId, Integer ruleId) {
-    return new CharacteristicDto()
-      .setRuleId(ruleId)
-      .setParentId(characteristicId)
-      .setRootId(rootCharacteristicId)
-      .setFunction(requirement.function())
-      .setFactorValue((double) requirement.factorValue())
-      .setFactorUnit(fromUnit(requirement.factorUnit()))
-      .setOffsetValue((double) requirement.offsetValue())
-      .setOffsetUnit(fromUnit(requirement.offsetUnit()))
-      .setEnabled(true)
-      .setCreatedAt(requirement.createdAt())
-      .setUpdatedAt(requirement.updatedAt());
-  }
-
-  private static WorkDuration.UNIT toUnit(@Nullable String requirementUnit) {
-    if (requirementUnit != null) {
-      if (DAYS.equals(requirementUnit)) {
-        return WorkDuration.UNIT.DAYS;
-      } else if (HOURS.equals(requirementUnit)) {
-        return WorkDuration.UNIT.HOURS;
-      } else if (MINUTES.equals(requirementUnit)) {
-        return WorkDuration.UNIT.MINUTES;
-      }
-      throw new IllegalStateException("Invalid unit : " + requirementUnit);
-    }
-    return null;
-  }
-
-  private static String fromUnit(@Nullable WorkDuration.UNIT unit) {
-    if (unit != null) {
-      if (WorkDuration.UNIT.DAYS.equals(unit)) {
-        return DAYS;
-      } else if (WorkDuration.UNIT.HOURS.equals(unit)) {
-        return HOURS;
-      } else if (WorkDuration.UNIT.MINUTES.equals(unit)) {
-        return MINUTES;
-      }
-      throw new IllegalStateException("Invalid unit : " + unit);
-    }
-    return null;
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/db/CharacteristicMapper.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/db/CharacteristicMapper.java
deleted file mode 100644 (file)
index 7ab1b29..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt.db;
-
-import java.util.List;
-
-public interface CharacteristicMapper {
-
-  List<CharacteristicDto> selectEnabledCharacteristics();
-
-  List<CharacteristicDto> selectCharacteristics();
-
-  List<CharacteristicDto> selectEnabledRootCharacteristics();
-
-  CharacteristicDto selectByKey(String key);
-
-  CharacteristicDto selectById(int id);
-
-  CharacteristicDto selectByRuleId(Integer ruleId);
-
-  void insert(CharacteristicDto characteristic);
-
-  int update(CharacteristicDto characteristic);
-
-  int disable(Integer id);
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/db/package-info.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/db/package-info.java
deleted file mode 100644 (file)
index 815db16..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.
- */
-
-@ParametersAreNonnullByDefault
-package org.sonar.core.technicaldebt.db;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-core/src/main/java/org/sonar/core/technicaldebt/package-info.java b/sonar-core/src/main/java/org/sonar/core/technicaldebt/package-info.java
deleted file mode 100644 (file)
index 268f4db..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.core.technicaldebt;
-
-import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-core/src/main/resources/org/sonar/core/debt/db/CharacteristicMapper.xml b/sonar-core/src/main/resources/org/sonar/core/debt/db/CharacteristicMapper.xml
new file mode 100644 (file)
index 0000000..ff16da1
--- /dev/null
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mappei.dtd">
+
+<mapper namespace="org.sonar.core.debt.db.CharacteristicMapper">
+
+  <sql id="characteristicColumns">
+    c.id,
+    c.kee as kee,
+    c.name as name,
+    c.parent_id as parentId,
+    c.root_id as rootId,
+    c.characteristic_order as characteristicOrder,
+    c.rule_id as ruleId,
+    c.function_key as functionKey,
+    c.factor_value as factorValue,
+    c.factor_unit as factorUnit,
+    c.offset_value as offsetValue,
+    c.offset_unit as offsetUnit,
+    c.enabled as enabled,
+    c.created_at as createdAt,
+    c.updated_at as updatedAt
+  </sql>
+
+  <select id="selectEnabledCharacteristics" parameterType="map" resultType="Characteristic">
+    select <include refid="characteristicColumns"/>
+    from characteristics c
+    <where>
+      and c.enabled=${_true}
+    </where>
+  </select>
+
+  <select id="selectCharacteristics" parameterType="map" resultType="Characteristic">
+    select <include refid="characteristicColumns"/>
+    from characteristics c
+    <where>
+      and c.rule_id is null
+      and c.enabled=${_true}
+    </where>
+  </select>
+
+  <select id="selectEnabledRootCharacteristics" parameterType="map" resultType="Characteristic">
+    select <include refid="characteristicColumns"/>
+    from characteristics c
+    <where>
+      and c.parent_id is null
+      and c.rule_id is null
+      and c.enabled=${_true}
+    </where>
+    order by characteristic_order asc
+  </select>
+
+  <select id="selectByKey" parameterType="String" resultType="Characteristic">
+    select <include refid="characteristicColumns"/>
+    from characteristics c
+    <where>
+      and c.kee=#{key}
+      and c.enabled=${_true}
+    </where>
+  </select>
+
+  <select id="selectById" parameterType="Integer" resultType="Characteristic">
+    select <include refid="characteristicColumns"/>
+    from characteristics c
+    <where>
+      and c.id=#{id}
+      and c.enabled=${_true}
+    </where>
+  </select>
+
+  <select id="selectByRuleId" parameterType="Integer" resultType="Characteristic">
+    select <include refid="characteristicColumns"/>
+    from characteristics c
+    <where>
+      and c.rule_id=#{ruleId}
+      and c.enabled=${_true}
+    </where>
+  </select>
+
+  <insert id="insert" parameterType="Characteristic" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
+    INSERT INTO characteristics (kee, name, parent_id, root_id, characteristic_order,
+    rule_id, function_key, factor_value, factor_unit, offset_value, offset_unit,
+    enabled, created_at, updated_at)
+    VALUES (#{kee}, #{name}, #{parentId}, #{rootId}, #{characteristicOrder},
+    #{ruleId}, #{functionKey}, #{factorValue}, #{factorUnit}, #{offsetValue}, #{offsetUnit},
+    #{enabled}, current_timestamp, current_timestamp)
+  </insert>
+
+  <update id="update" parameterType="Characteristic">
+    update characteristics set
+    name=#{name},
+    parent_id=#{parentId},
+    root_id=#{rootId},
+    characteristic_order=#{characteristicOrder},
+    rule_id=#{ruleId},
+    function_key=#{functionKey},
+    factor_value=#{factorValue},
+    factor_unit=#{factorUnit},
+    offset_value=#{offsetValue},
+    offset_unit=#{offsetUnit},
+    enabled=#{enabled},
+    updated_at=current_timestamp
+    where id=#{id}
+  </update>
+
+  <update id="disable" parameterType="Integer">
+    update characteristics set
+    enabled=${_false},
+    updated_at=current_timestamp
+    where id=#{id}
+  </update>
+
+</mapper>
+
diff --git a/sonar-core/src/main/resources/org/sonar/core/technicaldebt/db/CharacteristicMapper.xml b/sonar-core/src/main/resources/org/sonar/core/technicaldebt/db/CharacteristicMapper.xml
deleted file mode 100644 (file)
index 2988115..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mappei.dtd">
-
-<mapper namespace="org.sonar.core.technicaldebt.db.CharacteristicMapper">
-
-  <sql id="characteristicColumns">
-    c.id,
-    c.kee as kee,
-    c.name as name,
-    c.parent_id as parentId,
-    c.root_id as rootId,
-    c.characteristic_order as characteristicOrder,
-    c.rule_id as ruleId,
-    c.function_key as functionKey,
-    c.factor_value as factorValue,
-    c.factor_unit as factorUnit,
-    c.offset_value as offsetValue,
-    c.offset_unit as offsetUnit,
-    c.enabled as enabled,
-    c.created_at as createdAt,
-    c.updated_at as updatedAt
-  </sql>
-
-  <select id="selectEnabledCharacteristics" parameterType="map" resultType="Characteristic">
-    select <include refid="characteristicColumns"/>
-    from characteristics c
-    <where>
-      and c.enabled=${_true}
-    </where>
-  </select>
-
-  <select id="selectCharacteristics" parameterType="map" resultType="Characteristic">
-    select <include refid="characteristicColumns"/>
-    from characteristics c
-    <where>
-      and c.rule_id is null
-      and c.enabled=${_true}
-    </where>
-  </select>
-
-  <select id="selectEnabledRootCharacteristics" parameterType="map" resultType="Characteristic">
-    select <include refid="characteristicColumns"/>
-    from characteristics c
-    <where>
-      and c.parent_id is null
-      and c.rule_id is null
-      and c.enabled=${_true}
-    </where>
-    order by characteristic_order asc
-  </select>
-
-  <select id="selectByKey" parameterType="String" resultType="Characteristic">
-    select <include refid="characteristicColumns"/>
-    from characteristics c
-    <where>
-      and c.kee=#{key}
-      and c.enabled=${_true}
-    </where>
-  </select>
-
-  <select id="selectById" parameterType="Integer" resultType="Characteristic">
-    select <include refid="characteristicColumns"/>
-    from characteristics c
-    <where>
-      and c.id=#{id}
-      and c.enabled=${_true}
-    </where>
-  </select>
-
-  <select id="selectByRuleId" parameterType="Integer" resultType="Characteristic">
-    select <include refid="characteristicColumns"/>
-    from characteristics c
-    <where>
-      and c.rule_id=#{ruleId}
-      and c.enabled=${_true}
-    </where>
-  </select>
-
-  <insert id="insert" parameterType="Characteristic" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
-    INSERT INTO characteristics (kee, name, parent_id, root_id, characteristic_order,
-    rule_id, function_key, factor_value, factor_unit, offset_value, offset_unit,
-    enabled, created_at, updated_at)
-    VALUES (#{kee}, #{name}, #{parentId}, #{rootId}, #{characteristicOrder},
-    #{ruleId}, #{functionKey}, #{factorValue}, #{factorUnit}, #{offsetValue}, #{offsetUnit},
-    #{enabled}, current_timestamp, current_timestamp)
-  </insert>
-
-  <update id="update" parameterType="Characteristic">
-    update characteristics set
-    name=#{name},
-    parent_id=#{parentId},
-    root_id=#{rootId},
-    characteristic_order=#{characteristicOrder},
-    rule_id=#{ruleId},
-    function_key=#{functionKey},
-    factor_value=#{factorValue},
-    factor_unit=#{factorUnit},
-    offset_value=#{offsetValue},
-    offset_unit=#{offsetUnit},
-    enabled=#{enabled},
-    updated_at=current_timestamp
-    where id=#{id}
-  </update>
-
-  <update id="disable" parameterType="Integer">
-    update characteristics set
-    enabled=${_false},
-    updated_at=current_timestamp
-    where id=#{id}
-  </update>
-
-</mapper>
-
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/CharacteristicsDebtModelSynchronizerTest.java b/sonar-core/src/test/java/org/sonar/core/debt/CharacteristicsDebtModelSynchronizerTest.java
new file mode 100644 (file)
index 0000000..4030cc8
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.collect.Lists;
+import org.apache.ibatis.session.SqlSession;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.debt.db.CharacteristicDao;
+import org.sonar.core.debt.db.CharacteristicDto;
+import org.sonar.core.persistence.MyBatis;
+
+import java.io.Reader;
+import java.util.Collections;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CharacteristicsDebtModelSynchronizerTest {
+
+  @Mock
+  MyBatis myBatis;
+
+  @Mock
+  SqlSession session;
+
+  @Mock
+  DebtModelPluginRepository debtModelPluginRepository;
+
+  @Mock
+  CharacteristicDao dao;
+
+  @Mock
+  CharacteristicsDebtModelXMLImporter xmlImporter;
+
+  Integer currentId = 1;
+
+  private DefaultTechnicalDebtModel defaultModel;
+
+  private CharacteristicsDebtModelSynchronizer manager;
+
+  @Before
+  public void initAndMerge() throws Exception {
+    when(myBatis.openSession()).thenReturn(session);
+
+    defaultModel = new DefaultTechnicalDebtModel();
+    Reader defaultModelReader = mock(Reader.class);
+    when(debtModelPluginRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
+    when(xmlImporter.importXML(eq(defaultModelReader), any(ValidationMessages.class))).thenReturn(defaultModel);
+
+    doAnswer(new Answer() {
+      public Object answer(InvocationOnMock invocation) {
+        Object[] args = invocation.getArguments();
+        CharacteristicDto dto = (CharacteristicDto) args[0];
+        dto.setId(currentId++);
+        return null;
+      }
+    }).when(dao).insert(any(CharacteristicDto.class), any(SqlSession.class));
+
+
+    manager = new CharacteristicsDebtModelSynchronizer(myBatis, dao, debtModelPluginRepository, xmlImporter);
+  }
+
+  @Test
+  public void create_default_model_on_first_execution_when_no_plugin() throws Exception {
+    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(rootCharacteristic);
+    defaultModel.addRootCharacteristic(rootCharacteristic);
+
+    when(debtModelPluginRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
+    when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
+
+    manager.synchronize(ValidationMessages.create());
+
+    verify(dao).selectEnabledCharacteristics();
+    ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
+    verify(dao, times(2)).insert(characteristicCaptor.capture(), eq(session));
+
+    List<CharacteristicDto> result = characteristicCaptor.getAllValues();
+    assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
+    assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+    verifyNoMoreInteractions(dao);
+  }
+
+  @Test
+  public void not_create_default_model_if_already_exists() throws Exception {
+    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(rootCharacteristic);
+    defaultModel.addRootCharacteristic(rootCharacteristic);
+
+    when(debtModelPluginRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
+    when(dao.selectEnabledCharacteristics()).thenReturn(Lists.newArrayList(new CharacteristicDto()));
+
+    manager.synchronize(ValidationMessages.create());
+
+    verify(dao, never()).insert(any(CharacteristicDto.class), eq(session));
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/CharacteristicsDebtModelXMLImporterTest.java b/sonar-core/src/test/java/org/sonar/core/debt/CharacteristicsDebtModelXMLImporterTest.java
new file mode 100644 (file)
index 0000000..c68f4ac
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import org.junit.Test;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.utils.ValidationMessages;
+
+import java.io.IOException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class CharacteristicsDebtModelXMLImporterTest {
+
+  @Test
+  public void import_characteristics() {
+    String xml = getFileContent("import_characteristics.xml");
+
+    ValidationMessages messages = ValidationMessages.create();
+    DefaultTechnicalDebtModel debtModel = new CharacteristicsDebtModelXMLImporter().importXML(xml, messages);
+
+    assertThat(debtModel.rootCharacteristics()).hasSize(2);
+    assertThat(debtModel.rootCharacteristics().get(0).key()).isEqualTo("PORTABILITY");
+    assertThat(debtModel.rootCharacteristics().get(1).key()).isEqualTo("MAINTAINABILITY");
+
+    DefaultCharacteristic portability = debtModel.characteristicByKey("PORTABILITY");
+    assertThat(portability.order()).isEqualTo(1);
+    assertThat(portability.children()).hasSize(2);
+    assertThat(portability.children().get(0).key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+    assertThat(debtModel.characteristicByKey("COMPILER_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
+    assertThat(portability.children().get(1).key()).isEqualTo("HARDWARE_RELATED_PORTABILITY");
+    assertThat(debtModel.characteristicByKey("HARDWARE_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
+
+    DefaultCharacteristic maintainability = debtModel.characteristicByKey("MAINTAINABILITY");
+    assertThat(maintainability.order()).isEqualTo(2);
+    assertThat(maintainability.children()).hasSize(1);
+    assertThat(maintainability.children().get(0).key()).isEqualTo("READABILITY");
+    assertThat(debtModel.characteristicByKey("READABILITY").parent().key()).isEqualTo("MAINTAINABILITY");
+  }
+
+  @Test
+  public void import_badly_formatted_xml() {
+    String xml = getFileContent("import_badly_formatted_xml.xml");
+
+    ValidationMessages messages = ValidationMessages.create();
+    DefaultTechnicalDebtModel debtModel = new CharacteristicsDebtModelXMLImporter().importXML(xml, messages);
+
+    checkXmlCorrectlyImported(debtModel, messages);
+  }
+
+  private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, ValidationMessages messages) {
+    assertThat(messages.getErrors()).isEmpty();
+
+    // characteristics
+    assertThat(sqale.rootCharacteristics()).hasSize(2);
+    DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
+    assertThat(efficiency.name()).isEqualTo("Efficiency");
+
+    // sub-characteristics
+    assertThat(efficiency.children()).hasSize(1);
+    DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
+    assertThat(memoryEfficiency.name()).isEqualTo("Memory use");
+  }
+
+  private String getFileContent(String file) {
+    try {
+      return Resources.toString(Resources.getResource(CharacteristicsDebtModelXMLImporterTest.class, "CharacteristicsDebtModelXMLImporterTest/" + file), Charsets.UTF_8);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/DebtModelPluginRepositoryTest.java b/sonar-core/src/test/java/org/sonar/core/debt/DebtModelPluginRepositoryTest.java
new file mode 100644 (file)
index 0000000..9e8d7c9
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.io.Resources;
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.SonarPlugin;
+import org.sonar.api.platform.PluginMetadata;
+import org.sonar.api.platform.PluginRepository;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DebtModelPluginRepositoryTest {
+
+  private static final String TEST_XML_PREFIX_PATH = "org/sonar/core/debt/TechnicalDebtModelRepositoryTest/";
+
+  private DebtModelPluginRepository modelFinder;
+
+  @Test
+  public void test_component_initialization() throws Exception {
+    // we do have the "csharp-model.xml" file in src/test/resources
+    PluginMetadata csharpPluginMetadata = mock(PluginMetadata.class);
+    when(csharpPluginMetadata.getKey()).thenReturn("csharp");
+
+    // but we don' have the "php-model.xml" one
+    PluginMetadata phpPluginMetadata = mock(PluginMetadata.class);
+    when(phpPluginMetadata.getKey()).thenReturn("php");
+
+    PluginRepository repository = mock(PluginRepository.class);
+    when(repository.getMetadata()).thenReturn(Lists.newArrayList(csharpPluginMetadata, phpPluginMetadata));
+    FakePlugin fakePlugin = new FakePlugin();
+    when(repository.getPlugin(anyString())).thenReturn(fakePlugin);
+    modelFinder = new DebtModelPluginRepository(repository, TEST_XML_PREFIX_PATH);
+
+    // when
+    modelFinder.start();
+
+    // assert
+    Collection<String> contributingPluginList = modelFinder.getContributingPluginList();
+    assertThat(contributingPluginList.size()).isEqualTo(2);
+    assertThat(contributingPluginList).containsOnly("technical-debt", "csharp");
+  }
+
+  @Test
+  public void contributing_plugin_list() throws Exception {
+    initModel();
+    Collection<String> contributingPluginList = modelFinder.getContributingPluginList();
+    assertThat(contributingPluginList.size()).isEqualTo(2);
+    assertThat(contributingPluginList).contains("csharp", "java");
+  }
+
+  @Test
+  public void get_content_for_xml_file() throws Exception {
+    initModel();
+    Reader xmlFileReader = null;
+    try {
+      xmlFileReader = modelFinder.createReaderForXMLFile("csharp");
+      assertNotNull(xmlFileReader);
+      List<String> lines = IOUtils.readLines(xmlFileReader);
+      assertThat(lines.size()).isEqualTo(25);
+      assertThat(lines.get(0)).isEqualTo("<sqale>");
+    } catch (Exception e) {
+      fail("Should be able to read the XML file.");
+    } finally {
+      IOUtils.closeQuietly(xmlFileReader);
+    }
+  }
+
+  @Test
+  public void return_xml_file_path_for_plugin() throws Exception {
+    initModel();
+    assertThat(modelFinder.getXMLFilePath("foo")).isEqualTo(TEST_XML_PREFIX_PATH + "foo-model.xml");
+  }
+
+  @Test
+  public void contain_default_model() throws Exception {
+    modelFinder = new DebtModelPluginRepository(mock(PluginRepository.class));
+    modelFinder.start();
+    assertThat(modelFinder.getContributingPluginKeyToClassLoader().keySet()).containsOnly("technical-debt");
+  }
+
+  private void initModel() throws MalformedURLException {
+    Map<String, ClassLoader> contributingPluginKeyToClassLoader = Maps.newHashMap();
+    contributingPluginKeyToClassLoader.put("csharp", newClassLoader());
+    contributingPluginKeyToClassLoader.put("java", newClassLoader());
+    modelFinder = new DebtModelPluginRepository(contributingPluginKeyToClassLoader, TEST_XML_PREFIX_PATH);
+  }
+
+  private ClassLoader newClassLoader() throws MalformedURLException {
+    ClassLoader loader = mock(ClassLoader.class);
+    when(loader.getResourceAsStream(anyString())).thenAnswer(new Answer<InputStream>() {
+      public InputStream answer(InvocationOnMock invocation) throws Throwable {
+        return new FileInputStream(Resources.getResource((String) invocation.getArguments()[0]).getPath());
+      }
+    });
+    return loader;
+  }
+
+  class FakePlugin extends SonarPlugin {
+    public List getExtensions() {
+      return null;
+    }
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/DefaultTechnicalDebtManagerTest.java b/sonar-core/src/test/java/org/sonar/core/debt/DefaultTechnicalDebtManagerTest.java
new file mode 100644 (file)
index 0000000..ef7001e
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.technicaldebt.server.Characteristic;
+import org.sonar.api.utils.internal.WorkDuration;
+import org.sonar.core.debt.db.CharacteristicDao;
+import org.sonar.core.debt.db.CharacteristicDto;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DefaultTechnicalDebtManagerTest {
+
+  @Mock
+  CharacteristicDao dao;
+
+  @Mock
+  RuleFinder ruleFinder;
+
+  DefaultTechnicalDebtManager finder;
+
+  @Before
+  public void setUp() throws Exception {
+    finder = new DefaultTechnicalDebtManager(dao, ruleFinder);
+  }
+
+  @Test
+  public void find_root_characteristics() throws Exception {
+    CharacteristicDto rootCharacteristicDto = new CharacteristicDto()
+      .setId(1)
+      .setKey("MEMORY_EFFICIENCY")
+      .setName("Memory use");
+    when(dao.selectEnabledRootCharacteristics()).thenReturn(newArrayList(rootCharacteristicDto));
+
+    List<Characteristic> result = finder.findRootCharacteristics();
+    assertThat(result).hasSize(1);
+
+    Characteristic rootCharacteristic = result.get(0);
+    assertThat(rootCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
+    assertThat(rootCharacteristic.name()).isEqualTo("Memory use");
+    assertThat(rootCharacteristic.parentId()).isNull();
+    assertThat(rootCharacteristic.rootId()).isNull();
+  }
+
+  @Test
+  public void find_requirement() throws Exception {
+    Rule rule = Rule.create("repo", "key");
+    rule.setId(1);
+
+    when(dao.selectByRuleId(rule.getId())).thenReturn(
+      new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear")
+        .setFactorValue(30.0).setFactorUnit("mn")
+        .setOffsetValue(0.0).setOffsetUnit("d")
+    );
+
+    Characteristic result = finder.findRequirementByRule(rule);
+
+    assertThat(result.id()).isEqualTo(3);
+    assertThat(result.parentId()).isEqualTo(2);
+    assertThat(result.rootId()).isEqualTo(1);
+    assertThat(result.ruleKey()).isEqualTo(RuleKey.of("repo", "key"));
+    assertThat(result.function()).isEqualTo("linear");
+    assertThat(result.factorValue()).isEqualTo(30);
+    assertThat(result.factorUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
+    assertThat(result.offsetValue()).isEqualTo(0);
+    assertThat(result.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
+  }
+
+  @Test
+  public void not_find_requirement() throws Exception {
+    Rule rule = Rule.create("repo", "key");
+    rule.setId(1);
+
+    when(dao.selectByRuleId(rule.getId())).thenReturn(null);
+
+    Characteristic result = finder.findRequirementByRule(rule);
+    assertThat(result).isNull();
+  }
+
+  @Test
+  public void find_characteristic() throws Exception {
+    Rule rule = Rule.create("repo", "key");
+    rule.setId(1);
+
+    when(dao.selectById(2)).thenReturn(
+      new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler").setParentId(1).setRootId(1));
+
+    Characteristic result = finder.findCharacteristicById(2);
+
+    assertThat(result.id()).isEqualTo(2);
+    assertThat(result.parentId()).isEqualTo(1);
+    assertThat(result.rootId()).isEqualTo(1);
+    assertThat(result.key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+    assertThat(result.name()).isEqualTo("Compiler");
+  }
+
+  @Test
+  public void not_find_characteristic() throws Exception {
+    Rule rule = Rule.create("repo", "key");
+    rule.setId(1);
+
+    when(dao.selectById(rule.getId())).thenReturn(null);
+
+    Characteristic result = finder.findCharacteristicById(2);
+    assertThat(result).isNull();
+  }
+
+  @Test
+  public void find_requirement_by_rule_id() throws Exception {
+    Rule rule = Rule.create("repo", "key");
+    rule.setId(1);
+
+    when(ruleFinder.findById(1)).thenReturn(rule);
+
+    when(dao.selectByRuleId(rule.getId())).thenReturn(
+      new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear")
+        .setFactorValue(30.0).setFactorUnit("mn")
+        .setOffsetValue(0.0).setOffsetUnit("d")
+    );
+
+    Characteristic result = finder.findRequirementByRuleId(1);
+
+    assertThat(result.id()).isEqualTo(3);
+    assertThat(result.parentId()).isEqualTo(2);
+    assertThat(result.rootId()).isEqualTo(1);
+    assertThat(result.ruleKey()).isEqualTo(RuleKey.of("repo", "key"));
+    assertThat(result.function()).isEqualTo("linear");
+    assertThat(result.factorValue()).isEqualTo(30);
+    assertThat(result.factorUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
+    assertThat(result.offsetValue()).isEqualTo(0);
+    assertThat(result.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
+
+  }
+
+  @Test
+  public void not_find_requirement_by_rule_id_on_unknown_requirement() throws Exception {
+    Rule rule = Rule.create("repo", "key");
+    rule.setId(1);
+
+    when(ruleFinder.findById(1)).thenReturn(rule);
+
+    when(dao.selectByRuleId(rule.getId())).thenReturn(null);
+
+    assertThat(finder.findRequirementByRuleId(1)).isNull();
+  }
+
+  @Test
+  public void fail_to_find_requirement_by_rule_id_if_unknown_rule_id() throws Exception {
+    when(dao.selectByRuleId(1)).thenReturn(
+      new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear").setFactorValue(30.0).setFactorUnit("mn"));
+    when(ruleFinder.findById(1)).thenReturn(null);
+    try {
+      finder.findRequirementByRuleId(1);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalArgumentException.class);
+    }
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/DefaultTechnicalDebtModelTest.java b/sonar-core/src/test/java/org/sonar/core/debt/DefaultTechnicalDebtModelTest.java
new file mode 100644 (file)
index 0000000..a3c9dd7
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.internal.WorkDuration;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class DefaultTechnicalDebtModelTest {
+
+  private DefaultTechnicalDebtModel sqaleModel;
+
+  @Before
+  public void setUp() throws Exception {
+    sqaleModel = new DefaultTechnicalDebtModel();
+  }
+
+  @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);
+
+    assertThat(sqaleModel.rootCharacteristics()).hasSize(1);
+    DefaultCharacteristic resultRootCharacteristic = sqaleModel.rootCharacteristics().get(0);
+    assertThat(resultRootCharacteristic).isEqualTo(rootCharacteristic);
+  }
+
+  @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("UNKNOWN")).isNull();
+  }
+
+  @Test
+  public void get_requirement_by_rule_key() throws Exception {
+    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
+      .setKey("MEMORY_EFFICIENCY")
+      .setName("Memory use");
+
+    DefaultCharacteristic characteristic = new DefaultCharacteristic()
+      .setKey("EFFICIENCY")
+      .setName("Efficiency")
+      .setParent(rootCharacteristic);
+
+    RuleKey ruleKey = RuleKey.of("checkstyle", "Regexp");
+    DefaultRequirement requirement = new DefaultRequirement()
+      .setCharacteristic(characteristic)
+      .setRuleKey(ruleKey)
+      .setFunction("linear")
+      .setFactorValue(2)
+      .setFactorUnit(WorkDuration.UNIT.HOURS)
+      .setOffsetValue(0)
+      .setOffsetUnit(WorkDuration.UNIT.HOURS);
+
+    sqaleModel.addRootCharacteristic(rootCharacteristic);
+
+    assertThat(sqaleModel.requirementsByRule(ruleKey)).isEqualTo(requirement);
+    assertThat(sqaleModel.requirementsByRule(RuleKey.of("not", "found"))).isNull();
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/RulesDebtModelXMLImporterTest.java b/sonar-core/src/test/java/org/sonar/core/debt/RulesDebtModelXMLImporterTest.java
new file mode 100644 (file)
index 0000000..8caa1a4
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import org.junit.Test;
+import org.sonar.api.rule.RemediationFunction;
+import org.sonar.api.rule.RuleKey;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class RulesDebtModelXMLImporterTest {
+
+  RulesDebtModelXMLImporter importer = new RulesDebtModelXMLImporter();
+
+  @Test
+  public void import_rules() {
+    String xml = getFileContent("import_rules.xml");
+
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).hasSize(2);
+  }
+
+  @Test
+  public void import_linear() {
+    String xml = getFileContent("import_linear.xml");
+
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).hasSize(1);
+
+    RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+    assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
+    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
+    assertThat(ruleDebt.factor()).isEqualTo("3h");
+    assertThat(ruleDebt.offset()).isEqualTo("0d");
+  }
+
+  @Test
+  public void import_linear_with_offset() {
+    String xml = getFileContent("import_linear_with_offset.xml");
+
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).hasSize(1);
+
+    RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
+    assertThat(ruleDebt.factor()).isEqualTo("3h");
+    assertThat(ruleDebt.offset()).isEqualTo("1min");
+  }
+
+  @Test
+  public void import_constant_issue() {
+    String xml = getFileContent("import_constant_issue.xml");
+
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).hasSize(1);
+
+    RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.CONSTANT_ISSUE);
+    assertThat(ruleDebt.factor()).isEqualTo("0d");
+    assertThat(ruleDebt.offset()).isEqualTo("3d");
+  }
+
+  @Test
+  public void use_default_unit_when_no_unit() {
+    String xml = getFileContent("use_default_unit_when_no_unit.xml");
+
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).hasSize(1);
+
+    RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
+    assertThat(ruleDebt.factor()).isEqualTo("3d");
+    assertThat(ruleDebt.offset()).isEqualTo("1d");
+  }
+
+  @Test
+  public void replace_mn_by_min() {
+    String xml = getFileContent("replace_mn_by_min.xml");
+
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).hasSize(1);
+
+    RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
+    assertThat(ruleDebt.factor()).isEqualTo("3min");
+    assertThat(ruleDebt.offset()).isEqualTo("0d");
+  }
+
+  @Test
+  public void convert_deprecated_linear_with_threshold_function_by_linear_function() {
+    String xml = getFileContent("convert_deprecated_linear_with_threshold_function_by_linear_function.xml");
+
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).hasSize(1);
+
+    RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
+    assertThat(ruleDebt.factor()).isEqualTo("3h");
+    assertThat(ruleDebt.offset()).isEqualTo("0d");
+  }
+
+  @Test
+  public void ignore_deprecated_constant_per_file_function() {
+    String xml = getFileContent("ignore_deprecated_constant_per_file_function.xml");
+
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).isEmpty();
+  }
+
+  @Test
+  public void ignore_rule_on_root_characteristics() {
+    String xml = getFileContent("ignore_rule_on_root_characteristics.xml");
+
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).isEmpty();
+  }
+
+  @Test
+  public void import_badly_formatted_xml() {
+    String xml = getFileContent("import_badly_formatted_xml.xml");
+
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).hasSize(1);
+
+    RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+    assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
+    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
+    assertThat(ruleDebt.factor()).isEqualTo("3h");
+    assertThat(ruleDebt.offset()).isEqualTo("0d");
+  }
+
+  @Test
+  public void ignore_invalid_value() throws Exception {
+    String xml = getFileContent("ignore_invalid_value.xml");
+    List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+    assertThat(results).isEmpty();
+  }
+
+  private String getFileContent(String file) {
+    try {
+      return Resources.toString(Resources.getResource(RulesDebtModelXMLImporterTest.class, "RulesDebtModelXMLImporterTest/" + file), Charsets.UTF_8);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/TechnicalDebtModelSynchronizerTest.java b/sonar-core/src/test/java/org/sonar/core/debt/TechnicalDebtModelSynchronizerTest.java
new file mode 100644 (file)
index 0000000..0244c42
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.collect.Lists;
+import org.apache.ibatis.session.SqlSession;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.api.utils.internal.WorkDuration;
+import org.sonar.core.debt.db.CharacteristicDao;
+import org.sonar.core.debt.db.CharacteristicDto;
+import org.sonar.core.persistence.MyBatis;
+
+import java.io.Reader;
+import java.util.Collections;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+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.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TechnicalDebtModelSynchronizerTest {
+
+  @Mock
+  MyBatis myBatis;
+
+  @Mock
+  SqlSession session;
+
+  @Mock
+  DebtModelPluginRepository debtModelPluginRepository;
+
+  @Mock
+  TechnicalDebtRuleCache ruleCache;
+
+  @Mock
+  CharacteristicDao dao;
+
+  @Mock
+  TechnicalDebtXMLImporter xmlImporter;
+
+  Integer currentId = 1;
+
+  private DefaultTechnicalDebtModel defaultModel;
+
+  private TechnicalDebtModelSynchronizer manager;
+
+  @Before
+  public void initAndMerge() throws Exception {
+    when(myBatis.openSession()).thenReturn(session);
+
+    defaultModel = new DefaultTechnicalDebtModel();
+    Reader defaultModelReader = mock(Reader.class);
+    when(debtModelPluginRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
+    when(xmlImporter.importXML(eq(defaultModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(defaultModel);
+
+    doAnswer(new Answer() {
+      public Object answer(InvocationOnMock invocation) {
+        Object[] args = invocation.getArguments();
+        CharacteristicDto dto = (CharacteristicDto) args[0];
+        dto.setId(currentId++);
+        return null;
+      }
+    }).when(dao).insert(any(CharacteristicDto.class), any(SqlSession.class));
+
+
+    manager = new TechnicalDebtModelSynchronizer(myBatis, dao, debtModelPluginRepository, xmlImporter);
+  }
+
+  @Test
+  public void create_default_model_on_first_execution_when_no_plugin() throws Exception {
+    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(rootCharacteristic);
+    defaultModel.addRootCharacteristic(rootCharacteristic);
+
+    when(debtModelPluginRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
+    when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
+
+    manager.synchronize(ValidationMessages.create(), ruleCache);
+
+    verify(dao).selectEnabledCharacteristics();
+    ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
+    verify(dao, times(2)).insert(characteristicCaptor.capture(), eq(session));
+
+    List<CharacteristicDto> result = characteristicCaptor.getAllValues();
+    assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
+    assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+    verifyNoMoreInteractions(dao);
+  }
+
+  @Test
+  public void create_model_with_requirements_from_plugin_on_first_execution() throws Exception {
+    // Default model
+    DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic).setRoot(defaultRootCharacteristic);
+    defaultModel.addRootCharacteristic(defaultRootCharacteristic);
+
+    // No db model
+    when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
+
+    // Java model
+    DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
+    DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+    DefaultCharacteristic javaCharacteristic = new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(javaRootCharacteristic).setRoot(javaRootCharacteristic);
+    javaModel.addRootCharacteristic(javaRootCharacteristic);
+
+    Rule rule = Rule.create();
+    rule.setId(10);
+    RuleKey ruleKey = RuleKey.of("checkstyle", "import");
+    when(ruleCache.getByRuleKey(ruleKey)).thenReturn(rule);
+    new DefaultRequirement().setRuleKey(ruleKey)
+      .setFunction("linear")
+      .setFactorValue(30)
+      .setFactorUnit(WorkDuration.UNIT.MINUTES)
+      .setCharacteristic(javaCharacteristic)
+      .setRootCharacteristic(javaRootCharacteristic);
+
+    Reader javaModelReader = mock(Reader.class);
+    when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
+    when(debtModelPluginRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
+    when(debtModelPluginRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
+
+    manager.synchronize(ValidationMessages.create(), ruleCache);
+
+    verify(dao).selectEnabledCharacteristics();
+    ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
+    verify(dao, times(3)).insert(characteristicCaptor.capture(), eq(session));
+
+    List<CharacteristicDto> result = characteristicCaptor.getAllValues();
+    assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
+    assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+    assertThat(result.get(2).getRuleId()).isEqualTo(10);
+    verifyNoMoreInteractions(dao);
+  }
+
+  @Test
+  public void add_new_requirements_from_plugin() throws Exception {
+    // Default model
+    DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic).setRoot(defaultRootCharacteristic);
+    defaultModel.addRootCharacteristic(defaultRootCharacteristic);
+
+    // Db model
+    CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
+    CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1).setRootId(1);
+    CharacteristicDto requirement = new CharacteristicDto().setId(3)
+      .setRuleId(10).setParentId(2).setRootId(1).setFactorValue(30.0).setFactorUnit("mn");
+
+    RuleKey ruleKey1 = RuleKey.of("checkstyle", "import");
+    Rule rule1 = Rule.create();
+    rule1.setId(10);
+    when(ruleCache.getByRuleKey(ruleKey1)).thenReturn(rule1);
+    when(ruleCache.exists(10)).thenReturn(true);
+    when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(requirement, dbCharacteristic, dbRootCharacteristic));
+
+    // Java model
+    DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
+    DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+    DefaultCharacteristic javaCharacteristic = new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(javaRootCharacteristic).setRoot(javaRootCharacteristic);
+    javaModel.addRootCharacteristic(javaRootCharacteristic);
+
+    RuleKey ruleKey2 = RuleKey.of("checkstyle", "export");
+    Rule rule2 = Rule.create();
+    rule2.setId(11);
+    when(ruleCache.getByRuleKey(ruleKey2)).thenReturn(rule2);
+
+    // New requirement
+    new DefaultRequirement().setRuleKey(ruleKey2)
+      .setFunction("linear")
+      .setFactorValue(1)
+      .setFactorUnit(WorkDuration.UNIT.HOURS)
+      .setCharacteristic(javaCharacteristic)
+      .setRootCharacteristic(javaRootCharacteristic);
+
+    Reader javaModelReader = mock(Reader.class);
+    when(debtModelPluginRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
+    when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
+    when(debtModelPluginRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
+
+    manager.synchronize(ValidationMessages.create(), ruleCache);
+
+    verify(dao).selectEnabledCharacteristics();
+    ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
+    verify(dao).insert(characteristicCaptor.capture(), eq(session));
+    assertThat(characteristicCaptor.getValue().getRuleId()).isEqualTo(11);
+    verifyNoMoreInteractions(dao);
+  }
+
+  @Test
+  public void disable_requirements_on_not_existing_rules() throws Exception {
+    // Default model
+    DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic);
+    defaultModel.addRootCharacteristic(defaultRootCharacteristic);
+
+    // Db model
+    CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
+    CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1);
+    // To be disabled as rule does not exists
+    CharacteristicDto requirement = new CharacteristicDto().setId(3)
+      .setRuleId(10).setParentId(2).setFactorValue(30.0).setFactorUnit("mn");
+
+    when(ruleCache.exists(10)).thenReturn(false);
+
+    when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(dbRootCharacteristic, dbCharacteristic, requirement));
+
+    manager.synchronize(ValidationMessages.create(), ruleCache);
+
+    verify(dao).selectEnabledCharacteristics();
+    verify(dao).disable(eq(3), eq(session));
+    verifyNoMoreInteractions(dao);
+  }
+
+  @Test
+  public void fail_when_plugin_defines_characteristics_not_defined_in_default_model() throws Exception {
+    try {
+      // Default model
+      DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+      new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic);
+      defaultModel.addRootCharacteristic(defaultRootCharacteristic);
+
+      // Db model
+      CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
+      CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1);
+      when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(dbRootCharacteristic, dbCharacteristic));
+
+      // Java model
+      DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
+      DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+      new DefaultCharacteristic().setKey("NEW_CHARACTERISTIC").setParent(javaRootCharacteristic);
+      javaModel.addRootCharacteristic(javaRootCharacteristic);
+
+      Reader javaModelReader = mock(Reader.class);
+      when(debtModelPluginRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
+      when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
+      when(debtModelPluginRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
+
+      manager.synchronize(ValidationMessages.create(), ruleCache);
+      fail();
+    } catch (Exception e) {
+      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The characteristic : NEW_CHARACTERISTIC cannot be used as it's not available in default characteristics.");
+    } finally {
+      verify(dao).selectEnabledCharacteristics();
+      verifyNoMoreInteractions(dao);
+    }
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/TechnicalDebtRuleCacheTest.java b/sonar-core/src/test/java/org/sonar/core/debt/TechnicalDebtRuleCacheTest.java
new file mode 100644 (file)
index 0000000..0cb884e
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.collect.Lists;
+import org.fest.assertions.Assertions;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RuleQuery;
+
+import java.util.Collections;
+
+public class TechnicalDebtRuleCacheTest {
+
+  @Test
+  public void lazy_load_rules_on_first_call() throws Exception {
+
+    RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
+    Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Collections.EMPTY_LIST);
+
+    TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
+    technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
+    technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
+
+    Mockito.verify(ruleFinder, Mockito.times(1)).findAll(Matchers.any(RuleQuery.class));
+  }
+
+  @Test
+  public void return_matching_rule() throws Exception {
+
+    Rule rule1 = Rule.create("repo1", "rule1");
+    Rule rule2 = Rule.create("repo2", "rule2");
+
+    RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
+    Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1, rule2));
+
+    TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
+    Rule actualRule1 = technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
+    Rule actualRule2 = technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo2", "rule2"));
+
+    Assertions.assertThat(actualRule1).isEqualTo(rule1);
+    Assertions.assertThat(actualRule2).isEqualTo(rule2);
+  }
+
+  @Test
+  public void return_if_rule_exists() throws Exception {
+
+    Rule rule1 = Rule.create("repo1", "rule1");
+
+    RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
+    Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1));
+
+    TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
+
+    Assertions.assertThat(technicalDebtRuleCache.exists(RuleKey.of("repo1", "rule1"))).isTrue();
+    Assertions.assertThat(technicalDebtRuleCache.exists(RuleKey.of("repo2", "rule2"))).isFalse();
+  }
+
+  @Test
+  public void return_if_rule_id_exists() throws Exception {
+
+    Rule rule1 = Rule.create("repo1", "rule1");
+    rule1.setId(1);
+
+    RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
+    Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1));
+
+    TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
+
+    Assertions.assertThat(technicalDebtRuleCache.exists(1)).isTrue();
+    Assertions.assertThat(technicalDebtRuleCache.exists(2)).isFalse();
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/TechnicalDebtXMLImporterTest.java b/sonar-core/src/test/java/org/sonar/core/debt/TechnicalDebtXMLImporterTest.java
new file mode 100644 (file)
index 0000000..ad7f8d0
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.Lists;
+import com.google.common.io.Resources;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RuleQuery;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.api.utils.internal.WorkDuration;
+
+import java.io.IOException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class TechnicalDebtXMLImporterTest {
+
+  @Test
+  public void import_characteristics() {
+    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+    String xml = getFileContent("import_characteristics.xml");
+
+    ValidationMessages messages = ValidationMessages.create();
+    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+    assertThat(sqale.rootCharacteristics()).hasSize(2);
+    assertThat(sqale.rootCharacteristics().get(0).key()).isEqualTo("PORTABILITY");
+    assertThat(sqale.rootCharacteristics().get(1).key()).isEqualTo("MAINTAINABILITY");
+
+    DefaultCharacteristic portability = sqale.characteristicByKey("PORTABILITY");
+    assertThat(portability.order()).isEqualTo(1);
+    assertThat(portability.children()).hasSize(2);
+    assertThat(portability.children().get(0).key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+    assertThat(sqale.characteristicByKey("COMPILER_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
+    assertThat(portability.children().get(1).key()).isEqualTo("HARDWARE_RELATED_PORTABILITY");
+    assertThat(sqale.characteristicByKey("HARDWARE_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
+
+    DefaultCharacteristic maintainability = sqale.characteristicByKey("MAINTAINABILITY");
+    assertThat(maintainability.order()).isEqualTo(2);
+    assertThat(maintainability.children()).hasSize(1);
+    assertThat(maintainability.children().get(0).key()).isEqualTo("READABILITY");
+    assertThat(sqale.characteristicByKey("READABILITY").parent().key()).isEqualTo("MAINTAINABILITY");
+  }
+
+  @Test
+  public void use_default_unit_when_no_unit() {
+    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+    String xml = getFileContent("use_default_unit_when_no_unit.xml");
+
+    ValidationMessages messages = ValidationMessages.create();
+    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+    DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
+    DefaultRequirement requirement = memoryEfficiency.requirements().get(0);
+    assertThat(requirement.factorValue()).isEqualTo(3);
+    assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
+    assertThat(requirement.offsetValue()).isEqualTo(1);
+    assertThat(requirement.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
+  }
+
+  @Test
+  public void import_xml_with_linear_function() {
+    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+    String xml = getFileContent("shouldImportXML_with_linear.xml");
+
+    ValidationMessages messages = ValidationMessages.create();
+    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+    checkXmlCorrectlyImported(sqale, messages);
+  }
+
+  @Test
+  public void import_xml_with_linear_with_offset() {
+    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+    String xml = getFileContent("shouldImportXML_with_linear_with_offset.xml");
+
+    ValidationMessages messages = ValidationMessages.create();
+    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+    checkXmlCorrectlyImported(sqale, 1, WorkDuration.UNIT.HOURS, messages);
+  }
+
+  @Test
+  public void convert_deprecated_linear_with_threshold_function_by_linear_function() {
+    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+    String xml = getFileContent("shouldImportXML_with_deprecated_linear_with_threshold.xml");
+
+    ValidationMessages messages = ValidationMessages.create();
+    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+    checkXmlCorrectlyImported(sqale, 0, WorkDuration.UNIT.DAYS, messages);
+    assertThat(messages.getWarnings()).hasSize(1);
+  }
+
+  @Test
+  public void ignore_deprecated_constant_per_file_function() {
+    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+    String xml = getFileContent("shouldImportXML_with_deprecated_constant_per_file.xml");
+
+    ValidationMessages messages = ValidationMessages.create();
+    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+    assertThat(messages.getWarnings()).hasSize(1);
+
+    // characteristics
+    assertThat(sqale.rootCharacteristics()).hasSize(1);
+    DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
+    assertThat(efficiency.requirements()).isEmpty();
+  }
+
+  @Test
+  public void ignore_requirement_on_root_characteristics() {
+    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+    String xml = getFileContent("ignore_requirement_on_root_characteristics.xml");
+
+    ValidationMessages messages = ValidationMessages.create();
+    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+    assertThat(messages.getWarnings()).hasSize(1);
+
+    assertThat(sqale.characteristics()).hasSize(1);
+    DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
+    assertThat(efficiency.requirements()).isEmpty();
+    assertThat(messages.getWarnings().get(0)).contains("checkstyle");
+  }
+
+  @Test
+  public void shouldBadlyFormattedImportXML() {
+    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+    String xml = getFileContent("shouldImportXML_badly-formatted.xml");
+
+    ValidationMessages messages = ValidationMessages.create();
+    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+    checkXmlCorrectlyImported(sqale, messages);
+  }
+
+  @Test
+  public void ignore_requirement_with_not_found_rule() {
+    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+    String xml = getFileContent("shouldLogWarningIfRuleNotFound.xml");
+    ValidationMessages messages = ValidationMessages.create();
+
+    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+    assertThat(messages.getWarnings()).hasSize(1);
+    assertThat(messages.getWarnings().get(0)).isEqualTo("Rule not found: [repository=findbugs, key=Foo]");
+
+    // characteristics
+    assertThat(sqale.rootCharacteristics()).hasSize(1);
+    DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
+    assertThat(efficiency.requirements()).isEmpty();
+    assertThat(messages.getWarnings().get(0)).contains("findbugs");
+  }
+
+  @Test
+  public void shouldNotifyOnUnexpectedValueTypeInXml() throws Exception {
+
+    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+    String xml = getFileContent("shouldRejectXML_with_invalid_value.xml");
+    ValidationMessages messages = ValidationMessages.create();
+
+    new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+    assertThat(messages.getErrors()).hasSize(1);
+    assertThat(messages.getErrors().get(0)).isEqualTo("Cannot import value 'abc' for field factor - Expected a numeric value instead");
+  }
+
+  private TechnicalDebtRuleCache mockRuleCache() {
+    RuleFinder finder = Mockito.mock(RuleFinder.class);
+    Mockito.when(finder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(Rule.create("checkstyle", "Regexp", "Regular expression")));
+    return new TechnicalDebtRuleCache(finder);
+  }
+
+  private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, ValidationMessages messages) {
+    checkXmlCorrectlyImported(sqale, 0, WorkDuration.UNIT.DAYS, messages);
+  }
+
+  private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, Integer offsetValue, WorkDuration.UNIT offsetUnit, ValidationMessages messages) {
+    assertThat(messages.getErrors()).isEmpty();
+
+    // characteristics
+    assertThat(sqale.rootCharacteristics()).hasSize(2);
+    DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
+    assertThat(efficiency.name()).isEqualTo("Efficiency");
+
+    // sub-characteristics
+    assertThat(efficiency.children()).hasSize(1);
+    DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
+    assertThat(memoryEfficiency.name()).isEqualTo("Memory use");
+
+    // requirement
+    assertThat(memoryEfficiency.requirements()).hasSize(1);
+    DefaultRequirement requirement = memoryEfficiency.requirements().get(0);
+    assertThat(requirement.ruleKey().repository()).isEqualTo("checkstyle");
+    assertThat(requirement.ruleKey().rule()).isEqualTo("Regexp");
+    assertThat(requirement.function()).isEqualTo("linear");
+    assertThat(requirement.factorValue()).isEqualTo(3);
+    assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.HOURS);
+    assertThat(requirement.offsetValue()).isEqualTo(offsetValue);
+    assertThat(requirement.offsetUnit()).isEqualTo(offsetUnit);
+    assertThat(requirement.characteristic().key()).isEqualTo("MEMORY_EFFICIENCY");
+    assertThat(requirement.rootCharacteristic().key()).isEqualTo("EFFICIENCY");
+  }
+
+  private String getFileContent(String file) {
+    try {
+      return Resources.toString(Resources.getResource(TechnicalDebtXMLImporterTest.class, "TechnicalDebtXMLImporterTest/" + file), Charsets.UTF_8);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/db/CharacteristicDaoTest.java b/sonar-core/src/test/java/org/sonar/core/debt/db/CharacteristicDaoTest.java
new file mode 100644 (file)
index 0000000..928f8de
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt.db;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class CharacteristicDaoTest extends AbstractDaoTestCase {
+
+  private static final String[] EXCLUDED_COLUMNS = new String[]{"id", "depth", "description", "quality_model_id", "created_at", "updated_at"};
+
+  CharacteristicDao dao;
+
+  @Before
+  public void createDao() {
+    dao = new CharacteristicDao(getMyBatis());
+  }
+
+  @Test
+  public void select_enabled_characteristics() {
+    setupData("shared");
+
+    List<CharacteristicDto> dtos = dao.selectEnabledCharacteristics();
+
+    assertThat(dtos).hasSize(3);
+
+    CharacteristicDto rootCharacteristic = dtos.get(0);
+    assertThat(rootCharacteristic.getId()).isEqualTo(1);
+    assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
+    assertThat(rootCharacteristic.getName()).isEqualTo("Portability");
+    assertThat(rootCharacteristic.getParentId()).isNull();
+    assertThat(rootCharacteristic.getRootId()).isNull();
+    assertThat(rootCharacteristic.getRuleId()).isNull();
+    assertThat(rootCharacteristic.getOrder()).isEqualTo(1);
+    assertThat(rootCharacteristic.isEnabled()).isTrue();
+    assertThat(rootCharacteristic.getCreatedAt()).isNotNull();
+    assertThat(rootCharacteristic.getUpdatedAt()).isNotNull();
+
+    CharacteristicDto characteristic = dtos.get(1);
+    assertThat(characteristic.getId()).isEqualTo(2);
+    assertThat(characteristic.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+    assertThat(characteristic.getName()).isEqualTo("Compiler related portability");
+    assertThat(characteristic.getParentId()).isEqualTo(1);
+    assertThat(characteristic.getRootId()).isEqualTo(1);
+    assertThat(characteristic.getRuleId()).isNull();
+    assertThat(characteristic.getOrder()).isNull();
+    assertThat(characteristic.isEnabled()).isTrue();
+    assertThat(characteristic.getCreatedAt()).isNotNull();
+    assertThat(characteristic.getUpdatedAt()).isNotNull();
+
+    CharacteristicDto requirement = dtos.get(2);
+    assertThat(requirement.getId()).isEqualTo(3);
+    assertThat(requirement.getKey()).isNull();
+    assertThat(requirement.getName()).isNull();
+    assertThat(requirement.getParentId()).isEqualTo(2);
+    assertThat(requirement.getRootId()).isEqualTo(1);
+    assertThat(requirement.getRuleId()).isEqualTo(1);
+    assertThat(requirement.getOrder()).isNull();
+    assertThat(requirement.getFunction()).isEqualTo("linear_offset");
+    assertThat(requirement.getFactorValue()).isEqualTo(20.0);
+    assertThat(requirement.getFactorUnit()).isEqualTo("mn");
+    assertThat(requirement.getOffsetValue()).isEqualTo(30.0);
+    assertThat(requirement.getOffsetUnit()).isEqualTo("h");
+    assertThat(requirement.isEnabled()).isTrue();
+    assertThat(requirement.getCreatedAt()).isNotNull();
+    assertThat(requirement.getUpdatedAt()).isNull();
+  }
+
+  @Test
+  public void select_characteristics() {
+    setupData("shared");
+
+    List<CharacteristicDto> dtos = dao.selectCharacteristics();
+
+    assertThat(dtos).hasSize(2);
+
+    CharacteristicDto rootCharacteristic = dtos.get(0);
+    assertThat(rootCharacteristic.getId()).isEqualTo(1);
+    assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
+    assertThat(rootCharacteristic.getName()).isEqualTo("Portability");
+    assertThat(rootCharacteristic.getParentId()).isNull();
+    assertThat(rootCharacteristic.getRootId()).isNull();
+    assertThat(rootCharacteristic.getOrder()).isEqualTo(1);
+    assertThat(rootCharacteristic.isEnabled()).isTrue();
+    assertThat(rootCharacteristic.getCreatedAt()).isNotNull();
+    assertThat(rootCharacteristic.getUpdatedAt()).isNotNull();
+
+    CharacteristicDto characteristic = dtos.get(1);
+    assertThat(characteristic.getId()).isEqualTo(2);
+    assertThat(characteristic.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+    assertThat(characteristic.getName()).isEqualTo("Compiler related portability");
+    assertThat(characteristic.getParentId()).isEqualTo(1);
+    assertThat(characteristic.getRootId()).isEqualTo(1);
+    assertThat(characteristic.getOrder()).isNull();
+    assertThat(characteristic.isEnabled()).isTrue();
+    assertThat(characteristic.getCreatedAt()).isNotNull();
+    assertThat(characteristic.getUpdatedAt()).isNotNull();
+  }
+
+  @Test
+  public void select_enabled_root_characteristics() {
+    setupData("select_enabled_root_characteristics");
+
+    List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
+
+    assertThat(dtos).hasSize(1);
+
+    CharacteristicDto rootCharacteristic = dtos.get(0);
+    assertThat(rootCharacteristic.getId()).isEqualTo(1);
+    assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
+  }
+
+  @Test
+  public void select_enabled_root_characteristics_order_by_characteristic_order() {
+    setupData("select_enabled_root_characteristics_order_by_characteristic_order");
+
+    List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
+
+    assertThat(dtos).hasSize(3);
+    assertThat(dtos.get(0).getKey()).isEqualTo("TESTABILITY");
+    assertThat(dtos.get(1).getKey()).isEqualTo("PORTABILITY");
+    assertThat(dtos.get(2).getKey()).isEqualTo("MAINTAINABILITY");
+  }
+
+  @Test
+  public void select_requirement() {
+    setupData("shared");
+
+    CharacteristicDto dto = dao.selectByRuleId(1);
+
+    assertThat(dto).isNotNull();
+    assertThat(dto.getId()).isEqualTo(3);
+    assertThat(dto.getParentId()).isEqualTo(2);
+    assertThat(dto.getRootId()).isEqualTo(1);
+  }
+
+  @Test
+  public void select_characteristic_by_key() {
+    setupData("shared");
+
+    CharacteristicDto dto = dao.selectByKey("COMPILER_RELATED_PORTABILITY");
+    assertThat(dto).isNotNull();
+    assertThat(dto.getId()).isEqualTo(2);
+    assertThat(dto.getParentId()).isEqualTo(1);
+    assertThat(dto.getRootId()).isEqualTo(1);
+
+    dto = dao.selectByKey("PORTABILITY");
+    assertThat(dto).isNotNull();
+    assertThat(dto.getId()).isEqualTo(1);
+    assertThat(dto.getParentId()).isNull();
+    assertThat(dto.getRootId()).isNull();
+
+    assertThat(dao.selectByKey("UNKNOWN")).isNull();
+  }
+
+  @Test
+  public void select_characteristic_by_id() {
+    setupData("shared");
+
+    assertThat(dao.selectById(2)).isNotNull();
+    assertThat(dao.selectById(1)).isNotNull();
+
+    assertThat(dao.selectById(10)).isNull();
+  }
+
+  @Test
+  public void insert_characteristic() throws Exception {
+    CharacteristicDto dto = new CharacteristicDto()
+      .setKey("COMPILER_RELATED_PORTABILITY")
+      .setName("Compiler related portability")
+      .setOrder(1)
+      .setEnabled(true)
+      .setCreatedAt(DateUtils.parseDate("2013-11-20"));
+
+    dao.insert(dto);
+
+    checkTables("insert_characteristic", EXCLUDED_COLUMNS, "characteristics");
+  }
+
+  @Test
+  public void insert_requirement() throws Exception {
+    CharacteristicDto dto = new CharacteristicDto()
+      .setParentId(2)
+      .setRootId(1)
+      .setRuleId(1)
+      .setFunction("linear_offset")
+      .setFactorValue(20.0)
+      .setFactorUnit("mn")
+      .setOffsetValue(30.0)
+      .setOffsetUnit("h")
+      .setCreatedAt(DateUtils.parseDate("2013-11-20"))
+      .setEnabled(true);
+
+    dao.insert(dto);
+
+    checkTables("insert_requirement", EXCLUDED_COLUMNS, "characteristics");
+  }
+
+  @Test
+  public void update_characteristic() throws Exception {
+    setupData("update_characteristic");
+
+    CharacteristicDto dto = new CharacteristicDto()
+      .setId(1)
+        // The Key should not be changed
+      .setKey("NEW_KEY")
+      .setName("New name")
+      .setOrder(2)
+        // Created date should not changed
+      .setCreatedAt(DateUtils.parseDate("2013-11-22"))
+      .setEnabled(false);
+
+    dao.update(dto);
+
+    checkTables("update_characteristic", new String[]{"id", "depth", "description", "quality_model_id", "updated_at"}, "characteristics");
+  }
+
+  @Test
+  public void update_requirement() throws Exception {
+    setupData("update_requirement");
+
+    CharacteristicDto dto = new CharacteristicDto()
+      .setId(1)
+      .setParentId(3)
+      .setRootId(1)
+      .setRuleId(2)
+      .setFunction("linear")
+      .setFactorValue(21.0)
+      .setFactorUnit("h")
+      .setOffsetValue(null)
+      .setOffsetUnit(null)
+        // Created date should not changed
+      .setCreatedAt(DateUtils.parseDate("2013-11-22"))
+      .setEnabled(false);
+
+    dao.update(dto);
+
+    checkTables("update_requirement", EXCLUDED_COLUMNS, "characteristics");
+  }
+
+  @Test
+  public void disable() throws Exception {
+    setupData("disable");
+
+    dao.disable(1);
+
+    checkTables("disable", EXCLUDED_COLUMNS, "characteristics");
+  }
+
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/debt/db/CharacteristicDtoTest.java b/sonar-core/src/test/java/org/sonar/core/debt/db/CharacteristicDtoTest.java
new file mode 100644 (file)
index 0000000..7867f13
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.debt.db;
+
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.internal.WorkDuration;
+
+import java.util.Date;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class CharacteristicDtoTest {
+
+  @Test
+  public void to_dto_from_requirement() throws Exception {
+    DefaultRequirement requirement = new DefaultRequirement()
+      .setFunction("constant_issue")
+      .setFactorValue(10)
+      .setFactorUnit(WorkDuration.UNIT.DAYS)
+      .setOffsetValue(5)
+      .setOffsetUnit(WorkDuration.UNIT.MINUTES)
+      .setCreatedAt(new Date())
+      .setUpdatedAt(new Date());
+
+    CharacteristicDto dto = CharacteristicDto.toDto(requirement, 2, 1, 10);
+    assertThat(dto.getRuleId()).isEqualTo(10);
+    assertThat(dto.getParentId()).isEqualTo(2);
+    assertThat(dto.getRootId()).isEqualTo(1);
+    assertThat(dto.getFunction()).isEqualTo("constant_issue");
+    assertThat(dto.getFactorValue()).isEqualTo(10d);
+    assertThat(dto.getFactorUnit()).isEqualTo(CharacteristicDto.DAYS);
+    assertThat(dto.getOffsetValue()).isEqualTo(5d);
+    assertThat(dto.getOffsetUnit()).isEqualTo(CharacteristicDto.MINUTES);
+    assertThat(dto.isEnabled()).isTrue();
+    assertThat(dto.getCreatedAt()).isNotNull();
+    assertThat(dto.getUpdatedAt()).isNotNull();
+  }
+
+  @Test
+  public void to_requirement() throws Exception {
+    CharacteristicDto requirementDto = new CharacteristicDto()
+      .setId(3)
+      .setParentId(2)
+      .setRuleId(100)
+      .setFunction("linear")
+      .setFactorValue(2d)
+      .setFactorUnit(CharacteristicDto.DAYS)
+      .setOffsetValue(0d)
+      .setOffsetUnit(CharacteristicDto.MINUTES)
+      .setCreatedAt(new Date())
+      .setUpdatedAt(new Date());
+
+    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
+      .setKey("MEMORY_EFFICIENCY")
+      .setName("Memory use");
+
+    DefaultCharacteristic characteristic = new DefaultCharacteristic()
+      .setKey("EFFICIENCY")
+      .setName("Efficiency")
+      .setParent(rootCharacteristic);
+
+    DefaultRequirement requirement =  requirementDto.toRequirement(RuleKey.of("squid", "S106"), characteristic, rootCharacteristic);
+    assertThat(requirement.ruleKey()).isEqualTo(RuleKey.of("squid", "S106"));
+    assertThat(requirement.characteristic()).isEqualTo(characteristic);
+    assertThat(requirement.rootCharacteristic()).isEqualTo(rootCharacteristic);
+    assertThat(requirement.function()).isEqualTo("linear");
+    assertThat(requirement.factorValue()).isEqualTo(2);
+    assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
+    assertThat(requirement.offsetValue()).isEqualTo(0);
+    assertThat(requirement.offsetUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
+    assertThat(requirement.createdAt()).isNotNull();
+    assertThat(requirement.updatedAt()).isNotNull();
+
+  }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/CharacteristicsXMLImporterTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/CharacteristicsXMLImporterTest.java
deleted file mode 100644 (file)
index 6c5e26e..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.Resources;
-import org.junit.Test;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.utils.ValidationMessages;
-
-import java.io.IOException;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class CharacteristicsXMLImporterTest {
-
-  @Test
-  public void import_characteristics() {
-    String xml = getFileContent("import_characteristics.xml");
-
-    ValidationMessages messages = ValidationMessages.create();
-    DefaultTechnicalDebtModel debtModel = new CharacteristicsXMLImporter().importXML(xml, messages);
-
-    assertThat(debtModel.rootCharacteristics()).hasSize(2);
-    assertThat(debtModel.rootCharacteristics().get(0).key()).isEqualTo("PORTABILITY");
-    assertThat(debtModel.rootCharacteristics().get(1).key()).isEqualTo("MAINTAINABILITY");
-
-    DefaultCharacteristic portability = debtModel.characteristicByKey("PORTABILITY");
-    assertThat(portability.order()).isEqualTo(1);
-    assertThat(portability.children()).hasSize(2);
-    assertThat(portability.children().get(0).key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
-    assertThat(debtModel.characteristicByKey("COMPILER_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
-    assertThat(portability.children().get(1).key()).isEqualTo("HARDWARE_RELATED_PORTABILITY");
-    assertThat(debtModel.characteristicByKey("HARDWARE_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
-
-    DefaultCharacteristic maintainability = debtModel.characteristicByKey("MAINTAINABILITY");
-    assertThat(maintainability.order()).isEqualTo(2);
-    assertThat(maintainability.children()).hasSize(1);
-    assertThat(maintainability.children().get(0).key()).isEqualTo("READABILITY");
-    assertThat(debtModel.characteristicByKey("READABILITY").parent().key()).isEqualTo("MAINTAINABILITY");
-  }
-
-  @Test
-  public void import_badly_formatted_xml() {
-    String xml = getFileContent("import_badly_formatted_xml.xml");
-
-    ValidationMessages messages = ValidationMessages.create();
-    DefaultTechnicalDebtModel debtModel = new CharacteristicsXMLImporter().importXML(xml, messages);
-
-    checkXmlCorrectlyImported(debtModel, messages);
-  }
-
-  private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, ValidationMessages messages) {
-    assertThat(messages.getErrors()).isEmpty();
-
-    // characteristics
-    assertThat(sqale.rootCharacteristics()).hasSize(2);
-    DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
-    assertThat(efficiency.name()).isEqualTo("Efficiency");
-
-    // sub-characteristics
-    assertThat(efficiency.children()).hasSize(1);
-    DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
-    assertThat(memoryEfficiency.name()).isEqualTo("Memory use");
-  }
-
-  private String getFileContent(String file) {
-    try {
-      return Resources.toString(Resources.getResource(CharacteristicsXMLImporterTest.class, "CharacteristicsXMLImporterTest/" + file), Charsets.UTF_8);
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/DebtCharacteristicsSynchronizerTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/DebtCharacteristicsSynchronizerTest.java
deleted file mode 100644 (file)
index 657758b..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.collect.Lists;
-import org.apache.ibatis.session.SqlSession;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-
-import java.io.Reader;
-import java.util.Collections;
-import java.util.List;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class DebtCharacteristicsSynchronizerTest {
-
-  @Mock
-  MyBatis myBatis;
-
-  @Mock
-  SqlSession session;
-
-  @Mock
-  TechnicalDebtModelRepository technicalDebtModelRepository;
-
-  @Mock
-  CharacteristicDao dao;
-
-  @Mock
-  CharacteristicsXMLImporter xmlImporter;
-
-  Integer currentId = 1;
-
-  private DefaultTechnicalDebtModel defaultModel;
-
-  private DebtCharacteristicsSynchronizer manager;
-
-  @Before
-  public void initAndMerge() throws Exception {
-    when(myBatis.openSession()).thenReturn(session);
-
-    defaultModel = new DefaultTechnicalDebtModel();
-    Reader defaultModelReader = mock(Reader.class);
-    when(technicalDebtModelRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
-    when(xmlImporter.importXML(eq(defaultModelReader), any(ValidationMessages.class))).thenReturn(defaultModel);
-
-    doAnswer(new Answer() {
-      public Object answer(InvocationOnMock invocation) {
-        Object[] args = invocation.getArguments();
-        CharacteristicDto dto = (CharacteristicDto) args[0];
-        dto.setId(currentId++);
-        return null;
-      }
-    }).when(dao).insert(any(CharacteristicDto.class), any(SqlSession.class));
-
-
-    manager = new DebtCharacteristicsSynchronizer(myBatis, dao, technicalDebtModelRepository, xmlImporter);
-  }
-
-  @Test
-  public void create_default_model_on_first_execution_when_no_plugin() throws Exception {
-    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
-    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(rootCharacteristic);
-    defaultModel.addRootCharacteristic(rootCharacteristic);
-
-    when(technicalDebtModelRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
-    when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
-
-    manager.synchronize(ValidationMessages.create());
-
-    verify(dao).selectEnabledCharacteristics();
-    ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
-    verify(dao, times(2)).insert(characteristicCaptor.capture(), eq(session));
-
-    List<CharacteristicDto> result = characteristicCaptor.getAllValues();
-    assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
-    assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
-    verifyNoMoreInteractions(dao);
-  }
-
-  @Test
-  public void not_create_default_model_if_already_exists() throws Exception {
-    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
-    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(rootCharacteristic);
-    defaultModel.addRootCharacteristic(rootCharacteristic);
-
-    when(technicalDebtModelRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
-    when(dao.selectEnabledCharacteristics()).thenReturn(Lists.newArrayList(new CharacteristicDto()));
-
-    manager.synchronize(ValidationMessages.create());
-
-    verify(dao, never()).insert(any(CharacteristicDto.class), eq(session));
-  }
-
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManagerTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/DefaultTechnicalDebtManagerTest.java
deleted file mode 100644 (file)
index 9095488..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.technicaldebt.server.Characteristic;
-import org.sonar.api.utils.internal.WorkDuration;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class DefaultTechnicalDebtManagerTest {
-
-  @Mock
-  CharacteristicDao dao;
-
-  @Mock
-  RuleFinder ruleFinder;
-
-  DefaultTechnicalDebtManager finder;
-
-  @Before
-  public void setUp() throws Exception {
-    finder = new DefaultTechnicalDebtManager(dao, ruleFinder);
-  }
-
-  @Test
-  public void find_root_characteristics() throws Exception {
-    CharacteristicDto rootCharacteristicDto = new CharacteristicDto()
-      .setId(1)
-      .setKey("MEMORY_EFFICIENCY")
-      .setName("Memory use");
-    when(dao.selectEnabledRootCharacteristics()).thenReturn(newArrayList(rootCharacteristicDto));
-
-    List<Characteristic> result = finder.findRootCharacteristics();
-    assertThat(result).hasSize(1);
-
-    Characteristic rootCharacteristic = result.get(0);
-    assertThat(rootCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(rootCharacteristic.name()).isEqualTo("Memory use");
-    assertThat(rootCharacteristic.parentId()).isNull();
-    assertThat(rootCharacteristic.rootId()).isNull();
-  }
-
-  @Test
-  public void find_requirement() throws Exception {
-    Rule rule = Rule.create("repo", "key");
-    rule.setId(1);
-
-    when(dao.selectByRuleId(rule.getId())).thenReturn(
-      new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear")
-        .setFactorValue(30.0).setFactorUnit("mn")
-        .setOffsetValue(0.0).setOffsetUnit("d")
-    );
-
-    Characteristic result = finder.findRequirementByRule(rule);
-
-    assertThat(result.id()).isEqualTo(3);
-    assertThat(result.parentId()).isEqualTo(2);
-    assertThat(result.rootId()).isEqualTo(1);
-    assertThat(result.ruleKey()).isEqualTo(RuleKey.of("repo", "key"));
-    assertThat(result.function()).isEqualTo("linear");
-    assertThat(result.factorValue()).isEqualTo(30);
-    assertThat(result.factorUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
-    assertThat(result.offsetValue()).isEqualTo(0);
-    assertThat(result.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
-  }
-
-  @Test
-  public void not_find_requirement() throws Exception {
-    Rule rule = Rule.create("repo", "key");
-    rule.setId(1);
-
-    when(dao.selectByRuleId(rule.getId())).thenReturn(null);
-
-    Characteristic result = finder.findRequirementByRule(rule);
-    assertThat(result).isNull();
-  }
-
-  @Test
-  public void find_characteristic() throws Exception {
-    Rule rule = Rule.create("repo", "key");
-    rule.setId(1);
-
-    when(dao.selectById(2)).thenReturn(
-      new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler").setParentId(1).setRootId(1));
-
-    Characteristic result = finder.findCharacteristicById(2);
-
-    assertThat(result.id()).isEqualTo(2);
-    assertThat(result.parentId()).isEqualTo(1);
-    assertThat(result.rootId()).isEqualTo(1);
-    assertThat(result.key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
-    assertThat(result.name()).isEqualTo("Compiler");
-  }
-
-  @Test
-  public void not_find_characteristic() throws Exception {
-    Rule rule = Rule.create("repo", "key");
-    rule.setId(1);
-
-    when(dao.selectById(rule.getId())).thenReturn(null);
-
-    Characteristic result = finder.findCharacteristicById(2);
-    assertThat(result).isNull();
-  }
-
-  @Test
-  public void find_requirement_by_rule_id() throws Exception {
-    Rule rule = Rule.create("repo", "key");
-    rule.setId(1);
-
-    when(ruleFinder.findById(1)).thenReturn(rule);
-
-    when(dao.selectByRuleId(rule.getId())).thenReturn(
-      new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear")
-        .setFactorValue(30.0).setFactorUnit("mn")
-        .setOffsetValue(0.0).setOffsetUnit("d")
-    );
-
-    Characteristic result = finder.findRequirementByRuleId(1);
-
-    assertThat(result.id()).isEqualTo(3);
-    assertThat(result.parentId()).isEqualTo(2);
-    assertThat(result.rootId()).isEqualTo(1);
-    assertThat(result.ruleKey()).isEqualTo(RuleKey.of("repo", "key"));
-    assertThat(result.function()).isEqualTo("linear");
-    assertThat(result.factorValue()).isEqualTo(30);
-    assertThat(result.factorUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
-    assertThat(result.offsetValue()).isEqualTo(0);
-    assertThat(result.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
-
-  }
-
-  @Test
-  public void not_find_requirement_by_rule_id_on_unknown_requirement() throws Exception {
-    Rule rule = Rule.create("repo", "key");
-    rule.setId(1);
-
-    when(ruleFinder.findById(1)).thenReturn(rule);
-
-    when(dao.selectByRuleId(rule.getId())).thenReturn(null);
-
-    assertThat(finder.findRequirementByRuleId(1)).isNull();
-  }
-
-  @Test
-  public void fail_to_find_requirement_by_rule_id_if_unknown_rule_id() throws Exception {
-    when(dao.selectByRuleId(1)).thenReturn(
-      new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear").setFactorValue(30.0).setFactorUnit("mn"));
-    when(ruleFinder.findById(1)).thenReturn(null);
-    try {
-      finder.findRequirementByRuleId(1);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalArgumentException.class);
-    }
-  }
-}
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
deleted file mode 100644 (file)
index ef857e1..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.internal.WorkDuration;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class DefaultTechnicalDebtModelTest {
-
-  private DefaultTechnicalDebtModel sqaleModel;
-
-  @Before
-  public void setUp() throws Exception {
-    sqaleModel = new DefaultTechnicalDebtModel();
-  }
-
-  @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);
-
-    assertThat(sqaleModel.rootCharacteristics()).hasSize(1);
-    DefaultCharacteristic resultRootCharacteristic = sqaleModel.rootCharacteristics().get(0);
-    assertThat(resultRootCharacteristic).isEqualTo(rootCharacteristic);
-  }
-
-  @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("UNKNOWN")).isNull();
-  }
-
-  @Test
-  public void get_requirement_by_rule_key() throws Exception {
-    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
-      .setKey("MEMORY_EFFICIENCY")
-      .setName("Memory use");
-
-    DefaultCharacteristic characteristic = new DefaultCharacteristic()
-      .setKey("EFFICIENCY")
-      .setName("Efficiency")
-      .setParent(rootCharacteristic);
-
-    RuleKey ruleKey = RuleKey.of("checkstyle", "Regexp");
-    DefaultRequirement requirement = new DefaultRequirement()
-      .setCharacteristic(characteristic)
-      .setRuleKey(ruleKey)
-      .setFunction("linear")
-      .setFactorValue(2)
-      .setFactorUnit(WorkDuration.UNIT.HOURS)
-      .setOffsetValue(0)
-      .setOffsetUnit(WorkDuration.UNIT.HOURS);
-
-    sqaleModel.addRootCharacteristic(rootCharacteristic);
-
-    assertThat(sqaleModel.requirementsByRule(ruleKey)).isEqualTo(requirement);
-    assertThat(sqaleModel.requirementsByRule(RuleKey.of("not", "found"))).isNull();
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/RuleDebtXMLImporterTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/RuleDebtXMLImporterTest.java
deleted file mode 100644 (file)
index f040046..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.Resources;
-import org.junit.Test;
-import org.sonar.api.rule.RemediationFunction;
-import org.sonar.api.rule.RuleKey;
-
-import java.io.IOException;
-import java.util.List;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class RuleDebtXMLImporterTest {
-
-  RuleDebtXMLImporter importer = new RuleDebtXMLImporter();
-
-  @Test
-  public void import_rules() {
-    String xml = getFileContent("import_rules.xml");
-
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).hasSize(2);
-  }
-
-  @Test
-  public void import_linear() {
-    String xml = getFileContent("import_linear.xml");
-
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).hasSize(1);
-
-    RuleDebtXMLImporter.RuleDebt ruleDebt = results.get(0);
-    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
-    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
-    assertThat(ruleDebt.factor()).isEqualTo("3h");
-    assertThat(ruleDebt.offset()).isEqualTo("0d");
-  }
-
-  @Test
-  public void import_linear_with_offset() {
-    String xml = getFileContent("import_linear_with_offset.xml");
-
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).hasSize(1);
-
-    RuleDebtXMLImporter.RuleDebt ruleDebt = results.get(0);
-    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
-    assertThat(ruleDebt.factor()).isEqualTo("3h");
-    assertThat(ruleDebt.offset()).isEqualTo("1min");
-  }
-
-  @Test
-  public void import_constant_issue() {
-    String xml = getFileContent("import_constant_issue.xml");
-
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).hasSize(1);
-
-    RuleDebtXMLImporter.RuleDebt ruleDebt = results.get(0);
-    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.CONSTANT_ISSUE);
-    assertThat(ruleDebt.factor()).isEqualTo("0d");
-    assertThat(ruleDebt.offset()).isEqualTo("3d");
-  }
-
-  @Test
-  public void use_default_unit_when_no_unit() {
-    String xml = getFileContent("use_default_unit_when_no_unit.xml");
-
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).hasSize(1);
-
-    RuleDebtXMLImporter.RuleDebt ruleDebt = results.get(0);
-    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
-    assertThat(ruleDebt.factor()).isEqualTo("3d");
-    assertThat(ruleDebt.offset()).isEqualTo("1d");
-  }
-
-  @Test
-  public void replace_mn_by_min() {
-    String xml = getFileContent("replace_mn_by_min.xml");
-
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).hasSize(1);
-
-    RuleDebtXMLImporter.RuleDebt ruleDebt = results.get(0);
-    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
-    assertThat(ruleDebt.factor()).isEqualTo("3min");
-    assertThat(ruleDebt.offset()).isEqualTo("0d");
-  }
-
-  @Test
-  public void convert_deprecated_linear_with_threshold_function_by_linear_function() {
-    String xml = getFileContent("convert_deprecated_linear_with_threshold_function_by_linear_function.xml");
-
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).hasSize(1);
-
-    RuleDebtXMLImporter.RuleDebt ruleDebt = results.get(0);
-    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
-    assertThat(ruleDebt.factor()).isEqualTo("3h");
-    assertThat(ruleDebt.offset()).isEqualTo("0d");
-  }
-
-  @Test
-  public void ignore_deprecated_constant_per_file_function() {
-    String xml = getFileContent("ignore_deprecated_constant_per_file_function.xml");
-
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).isEmpty();
-  }
-
-  @Test
-  public void ignore_rule_on_root_characteristics() {
-    String xml = getFileContent("ignore_rule_on_root_characteristics.xml");
-
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).isEmpty();
-  }
-
-  @Test
-  public void import_badly_formatted_xml() {
-    String xml = getFileContent("import_badly_formatted_xml.xml");
-
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).hasSize(1);
-
-    RuleDebtXMLImporter.RuleDebt ruleDebt = results.get(0);
-    assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
-    assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
-    assertThat(ruleDebt.factor()).isEqualTo("3h");
-    assertThat(ruleDebt.offset()).isEqualTo("0d");
-  }
-
-  @Test
-  public void ignore_invalid_value() throws Exception {
-    String xml = getFileContent("ignore_invalid_value.xml");
-    List<RuleDebtXMLImporter.RuleDebt> results = importer.importXML(xml);
-    assertThat(results).isEmpty();
-  }
-
-  private String getFileContent(String file) {
-    try {
-      return Resources.toString(Resources.getResource(RuleDebtXMLImporterTest.class, "RuleDebtXMLImporterTest/" + file), Charsets.UTF_8);
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest.java
deleted file mode 100644 (file)
index 0b69fa8..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.io.Resources;
-import org.apache.commons.io.IOUtils;
-import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.SonarPlugin;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
-
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.Reader;
-import java.net.MalformedURLException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class TechnicalDebtModelRepositoryTest {
-
-  private static final String TEST_XML_PREFIX_PATH = "org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest/";
-
-  private TechnicalDebtModelRepository modelFinder;
-
-  @Test
-  public void test_component_initialization() throws Exception {
-    // we do have the "csharp-model.xml" file in src/test/resources
-    PluginMetadata csharpPluginMetadata = mock(PluginMetadata.class);
-    when(csharpPluginMetadata.getKey()).thenReturn("csharp");
-
-    // but we don' have the "php-model.xml" one
-    PluginMetadata phpPluginMetadata = mock(PluginMetadata.class);
-    when(phpPluginMetadata.getKey()).thenReturn("php");
-
-    PluginRepository repository = mock(PluginRepository.class);
-    when(repository.getMetadata()).thenReturn(Lists.newArrayList(csharpPluginMetadata, phpPluginMetadata));
-    FakePlugin fakePlugin = new FakePlugin();
-    when(repository.getPlugin(anyString())).thenReturn(fakePlugin);
-    modelFinder = new TechnicalDebtModelRepository(repository, TEST_XML_PREFIX_PATH);
-
-    // when
-    modelFinder.start();
-
-    // assert
-    Collection<String> contributingPluginList = modelFinder.getContributingPluginList();
-    assertThat(contributingPluginList.size()).isEqualTo(2);
-    assertThat(contributingPluginList).containsOnly("technical-debt", "csharp");
-  }
-
-  @Test
-  public void contributing_plugin_list() throws Exception {
-    initModel();
-    Collection<String> contributingPluginList = modelFinder.getContributingPluginList();
-    assertThat(contributingPluginList.size()).isEqualTo(2);
-    assertThat(contributingPluginList).contains("csharp", "java");
-  }
-
-  @Test
-  public void get_content_for_xml_file() throws Exception {
-    initModel();
-    Reader xmlFileReader = null;
-    try {
-      xmlFileReader = modelFinder.createReaderForXMLFile("csharp");
-      assertNotNull(xmlFileReader);
-      List<String> lines = IOUtils.readLines(xmlFileReader);
-      assertThat(lines.size()).isEqualTo(25);
-      assertThat(lines.get(0)).isEqualTo("<sqale>");
-    } catch (Exception e) {
-      fail("Should be able to read the XML file.");
-    } finally {
-      IOUtils.closeQuietly(xmlFileReader);
-    }
-  }
-
-  @Test
-  public void return_xml_file_path_for_plugin() throws Exception {
-    initModel();
-    assertThat(modelFinder.getXMLFilePath("foo")).isEqualTo(TEST_XML_PREFIX_PATH + "foo-model.xml");
-  }
-
-  @Test
-  public void contain_default_model() throws Exception {
-    modelFinder = new TechnicalDebtModelRepository(mock(PluginRepository.class));
-    modelFinder.start();
-    assertThat(modelFinder.getContributingPluginKeyToClassLoader().keySet()).containsOnly("technical-debt");
-  }
-
-  private void initModel() throws MalformedURLException {
-    Map<String, ClassLoader> contributingPluginKeyToClassLoader = Maps.newHashMap();
-    contributingPluginKeyToClassLoader.put("csharp", newClassLoader());
-    contributingPluginKeyToClassLoader.put("java", newClassLoader());
-    modelFinder = new TechnicalDebtModelRepository(contributingPluginKeyToClassLoader, TEST_XML_PREFIX_PATH);
-  }
-
-  private ClassLoader newClassLoader() throws MalformedURLException {
-    ClassLoader loader = mock(ClassLoader.class);
-    when(loader.getResourceAsStream(anyString())).thenAnswer(new Answer<InputStream>() {
-      public InputStream answer(InvocationOnMock invocation) throws Throwable {
-        return new FileInputStream(Resources.getResource((String) invocation.getArguments()[0]).getPath());
-      }
-    });
-    return loader;
-  }
-
-  class FakePlugin extends SonarPlugin {
-    public List getExtensions() {
-      return null;
-    }
-  }
-
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtModelSynchronizerTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtModelSynchronizerTest.java
deleted file mode 100644 (file)
index 5419bb9..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.collect.Lists;
-import org.apache.ibatis.session.SqlSession;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.api.utils.internal.WorkDuration;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-
-import java.io.Reader;
-import java.util.Collections;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-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.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class TechnicalDebtModelSynchronizerTest {
-
-  @Mock
-  MyBatis myBatis;
-
-  @Mock
-  SqlSession session;
-
-  @Mock
-  TechnicalDebtModelRepository technicalDebtModelRepository;
-
-  @Mock
-  TechnicalDebtRuleCache ruleCache;
-
-  @Mock
-  CharacteristicDao dao;
-
-  @Mock
-  TechnicalDebtXMLImporter xmlImporter;
-
-  Integer currentId = 1;
-
-  private DefaultTechnicalDebtModel defaultModel;
-
-  private TechnicalDebtModelSynchronizer manager;
-
-  @Before
-  public void initAndMerge() throws Exception {
-    when(myBatis.openSession()).thenReturn(session);
-
-    defaultModel = new DefaultTechnicalDebtModel();
-    Reader defaultModelReader = mock(Reader.class);
-    when(technicalDebtModelRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
-    when(xmlImporter.importXML(eq(defaultModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(defaultModel);
-
-    doAnswer(new Answer() {
-      public Object answer(InvocationOnMock invocation) {
-        Object[] args = invocation.getArguments();
-        CharacteristicDto dto = (CharacteristicDto) args[0];
-        dto.setId(currentId++);
-        return null;
-      }
-    }).when(dao).insert(any(CharacteristicDto.class), any(SqlSession.class));
-
-
-    manager = new TechnicalDebtModelSynchronizer(myBatis, dao, technicalDebtModelRepository, xmlImporter);
-  }
-
-  @Test
-  public void create_default_model_on_first_execution_when_no_plugin() throws Exception {
-    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
-    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(rootCharacteristic);
-    defaultModel.addRootCharacteristic(rootCharacteristic);
-
-    when(technicalDebtModelRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
-    when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
-
-    manager.synchronize(ValidationMessages.create(), ruleCache);
-
-    verify(dao).selectEnabledCharacteristics();
-    ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
-    verify(dao, times(2)).insert(characteristicCaptor.capture(), eq(session));
-
-    List<CharacteristicDto> result = characteristicCaptor.getAllValues();
-    assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
-    assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
-    verifyNoMoreInteractions(dao);
-  }
-
-  @Test
-  public void create_model_with_requirements_from_plugin_on_first_execution() throws Exception {
-    // Default model
-    DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
-    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic).setRoot(defaultRootCharacteristic);
-    defaultModel.addRootCharacteristic(defaultRootCharacteristic);
-
-    // No db model
-    when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
-
-    // Java model
-    DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
-    DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
-    DefaultCharacteristic javaCharacteristic = new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(javaRootCharacteristic).setRoot(javaRootCharacteristic);
-    javaModel.addRootCharacteristic(javaRootCharacteristic);
-
-    Rule rule = Rule.create();
-    rule.setId(10);
-    RuleKey ruleKey = RuleKey.of("checkstyle", "import");
-    when(ruleCache.getByRuleKey(ruleKey)).thenReturn(rule);
-    new DefaultRequirement().setRuleKey(ruleKey)
-      .setFunction("linear")
-      .setFactorValue(30)
-      .setFactorUnit(WorkDuration.UNIT.MINUTES)
-      .setCharacteristic(javaCharacteristic)
-      .setRootCharacteristic(javaRootCharacteristic);
-
-    Reader javaModelReader = mock(Reader.class);
-    when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
-    when(technicalDebtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
-    when(technicalDebtModelRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
-
-    manager.synchronize(ValidationMessages.create(), ruleCache);
-
-    verify(dao).selectEnabledCharacteristics();
-    ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
-    verify(dao, times(3)).insert(characteristicCaptor.capture(), eq(session));
-
-    List<CharacteristicDto> result = characteristicCaptor.getAllValues();
-    assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
-    assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
-    assertThat(result.get(2).getRuleId()).isEqualTo(10);
-    verifyNoMoreInteractions(dao);
-  }
-
-  @Test
-  public void add_new_requirements_from_plugin() throws Exception {
-    // Default model
-    DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
-    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic).setRoot(defaultRootCharacteristic);
-    defaultModel.addRootCharacteristic(defaultRootCharacteristic);
-
-    // Db model
-    CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
-    CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1).setRootId(1);
-    CharacteristicDto requirement = new CharacteristicDto().setId(3)
-      .setRuleId(10).setParentId(2).setRootId(1).setFactorValue(30.0).setFactorUnit("mn");
-
-    RuleKey ruleKey1 = RuleKey.of("checkstyle", "import");
-    Rule rule1 = Rule.create();
-    rule1.setId(10);
-    when(ruleCache.getByRuleKey(ruleKey1)).thenReturn(rule1);
-    when(ruleCache.exists(10)).thenReturn(true);
-    when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(requirement, dbCharacteristic, dbRootCharacteristic));
-
-    // Java model
-    DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
-    DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
-    DefaultCharacteristic javaCharacteristic = new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(javaRootCharacteristic).setRoot(javaRootCharacteristic);
-    javaModel.addRootCharacteristic(javaRootCharacteristic);
-
-    RuleKey ruleKey2 = RuleKey.of("checkstyle", "export");
-    Rule rule2 = Rule.create();
-    rule2.setId(11);
-    when(ruleCache.getByRuleKey(ruleKey2)).thenReturn(rule2);
-
-    // New requirement
-    new DefaultRequirement().setRuleKey(ruleKey2)
-      .setFunction("linear")
-      .setFactorValue(1)
-      .setFactorUnit(WorkDuration.UNIT.HOURS)
-      .setCharacteristic(javaCharacteristic)
-      .setRootCharacteristic(javaRootCharacteristic);
-
-    Reader javaModelReader = mock(Reader.class);
-    when(technicalDebtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
-    when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
-    when(technicalDebtModelRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
-
-    manager.synchronize(ValidationMessages.create(), ruleCache);
-
-    verify(dao).selectEnabledCharacteristics();
-    ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
-    verify(dao).insert(characteristicCaptor.capture(), eq(session));
-    assertThat(characteristicCaptor.getValue().getRuleId()).isEqualTo(11);
-    verifyNoMoreInteractions(dao);
-  }
-
-  @Test
-  public void disable_requirements_on_not_existing_rules() throws Exception {
-    // Default model
-    DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
-    new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic);
-    defaultModel.addRootCharacteristic(defaultRootCharacteristic);
-
-    // Db model
-    CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
-    CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1);
-    // To be disabled as rule does not exists
-    CharacteristicDto requirement = new CharacteristicDto().setId(3)
-      .setRuleId(10).setParentId(2).setFactorValue(30.0).setFactorUnit("mn");
-
-    when(ruleCache.exists(10)).thenReturn(false);
-
-    when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(dbRootCharacteristic, dbCharacteristic, requirement));
-
-    manager.synchronize(ValidationMessages.create(), ruleCache);
-
-    verify(dao).selectEnabledCharacteristics();
-    verify(dao).disable(eq(3), eq(session));
-    verifyNoMoreInteractions(dao);
-  }
-
-  @Test
-  public void fail_when_plugin_defines_characteristics_not_defined_in_default_model() throws Exception {
-    try {
-      // Default model
-      DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
-      new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic);
-      defaultModel.addRootCharacteristic(defaultRootCharacteristic);
-
-      // Db model
-      CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
-      CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1);
-      when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(dbRootCharacteristic, dbCharacteristic));
-
-      // Java model
-      DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
-      DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
-      new DefaultCharacteristic().setKey("NEW_CHARACTERISTIC").setParent(javaRootCharacteristic);
-      javaModel.addRootCharacteristic(javaRootCharacteristic);
-
-      Reader javaModelReader = mock(Reader.class);
-      when(technicalDebtModelRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
-      when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
-      when(technicalDebtModelRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
-
-      manager.synchronize(ValidationMessages.create(), ruleCache);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The characteristic : NEW_CHARACTERISTIC cannot be used as it's not available in default characteristics.");
-    } finally {
-      verify(dao).selectEnabledCharacteristics();
-      verifyNoMoreInteractions(dao);
-    }
-  }
-
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtRuleCacheTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtRuleCacheTest.java
deleted file mode 100644 (file)
index 7185f79..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.collect.Lists;
-import org.fest.assertions.Assertions;
-import org.junit.Test;
-import org.mockito.Matchers;
-import org.mockito.Mockito;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.rules.RuleQuery;
-
-import java.util.Collections;
-
-public class TechnicalDebtRuleCacheTest {
-
-  @Test
-  public void lazy_load_rules_on_first_call() throws Exception {
-
-    RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
-    Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Collections.EMPTY_LIST);
-
-    TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
-    technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
-    technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
-
-    Mockito.verify(ruleFinder, Mockito.times(1)).findAll(Matchers.any(RuleQuery.class));
-  }
-
-  @Test
-  public void return_matching_rule() throws Exception {
-
-    Rule rule1 = Rule.create("repo1", "rule1");
-    Rule rule2 = Rule.create("repo2", "rule2");
-
-    RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
-    Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1, rule2));
-
-    TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
-    Rule actualRule1 = technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
-    Rule actualRule2 = technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo2", "rule2"));
-
-    Assertions.assertThat(actualRule1).isEqualTo(rule1);
-    Assertions.assertThat(actualRule2).isEqualTo(rule2);
-  }
-
-  @Test
-  public void return_if_rule_exists() throws Exception {
-
-    Rule rule1 = Rule.create("repo1", "rule1");
-
-    RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
-    Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1));
-
-    TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
-
-    Assertions.assertThat(technicalDebtRuleCache.exists(RuleKey.of("repo1", "rule1"))).isTrue();
-    Assertions.assertThat(technicalDebtRuleCache.exists(RuleKey.of("repo2", "rule2"))).isFalse();
-  }
-
-  @Test
-  public void return_if_rule_id_exists() throws Exception {
-
-    Rule rule1 = Rule.create("repo1", "rule1");
-    rule1.setId(1);
-
-    RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
-    Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1));
-
-    TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
-
-    Assertions.assertThat(technicalDebtRuleCache.exists(1)).isTrue();
-    Assertions.assertThat(technicalDebtRuleCache.exists(2)).isFalse();
-  }
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest.java
deleted file mode 100644 (file)
index 64c5dea..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.Lists;
-import com.google.common.io.Resources;
-import org.junit.Test;
-import org.mockito.Matchers;
-import org.mockito.Mockito;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.rules.RuleQuery;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.api.utils.internal.WorkDuration;
-
-import java.io.IOException;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class TechnicalDebtXMLImporterTest {
-
-  @Test
-  public void import_characteristics() {
-    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
-    String xml = getFileContent("import_characteristics.xml");
-
-    ValidationMessages messages = ValidationMessages.create();
-    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
-    assertThat(sqale.rootCharacteristics()).hasSize(2);
-    assertThat(sqale.rootCharacteristics().get(0).key()).isEqualTo("PORTABILITY");
-    assertThat(sqale.rootCharacteristics().get(1).key()).isEqualTo("MAINTAINABILITY");
-
-    DefaultCharacteristic portability = sqale.characteristicByKey("PORTABILITY");
-    assertThat(portability.order()).isEqualTo(1);
-    assertThat(portability.children()).hasSize(2);
-    assertThat(portability.children().get(0).key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
-    assertThat(sqale.characteristicByKey("COMPILER_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
-    assertThat(portability.children().get(1).key()).isEqualTo("HARDWARE_RELATED_PORTABILITY");
-    assertThat(sqale.characteristicByKey("HARDWARE_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
-
-    DefaultCharacteristic maintainability = sqale.characteristicByKey("MAINTAINABILITY");
-    assertThat(maintainability.order()).isEqualTo(2);
-    assertThat(maintainability.children()).hasSize(1);
-    assertThat(maintainability.children().get(0).key()).isEqualTo("READABILITY");
-    assertThat(sqale.characteristicByKey("READABILITY").parent().key()).isEqualTo("MAINTAINABILITY");
-  }
-
-  @Test
-  public void use_default_unit_when_no_unit() {
-    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
-    String xml = getFileContent("use_default_unit_when_no_unit.xml");
-
-    ValidationMessages messages = ValidationMessages.create();
-    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
-    DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
-    DefaultRequirement requirement = memoryEfficiency.requirements().get(0);
-    assertThat(requirement.factorValue()).isEqualTo(3);
-    assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
-    assertThat(requirement.offsetValue()).isEqualTo(1);
-    assertThat(requirement.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
-  }
-
-  @Test
-  public void import_xml_with_linear_function() {
-    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
-    String xml = getFileContent("shouldImportXML_with_linear.xml");
-
-    ValidationMessages messages = ValidationMessages.create();
-    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
-    checkXmlCorrectlyImported(sqale, messages);
-  }
-
-  @Test
-  public void import_xml_with_linear_with_offset() {
-    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
-    String xml = getFileContent("shouldImportXML_with_linear_with_offset.xml");
-
-    ValidationMessages messages = ValidationMessages.create();
-    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
-    checkXmlCorrectlyImported(sqale, 1, WorkDuration.UNIT.HOURS, messages);
-  }
-
-  @Test
-  public void convert_deprecated_linear_with_threshold_function_by_linear_function() {
-    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
-    String xml = getFileContent("shouldImportXML_with_deprecated_linear_with_threshold.xml");
-
-    ValidationMessages messages = ValidationMessages.create();
-    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
-    checkXmlCorrectlyImported(sqale, 0, WorkDuration.UNIT.DAYS, messages);
-    assertThat(messages.getWarnings()).hasSize(1);
-  }
-
-  @Test
-  public void ignore_deprecated_constant_per_file_function() {
-    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
-    String xml = getFileContent("shouldImportXML_with_deprecated_constant_per_file.xml");
-
-    ValidationMessages messages = ValidationMessages.create();
-    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
-    assertThat(messages.getWarnings()).hasSize(1);
-
-    // characteristics
-    assertThat(sqale.rootCharacteristics()).hasSize(1);
-    DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
-    assertThat(efficiency.requirements()).isEmpty();
-  }
-
-  @Test
-  public void ignore_requirement_on_root_characteristics() {
-    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
-    String xml = getFileContent("ignore_requirement_on_root_characteristics.xml");
-
-    ValidationMessages messages = ValidationMessages.create();
-    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
-    assertThat(messages.getWarnings()).hasSize(1);
-
-    assertThat(sqale.characteristics()).hasSize(1);
-    DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
-    assertThat(efficiency.requirements()).isEmpty();
-    assertThat(messages.getWarnings().get(0)).contains("checkstyle");
-  }
-
-  @Test
-  public void shouldBadlyFormattedImportXML() {
-    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-    String xml = getFileContent("shouldImportXML_badly-formatted.xml");
-
-    ValidationMessages messages = ValidationMessages.create();
-    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
-    checkXmlCorrectlyImported(sqale, messages);
-  }
-
-  @Test
-  public void ignore_requirement_with_not_found_rule() {
-    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-    String xml = getFileContent("shouldLogWarningIfRuleNotFound.xml");
-    ValidationMessages messages = ValidationMessages.create();
-
-    DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
-    assertThat(messages.getWarnings()).hasSize(1);
-    assertThat(messages.getWarnings().get(0)).isEqualTo("Rule not found: [repository=findbugs, key=Foo]");
-
-    // characteristics
-    assertThat(sqale.rootCharacteristics()).hasSize(1);
-    DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
-    assertThat(efficiency.requirements()).isEmpty();
-    assertThat(messages.getWarnings().get(0)).contains("findbugs");
-  }
-
-  @Test
-  public void shouldNotifyOnUnexpectedValueTypeInXml() throws Exception {
-
-    TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
-    String xml = getFileContent("shouldRejectXML_with_invalid_value.xml");
-    ValidationMessages messages = ValidationMessages.create();
-
-    new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
-    assertThat(messages.getErrors()).hasSize(1);
-    assertThat(messages.getErrors().get(0)).isEqualTo("Cannot import value 'abc' for field factor - Expected a numeric value instead");
-  }
-
-  private TechnicalDebtRuleCache mockRuleCache() {
-    RuleFinder finder = Mockito.mock(RuleFinder.class);
-    Mockito.when(finder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(Rule.create("checkstyle", "Regexp", "Regular expression")));
-    return new TechnicalDebtRuleCache(finder);
-  }
-
-  private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, ValidationMessages messages) {
-    checkXmlCorrectlyImported(sqale, 0, WorkDuration.UNIT.DAYS, messages);
-  }
-
-  private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, Integer offsetValue, WorkDuration.UNIT offsetUnit, ValidationMessages messages) {
-    assertThat(messages.getErrors()).isEmpty();
-
-    // characteristics
-    assertThat(sqale.rootCharacteristics()).hasSize(2);
-    DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
-    assertThat(efficiency.name()).isEqualTo("Efficiency");
-
-    // sub-characteristics
-    assertThat(efficiency.children()).hasSize(1);
-    DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
-    assertThat(memoryEfficiency.name()).isEqualTo("Memory use");
-
-    // requirement
-    assertThat(memoryEfficiency.requirements()).hasSize(1);
-    DefaultRequirement requirement = memoryEfficiency.requirements().get(0);
-    assertThat(requirement.ruleKey().repository()).isEqualTo("checkstyle");
-    assertThat(requirement.ruleKey().rule()).isEqualTo("Regexp");
-    assertThat(requirement.function()).isEqualTo("linear");
-    assertThat(requirement.factorValue()).isEqualTo(3);
-    assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.HOURS);
-    assertThat(requirement.offsetValue()).isEqualTo(offsetValue);
-    assertThat(requirement.offsetUnit()).isEqualTo(offsetUnit);
-    assertThat(requirement.characteristic().key()).isEqualTo("MEMORY_EFFICIENCY");
-    assertThat(requirement.rootCharacteristic().key()).isEqualTo("EFFICIENCY");
-  }
-
-  private String getFileContent(String file) {
-    try {
-      return Resources.toString(Resources.getResource(TechnicalDebtXMLImporterTest.class, "TechnicalDebtXMLImporterTest/" + file), Charsets.UTF_8);
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/db/CharacteristicDaoTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/db/CharacteristicDaoTest.java
deleted file mode 100644 (file)
index 0e4341a..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt.db;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.persistence.AbstractDaoTestCase;
-
-import java.util.List;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class CharacteristicDaoTest extends AbstractDaoTestCase {
-
-  private static final String[] EXCLUDED_COLUMNS = new String[]{"id", "depth", "description", "quality_model_id", "created_at", "updated_at"};
-
-  CharacteristicDao dao;
-
-  @Before
-  public void createDao() {
-    dao = new CharacteristicDao(getMyBatis());
-  }
-
-  @Test
-  public void select_enabled_characteristics() {
-    setupData("shared");
-
-    List<CharacteristicDto> dtos = dao.selectEnabledCharacteristics();
-
-    assertThat(dtos).hasSize(3);
-
-    CharacteristicDto rootCharacteristic = dtos.get(0);
-    assertThat(rootCharacteristic.getId()).isEqualTo(1);
-    assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
-    assertThat(rootCharacteristic.getName()).isEqualTo("Portability");
-    assertThat(rootCharacteristic.getParentId()).isNull();
-    assertThat(rootCharacteristic.getRootId()).isNull();
-    assertThat(rootCharacteristic.getRuleId()).isNull();
-    assertThat(rootCharacteristic.getOrder()).isEqualTo(1);
-    assertThat(rootCharacteristic.isEnabled()).isTrue();
-    assertThat(rootCharacteristic.getCreatedAt()).isNotNull();
-    assertThat(rootCharacteristic.getUpdatedAt()).isNotNull();
-
-    CharacteristicDto characteristic = dtos.get(1);
-    assertThat(characteristic.getId()).isEqualTo(2);
-    assertThat(characteristic.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
-    assertThat(characteristic.getName()).isEqualTo("Compiler related portability");
-    assertThat(characteristic.getParentId()).isEqualTo(1);
-    assertThat(characteristic.getRootId()).isEqualTo(1);
-    assertThat(characteristic.getRuleId()).isNull();
-    assertThat(characteristic.getOrder()).isNull();
-    assertThat(characteristic.isEnabled()).isTrue();
-    assertThat(characteristic.getCreatedAt()).isNotNull();
-    assertThat(characteristic.getUpdatedAt()).isNotNull();
-
-    CharacteristicDto requirement = dtos.get(2);
-    assertThat(requirement.getId()).isEqualTo(3);
-    assertThat(requirement.getKey()).isNull();
-    assertThat(requirement.getName()).isNull();
-    assertThat(requirement.getParentId()).isEqualTo(2);
-    assertThat(requirement.getRootId()).isEqualTo(1);
-    assertThat(requirement.getRuleId()).isEqualTo(1);
-    assertThat(requirement.getOrder()).isNull();
-    assertThat(requirement.getFunction()).isEqualTo("linear_offset");
-    assertThat(requirement.getFactorValue()).isEqualTo(20.0);
-    assertThat(requirement.getFactorUnit()).isEqualTo("mn");
-    assertThat(requirement.getOffsetValue()).isEqualTo(30.0);
-    assertThat(requirement.getOffsetUnit()).isEqualTo("h");
-    assertThat(requirement.isEnabled()).isTrue();
-    assertThat(requirement.getCreatedAt()).isNotNull();
-    assertThat(requirement.getUpdatedAt()).isNull();
-  }
-
-  @Test
-  public void select_characteristics() {
-    setupData("shared");
-
-    List<CharacteristicDto> dtos = dao.selectCharacteristics();
-
-    assertThat(dtos).hasSize(2);
-
-    CharacteristicDto rootCharacteristic = dtos.get(0);
-    assertThat(rootCharacteristic.getId()).isEqualTo(1);
-    assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
-    assertThat(rootCharacteristic.getName()).isEqualTo("Portability");
-    assertThat(rootCharacteristic.getParentId()).isNull();
-    assertThat(rootCharacteristic.getRootId()).isNull();
-    assertThat(rootCharacteristic.getOrder()).isEqualTo(1);
-    assertThat(rootCharacteristic.isEnabled()).isTrue();
-    assertThat(rootCharacteristic.getCreatedAt()).isNotNull();
-    assertThat(rootCharacteristic.getUpdatedAt()).isNotNull();
-
-    CharacteristicDto characteristic = dtos.get(1);
-    assertThat(characteristic.getId()).isEqualTo(2);
-    assertThat(characteristic.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
-    assertThat(characteristic.getName()).isEqualTo("Compiler related portability");
-    assertThat(characteristic.getParentId()).isEqualTo(1);
-    assertThat(characteristic.getRootId()).isEqualTo(1);
-    assertThat(characteristic.getOrder()).isNull();
-    assertThat(characteristic.isEnabled()).isTrue();
-    assertThat(characteristic.getCreatedAt()).isNotNull();
-    assertThat(characteristic.getUpdatedAt()).isNotNull();
-  }
-
-  @Test
-  public void select_enabled_root_characteristics() {
-    setupData("select_enabled_root_characteristics");
-
-    List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
-
-    assertThat(dtos).hasSize(1);
-
-    CharacteristicDto rootCharacteristic = dtos.get(0);
-    assertThat(rootCharacteristic.getId()).isEqualTo(1);
-    assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
-  }
-
-  @Test
-  public void select_enabled_root_characteristics_order_by_characteristic_order() {
-    setupData("select_enabled_root_characteristics_order_by_characteristic_order");
-
-    List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
-
-    assertThat(dtos).hasSize(3);
-    assertThat(dtos.get(0).getKey()).isEqualTo("TESTABILITY");
-    assertThat(dtos.get(1).getKey()).isEqualTo("PORTABILITY");
-    assertThat(dtos.get(2).getKey()).isEqualTo("MAINTAINABILITY");
-  }
-
-  @Test
-  public void select_requirement() {
-    setupData("shared");
-
-    CharacteristicDto dto = dao.selectByRuleId(1);
-
-    assertThat(dto).isNotNull();
-    assertThat(dto.getId()).isEqualTo(3);
-    assertThat(dto.getParentId()).isEqualTo(2);
-    assertThat(dto.getRootId()).isEqualTo(1);
-  }
-
-  @Test
-  public void select_characteristic_by_key() {
-    setupData("shared");
-
-    CharacteristicDto dto = dao.selectByKey("COMPILER_RELATED_PORTABILITY");
-    assertThat(dto).isNotNull();
-    assertThat(dto.getId()).isEqualTo(2);
-    assertThat(dto.getParentId()).isEqualTo(1);
-    assertThat(dto.getRootId()).isEqualTo(1);
-
-    dto = dao.selectByKey("PORTABILITY");
-    assertThat(dto).isNotNull();
-    assertThat(dto.getId()).isEqualTo(1);
-    assertThat(dto.getParentId()).isNull();
-    assertThat(dto.getRootId()).isNull();
-
-    assertThat(dao.selectByKey("UNKNOWN")).isNull();
-  }
-
-  @Test
-  public void select_characteristic_by_id() {
-    setupData("shared");
-
-    assertThat(dao.selectById(2)).isNotNull();
-    assertThat(dao.selectById(1)).isNotNull();
-
-    assertThat(dao.selectById(10)).isNull();
-  }
-
-  @Test
-  public void insert_characteristic() throws Exception {
-    CharacteristicDto dto = new CharacteristicDto()
-      .setKey("COMPILER_RELATED_PORTABILITY")
-      .setName("Compiler related portability")
-      .setOrder(1)
-      .setEnabled(true)
-      .setCreatedAt(DateUtils.parseDate("2013-11-20"));
-
-    dao.insert(dto);
-
-    checkTables("insert_characteristic", EXCLUDED_COLUMNS, "characteristics");
-  }
-
-  @Test
-  public void insert_requirement() throws Exception {
-    CharacteristicDto dto = new CharacteristicDto()
-      .setParentId(2)
-      .setRootId(1)
-      .setRuleId(1)
-      .setFunction("linear_offset")
-      .setFactorValue(20.0)
-      .setFactorUnit("mn")
-      .setOffsetValue(30.0)
-      .setOffsetUnit("h")
-      .setCreatedAt(DateUtils.parseDate("2013-11-20"))
-      .setEnabled(true);
-
-    dao.insert(dto);
-
-    checkTables("insert_requirement", EXCLUDED_COLUMNS, "characteristics");
-  }
-
-  @Test
-  public void update_characteristic() throws Exception {
-    setupData("update_characteristic");
-
-    CharacteristicDto dto = new CharacteristicDto()
-      .setId(1)
-        // The Key should not be changed
-      .setKey("NEW_KEY")
-      .setName("New name")
-      .setOrder(2)
-        // Created date should not changed
-      .setCreatedAt(DateUtils.parseDate("2013-11-22"))
-      .setEnabled(false);
-
-    dao.update(dto);
-
-    checkTables("update_characteristic", new String[]{"id", "depth", "description", "quality_model_id", "updated_at"}, "characteristics");
-  }
-
-  @Test
-  public void update_requirement() throws Exception {
-    setupData("update_requirement");
-
-    CharacteristicDto dto = new CharacteristicDto()
-      .setId(1)
-      .setParentId(3)
-      .setRootId(1)
-      .setRuleId(2)
-      .setFunction("linear")
-      .setFactorValue(21.0)
-      .setFactorUnit("h")
-      .setOffsetValue(null)
-      .setOffsetUnit(null)
-        // Created date should not changed
-      .setCreatedAt(DateUtils.parseDate("2013-11-22"))
-      .setEnabled(false);
-
-    dao.update(dto);
-
-    checkTables("update_requirement", EXCLUDED_COLUMNS, "characteristics");
-  }
-
-  @Test
-  public void disable() throws Exception {
-    setupData("disable");
-
-    dao.disable(1);
-
-    checkTables("disable", EXCLUDED_COLUMNS, "characteristics");
-  }
-
-}
diff --git a/sonar-core/src/test/java/org/sonar/core/technicaldebt/db/CharacteristicDtoTest.java b/sonar-core/src/test/java/org/sonar/core/technicaldebt/db/CharacteristicDtoTest.java
deleted file mode 100644 (file)
index f673018..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.technicaldebt.db;
-
-import org.junit.Test;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.internal.WorkDuration;
-
-import java.util.Date;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class CharacteristicDtoTest {
-
-  @Test
-  public void to_dto_from_requirement() throws Exception {
-    DefaultRequirement requirement = new DefaultRequirement()
-      .setFunction("constant_issue")
-      .setFactorValue(10)
-      .setFactorUnit(WorkDuration.UNIT.DAYS)
-      .setOffsetValue(5)
-      .setOffsetUnit(WorkDuration.UNIT.MINUTES)
-      .setCreatedAt(new Date())
-      .setUpdatedAt(new Date());
-
-    CharacteristicDto dto = CharacteristicDto.toDto(requirement, 2, 1, 10);
-    assertThat(dto.getRuleId()).isEqualTo(10);
-    assertThat(dto.getParentId()).isEqualTo(2);
-    assertThat(dto.getRootId()).isEqualTo(1);
-    assertThat(dto.getFunction()).isEqualTo("constant_issue");
-    assertThat(dto.getFactorValue()).isEqualTo(10d);
-    assertThat(dto.getFactorUnit()).isEqualTo(CharacteristicDto.DAYS);
-    assertThat(dto.getOffsetValue()).isEqualTo(5d);
-    assertThat(dto.getOffsetUnit()).isEqualTo(CharacteristicDto.MINUTES);
-    assertThat(dto.isEnabled()).isTrue();
-    assertThat(dto.getCreatedAt()).isNotNull();
-    assertThat(dto.getUpdatedAt()).isNotNull();
-  }
-
-  @Test
-  public void to_requirement() throws Exception {
-    CharacteristicDto requirementDto = new CharacteristicDto()
-      .setId(3)
-      .setParentId(2)
-      .setRuleId(100)
-      .setFunction("linear")
-      .setFactorValue(2d)
-      .setFactorUnit(CharacteristicDto.DAYS)
-      .setOffsetValue(0d)
-      .setOffsetUnit(CharacteristicDto.MINUTES)
-      .setCreatedAt(new Date())
-      .setUpdatedAt(new Date());
-
-    DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
-      .setKey("MEMORY_EFFICIENCY")
-      .setName("Memory use");
-
-    DefaultCharacteristic characteristic = new DefaultCharacteristic()
-      .setKey("EFFICIENCY")
-      .setName("Efficiency")
-      .setParent(rootCharacteristic);
-
-    DefaultRequirement requirement =  requirementDto.toRequirement(RuleKey.of("squid", "S106"), characteristic, rootCharacteristic);
-    assertThat(requirement.ruleKey()).isEqualTo(RuleKey.of("squid", "S106"));
-    assertThat(requirement.characteristic()).isEqualTo(characteristic);
-    assertThat(requirement.rootCharacteristic()).isEqualTo(rootCharacteristic);
-    assertThat(requirement.function()).isEqualTo("linear");
-    assertThat(requirement.factorValue()).isEqualTo(2);
-    assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
-    assertThat(requirement.offsetValue()).isEqualTo(0);
-    assertThat(requirement.offsetUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
-    assertThat(requirement.createdAt()).isNotNull();
-    assertThat(requirement.updatedAt()).isNotNull();
-
-  }
-}
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/CharacteristicsDebtModelXMLImporterTest/import_badly_formatted_xml.xml b/sonar-core/src/test/resources/org/sonar/core/debt/CharacteristicsDebtModelXMLImporterTest/import_badly_formatted_xml.xml
new file mode 100644 (file)
index 0000000..3abb870
--- /dev/null
@@ -0,0 +1,43 @@
+<!--
+  ~ SonarQube, open source software quality management tool.
+  ~ Copyright (C) 2008-2013 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.
+  -->
+
+<sqale>
+  <chc>
+    <key>USABILITY
+    </key>
+    <name>Usability
+    </name>
+    <desc>Estimate usability
+    </desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY
+    </key>
+    <name>Efficiency
+    </name>
+    <chc>
+      <key>MEMORY_EFFICIENCY
+      </key>
+      <name>Memory use
+      </name>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/CharacteristicsDebtModelXMLImporterTest/import_characteristics.xml b/sonar-core/src/test/resources/org/sonar/core/debt/CharacteristicsDebtModelXMLImporterTest/import_characteristics.xml
new file mode 100644 (file)
index 0000000..bc7f756
--- /dev/null
@@ -0,0 +1,22 @@
+<sqale>
+  <chc>
+    <key>PORTABILITY</key>
+    <name>Portability</name>
+    <chc>
+      <key>COMPILER_RELATED_PORTABILITY</key>
+      <name>Compiler related portability</name>
+    </chc>
+    <chc>
+      <key>HARDWARE_RELATED_PORTABILITY</key>
+      <name>Hardware related portability</name>
+    </chc>
+  </chc>
+  <chc>
+    <key>MAINTAINABILITY</key>
+    <name>Maintainability</name>
+    <chc>
+      <key>READABILITY</key>
+      <name>Readability</name>
+    </chc>
+  </chc>
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/convert_deprecated_linear_with_threshold_function_by_linear_function.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/convert_deprecated_linear_with_threshold_function_by_linear_function.xml
new file mode 100644 (file)
index 0000000..9ebc69b
--- /dev/null
@@ -0,0 +1,36 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFunction</key>
+          <!-- Should be replaced by linear -->
+          <txt>linear_threshold</txt>
+        </prop>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <!-- Should be ignored -->
+        <prop>
+          <key>offset</key>
+          <val>1.0</val>
+          <txt>h</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/ignore_deprecated_constant_per_file_function.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/ignore_deprecated_constant_per_file_function.xml
new file mode 100644 (file)
index 0000000..4b8ae3f
--- /dev/null
@@ -0,0 +1,25 @@
+<sqale>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <!-- Should be ignored -->
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>constant_resource</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/ignore_invalid_value.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/ignore_invalid_value.xml
new file mode 100644 (file)
index 0000000..bb6bdbb
--- /dev/null
@@ -0,0 +1,28 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>factor</key>
+          <val>abc</val>
+        </prop>
+        <prop>
+          <key>function</key>
+          <txt>linear</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/ignore_rule_on_root_characteristics.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/ignore_rule_on_root_characteristics.xml
new file mode 100644 (file)
index 0000000..bcf3ed8
--- /dev/null
@@ -0,0 +1,19 @@
+<sqale>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <rule-repo>checkstyle</rule-repo>
+      <rule-key>Regexp</rule-key>
+      <prop>
+        <key>remediationFactor</key>
+        <val>3.0</val>
+        <txt>h</txt>
+      </prop>
+      <prop>
+        <key>remediationFunction</key>
+        <txt>linear</txt>
+      </prop>
+    </chc>
+  </chc>
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_badly_formatted_xml.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_badly_formatted_xml.xml
new file mode 100644 (file)
index 0000000..6c7d153
--- /dev/null
@@ -0,0 +1,43 @@
+<sqale>
+  <chc>
+    <key>USABILITY
+    </key>
+    <name>Usability
+    </name>
+    <desc>Estimate usability
+    </desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY
+    </key>
+    <name>Efficiency
+    </name>
+    <chc>
+      <key>MEMORY_EFFICIENCY
+      </key>
+      <name>Memory use
+      </name>
+      <chc>
+        <rule-repo>checkstyle
+        </rule-repo>
+        <rule-key>Regexp
+        </rule-key>
+        <prop>
+          <key>remediationFactor
+          </key>
+          <val>3.0
+          </val>
+          <txt>h
+          </txt>
+        </prop>
+        <prop>
+          <key>remediationFunction
+          </key>
+          <txt>linear
+          </txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_constant_issue.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_constant_issue.xml
new file mode 100644 (file)
index 0000000..86b1f55
--- /dev/null
@@ -0,0 +1,29 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>offset</key>
+          <val>3.0</val>
+          <txt>d</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>constant_issue</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_linear.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_linear.xml
new file mode 100644 (file)
index 0000000..f641a51
--- /dev/null
@@ -0,0 +1,29 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>linear</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_linear_with_offset.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_linear_with_offset.xml
new file mode 100644 (file)
index 0000000..d1af28f
--- /dev/null
@@ -0,0 +1,54 @@
+<!--
+  ~ SonarQube, open source software quality management tool.
+  ~ Copyright (C) 2008-2013 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.
+  -->
+
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>linear_offset</txt>
+        </prop>
+        <prop>
+          <key>offset</key>
+          <val>1.0</val>
+          <txt>min</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_rules.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/import_rules.xml
new file mode 100644 (file)
index 0000000..d035d7b
--- /dev/null
@@ -0,0 +1,58 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>linear</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+  <chc>
+    <key>PORTABILITY</key>
+    <name>Portability</name>
+    <chc>
+      <key>COMPILER_RELATED_PORTABILITY</key>
+      <name>Compiler related portability</name>
+    </chc>
+    <chc>
+      <key>HARDWARE_RELATED_PORTABILITY</key>
+      <name>Hardware related portability</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp2</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>linear</txt>
+        </prop>
+        <prop>
+          <key>offset</key>
+          <val>1.0</val>
+          <txt>h</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/replace_mn_by_min.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/replace_mn_by_min.xml
new file mode 100644 (file)
index 0000000..3254fef
--- /dev/null
@@ -0,0 +1,49 @@
+<!--
+  ~ SonarQube, open source software quality management tool.
+  ~ Copyright (C) 2008-2013 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.
+  -->
+
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>mn</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>linear</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/use_default_unit_when_no_unit.xml b/sonar-core/src/test/resources/org/sonar/core/debt/RulesDebtModelXMLImporterTest/use_default_unit_when_no_unit.xml
new file mode 100644 (file)
index 0000000..f05e512
--- /dev/null
@@ -0,0 +1,32 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>linear</txt>
+        </prop>
+        <prop>
+          <key>offset</key>
+          <val>1.0</val>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtModelRepositoryTest/csharp-model.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtModelRepositoryTest/csharp-model.xml
new file mode 100644 (file)
index 0000000..e4569a2
--- /dev/null
@@ -0,0 +1,25 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <rule-repo>gendarme</rule-repo>
+      <rule-key>EnsureLocalDisposalRule</rule-key>
+      <prop>
+        <key>remediationFactor</key>
+        <val>0.125</val>
+        <txt>d</txt>
+      </prop>
+      <prop>
+        <key>remediationFunction</key>
+        <txt>linear</txt>
+      </prop>
+    </chc>
+  </chc>
+
+</sqale>
\ No newline at end of file
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtModelRepositoryTest/java-model.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtModelRepositoryTest/java-model.xml
new file mode 100644 (file)
index 0000000..0b37f56
--- /dev/null
@@ -0,0 +1,25 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <rule-repo>squid-cobol</rule-repo>
+      <rule-key>CheckLoop</rule-key>
+      <prop>
+        <key>remediationFactor</key>
+        <val>0.125</val>
+        <txt>d</txt>
+      </prop>
+      <prop>
+        <key>remediationFunction</key>
+        <txt>linear</txt>
+      </prop>
+    </chc>
+  </chc>
+
+</sqale>
\ No newline at end of file
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/ignore_requirement_on_root_characteristics.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/ignore_requirement_on_root_characteristics.xml
new file mode 100644 (file)
index 0000000..bcf3ed8
--- /dev/null
@@ -0,0 +1,19 @@
+<sqale>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <rule-repo>checkstyle</rule-repo>
+      <rule-key>Regexp</rule-key>
+      <prop>
+        <key>remediationFactor</key>
+        <val>3.0</val>
+        <txt>h</txt>
+      </prop>
+      <prop>
+        <key>remediationFunction</key>
+        <txt>linear</txt>
+      </prop>
+    </chc>
+  </chc>
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/import_characteristics.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/import_characteristics.xml
new file mode 100644 (file)
index 0000000..bc7f756
--- /dev/null
@@ -0,0 +1,22 @@
+<sqale>
+  <chc>
+    <key>PORTABILITY</key>
+    <name>Portability</name>
+    <chc>
+      <key>COMPILER_RELATED_PORTABILITY</key>
+      <name>Compiler related portability</name>
+    </chc>
+    <chc>
+      <key>HARDWARE_RELATED_PORTABILITY</key>
+      <name>Hardware related portability</name>
+    </chc>
+  </chc>
+  <chc>
+    <key>MAINTAINABILITY</key>
+    <name>Maintainability</name>
+    <chc>
+      <key>READABILITY</key>
+      <name>Readability</name>
+    </chc>
+  </chc>
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_badly-formatted.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_badly-formatted.xml
new file mode 100644 (file)
index 0000000..6c7d153
--- /dev/null
@@ -0,0 +1,43 @@
+<sqale>
+  <chc>
+    <key>USABILITY
+    </key>
+    <name>Usability
+    </name>
+    <desc>Estimate usability
+    </desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY
+    </key>
+    <name>Efficiency
+    </name>
+    <chc>
+      <key>MEMORY_EFFICIENCY
+      </key>
+      <name>Memory use
+      </name>
+      <chc>
+        <rule-repo>checkstyle
+        </rule-repo>
+        <rule-key>Regexp
+        </rule-key>
+        <prop>
+          <key>remediationFactor
+          </key>
+          <val>3.0
+          </val>
+          <txt>h
+          </txt>
+        </prop>
+        <prop>
+          <key>remediationFunction
+          </key>
+          <txt>linear
+          </txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_constant_per_file.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_constant_per_file.xml
new file mode 100644 (file)
index 0000000..4b8ae3f
--- /dev/null
@@ -0,0 +1,25 @@
+<sqale>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <!-- Should be ignored -->
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>constant_resource</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_linear_with_threshold.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_linear_with_threshold.xml
new file mode 100644 (file)
index 0000000..9ebc69b
--- /dev/null
@@ -0,0 +1,36 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFunction</key>
+          <!-- Should be replaced by linear -->
+          <txt>linear_threshold</txt>
+        </prop>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <!-- Should be ignored -->
+        <prop>
+          <key>offset</key>
+          <val>1.0</val>
+          <txt>h</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear.xml
new file mode 100644 (file)
index 0000000..f641a51
--- /dev/null
@@ -0,0 +1,29 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>linear</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear_with_offset.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear_with_offset.xml
new file mode 100644 (file)
index 0000000..d12f70d
--- /dev/null
@@ -0,0 +1,34 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>linear</txt>
+        </prop>
+        <prop>
+          <key>offset</key>
+          <val>1.0</val>
+          <txt>h</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldLogWarningIfRuleNotFound.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldLogWarningIfRuleNotFound.xml
new file mode 100644 (file)
index 0000000..2898f45
--- /dev/null
@@ -0,0 +1,23 @@
+<sqale>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>findbugs</rule-repo>
+        <rule-key>Foo</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+          <txt>h</txt>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>linear</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldRejectXML_with_invalid_value.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/shouldRejectXML_with_invalid_value.xml
new file mode 100644 (file)
index 0000000..bb6bdbb
--- /dev/null
@@ -0,0 +1,28 @@
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>factor</key>
+          <val>abc</val>
+        </prop>
+        <prop>
+          <key>function</key>
+          <txt>linear</txt>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/use_default_unit_when_no_unit.xml b/sonar-core/src/test/resources/org/sonar/core/debt/TechnicalDebtXMLImporterTest/use_default_unit_when_no_unit.xml
new file mode 100644 (file)
index 0000000..f83ca79
--- /dev/null
@@ -0,0 +1,52 @@
+<!--
+  ~ SonarQube, open source software quality management tool.
+  ~ Copyright (C) 2008-2013 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.
+  -->
+
+<sqale>
+  <chc>
+    <key>USABILITY</key>
+    <name>Usability</name>
+    <desc>Estimate usability</desc>
+  </chc>
+  <chc>
+    <key>EFFICIENCY</key>
+    <name>Efficiency</name>
+    <chc>
+      <key>MEMORY_EFFICIENCY</key>
+      <name>Memory use</name>
+      <chc>
+        <rule-repo>checkstyle</rule-repo>
+        <rule-key>Regexp</rule-key>
+        <prop>
+          <key>remediationFactor</key>
+          <val>3.0</val>
+        </prop>
+        <prop>
+          <key>remediationFunction</key>
+          <txt>linear</txt>
+        </prop>
+        <prop>
+          <key>offset</key>
+          <val>1.0</val>
+        </prop>
+      </chc>
+    </chc>
+  </chc>
+
+</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/disable-result.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/disable-result.xml
new file mode 100644 (file)
index 0000000..81b97e0
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+                   created_at="2013-11-20" updated_at="[null]"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/disable.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/disable.xml
new file mode 100644 (file)
index 0000000..a970b32
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/insert_characteristic-result.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/insert_characteristic-result.xml
new file mode 100644 (file)
index 0000000..b6e2d5d
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+                   created_at="2013-11-20" updated_at="[null]"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/insert_requirement-result.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/insert_requirement-result.xml
new file mode 100644 (file)
index 0000000..2b1ccb8
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <characteristics id="1" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1" characteristic_order="[null]"
+                   function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
+                   created_at="2013-11-20" updated_at="[null]"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/select_enabled_root_characteristics.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/select_enabled_root_characteristics.xml
new file mode 100644 (file)
index 0000000..c8200af
--- /dev/null
@@ -0,0 +1,29 @@
+<dataset>
+
+  <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+  <characteristics id="2" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="[null]"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+  <!-- requirement -->
+  <characteristics id="3" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1"
+                   function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
+                   created_at="2013-11-20" updated_at="[null]"/>
+
+  <!-- disabled characteristics -->
+  <characteristics id="4" kee="DISABLED_CHARACTERISTIC" name="Disabled characteristic" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="2"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+  <!-- disabled requirement -->
+  <characteristics id="5" kee="[null]" name="[null]" parent_id="4" root_id="4" rule_id="1"
+                   function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+
+  <rules id="1" plugin_rule_key="import" plugin_config_key="regexp" plugin_name="checkstyle" description="[null]" priority="3" status="READY" cardinality="SINGLE" parent_id="[null]" name="Regular exp"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/select_enabled_root_characteristics_order_by_characteristic_order.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/select_enabled_root_characteristics_order_by_characteristic_order.xml
new file mode 100644 (file)
index 0000000..00a47fd
--- /dev/null
@@ -0,0 +1,15 @@
+<dataset>
+
+  <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="2"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+  <characteristics id="2" kee="TESTABILITY" name="Testability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+  <characteristics id="3" kee="MAINTAINABILITY" name="Maintainability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="4"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/shared.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/shared.xml
new file mode 100644 (file)
index 0000000..d84c39d
--- /dev/null
@@ -0,0 +1,36 @@
+<dataset>
+
+  <!-- Root characteristic -->
+  <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+  <!-- Characteristic -->
+  <characteristics id="2" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="[null]"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+  <!-- Requirement -->
+  <characteristics id="3" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1"
+                   function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
+                   created_at="2013-11-20" updated_at="[null]"/>
+
+  <!-- Disabled root characteristic -->
+  <characteristics id="4" kee="DISABLED_ROOT_CHARACTERISTIC" name="Disabled root characteristic" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="2"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+  <!-- Disabled characteristic -->
+  <characteristics id="5" kee="DISABLED_CHARACTERISTIC" name="Disabled characteristic" parent_id="4" root_id="4" rule_id="[null]" characteristic_order="[null]"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+  <!-- Disabled requirement -->
+  <characteristics id="6" kee="[null]" name="[null]" parent_id="5" root_id="4" rule_id="1"
+                   function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+
+  <rules id="1" plugin_rule_key="import" plugin_config_key="regexp" plugin_name="checkstyle" description="[null]" priority="3" status="READY" cardinality="SINGLE" parent_id="[null]" name="Regular exp"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_characteristic-result.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_characteristic-result.xml
new file mode 100644 (file)
index 0000000..026a505
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="New name" parent_id="[null]" rule_id="[null]" root_id="[null]" characteristic_order="2"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_characteristic.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_characteristic.xml
new file mode 100644 (file)
index 0000000..b4817ec
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-20"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_requirement-result.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_requirement-result.xml
new file mode 100644 (file)
index 0000000..71c4150
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <characteristics id="1" kee="[null]" name="[null]" parent_id="3" root_id="1" rule_id="2" characteristic_order="[null]"
+                   function_key="linear" factor_value="21.0" factor_unit="h" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_requirement.xml b/sonar-core/src/test/resources/org/sonar/core/debt/db/CharacteristicDaoTest/update_requirement.xml
new file mode 100644 (file)
index 0000000..2b1ccb8
--- /dev/null
@@ -0,0 +1,7 @@
+<dataset>
+
+  <characteristics id="1" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1" characteristic_order="[null]"
+                   function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
+                   created_at="2013-11-20" updated_at="[null]"/>
+
+</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/CharacteristicsXMLImporterTest/import_badly_formatted_xml.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/CharacteristicsXMLImporterTest/import_badly_formatted_xml.xml
deleted file mode 100644 (file)
index 3abb870..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<!--
-  ~ SonarQube, open source software quality management tool.
-  ~ Copyright (C) 2008-2013 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.
-  -->
-
-<sqale>
-  <chc>
-    <key>USABILITY
-    </key>
-    <name>Usability
-    </name>
-    <desc>Estimate usability
-    </desc>
-  </chc>
-  <chc>
-    <key>EFFICIENCY
-    </key>
-    <name>Efficiency
-    </name>
-    <chc>
-      <key>MEMORY_EFFICIENCY
-      </key>
-      <name>Memory use
-      </name>
-    </chc>
-  </chc>
-
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/CharacteristicsXMLImporterTest/import_characteristics.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/CharacteristicsXMLImporterTest/import_characteristics.xml
deleted file mode 100644 (file)
index bc7f756..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<sqale>
-  <chc>
-    <key>PORTABILITY</key>
-    <name>Portability</name>
-    <chc>
-      <key>COMPILER_RELATED_PORTABILITY</key>
-      <name>Compiler related portability</name>
-    </chc>
-    <chc>
-      <key>HARDWARE_RELATED_PORTABILITY</key>
-      <name>Hardware related portability</name>
-    </chc>
-  </chc>
-  <chc>
-    <key>MAINTAINABILITY</key>
-    <name>Maintainability</name>
-    <chc>
-      <key>READABILITY</key>
-      <name>Readability</name>
-    </chc>
-  </chc>
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest/csharp-model.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest/csharp-model.xml
deleted file mode 100644 (file)
index e4569a2..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<sqale>
-  <chc>
-    <key>USABILITY</key>
-    <name>Usability</name>
-    <desc>Estimate usability</desc>
-  </chc>
-  <chc>
-    <key>EFFICIENCY</key>
-    <name>Efficiency</name>
-    <chc>
-      <rule-repo>gendarme</rule-repo>
-      <rule-key>EnsureLocalDisposalRule</rule-key>
-      <prop>
-        <key>remediationFactor</key>
-        <val>0.125</val>
-        <txt>d</txt>
-      </prop>
-      <prop>
-        <key>remediationFunction</key>
-        <txt>linear</txt>
-      </prop>
-    </chc>
-  </chc>
-
-</sqale>
\ No newline at end of file
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest/java-model.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest/java-model.xml
deleted file mode 100644 (file)
index 0b37f56..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<sqale>
-  <chc>
-    <key>USABILITY</key>
-    <name>Usability</name>
-    <desc>Estimate usability</desc>
-  </chc>
-  <chc>
-    <key>EFFICIENCY</key>
-    <name>Efficiency</name>
-    <chc>
-      <rule-repo>squid-cobol</rule-repo>
-      <rule-key>CheckLoop</rule-key>
-      <prop>
-        <key>remediationFactor</key>
-        <val>0.125</val>
-        <txt>d</txt>
-      </prop>
-      <prop>
-        <key>remediationFunction</key>
-        <txt>linear</txt>
-      </prop>
-    </chc>
-  </chc>
-
-</sqale>
\ No newline at end of file
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/ignore_requirement_on_root_characteristics.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/ignore_requirement_on_root_characteristics.xml
deleted file mode 100644 (file)
index bcf3ed8..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<sqale>
-  <chc>
-    <key>EFFICIENCY</key>
-    <name>Efficiency</name>
-    <chc>
-      <rule-repo>checkstyle</rule-repo>
-      <rule-key>Regexp</rule-key>
-      <prop>
-        <key>remediationFactor</key>
-        <val>3.0</val>
-        <txt>h</txt>
-      </prop>
-      <prop>
-        <key>remediationFunction</key>
-        <txt>linear</txt>
-      </prop>
-    </chc>
-  </chc>
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/import_characteristics.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/import_characteristics.xml
deleted file mode 100644 (file)
index bc7f756..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<sqale>
-  <chc>
-    <key>PORTABILITY</key>
-    <name>Portability</name>
-    <chc>
-      <key>COMPILER_RELATED_PORTABILITY</key>
-      <name>Compiler related portability</name>
-    </chc>
-    <chc>
-      <key>HARDWARE_RELATED_PORTABILITY</key>
-      <name>Hardware related portability</name>
-    </chc>
-  </chc>
-  <chc>
-    <key>MAINTAINABILITY</key>
-    <name>Maintainability</name>
-    <chc>
-      <key>READABILITY</key>
-      <name>Readability</name>
-    </chc>
-  </chc>
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_badly-formatted.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_badly-formatted.xml
deleted file mode 100644 (file)
index 6c7d153..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<sqale>
-  <chc>
-    <key>USABILITY
-    </key>
-    <name>Usability
-    </name>
-    <desc>Estimate usability
-    </desc>
-  </chc>
-  <chc>
-    <key>EFFICIENCY
-    </key>
-    <name>Efficiency
-    </name>
-    <chc>
-      <key>MEMORY_EFFICIENCY
-      </key>
-      <name>Memory use
-      </name>
-      <chc>
-        <rule-repo>checkstyle
-        </rule-repo>
-        <rule-key>Regexp
-        </rule-key>
-        <prop>
-          <key>remediationFactor
-          </key>
-          <val>3.0
-          </val>
-          <txt>h
-          </txt>
-        </prop>
-        <prop>
-          <key>remediationFunction
-          </key>
-          <txt>linear
-          </txt>
-        </prop>
-      </chc>
-    </chc>
-  </chc>
-
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_constant_per_file.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_constant_per_file.xml
deleted file mode 100644 (file)
index 4b8ae3f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<sqale>
-  <chc>
-    <key>EFFICIENCY</key>
-    <name>Efficiency</name>
-    <chc>
-      <key>MEMORY_EFFICIENCY</key>
-      <name>Memory use</name>
-      <!-- Should be ignored -->
-      <chc>
-        <rule-repo>checkstyle</rule-repo>
-        <rule-key>Regexp</rule-key>
-        <prop>
-          <key>remediationFactor</key>
-          <val>3.0</val>
-          <txt>h</txt>
-        </prop>
-        <prop>
-          <key>remediationFunction</key>
-          <txt>constant_resource</txt>
-        </prop>
-      </chc>
-    </chc>
-  </chc>
-
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_linear_with_threshold.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_deprecated_linear_with_threshold.xml
deleted file mode 100644 (file)
index 9ebc69b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<sqale>
-  <chc>
-    <key>USABILITY</key>
-    <name>Usability</name>
-    <desc>Estimate usability</desc>
-  </chc>
-  <chc>
-    <key>EFFICIENCY</key>
-    <name>Efficiency</name>
-    <chc>
-      <key>MEMORY_EFFICIENCY</key>
-      <name>Memory use</name>
-      <chc>
-        <rule-repo>checkstyle</rule-repo>
-        <rule-key>Regexp</rule-key>
-        <prop>
-          <key>remediationFunction</key>
-          <!-- Should be replaced by linear -->
-          <txt>linear_threshold</txt>
-        </prop>
-        <prop>
-          <key>remediationFactor</key>
-          <val>3.0</val>
-          <txt>h</txt>
-        </prop>
-        <!-- Should be ignored -->
-        <prop>
-          <key>offset</key>
-          <val>1.0</val>
-          <txt>h</txt>
-        </prop>
-      </chc>
-    </chc>
-  </chc>
-
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear.xml
deleted file mode 100644 (file)
index f641a51..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<sqale>
-  <chc>
-    <key>USABILITY</key>
-    <name>Usability</name>
-    <desc>Estimate usability</desc>
-  </chc>
-  <chc>
-    <key>EFFICIENCY</key>
-    <name>Efficiency</name>
-    <chc>
-      <key>MEMORY_EFFICIENCY</key>
-      <name>Memory use</name>
-      <chc>
-        <rule-repo>checkstyle</rule-repo>
-        <rule-key>Regexp</rule-key>
-        <prop>
-          <key>remediationFactor</key>
-          <val>3.0</val>
-          <txt>h</txt>
-        </prop>
-        <prop>
-          <key>remediationFunction</key>
-          <txt>linear</txt>
-        </prop>
-      </chc>
-    </chc>
-  </chc>
-
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear_with_offset.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldImportXML_with_linear_with_offset.xml
deleted file mode 100644 (file)
index d12f70d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<sqale>
-  <chc>
-    <key>USABILITY</key>
-    <name>Usability</name>
-    <desc>Estimate usability</desc>
-  </chc>
-  <chc>
-    <key>EFFICIENCY</key>
-    <name>Efficiency</name>
-    <chc>
-      <key>MEMORY_EFFICIENCY</key>
-      <name>Memory use</name>
-      <chc>
-        <rule-repo>checkstyle</rule-repo>
-        <rule-key>Regexp</rule-key>
-        <prop>
-          <key>remediationFactor</key>
-          <val>3.0</val>
-          <txt>h</txt>
-        </prop>
-        <prop>
-          <key>remediationFunction</key>
-          <txt>linear</txt>
-        </prop>
-        <prop>
-          <key>offset</key>
-          <val>1.0</val>
-          <txt>h</txt>
-        </prop>
-      </chc>
-    </chc>
-  </chc>
-
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldLogWarningIfRuleNotFound.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldLogWarningIfRuleNotFound.xml
deleted file mode 100644 (file)
index 2898f45..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<sqale>
-  <chc>
-    <key>EFFICIENCY</key>
-    <name>Efficiency</name>
-    <chc>
-      <key>MEMORY_EFFICIENCY</key>
-      <name>Memory use</name>
-      <chc>
-        <rule-repo>findbugs</rule-repo>
-        <rule-key>Foo</rule-key>
-        <prop>
-          <key>remediationFactor</key>
-          <val>3.0</val>
-          <txt>h</txt>
-        </prop>
-        <prop>
-          <key>remediationFunction</key>
-          <txt>linear</txt>
-        </prop>
-      </chc>
-    </chc>
-  </chc>
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldRejectXML_with_invalid_value.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/shouldRejectXML_with_invalid_value.xml
deleted file mode 100644 (file)
index bb6bdbb..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<sqale>
-  <chc>
-    <key>USABILITY</key>
-    <name>Usability</name>
-    <desc>Estimate usability</desc>
-  </chc>
-  <chc>
-    <key>EFFICIENCY</key>
-    <name>Efficiency</name>
-    <chc>
-      <key>MEMORY_EFFICIENCY</key>
-      <name>Memory use</name>
-      <chc>
-        <rule-repo>checkstyle</rule-repo>
-        <rule-key>Regexp</rule-key>
-        <prop>
-          <key>factor</key>
-          <val>abc</val>
-        </prop>
-        <prop>
-          <key>function</key>
-          <txt>linear</txt>
-        </prop>
-      </chc>
-    </chc>
-  </chc>
-
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/use_default_unit_when_no_unit.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/TechnicalDebtXMLImporterTest/use_default_unit_when_no_unit.xml
deleted file mode 100644 (file)
index f83ca79..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-<!--
-  ~ SonarQube, open source software quality management tool.
-  ~ Copyright (C) 2008-2013 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.
-  -->
-
-<sqale>
-  <chc>
-    <key>USABILITY</key>
-    <name>Usability</name>
-    <desc>Estimate usability</desc>
-  </chc>
-  <chc>
-    <key>EFFICIENCY</key>
-    <name>Efficiency</name>
-    <chc>
-      <key>MEMORY_EFFICIENCY</key>
-      <name>Memory use</name>
-      <chc>
-        <rule-repo>checkstyle</rule-repo>
-        <rule-key>Regexp</rule-key>
-        <prop>
-          <key>remediationFactor</key>
-          <val>3.0</val>
-        </prop>
-        <prop>
-          <key>remediationFunction</key>
-          <txt>linear</txt>
-        </prop>
-        <prop>
-          <key>offset</key>
-          <val>1.0</val>
-        </prop>
-      </chc>
-    </chc>
-  </chc>
-
-</sqale>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/disable-result.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/disable-result.xml
deleted file mode 100644 (file)
index 81b97e0..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<dataset>
-
-  <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
-                   created_at="2013-11-20" updated_at="[null]"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/disable.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/disable.xml
deleted file mode 100644 (file)
index a970b32..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<dataset>
-
-  <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/insert_characteristic-result.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/insert_characteristic-result.xml
deleted file mode 100644 (file)
index b6e2d5d..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<dataset>
-
-  <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
-                   created_at="2013-11-20" updated_at="[null]"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/insert_requirement-result.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/insert_requirement-result.xml
deleted file mode 100644 (file)
index 2b1ccb8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<dataset>
-
-  <characteristics id="1" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1" characteristic_order="[null]"
-                   function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
-                   created_at="2013-11-20" updated_at="[null]"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/select_enabled_root_characteristics.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/select_enabled_root_characteristics.xml
deleted file mode 100644 (file)
index c8200af..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<dataset>
-
-  <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-  <characteristics id="2" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="[null]"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-  <!-- requirement -->
-  <characteristics id="3" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1"
-                   function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
-                   created_at="2013-11-20" updated_at="[null]"/>
-
-  <!-- disabled characteristics -->
-  <characteristics id="4" kee="DISABLED_CHARACTERISTIC" name="Disabled characteristic" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="2"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-  <!-- disabled requirement -->
-  <characteristics id="5" kee="[null]" name="[null]" parent_id="4" root_id="4" rule_id="1"
-                   function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-
-  <rules id="1" plugin_rule_key="import" plugin_config_key="regexp" plugin_name="checkstyle" description="[null]" priority="3" status="READY" cardinality="SINGLE" parent_id="[null]" name="Regular exp"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/select_enabled_root_characteristics_order_by_characteristic_order.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/select_enabled_root_characteristics_order_by_characteristic_order.xml
deleted file mode 100644 (file)
index 00a47fd..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-<dataset>
-
-  <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="2"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-  <characteristics id="2" kee="TESTABILITY" name="Testability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-  <characteristics id="3" kee="MAINTAINABILITY" name="Maintainability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="4"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/shared.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/shared.xml
deleted file mode 100644 (file)
index d84c39d..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-<dataset>
-
-  <!-- Root characteristic -->
-  <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-  <!-- Characteristic -->
-  <characteristics id="2" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="[null]"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-  <!-- Requirement -->
-  <characteristics id="3" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1"
-                   function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
-                   created_at="2013-11-20" updated_at="[null]"/>
-
-  <!-- Disabled root characteristic -->
-  <characteristics id="4" kee="DISABLED_ROOT_CHARACTERISTIC" name="Disabled root characteristic" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="2"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-  <!-- Disabled characteristic -->
-  <characteristics id="5" kee="DISABLED_CHARACTERISTIC" name="Disabled characteristic" parent_id="4" root_id="4" rule_id="[null]" characteristic_order="[null]"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-  <!-- Disabled requirement -->
-  <characteristics id="6" kee="[null]" name="[null]" parent_id="5" root_id="4" rule_id="1"
-                   function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-
-  <rules id="1" plugin_rule_key="import" plugin_config_key="regexp" plugin_name="checkstyle" description="[null]" priority="3" status="READY" cardinality="SINGLE" parent_id="[null]" name="Regular exp"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_characteristic-result.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_characteristic-result.xml
deleted file mode 100644 (file)
index 026a505..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<dataset>
-
-  <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="New name" parent_id="[null]" rule_id="[null]" root_id="[null]" characteristic_order="2"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_characteristic.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_characteristic.xml
deleted file mode 100644 (file)
index b4817ec..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<dataset>
-
-  <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
-                   function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
-                   created_at="2013-11-20" updated_at="2013-11-20"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_requirement-result.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_requirement-result.xml
deleted file mode 100644 (file)
index 71c4150..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<dataset>
-
-  <characteristics id="1" kee="[null]" name="[null]" parent_id="3" root_id="1" rule_id="2" characteristic_order="[null]"
-                   function_key="linear" factor_value="21.0" factor_unit="h" offset_value="[null]" offset_unit="[null]" enabled="[false]"
-                   created_at="2013-11-20" updated_at="2013-11-22"/>
-
-</dataset>
diff --git a/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_requirement.xml b/sonar-core/src/test/resources/org/sonar/core/technicaldebt/db/CharacteristicDaoTest/update_requirement.xml
deleted file mode 100644 (file)
index 2b1ccb8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<dataset>
-
-  <characteristics id="1" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1" characteristic_order="[null]"
-                   function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
-                   created_at="2013-11-20" updated_at="[null]"/>
-
-</dataset>
index 3a78d88179f5e97f78a8365a9e20debcac265474..60b571fe4b3cc7be5c84d05c33fe4eb97644f69f 100644 (file)
@@ -38,8 +38,8 @@ 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.debt.DefaultTechnicalDebtManager;
 import org.sonar.core.issue.workflow.Transition;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager;
 import org.sonar.markdown.Markdown;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.issue.ActionService;
index d08ff9f9a6655c1ba6d5387a52dd6533612ba223..ba01ebe965325fe13ae18e18d56cebea4ec5d8af 100644 (file)
@@ -40,6 +40,7 @@ import org.sonar.api.utils.internal.TempFolderCleaner;
 import org.sonar.core.component.SnapshotPerspectives;
 import org.sonar.core.component.db.ComponentDao;
 import org.sonar.core.config.Logback;
+import org.sonar.core.debt.*;
 import org.sonar.core.i18n.DefaultI18n;
 import org.sonar.core.i18n.GwtI18n;
 import org.sonar.core.i18n.RuleI18nManager;
@@ -63,7 +64,6 @@ import org.sonar.core.qualitygate.db.QualityGateConditionDao;
 import org.sonar.core.qualitygate.db.QualityGateDao;
 import org.sonar.core.resource.DefaultResourcePermissions;
 import org.sonar.core.rule.DefaultRuleFinder;
-import org.sonar.core.technicaldebt.*;
 import org.sonar.core.test.TestPlanPerspectiveLoader;
 import org.sonar.core.test.TestablePerspectiveLoader;
 import org.sonar.core.timemachine.Periods;
@@ -384,11 +384,11 @@ public final class Platform {
     // technical debt
     servicesContainer.addSingleton(DebtService.class);
     servicesContainer.addSingleton(TechnicalDebtModelSynchronizer.class);
-    servicesContainer.addSingleton(DebtCharacteristicsSynchronizer.class);
-    servicesContainer.addSingleton(TechnicalDebtModelRepository.class);
+    servicesContainer.addSingleton(CharacteristicsDebtModelSynchronizer.class);
+    servicesContainer.addSingleton(DebtModelPluginRepository.class);
     servicesContainer.addSingleton(TechnicalDebtXMLImporter.class);
-    servicesContainer.addSingleton(RuleDebtXMLImporter.class);
-    servicesContainer.addSingleton(CharacteristicsXMLImporter.class);
+    servicesContainer.addSingleton(RulesDebtModelXMLImporter.class);
+    servicesContainer.addSingleton(CharacteristicsDebtModelXMLImporter.class);
     servicesContainer.addSingleton(DefaultTechnicalDebtManager.class);
 
     // source
index f96f117a0347d490fb71bd92ea64f712e76412ba..6dd2f58a86123c079b463e6d1e89697f6e0bab31 100644 (file)
@@ -30,9 +30,9 @@ import org.sonar.api.rules.RuleRepository;
 import org.sonar.api.server.rule.RuleDefinitions;
 import org.sonar.api.server.rule.RuleParamType;
 import org.sonar.check.Cardinality;
+import org.sonar.core.debt.DebtModelPluginRepository;
+import org.sonar.core.debt.RulesDebtModelXMLImporter;
 import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.core.technicaldebt.RuleDebtXMLImporter;
-import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
 
 import javax.annotation.CheckForNull;
 
@@ -52,24 +52,24 @@ public class DeprecatedRuleDefinitions implements RuleDefinitions {
   private final RuleI18nManager i18n;
   private final RuleRepository[] repositories;
 
-  private final TechnicalDebtModelRepository languageModelFinder;
-  private final RuleDebtXMLImporter importer;
+  private final DebtModelPluginRepository languageModelFinder;
+  private final RulesDebtModelXMLImporter importer;
 
-  public DeprecatedRuleDefinitions(RuleI18nManager i18n, RuleRepository[] repositories, TechnicalDebtModelRepository languageModelFinder, RuleDebtXMLImporter importer) {
+  public DeprecatedRuleDefinitions(RuleI18nManager i18n, RuleRepository[] repositories, DebtModelPluginRepository languageModelFinder, RulesDebtModelXMLImporter importer) {
     this.i18n = i18n;
     this.repositories = repositories;
     this.languageModelFinder = languageModelFinder;
     this.importer = importer;
   }
 
-  public DeprecatedRuleDefinitions(RuleI18nManager i18n, TechnicalDebtModelRepository languageModelFinder, RuleDebtXMLImporter importer) {
+  public DeprecatedRuleDefinitions(RuleI18nManager i18n, DebtModelPluginRepository languageModelFinder, RulesDebtModelXMLImporter importer) {
     this(i18n, new RuleRepository[0], languageModelFinder, importer);
   }
 
   @Override
   public void define(Context context) {
     // Load rule debt definitions from xml files provided by plugin
-    List<RuleDebtXMLImporter.RuleDebt> ruleDebts = loadRuleDebtList();
+    List<RulesDebtModelXMLImporter.RuleDebt> ruleDebts = loadRuleDebtList();
 
     for (RuleRepository repository : repositories) {
       // RuleRepository API does not handle difference between new and extended repositories,
@@ -101,8 +101,8 @@ public class DeprecatedRuleDefinitions implements RuleDefinitions {
     }
   }
 
-  private void updateRuleDebtDefinitions(NewRule newRule, String repoKey, String ruleKey, List<RuleDebtXMLImporter.RuleDebt> ruleDebts){
-    RuleDebtXMLImporter.RuleDebt ruleDebt = findRequirement(ruleDebts, repoKey, ruleKey);
+  private void updateRuleDebtDefinitions(NewRule newRule, String repoKey, String ruleKey, List<RulesDebtModelXMLImporter.RuleDebt> ruleDebts){
+    RulesDebtModelXMLImporter.RuleDebt ruleDebt = findRequirement(ruleDebts, repoKey, ruleKey);
     if (ruleDebt != null) {
       newRule.setCharacteristicKey(ruleDebt.characteristicKey());
       newRule.setRemediationFunction(ruleDebt.function());
@@ -138,15 +138,15 @@ public class DeprecatedRuleDefinitions implements RuleDefinitions {
     return StringUtils.defaultIfBlank(desc, null);
   }
 
-  public List<RuleDebtXMLImporter.RuleDebt> loadRuleDebtList() {
-    List<RuleDebtXMLImporter.RuleDebt> ruleDebtList = newArrayList();
+  public List<RulesDebtModelXMLImporter.RuleDebt> loadRuleDebtList() {
+    List<RulesDebtModelXMLImporter.RuleDebt> ruleDebtList = newArrayList();
     for (String pluginKey : getContributingPluginListWithoutSqale()) {
       ruleDebtList.addAll(loadRuleDebtsFromXml(pluginKey));
     }
     return ruleDebtList;
   }
 
-  public List<RuleDebtXMLImporter.RuleDebt> loadRuleDebtsFromXml(String pluginKey) {
+  public List<RulesDebtModelXMLImporter.RuleDebt> loadRuleDebtsFromXml(String pluginKey) {
     Reader xmlFileReader = null;
     try {
       xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
@@ -158,15 +158,15 @@ public class DeprecatedRuleDefinitions implements RuleDefinitions {
 
   private Collection<String> getContributingPluginListWithoutSqale() {
     Collection<String> pluginList = newArrayList(languageModelFinder.getContributingPluginList());
-    pluginList.remove(TechnicalDebtModelRepository.DEFAULT_MODEL);
+    pluginList.remove(DebtModelPluginRepository.DEFAULT_MODEL);
     return pluginList;
   }
 
   @CheckForNull
-  private RuleDebtXMLImporter.RuleDebt findRequirement(List<RuleDebtXMLImporter.RuleDebt> requirements, final String repoKey, final String ruleKey) {
-    return Iterables.find(requirements, new Predicate<RuleDebtXMLImporter.RuleDebt>() {
+  private RulesDebtModelXMLImporter.RuleDebt findRequirement(List<RulesDebtModelXMLImporter.RuleDebt> requirements, final String repoKey, final String ruleKey) {
+    return Iterables.find(requirements, new Predicate<RulesDebtModelXMLImporter.RuleDebt>() {
       @Override
-      public boolean apply(RuleDebtXMLImporter.RuleDebt input) {
+      public boolean apply(RulesDebtModelXMLImporter.RuleDebt input) {
         return input.ruleKey().equals(RuleKey.of(repoKey, ruleKey));
       }
     }, null);
index 24fd9f7448c3ef1d7c8d82ed9f367622a3024723..11831d563385e1f5e76196d6249953f2400baeef 100644 (file)
@@ -35,11 +35,11 @@ import org.sonar.api.server.rule.RuleDefinitions;
 import org.sonar.api.utils.System2;
 import org.sonar.api.utils.TimeProfiler;
 import org.sonar.check.Cardinality;
+import org.sonar.core.debt.db.CharacteristicDao;
+import org.sonar.core.debt.db.CharacteristicDto;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.qualityprofile.db.ActiveRuleDao;
 import org.sonar.core.rule.*;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
 import org.sonar.server.qualityprofile.ProfilesManager;
 import org.sonar.server.startup.RegisterDebtCharacteristicModel;
 
index 5395740c12739ffcabb8fb9ffb651e44f52476fc..b11a2690ece471223b7298809bee13260989de48 100644 (file)
@@ -24,15 +24,15 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.utils.TimeProfiler;
 import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.technicaldebt.DebtCharacteristicsSynchronizer;
+import org.sonar.core.debt.CharacteristicsDebtModelSynchronizer;
 
 public class RegisterDebtCharacteristicModel {
 
   private static final Logger LOGGER = LoggerFactory.getLogger(RegisterDebtCharacteristicModel.class);
 
-  private final DebtCharacteristicsSynchronizer manager;
+  private final CharacteristicsDebtModelSynchronizer manager;
 
-  public RegisterDebtCharacteristicModel(DebtCharacteristicsSynchronizer manager) {
+  public RegisterDebtCharacteristicModel(CharacteristicsDebtModelSynchronizer manager) {
     this.manager = manager;
   }
 
index 4d84d6e446aa5c85894b34be02a5dabeec87584e..47fa4048d921d05603529f5144a3a2e71a904440 100644 (file)
@@ -24,8 +24,8 @@ import org.slf4j.LoggerFactory;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.api.utils.TimeProfiler;
 import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.technicaldebt.TechnicalDebtModelSynchronizer;
-import org.sonar.core.technicaldebt.TechnicalDebtRuleCache;
+import org.sonar.core.debt.TechnicalDebtModelSynchronizer;
+import org.sonar.core.debt.TechnicalDebtRuleCache;
 import org.sonar.server.rule.RuleRegistration;
 
 public final class RegisterTechnicalDebtModel {
index 55b2cb52a4f1971b66782971568abbb770452d44..9ea942bbd361916e0f2427fe6e511412b9fd1643 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.technicaldebt;
 
 import org.sonar.api.ServerComponent;
 import org.sonar.api.technicaldebt.server.Characteristic;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager;
+import org.sonar.core.debt.DefaultTechnicalDebtManager;
 
 import javax.annotation.CheckForNull;
 
index 5d9c8edeb542cea44f5ec1214c826ba9838c2cdb..345ffaef45855bd2085377833389e3f209a670ee 100644 (file)
@@ -46,10 +46,10 @@ import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.Durations;
 import org.sonar.api.web.UserRole;
 import org.sonar.core.component.ComponentDto;
+import org.sonar.core.debt.DefaultTechnicalDebtManager;
 import org.sonar.core.issue.DefaultActionPlan;
 import org.sonar.core.issue.DefaultIssueQueryResult;
 import org.sonar.core.issue.workflow.Transition;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager;
 import org.sonar.core.user.DefaultUser;
 import org.sonar.server.issue.ActionService;
 import org.sonar.server.issue.IssueChangelog;
index 00fd9e91ece41d07fb21373275bedd456daa1e42..72637b17c751102537d9398e77a7859eac188a17 100644 (file)
@@ -31,9 +31,9 @@ import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.RulePriority;
 import org.sonar.api.rules.RuleRepository;
 import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.core.debt.DebtModelPluginRepository;
+import org.sonar.core.debt.RulesDebtModelXMLImporter;
 import org.sonar.core.i18n.RuleI18nManager;
-import org.sonar.core.technicaldebt.RuleDebtXMLImporter;
-import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
 
 import java.io.Reader;
 import java.util.Arrays;
@@ -52,10 +52,10 @@ public class DeprecatedRuleDefinitionsTest {
   RuleI18nManager i18n;
 
   @Mock
-  TechnicalDebtModelRepository debtModelRepository;
+  DebtModelPluginRepository debtModelRepository;
 
   @Mock
-  RuleDebtXMLImporter importer;
+  RulesDebtModelXMLImporter importer;
 
   static class CheckstyleRules extends RuleRepository {
     public CheckstyleRules() {
@@ -154,8 +154,8 @@ public class DeprecatedRuleDefinitionsTest {
   public void define_rule_debt() throws Exception {
     RuleDefinitions.Context context = new RuleDefinitions.Context();
 
-    List<RuleDebtXMLImporter.RuleDebt> ruleDebts = newArrayList(
-      new RuleDebtXMLImporter.RuleDebt()
+    List<RulesDebtModelXMLImporter.RuleDebt> ruleDebts = newArrayList(
+      new RulesDebtModelXMLImporter.RuleDebt()
         .setCharacteristicKey("MEMORY_EFFICIENCY")
         .setRuleKey(RuleKey.of("checkstyle", "ConstantName"))
         .setFunction(RemediationFunction.LINEAR_OFFSET)
index f3e9b413fa948efb5da6d4a5aeebdcba2809f90f..386cfd35aa17518dc51d946ef398739e03d280cf 100644 (file)
@@ -26,12 +26,12 @@ import org.sonar.api.rule.RemediationFunction;
 import org.sonar.api.rule.RuleStatus;
 import org.sonar.api.rule.Severity;
 import org.sonar.api.server.rule.RuleDefinitions;
+import org.sonar.core.debt.db.CharacteristicDao;
 import org.sonar.core.persistence.AbstractDaoTestCase;
 import org.sonar.core.persistence.MyBatis;
 import org.sonar.core.qualityprofile.db.ActiveRuleDao;
 import org.sonar.core.rule.RuleDao;
 import org.sonar.core.rule.RuleTagDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
 import org.sonar.server.qualityprofile.ProfilesManager;
 import org.sonar.server.startup.RegisterDebtCharacteristicModel;
 
index 0dcd74a24c67b2bb0c24537546d2d7caedeb4e26..d01a6470d006e39f4a159aa0884d559f7ff080e8 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.startup;
 
 import org.junit.Test;
 import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.technicaldebt.DebtCharacteristicsSynchronizer;
+import org.sonar.core.debt.CharacteristicsDebtModelSynchronizer;
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.*;
@@ -31,7 +31,7 @@ public class RegisterDebtCharacteristicModelTest {
 
   @Test
   public void create_model() throws Exception {
-    DebtCharacteristicsSynchronizer synchronizer = mock(DebtCharacteristicsSynchronizer.class);
+    CharacteristicsDebtModelSynchronizer synchronizer = mock(CharacteristicsDebtModelSynchronizer.class);
     RegisterDebtCharacteristicModel sqaleDefinition = new RegisterDebtCharacteristicModel(synchronizer);
 
     sqaleDefinition.start();
index 1e3fcf55f911a6a149137768c913658a40e19930..017e7d5d1dfff307f2caf8f94c96aee3de442e2d 100644 (file)
@@ -22,8 +22,8 @@ package org.sonar.server.startup;
 import org.junit.Test;
 import org.sonar.api.rules.RuleFinder;
 import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.technicaldebt.TechnicalDebtModelSynchronizer;
-import org.sonar.core.technicaldebt.TechnicalDebtRuleCache;
+import org.sonar.core.debt.TechnicalDebtModelSynchronizer;
+import org.sonar.core.debt.TechnicalDebtRuleCache;
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.*;
index b66fc6c26f58329cc31d4c5a4b53632783751e9e..bbddd8ed334e28d53696540e47ef29bd64ba093a 100644 (file)
@@ -23,7 +23,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.technicaldebt.server.Characteristic;
 import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager;
+import org.sonar.core.debt.DefaultTechnicalDebtManager;
 
 import java.util.List;