]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5360 SONAR-5362 Fix update, delete or creation of rule parameters and active...
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 13 Jun 2014 15:56:05 +0000 (17:56 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 13 Jun 2014 15:56:05 +0000 (17:56 +0200)
sonar-server/src/main/java/org/sonar/server/qualityprofile/db/ActiveRuleDao.java
sonar-server/src/main/java/org/sonar/server/rule/Rule.java
sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java
sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java
sonar-server/src/main/java/org/sonar/server/rule/index/RuleDoc.java
sonar-server/src/test/java/org/sonar/server/rule/RuleCreatorMediumTest.java
sonar-server/src/test/java/org/sonar/server/rule/RuleUpdaterMediumTest.java

index 8d61d0128e17c8e06eba9876877173e3204e65d4..66b999fcf57f4cd38d814f7fab9576c2ef77a3c2 100644 (file)
@@ -27,12 +27,7 @@ import org.apache.ibatis.session.ResultHandler;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.System2;
 import org.sonar.core.persistence.DbSession;
-import org.sonar.core.qualityprofile.db.ActiveRuleDto;
-import org.sonar.core.qualityprofile.db.ActiveRuleKey;
-import org.sonar.core.qualityprofile.db.ActiveRuleMapper;
-import org.sonar.core.qualityprofile.db.ActiveRuleParamDto;
-import org.sonar.core.qualityprofile.db.QualityProfileDao;
-import org.sonar.core.qualityprofile.db.QualityProfileKey;
+import org.sonar.core.qualityprofile.db.*;
 import org.sonar.core.rule.RuleDto;
 import org.sonar.server.db.BaseDao;
 import org.sonar.server.rule.db.RuleDao;
@@ -41,6 +36,7 @@ import org.sonar.server.search.action.IndexAction;
 import org.sonar.server.search.action.KeyIndexAction;
 
 import javax.annotation.CheckForNull;
+
 import java.sql.Timestamp;
 import java.util.List;
 import java.util.Map;
@@ -175,8 +171,8 @@ public class ActiveRuleDao extends BaseDao<ActiveRuleMapper, ActiveRuleDto, Acti
   public void deleteParam(DbSession session, ActiveRuleDto activeRule, ActiveRuleParamDto activeRuleParam) {
     Preconditions.checkNotNull(activeRule.getId(), "ActiveRule is not persisted");
     Preconditions.checkNotNull(activeRuleParam.getId(), "ActiveRuleParam is not persisted");
-    mapper(session).updateParameter(activeRuleParam);
-    this.enqueueUpdate(activeRuleParam, activeRule.getKey(), session);
+    mapper(session).deleteParameter(activeRuleParam.getId());
+    this.enqueueDelete(activeRuleParam, activeRule.getKey(), session);
   }
 
   public void deleteByProfileKey(DbSession session, QualityProfileKey profileKey) {
index c918f8c3cda5951d858b79cdd8e77a7f2d2135ca..5237f23c7b1970582eb903639a7c803878b62e55 100644 (file)
@@ -70,6 +70,9 @@ public interface Rule {
 
   List<RuleParam> params();
 
+  @CheckForNull
+  RuleParam param(final String key);
+
   @CheckForNull
   String debtCharacteristicKey();
 
index 14d87785d39a5234a157a763eeb498000dd25556..6e43422287e590bd264ce996106ee6c8b7e8356e 100644 (file)
@@ -115,10 +115,9 @@ public class RuleCreator implements ServerComponent {
 
     for (RuleParamDto templateRuleParamDto : dbClient.ruleDao().findRuleParamsByRuleKey(dbSession, templateRuleDto.getKey())) {
       String newRuleParam = newRule.parameter(templateRuleParamDto.getName());
-      if (newRuleParam == null) {
-        throw new IllegalArgumentException(String.format("The parameter '%s' has not been set", templateRuleParamDto.getName()));
+      if (newRuleParam != null) {
+        createCustomRuleParams(newRuleParam, ruleDto, templateRuleParamDto, dbSession);
       }
-      createCustomRuleParams(newRuleParam, ruleDto, templateRuleParamDto, dbSession);
     }
     return ruleKey;
   }
index 11310a294c8b9db50f6cbfbf5be731db6d9461c1..b74ce3b2725df0a95dbf8c859d730ab4d29ebd28 100644 (file)
@@ -20,6 +20,8 @@
 package org.sonar.server.rule;
 
 import com.google.common.base.Strings;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
 import org.apache.commons.lang.ObjectUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.builder.EqualsBuilder;
@@ -37,12 +39,7 @@ import org.sonar.core.technicaldebt.db.CharacteristicDto;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.user.UserSession;
 
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-
-import static com.google.common.collect.Lists.newArrayList;
+import java.util.*;
 
 public class RuleUpdater implements ServerComponent {
 
@@ -65,11 +62,7 @@ public class RuleUpdater implements ServerComponent {
       // validate only the changes, not all the rule fields
       apply(update, context, userSession);
       dbClient.ruleDao().update(dbSession, context.rule);
-      for (RuleParamDto ruleParamDto : context.parameters) {
-        dbClient.ruleDao().updateRuleParam(dbSession, context.rule, ruleParamDto);
-      }
-      // update related active rules (for custom rules only)
-      updateActiveRule(dbSession, update, context.rule);
+      updateParameters(dbSession, update, context);
       dbSession.commit();
       return true;
 
@@ -78,20 +71,6 @@ public class RuleUpdater implements ServerComponent {
     }
   }
 
-  private void updateActiveRule(DbSession dbSession, RuleUpdate update, RuleDto rule) {
-    if (update.isCustomRule() && update.isChangeParameters()) {
-      for (ActiveRuleDto activeRuleDto : dbClient.activeRuleDao().findByRule(dbSession, rule)) {
-        for (ActiveRuleParamDto activeRuleParamDto : dbClient.activeRuleDao().findParamsByActiveRuleKey(dbSession, activeRuleDto.getKey())) {
-          String newValue = update.getParameters().get(activeRuleParamDto.getKey());
-          if (!Strings.isNullOrEmpty(newValue)) {
-            activeRuleParamDto.setValue(newValue);
-            dbClient.activeRuleDao().updateParam(dbSession, activeRuleDto, activeRuleParamDto);
-          }
-        }
-      }
-    }
-  }
-
   /**
    * Load all the DTOs required for validating changes and updating rule
    */
@@ -103,8 +82,6 @@ public class RuleUpdater implements ServerComponent {
       if (RuleStatus.REMOVED == context.rule.getStatus()) {
         throw new IllegalArgumentException("Rule with REMOVED status cannot be updated: " + change.getRuleKey());
       }
-      context.parameters = dbClient.ruleDao().findRuleParamsByRuleKey(dbSession, change.getRuleKey());
-
       String subCharacteristicKey = change.getDebtSubCharacteristicKey();
       if (subCharacteristicKey != null &&
         !subCharacteristicKey.equals(RuleUpdate.DEFAULT_DEBT_CHARACTERISTIC)) {
@@ -140,9 +117,6 @@ public class RuleUpdater implements ServerComponent {
     if (update.isChangeStatus()) {
       updateStatus(update, context);
     }
-    if (update.isChangeParameters()) {
-      updateParameters(update, context);
-    }
     if (update.isChangeMarkdownNote()) {
       updateMarkdownNote(update, context, userSession);
     }
@@ -194,19 +168,6 @@ public class RuleUpdater implements ServerComponent {
     }
   }
 
-  /**
-   * Only update existing parameters, ignore the ones that are not existing in the list
-   */
-  private void updateParameters(RuleUpdate update, Context context) {
-    for (RuleParamDto ruleParamDto : context.parameters) {
-      String value = update.parameter(ruleParamDto.getName());
-      if (!Strings.isNullOrEmpty(value)) {
-        ruleParamDto.setDefaultValue(value);
-      }
-      // Ignore parameter not existing in update.getParameters()
-    }
-  }
-
   private void updateTags(RuleUpdate update, Context context) {
     Set<String> tags = update.getTags();
     if (tags == null || tags.isEmpty()) {
@@ -225,7 +186,7 @@ public class RuleUpdater implements ServerComponent {
       context.rule.setRemediationCoefficient(null);
       context.rule.setRemediationOffset(null);
 
-    } else if (update.getDebtSubCharacteristicKey().equals(RuleUpdate.DEFAULT_DEBT_CHARACTERISTIC)) {
+    } else if (StringUtils.equals(update.getDebtSubCharacteristicKey(), RuleUpdate.DEFAULT_DEBT_CHARACTERISTIC)) {
       // reset to default
       context.rule.setSubCharacteristicId(null);
       context.rule.setRemediationFunction(null);
@@ -293,12 +254,87 @@ public class RuleUpdater implements ServerComponent {
       .isEquals();
   }
 
+
+  private void updateParameters(DbSession dbSession, RuleUpdate update, Context context) {
+    if (update.isChangeParameters() && update.isCustomRule()) {
+      RuleDto customRule = context.rule;
+      RuleDto templateRule = dbClient.ruleDao().getById(dbSession, customRule.getTemplateId());
+      List<RuleParamDto> templateRuleParams = dbClient.ruleDao().findRuleParamsByRuleKey(dbSession, templateRule.getKey());
+      List<String> paramKeys = new ArrayList<String>();
+
+      // Load active rules and its parameters in cache
+      Multimap<RuleDto, ActiveRuleDto> activeRules = ArrayListMultimap.create();
+      Multimap<ActiveRuleDto, ActiveRuleParamDto> activeRuleParams = ArrayListMultimap.create();
+      for (ActiveRuleDto activeRuleDto : dbClient.activeRuleDao().findByRule(dbSession, customRule)) {
+        activeRules.put(customRule, activeRuleDto);
+        for (ActiveRuleParamDto activeRuleParamDto : dbClient.activeRuleDao().findParamsByActiveRuleKey(dbSession, activeRuleDto.getKey())) {
+          activeRuleParams.put(activeRuleDto, activeRuleParamDto);
+        }
+      }
+
+      // Browse custom rule parameters to update or delete them
+      for (RuleParamDto ruleParamDto : dbClient.ruleDao().findRuleParamsByRuleKey(dbSession, update.getRuleKey())) {
+        String key = ruleParamDto.getName();
+        String value = update.parameter(key);
+        if (!Strings.isNullOrEmpty(value)) {
+          // Update rule param
+          ruleParamDto.setDefaultValue(value);
+          dbClient.ruleDao().updateRuleParam(dbSession, customRule, ruleParamDto);
+
+          // Update linked active rule params
+          for (ActiveRuleDto activeRuleDto : activeRules.get(customRule)) {
+            for (ActiveRuleParamDto activeRuleParamDto : activeRuleParams.get(activeRuleDto)) {
+              if (activeRuleParamDto.getKey().equals(key)) {
+                dbClient.activeRuleDao().updateParam(dbSession, activeRuleDto, activeRuleParamDto.setValue(value));
+              }
+            }
+          }
+        } else {
+          // Delete rule param
+          dbClient.ruleDao().removeRuleParam(dbSession, customRule, ruleParamDto);
+
+          // Delete linked active rule params
+          for (ActiveRuleDto activeRuleDto : activeRules.get(customRule)) {
+            for (ActiveRuleParamDto activeRuleParamDto : activeRuleParams.get(activeRuleDto)) {
+              if (activeRuleParamDto.getKey().equals(key)) {
+                dbClient.activeRuleDao().deleteParam(dbSession, activeRuleDto, activeRuleParamDto);
+              }
+            }
+          }
+        }
+        paramKeys.add(key);
+      }
+
+      // Browse template rule parameters to create new parameters
+      for (RuleParamDto templateRuleParam : templateRuleParams) {
+        String key = templateRuleParam.getName();
+        if (!paramKeys.contains(key)) {
+          String value = update.parameter(key);
+          if (!Strings.isNullOrEmpty(value)) {
+
+            // Create new param
+            RuleParamDto paramDto = RuleParamDto.createFor(customRule)
+              .setName(key)
+              .setDescription(templateRuleParam.getDescription())
+              .setDefaultValue(value)
+              .setType(templateRuleParam.getType());
+            dbClient.ruleDao().addRuleParam(dbSession, customRule, paramDto);
+
+            // Create new active rule param
+            for (ActiveRuleDto activeRuleDto : activeRules.get(customRule)) {
+              dbClient.activeRuleDao().addParam(dbSession, activeRuleDto, ActiveRuleParamDto.createFor(paramDto).setValue(value));
+            }
+          }
+        }
+      }
+    }
+  }
+
   /**
    * Data loaded before update
    */
   private static class Context {
     private RuleDto rule;
-    private List<RuleParamDto> parameters = newArrayList();
     private CharacteristicDto newCharacteristic;
   }
 
index 2847be7f87c78dcdd0901c7a8f869207ba742fb7..960baebd6a5a211a1176fa0618cd3b62af2212bc 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.server.rule.index;
 
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.rule.RuleStatus;
@@ -29,7 +31,9 @@ import org.sonar.server.rule.RuleParam;
 import org.sonar.server.search.BaseDoc;
 import org.sonar.server.search.IndexUtils;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
+
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -154,6 +158,17 @@ public class RuleDoc extends BaseDoc implements Rule {
     return params;
   }
 
+  @CheckForNull
+  @Override
+  public RuleParam param(final String key) {
+    return Iterables.find(params(), new Predicate<RuleParam>() {
+      @Override
+      public boolean apply(@Nullable RuleParam input) {
+        return input != null && input.key().equals(key);
+      }
+    }, null);
+  }
+
   @Override
   public String debtCharacteristicKey() {
     return (String) getNullableField(RuleNormalizer.RuleField.CHARACTERISTIC.field());
index edc6677b072557ebbbec69ee01d0a7ca09ca02d9..fd6cb7435a577524f5441f7d824b48c420406258 100644 (file)
@@ -111,6 +111,26 @@ public class RuleCreatorMediumTest {
     assertThat(param.getDefaultValue()).isEqualTo("a.*");
   }
 
+  @Test
+  public void not_fail_to_create_custom_rule_when_a_param_is_missing() throws Exception {
+    // insert template rule
+    RuleDto templateRule = createTemplateRule();
+
+    NewRule newRule = new NewRule()
+      .setRuleKey("CUSTOM_RULE")
+      .setTemplateKey(templateRule.getKey())
+      .setName("My custom")
+      .setHtmlDescription("Some description")
+      .setSeverity(Severity.MAJOR)
+      .setStatus(RuleStatus.READY);
+
+    RuleKey customRuleKey = creator.create(newRule);
+    dbSession.clearCache();
+
+    List<RuleParamDto> params = db.ruleDao().findRuleParamsByRuleKey(dbSession, customRuleKey);
+    assertThat(params).hasSize(0);
+  }
+
   @Test
   public void fail_to_create_custom_rule_when_missing_key() throws Exception {
     // insert template rule
@@ -318,28 +338,7 @@ public class RuleCreatorMediumTest {
     }
   }
 
-  @Test
-  public void fail_to_create_custom_rule_when_a_param_is_missing() throws Exception {
-    // insert template rule
-    RuleDto templateRule = createTemplateRule();
-
-    NewRule newRule = new NewRule()
-      .setRuleKey("CUSTOM_RULE")
-      .setTemplateKey(templateRule.getKey())
-      .setName("My custom")
-      .setHtmlDescription("Some description")
-      .setSeverity(Severity.MAJOR)
-      .setStatus(RuleStatus.READY);
-
-    try {
-      creator.create(newRule);
-      fail();
-    } catch (Exception e) {
-      assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The parameter 'regex' has not been set");
-    }
-  }
-
-  private RuleDto createTemplateRule(){
+  private RuleDto createTemplateRule() {
     RuleDto templateRule = dao.insert(dbSession,
       RuleTesting.newDto(RuleKey.of("java", "S001"))
         .setIsTemplate(true)
@@ -352,7 +351,7 @@ public class RuleCreatorMediumTest {
         .setEffortToFixDescription("desc")
         .setTags(Sets.newHashSet("usertag1", "usertag2"))
         .setSystemTags(Sets.newHashSet("tag1", "tag4"))
-    );
+      );
     RuleParamDto ruleParamDto = RuleParamDto.createFor(templateRule).setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*");
     dao.addRuleParam(dbSession, templateRule, ruleParamDto);
     dbSession.commit();
index b7ac34b46391ad2b16d1c8d97168da7e9772f235..08748a5b3b876a0bec5ec26ca5fc4ad79ff84c64 100644 (file)
@@ -365,16 +365,21 @@ public class RuleUpdaterMediumTest {
 
   @Test
   public void update_active_rule_parameters_when_updating_custom_rule() throws Exception {
-    // Create template rule with a parameter
+    // Create template rule with 3 parameters
     RuleDto templateRule = RuleTesting.newTemplateRule(RuleKey.of("java", "S001")).setLanguage("xoo");
     ruleDao.insert(dbSession, templateRule);
-    RuleParamDto templateRuleParam = RuleParamDto.createFor(templateRule).setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*");
-    ruleDao.addRuleParam(dbSession, templateRule, templateRuleParam);
-
-    // Create custom rule with a parameter
+    RuleParamDto templateRuleParam1 = RuleParamDto.createFor(templateRule).setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*");
+    ruleDao.addRuleParam(dbSession, templateRule, templateRuleParam1);
+    RuleParamDto templateRuleParam2 = RuleParamDto.createFor(templateRule).setName("format").setType("STRING").setDescription("format").setDefaultValue("csv");
+    ruleDao.addRuleParam(dbSession, templateRule, templateRuleParam2);
+    RuleParamDto templateRuleParam3 = RuleParamDto.createFor(templateRule).setName("message").setType("STRING").setDescription("message");
+    ruleDao.addRuleParam(dbSession, templateRule, templateRuleParam3);
+
+    // Create custom rule with 2 parameters
     RuleDto customRule = RuleTesting.newCustomRule(templateRule).setSeverity(Severity.MAJOR).setLanguage("xoo");
     ruleDao.insert(dbSession, customRule);
-    ruleDao.addRuleParam(dbSession, customRule, templateRuleParam.setDefaultValue("a.*"));
+    ruleDao.addRuleParam(dbSession, customRule, templateRuleParam1.setDefaultValue("a.*"));
+    ruleDao.addRuleParam(dbSession, customRule, templateRuleParam2.setDefaultValue("txt"));
 
     // Create a quality profile
     QualityProfileKey qualityProfileKey = QualityProfileKey.of("P1", "xoo");
@@ -390,14 +395,31 @@ public class RuleUpdaterMediumTest {
 
     dbSession.clearCache();
 
-    // Update custom rule parameter
+    // Update custom rule parameter 'regex', add 'message' and remove 'format'
     RuleUpdate update = RuleUpdate.createForCustomRule(customRule.getKey())
-      .setParameters(ImmutableMap.of("regex", "b.*"));
+      .setParameters(ImmutableMap.of("regex", "b.*", "message", "a message"));
     updater.update(update, UserSession.get());
 
-    // Verify active rule parameter has been updated
+    dbSession.clearCache();
+
+    // Verify custom rule parameters has been updated
+    Rule customRuleReloaded = ruleIndex.getByKey(customRule.getKey());
+    assertThat(customRuleReloaded.params()).hasSize(2);
+    assertThat(customRuleReloaded.param("regex")).isNotNull();
+    assertThat(customRuleReloaded.param("regex").defaultValue()).isEqualTo("b.*");
+    assertThat(customRuleReloaded.param("message")).isNotNull();
+    assertThat(customRuleReloaded.param("message").defaultValue()).isEqualTo("a message");
+    assertThat(customRuleReloaded.param("format")).isNull();
+
+    RuleParam param = customRuleReloaded.params().get(0);
+    assertThat(param.defaultValue()).isEqualTo("b.*");
+
+    // Verify active rule parameters has been updated
     ActiveRule activeRule = tester.get(ActiveRuleIndex.class).getByKey(ActiveRuleKey.of(qualityProfileKey, customRule.getKey()));
+    assertThat(activeRule.params()).hasSize(2);
     assertThat(activeRule.params().get("regex")).isEqualTo("b.*");
+    assertThat(activeRule.params().get("format")).isNull();
+    assertThat(activeRule.params().get("message")).isEqualTo("a message");
 
     // Verify that severity has not changed
     assertThat(activeRule.severity()).isEqualTo(Severity.BLOCKER);