diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-01-08 11:23:06 +0100 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-01-08 11:23:06 +0100 |
commit | 70341b03d1baaa714a6c6fc5c2e74b2a74ca461f (patch) | |
tree | 68259c7328a915a6f84d17f6a3a65ec75b52b683 /sonar-server/src | |
parent | 6ff546803495562681716b3a2abe65504d6435a7 (diff) | |
download | sonarqube-70341b03d1baaa714a6c6fc5c2e74b2a74ca461f.tar.gz sonarqube-70341b03d1baaa714a6c6fc5c2e74b2a74ca461f.zip |
SONAR-4923 Load active rule parent from E/S instead of db
Diffstat (limited to 'sonar-server/src')
15 files changed, 227 insertions, 268 deletions
diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/ProfileRuleChanged.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/ProfileRuleChanged.java index 76996df678f..603f74f7a2e 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/ProfileRuleChanged.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/ProfileRuleChanged.java @@ -24,10 +24,12 @@ package org.sonar.server.qualityprofile; public class ProfileRuleChanged { private QProfile profile; + private QProfile parentProfile; private QProfileRule rule; - public ProfileRuleChanged(QProfile profile, QProfileRule rule) { + public ProfileRuleChanged(QProfile profile, QProfile parentProfile, QProfileRule rule) { this.profile = profile; + this.parentProfile = parentProfile; this.rule = rule; } @@ -35,6 +37,10 @@ public class ProfileRuleChanged { return profile; } + public QProfile parentProfile() { + return parentProfile; + } + public QProfileRule rule() { return rule; } diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java index fd4890a9913..932cef26ba4 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperations.java @@ -207,7 +207,7 @@ public class QProfileActiveRuleOperations implements ServerComponent { try { RuleInheritanceActions actions = new RuleInheritanceActions(); - ActiveRuleDto parent = activeRuleDao.selectParent(activeRule.getId(), session); + ActiveRuleDto parent = activeRuleDao.selectById(activeRule.getParentId(), session); // Restore all parameters from parent List<ActiveRuleParamDto> parentParams = activeRuleDao.selectParamsByActiveRuleId(parent.getId(), session); diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRule.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRule.java index ebadde62678..837c52f1508 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRule.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileRule.java @@ -37,13 +37,14 @@ import java.util.Map; public class QProfileRule { private final Integer id; + private final Integer parentId; private final String key; private final String repositoryKey; private final String name; private final String description; private final String status; private final String cardinality; - private final Integer parentId; + private final Integer ruleId; private final Date createdAt; private final Date updatedAt; private final QProfileRuleNote ruleNote; @@ -63,7 +64,7 @@ public class QProfileRule { description = (String) ruleSource.get(RuleDocument.FIELD_DESCRIPTION); status = (String) ruleSource.get(RuleDocument.FIELD_STATUS); cardinality = (String) ruleSource.get("cardinality"); - parentId = (Integer) ruleSource.get(RuleDocument.FIELD_PARENT_KEY); + ruleId = (Integer) ruleSource.get(RuleDocument.FIELD_PARENT_KEY); createdAt = parseOptionalDate(RuleDocument.FIELD_CREATED_AT, ruleSource); updatedAt = parseOptionalDate(RuleDocument.FIELD_UPDATED_AT, ruleSource); @@ -84,10 +85,12 @@ public class QProfileRule { severity = (String) ruleSource.get(ActiveRuleDocument.FIELD_SEVERITY); inheritance = null; activeRuleNote = null; + parentId = null; } else { activeRuleId = (Integer) activeRuleSource.get(ActiveRuleDocument.FIELD_ID); severity = (String) activeRuleSource.get(ActiveRuleDocument.FIELD_SEVERITY); inheritance = (String) activeRuleSource.get(ActiveRuleDocument.FIELD_INHERITANCE); + parentId = (Integer) activeRuleSource.get(ActiveRuleDocument.FIELD_PARENT_ID); if (activeRuleSource.containsKey(ActiveRuleDocument.FIELD_NOTE)) { Map<String, Object> ruleNoteDocument = (Map<String, Object>) activeRuleSource.get(ActiveRuleDocument.FIELD_NOTE); @@ -187,6 +190,11 @@ public class QProfileRule { } @CheckForNull + public Integer ruleId() { + return ruleId; + } + + @CheckForNull public Integer parentId() { return parentId; } @@ -204,7 +212,7 @@ public class QProfileRule { } public boolean isEditable() { - return parentId != null; + return ruleId != null; } public List<QProfileRuleParam> params() { diff --git a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java index 3efe0d21145..9095be6bcc6 100644 --- a/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java +++ b/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java @@ -48,6 +48,8 @@ import static com.google.common.collect.Lists.newArrayList; */ public class QProfiles implements ServerComponent { + private static final String LANGUAGE_PARAM = "language"; + private final QualityProfileDao qualityProfileDao; private final ActiveRuleDao activeRuleDao; private final RuleDao ruleDao; @@ -182,7 +184,7 @@ public class QProfiles implements ServerComponent { } public void removeProjectByLanguage(String language, long projectId) { - Validation.checkMandatoryParameter(language, "language"); + Validation.checkMandatoryParameter(language, LANGUAGE_PARAM); ComponentDto project = (ComponentDto) findProjectNotNull(projectId); projectService.removeProject(language, project, UserSession.get()); @@ -267,9 +269,9 @@ public class QProfiles implements ServerComponent { String sanitizedNote = Strings.emptyToNull(note); if (sanitizedNote != null) { activeRuleOperations.updateActiveRuleNote(activeRule, note, UserSession.get()); - } else { - // Empty note -> do nothing } + // Empty note -> do nothing + return rules.getFromActiveRuleId(activeRule.getId()); } @@ -279,38 +281,11 @@ public class QProfiles implements ServerComponent { return rules.getFromActiveRuleId(activeRule.getId()); } - /** - * Used to load ancestor param of an active rule param - * <p/> - * TODO Ancestor params should be integrated into QProfileRuleParam or elsewhere in order to load all ancestor params once a time - */ - @CheckForNull - public ActiveRuleParamDto activeRuleParam(QProfileRule rule, String key) { - return findActiveRuleParam(activeRuleId(rule), key); - - } - - /** - * Used to load ancestor active rule of a profile rule - * <p/> - * TODO Ancestor active rules should be integrated into QProfileRule or elsewhere in order to load all ancestor active rules once a time - */ @CheckForNull public QProfileRule parentProfileRule(QProfileRule rule) { - ActiveRuleDto parent = activeRuleDao.selectParent(activeRuleId(rule)); - if (parent != null) { - return rules.getFromActiveRuleId(parent.getId()); - } - return null; + return rules.getFromActiveRuleId(rule.parentId()); } - private Integer activeRuleId(QProfileRule rule) { - Integer activeRuleId = rule.activeRuleId(); - if (activeRuleId == null) { - throw new IllegalArgumentException("Active rule id can't be null"); - } - return activeRuleId; - } // RULES @@ -353,6 +328,7 @@ public class QProfiles implements ServerComponent { } public int countActiveRules(QProfileRule rule){ + // TODO get it from E/S return activeRuleDao.selectByRuleId(rule.id()).size(); } @@ -363,7 +339,7 @@ public class QProfiles implements ServerComponent { private void validateNewProfile(String name, String language) { validateProfileName(name); - Validation.checkMandatoryParameter(language, "language"); + Validation.checkMandatoryParameter(language, LANGUAGE_PARAM); checkNotAlreadyExists(name, language); } @@ -502,12 +478,23 @@ public class QProfiles implements ServerComponent { return activeRuleDao.selectParamByActiveRuleAndKey(activeRuleId, key); } + @CheckForNull + private QProfile findParent(QProfile profile){ + QualityProfileDto parent = findQualityProfile(profile.parent(), profile.language()); + if (parent != null) { + return QProfile.from(parent); + } + return null; + } + private ProfileRuleChanged activeRuleChanged(QualityProfileDto qualityProfile, ActiveRuleDto activeRule) { - return new ProfileRuleChanged(QProfile.from(qualityProfile), rules.getFromActiveRuleId(activeRule.getId())); + QProfile profile = QProfile.from(qualityProfile); + return new ProfileRuleChanged(profile, findParent(profile), rules.getFromActiveRuleId(activeRule.getId())); } private ProfileRuleChanged activeRuleChanged(QualityProfileDto qualityProfile, RuleDto rule) { - return new ProfileRuleChanged(QProfile.from(qualityProfile), rules.getFromRuleId(rule.getId())); + QProfile profile = QProfile.from(qualityProfile); + return new ProfileRuleChanged(profile, findParent(profile), rules.getFromRuleId(rule.getId())); } } diff --git a/sonar-server/src/main/java/org/sonar/server/rule/ActiveRuleDocument.java b/sonar-server/src/main/java/org/sonar/server/rule/ActiveRuleDocument.java index 2db1b5f48a0..9e8ca6aa0f3 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule/ActiveRuleDocument.java +++ b/sonar-server/src/main/java/org/sonar/server/rule/ActiveRuleDocument.java @@ -23,6 +23,7 @@ package org.sonar.server.rule; public class ActiveRuleDocument { public static final String FIELD_ID = "id"; + public static final String FIELD_PARENT_ID = "parentId"; public static final String FIELD_SEVERITY = "severity"; public static final String FIELD_PROFILE_ID = "profileId"; public static final String FIELD_INHERITANCE = "inheritance"; diff --git a/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistry.java b/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistry.java index 3a2f4d0aad0..a2c43327ee4 100644 --- a/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistry.java +++ b/sonar-server/src/main/java/org/sonar/server/rule/RuleRegistry.java @@ -21,19 +21,18 @@ package org.sonar.server.rule; import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Lists; import com.google.common.collect.Multimap; +import org.apache.ibatis.session.SqlSession; import org.elasticsearch.ElasticSearchException; import org.elasticsearch.common.collect.Maps; import org.elasticsearch.common.io.BytesStream; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; -import org.sonar.api.database.DatabaseSession; import org.sonar.api.rule.Severity; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.ActiveRuleParam; import org.sonar.api.rules.Rule; import org.sonar.api.utils.TimeProfiler; +import org.sonar.core.persistence.MyBatis; +import org.sonar.core.qualityprofile.db.ActiveRuleDao; import org.sonar.core.qualityprofile.db.ActiveRuleDto; import org.sonar.core.qualityprofile.db.ActiveRuleParamDto; import org.sonar.core.rule.RuleDao; @@ -48,6 +47,8 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import static com.google.common.collect.Lists.newArrayList; + /** * Fill search index with rules * @@ -62,14 +63,16 @@ public class RuleRegistry { private static final String PARAM_NAMEORKEY = "nameOrKey"; private static final String PARAM_STATUS = "status"; - private SearchIndex searchIndex; - private RuleDao ruleDao; - private DatabaseSession session; + private final SearchIndex searchIndex; + private final RuleDao ruleDao; + private final ActiveRuleDao activeRuleDao; + private final MyBatis myBatis; - public RuleRegistry(SearchIndex searchIndex, RuleDao ruleDao, DatabaseSession session) { + public RuleRegistry(SearchIndex searchIndex, RuleDao ruleDao, ActiveRuleDao activeRuleDao, MyBatis myBatis) { this.searchIndex = searchIndex; this.ruleDao = ruleDao; - this.session = session; + this.activeRuleDao = activeRuleDao; + this.myBatis = myBatis; } public void start() { @@ -90,23 +93,29 @@ public class RuleRegistry { paramsByRule.put(param.getRuleId(), param); } - try { - bulkIndex(rules, paramsByRule); - } catch (IOException ioe) { - throw new IllegalStateException("Unable to index rules", ioe); - } + String[] ids = bulkIndexRules(rules, paramsByRule); + removeDeletedRules(ids); } public void bulkRegisterActiveRules() { - TimeProfiler profiler = new TimeProfiler(); - profiler.start("Rebuilding active rules index - query"); - List<ActiveRule> rules = session.getResults(ActiveRule.class); - profiler.stop(); - + SqlSession session = myBatis.openSession(); try { - bulkIndex(rules); - } catch (IOException ioe) { - throw new IllegalStateException("Unable to index active rules", ioe); + TimeProfiler profiler = new TimeProfiler(); + profiler.start("Rebuilding active rules index - query"); + + List<ActiveRuleDto> activeRules = activeRuleDao.selectAll(session); + List<ActiveRuleParamDto> activeRuleParams = activeRuleDao.selectAllParams(session); + profiler.stop(); + + Multimap<Integer, ActiveRuleParamDto> paramsByActiveRule = ArrayListMultimap.create(); + for (ActiveRuleParamDto param : activeRuleParams) { + paramsByActiveRule.put(param.getActiveRuleId(), param); + } + + String[] ids = bulkIndexActiveRules(activeRules, paramsByActiveRule); + removeDeletedActiveRules(ids); + } finally { + MyBatis.closeQuietly(session); } } @@ -140,7 +149,7 @@ public class RuleRegistry { } try { - List<Integer> result = Lists.newArrayList(); + List<Integer> result = newArrayList(); for (String docId : searchIndex.findDocumentIds(searchQuery)) { result.add(Integer.parseInt(docId)); } @@ -177,27 +186,35 @@ public class RuleRegistry { } } - private void bulkIndex(List<RuleDto> rules, Multimap<Integer, RuleParamDto> paramsByRule) throws IOException { - String[] ids = new String[rules.size()]; - BytesStream[] docs = new BytesStream[rules.size()]; - int index = 0; - TimeProfiler profiler = new TimeProfiler(); - profiler.start("Build rules documents"); - for (RuleDto rule : rules) { - ids[index] = rule.getId().toString(); - docs[index] = ruleDocument(rule, paramsByRule.get(rule.getId())); - index++; - } - profiler.stop(); - - if (!rules.isEmpty()) { - profiler.start("Index rules"); - searchIndex.bulkIndex(INDEX_RULES, TYPE_RULE, ids, docs); + private String[] bulkIndexRules(List<RuleDto> rules, Multimap<Integer, RuleParamDto> paramsByRule) { + try { + String[] ids = new String[rules.size()]; + BytesStream[] docs = new BytesStream[rules.size()]; + int index = 0; + TimeProfiler profiler = new TimeProfiler(); + profiler.start("Build rules documents"); + for (RuleDto rule : rules) { + ids[index] = rule.getId().toString(); + docs[index] = ruleDocument(rule, paramsByRule.get(rule.getId())); + index++; + } profiler.stop(); + + if (!rules.isEmpty()) { + profiler.start("Index rules"); + searchIndex.bulkIndex(INDEX_RULES, TYPE_RULE, ids, docs); + profiler.stop(); + } + return ids; + } catch (IOException ioe) { + throw new IllegalStateException("Unable to index rules", ioe); } + } + private void removeDeletedRules(String[] ids) { List<String> indexIds = searchIndex.findDocumentIds(SearchQuery.create().index(INDEX_RULES).type(TYPE_RULE)); indexIds.removeAll(Arrays.asList(ids)); + TimeProfiler profiler = new TimeProfiler(); if (!indexIds.isEmpty()) { profiler.start("Remove deleted rule documents"); searchIndex.bulkDelete(INDEX_RULES, TYPE_RULE, indexIds.toArray(new String[0])); @@ -205,48 +222,58 @@ public class RuleRegistry { } } - private void bulkIndex(List<ActiveRule> rules) throws IOException { - String[] ids = new String[rules.size()]; - BytesStream[] docs = new BytesStream[rules.size()]; - String[] parentIds = new String[rules.size()]; - int index = 0; - TimeProfiler profiler = new TimeProfiler(); - profiler.start("Build active rules documents"); - for (ActiveRule rule : rules) { - ids[index] = rule.getId().toString(); - docs[index] = activeRuleDocument(rule); - parentIds[index] = rule.getRule().getId().toString(); - index++; - } - profiler.stop(); - - if (!rules.isEmpty()) { - profiler.start("Index active rules"); - searchIndex.bulkIndex(INDEX_RULES, TYPE_ACTIVE_RULE, ids, docs, parentIds); - profiler.stop(); - } - - List<String> indexIds = searchIndex.findDocumentIds(SearchQuery.create().index(INDEX_RULES).type(TYPE_ACTIVE_RULE)); - indexIds.removeAll(Arrays.asList(ids)); - profiler.start("Remove deleted active rule documents"); - bulkDeleteActiveRules(indexIds); - profiler.stop(); - } - public void deleteActiveRules(List<Integer> activeRuleIds) { - List<String> indexIds = Lists.newArrayList(); - for (Integer ruleId: activeRuleIds) { + List<String> indexIds = newArrayList(); + for (Integer ruleId : activeRuleIds) { indexIds.add(ruleId.toString()); } bulkDeleteActiveRules(indexIds); } protected void bulkDeleteActiveRules(List<String> indexIds) { - if (! indexIds.isEmpty()) { + if (!indexIds.isEmpty()) { searchIndex.bulkDelete(INDEX_RULES, TYPE_ACTIVE_RULE, indexIds.toArray(new String[0])); } } + public String[] bulkIndexActiveRules(List<ActiveRuleDto> activeRules, Multimap<Integer, ActiveRuleParamDto> paramsByActiveRule) { + try { + int size = activeRules.size(); + String[] ids = new String[size]; + BytesStream[] docs = new BytesStream[size]; + String[] parentIds = new String[size]; + int index = 0; + + TimeProfiler profiler = new TimeProfiler(); + profiler.start("Build active rules documents"); + for (ActiveRuleDto activeRule : activeRules) { + ids[index] = activeRule.getId().toString(); + docs[index] = activeRuleDocument(activeRule, paramsByActiveRule.get(activeRule.getId())); + parentIds[index] = activeRule.getRulId().toString(); + index++; + } + profiler.stop(); + + if (!activeRules.isEmpty()) { + profiler.start("Index active rules"); + searchIndex.bulkIndex(INDEX_RULES, TYPE_ACTIVE_RULE, ids, docs, parentIds); + profiler.stop(); + } + return ids; + } catch (IOException e) { + throw new IllegalStateException("Unable to index active rules", e); + } + } + + private void removeDeletedActiveRules(String[] ids) { + TimeProfiler profiler = new TimeProfiler(); + List<String> indexIds = searchIndex.findDocumentIds(SearchQuery.create().index(INDEX_RULES).type(TYPE_ACTIVE_RULE)); + indexIds.removeAll(newArrayList(ids)); + profiler.start("Remove deleted active rule documents"); + bulkDeleteActiveRules(indexIds); + profiler.stop(); + } + private XContentBuilder ruleDocument(RuleDto rule, Collection<RuleParamDto> params) throws IOException { XContentBuilder document = XContentFactory.jsonBuilder() .startObject() @@ -286,60 +313,11 @@ public class RuleRegistry { return document; } - private XContentBuilder activeRuleDocument(ActiveRule rule) throws IOException { - XContentBuilder document = XContentFactory.jsonBuilder() - .startObject() - .field(ActiveRuleDocument.FIELD_ID, rule.getId()) - .field(ActiveRuleDocument.FIELD_SEVERITY, rule.getSeverity()) - .field(ActiveRuleDocument.FIELD_PROFILE_ID, rule.getRulesProfile().getId()) - .field(ActiveRuleDocument.FIELD_INHERITANCE, rule.getInheritance()); - if (rule.getNoteData() != null || rule.getNoteUserLogin() != null) { - document.startObject(RuleDocument.FIELD_NOTE) - .field(ActiveRuleDocument.FIELD_NOTE_DATA, rule.getNoteData()) - .field(ActiveRuleDocument.FIELD_NOTE_USER_LOGIN, rule.getNoteUserLogin()) - .field(ActiveRuleDocument.FIELD_NOTE_CREATED_AT, rule.getNoteCreatedAt()) - .field(ActiveRuleDocument.FIELD_NOTE_UPDATED_AT, rule.getNoteUpdatedAt()) - .endObject(); - } - if (!rule.getActiveRuleParams().isEmpty()) { - document.startArray(ActiveRuleDocument.FIELD_PARAMS); - for (ActiveRuleParam param : rule.getActiveRuleParams()) { - document.startObject() - .field(ActiveRuleDocument.FIELD_PARAM_KEY, param.getKey()) - .field(ActiveRuleDocument.FIELD_PARAM_VALUE, param.getValue()) - .endObject(); - } - document.endArray(); - } - document.endObject(); - return document; - } - - public void bulkIndexActiveRules(List<ActiveRuleDto> activeRules, Multimap<Integer, ActiveRuleParamDto> paramsByActiveRule) { - try { - int size = activeRules.size(); - String[] ids = new String[size]; - BytesStream[] docs = new BytesStream[size]; - String[] parentIds = new String[size]; - int index = 0; - for (ActiveRuleDto activeRule : activeRules) { - ids[index] = activeRule.getId().toString(); - docs[index] = activeRuleDocument(activeRule, paramsByActiveRule.get(activeRule.getId())); - parentIds[index] = activeRule.getRulId().toString(); - index++; - } - if (! activeRules.isEmpty()) { - searchIndex.bulkIndex(INDEX_RULES, TYPE_ACTIVE_RULE, ids, docs, parentIds); - } - } catch (IOException e) { - throw new IllegalStateException("Unable to index active rules", e); - } - } - private XContentBuilder activeRuleDocument(ActiveRuleDto activeRule, Collection<ActiveRuleParamDto> params) throws IOException { XContentBuilder document = XContentFactory.jsonBuilder() .startObject() .field(ActiveRuleDocument.FIELD_ID, activeRule.getId()) + .field(ActiveRuleDocument.FIELD_PARENT_ID, activeRule.getParentId()) .field(ActiveRuleDocument.FIELD_SEVERITY, Severity.get(activeRule.getSeverity())) .field(ActiveRuleDocument.FIELD_PROFILE_ID, activeRule.getProfileId()) .field(ActiveRuleDocument.FIELD_INHERITANCE, activeRule.getInheritance()); diff --git a/sonar-server/src/main/resources/com/sonar/search/active_rule_mapping.json b/sonar-server/src/main/resources/com/sonar/search/active_rule_mapping.json index 8e700a0f720..8fef621f2e6 100644 --- a/sonar-server/src/main/resources/com/sonar/search/active_rule_mapping.json +++ b/sonar-server/src/main/resources/com/sonar/search/active_rule_mapping.json @@ -19,6 +19,10 @@ "type": "integer", "index": "not_analyzed" }, + "parentId": { + "type": "integer", + "index": "not_analyzed" + }, "inheritance": { "type": "string", "index": "not_analyzed" diff --git a/sonar-server/src/main/webapp/WEB-INF/app/controllers/new_rules_configuration_controller.rb b/sonar-server/src/main/webapp/WEB-INF/app/controllers/new_rules_configuration_controller.rb index 2a72be6bc9e..c9ffb5211d6 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/controllers/new_rules_configuration_controller.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/controllers/new_rules_configuration_controller.rb @@ -130,11 +130,12 @@ class NewRulesConfigurationController < ApplicationController end end - profile = result.profile - rule = result.rule + profile = result.profile() + parent_profile = result.parentProfile() + rule = result.rule() render :update do |page| - page.replace_html("rule_#{rule.id}", :partial => 'rule', :object => rule, :locals => {:profile => profile, :rule => rule}) + page.replace_html("rule_#{rule.id}", :partial => 'rule', :object => rule, :locals => {:rule => rule, :profile => profile, :parent_profile => parent_profile}) page.assign('localModifications', true) end end @@ -196,10 +197,10 @@ class NewRulesConfigurationController < ApplicationController call_backend do @profile = Internal.quality_profiles.profile(params[:id].to_i) @rule = Internal.quality_profiles.rule(params[:rule_id].to_i) - if @rule.parentId().nil? + if @rule.ruleId().nil? redirect_to :action => 'index', :id => params[:id] else - @parent_rule = Internal.quality_profiles.rule(@rule.parentId()) + @parent_rule = Internal.quality_profiles.rule(@rule.ruleId()) @active_rules = Internal.quality_profiles.countActiveRules(@rule) end end @@ -290,9 +291,10 @@ class NewRulesConfigurationController < ApplicationController result = Internal.quality_profiles.updateActiveRuleParam(params[:profile_id].to_i, params[:active_rule_id].to_i, params[:param_id], params[:value]) end - profile = result.profile - rule = result.rule - render :partial => 'rule', :locals => {:profile => profile, :rule => rule} + profile = result.profile() + parent_profile = result.parentProfile() + rule = result.rule() + render :partial => 'rule', :locals => {:rule => rule, :profile => profile, :parent_profile => parent_profile} end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule.html.erb index 59e3fe97170..a4524819278 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule.html.erb @@ -1,4 +1,4 @@ -<% #locals = rule, profile -%> +<% #locals = rule, profile, parent_profile -%> <td nowrap valign="top" class="left" x="<%= rule.severity -%>" width="1%"> <form id="levels_<%= rule.id -%>" action="" class="rule-levels-form"> @@ -50,25 +50,23 @@ </div> <% - # TODO Ancestor active rule should be integrated in the result rule to prevent bunch of SQL queries to load ancestor profile and ancestor active rule for each active rules! - ancestor_active_rule = Internal.quality_profiles.parentProfileRule(rule) if (rule.inherited? || rule.overrides?) - if ancestor_active_rule || !rule.params.empty? - ancestor_profile = Internal.quality_profiles.parent(profile) + parent_active_rule = Internal.quality_profiles.parentProfileRule(rule) if (rule.inherited? || rule.overrides?) + if parent_active_rule || !rule.params.empty? %> <table width="100%" class="table spacer-bottom bordered background-gray"> <% - if ancestor_active_rule - ancestor_active_rule_link = link_to ancestor_profile.name, :controller => 'rules_configuration', :action => 'index', - :id => ancestor_profile.id, :rule_id => rule.id, :anchor => 'rule' + rule.id.to_s + if parent_active_rule + parent_active_rule_link = link_to parent_profile.name, :controller => 'rules_configuration', :action => 'index', + :id => parent_profile.id, :rule_id => rule.id, :anchor => 'rule' + rule.id.to_s %> <tr> <td colspan="2"> <%= message(rule.inherited? ? 'rules_configuration.rule_inherited_from_profile_x' : 'rules_configuration.rule_overriding_from_profile_x', - :params => ancestor_active_rule_link) -%> - <% if ancestor_active_rule.severity != rule.severity %> + :params => parent_active_rule_link) -%> + <% if parent_active_rule.severity != rule.severity %> <img src="<%= ApplicationController.root_context -%>/images/overrides.png" alt="Overrides parent definition" title="<%= message('rules_configuration.overrides_parent_definition') -%>" style="vertical-align: middle"/> <span class="form-val-note" style="font-weight: bold"> <%= message('rules_configuration.original_severity') -%> - : <%= ancestor_active_rule.severity -%></span> + : <%= parent_active_rule.severity -%></span> <% end %> <% if profiles_administrator? && rule.overrides? %> <form action="<%= url_for :overwrite_params => {:action => 'revert_rule', :id => profile.id, :active_rule_id => rule.activeRuleId} -%>" method="post" style="display: inline"> @@ -81,7 +79,7 @@ <% rule.params.each do |parameter| %> <tr id="param_<%= parameter.key -%>"> <%= render :partial => 'rule_param', :object => nil, - :locals => {:parameter => parameter, :profile => profile, :rule => rule, :ancestor_active_rule => ancestor_active_rule} %> + :locals => {:parameter => parameter, :profile => profile, :rule => rule, :parent_active_rule => parent_active_rule} %> </tr> <% end diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule_param.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule_param.html.erb index bf39d4b41fe..064c2220d9b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule_param.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/_rule_param.html.erb @@ -1,4 +1,4 @@ -<% # locals = rule, profile, parameter, ancestor_active_rule +<% # locals = rule, profile, parameter, parent_active_rule param_id = "#{rule.id}#{parameter.key}" # Display default value only for inactive rules param_value = parameter.default_value if !rule.activeRuleId @@ -29,9 +29,8 @@ <img src="<%= ApplicationController.root_context -%>/images/loading.gif" style="display:none;" id="param_loading_<%= param_id -%>" class="rule-param-loading"> <% end %> - <% if !rule.nil? && rule.overrides? && ancestor_active_rule - # TODO Ancestor active rule param should be integrated in the result to prevent bunch of SQL queries to load ancestor param for each active rule params! - ancestor_param = Internal.quality_profiles.activeRuleParam(ancestor_active_rule, parameter.key) + <% if !rule.nil? && rule.overrides? && parent_active_rule + ancestor_param = parent_active_rule.params.to_a.find {|param| param.key() == parameter.key} ancestor_value = ancestor_param && ancestor_param.value ? ancestor_param.value : '' %> <% if ancestor_value != param_value %> diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/index.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/index.html.erb index 5fef09ee2a2..7373345480b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/index.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/new_rules_configuration/index.html.erb @@ -143,10 +143,11 @@ <tr><td colspan="3" class="even"><%= message('no_results') -%>.</td></tr> <% end %> <% + parent_profile = Internal.quality_profiles.parent(@profile) @current_rules.each do |rule| %> <tr id="rule_<%= rule.id -%>"> - <%= render :partial => 'rule', :object => rule, :locals => {:profile => @profile, :rule => rule} %> + <%= render :partial => 'rule', :object => rule, :locals => {:rule => rule, :profile => @profile, :parent_profile => parent_profile} %> </tr> <% end %> </tbody> diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java index 9d2bad66b93..6ee84509e70 100644 --- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfileActiveRuleOperationsTest.java @@ -296,9 +296,9 @@ public class QProfileActiveRuleOperationsTest { @Test public void revert_active_rule_with_severity_to_update() throws Exception { - ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1).setInheritance(ActiveRuleDto.OVERRIDES); + ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1).setInheritance(ActiveRuleDto.OVERRIDES).setParentId(4); ActiveRuleDto parent = new ActiveRuleDto().setId(4).setProfileId(1).setRuleId(10).setSeverity(2); - when(activeRuleDao.selectParent(5, session)).thenReturn(parent); + when(activeRuleDao.selectById(4, session)).thenReturn(parent); when(profilesManager.ruleSeverityChanged(eq(1), eq(5), eq(RulePriority.MINOR), eq(RulePriority.MAJOR), eq("Nicolas"))).thenReturn(new RuleInheritanceActions()); @@ -318,13 +318,13 @@ public class QProfileActiveRuleOperationsTest { @Test public void revert_active_rule_with_param_to_update() throws Exception { - ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1).setInheritance(ActiveRuleDto.OVERRIDES); + ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1).setInheritance(ActiveRuleDto.OVERRIDES).setParentId(4); when(activeRuleDao.selectParamsByActiveRuleId(eq(5), eq(session))).thenReturn(newArrayList( new ActiveRuleParamDto().setId(102).setActiveRuleId(5).setKey("max").setValue("20") )); ActiveRuleDto parent = new ActiveRuleDto().setId(4).setProfileId(1).setRuleId(10).setSeverity(1); - when(activeRuleDao.selectParent(5, session)).thenReturn(parent); + when(activeRuleDao.selectById(4, session)).thenReturn(parent); when(activeRuleDao.selectParamsByActiveRuleId(eq(4), eq(session))).thenReturn(newArrayList( new ActiveRuleParamDto().setId(100).setActiveRuleId(5).setKey("max").setValue("15") )); @@ -351,13 +351,13 @@ public class QProfileActiveRuleOperationsTest { @Test public void revert_active_rule_with_param_to_delete() throws Exception { - ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1).setInheritance(ActiveRuleDto.OVERRIDES); + ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1).setInheritance(ActiveRuleDto.OVERRIDES).setParentId(4); when(activeRuleDao.selectParamsByActiveRuleId(eq(5), eq(session))).thenReturn(newArrayList( new ActiveRuleParamDto().setId(103).setActiveRuleId(5).setKey("format").setValue("abc")) ); ActiveRuleDto parent = new ActiveRuleDto().setId(4).setProfileId(1).setRuleId(10).setSeverity(1); - when(activeRuleDao.selectParent(5, session)).thenReturn(parent); + when(activeRuleDao.selectById(4, session)).thenReturn(parent); when(profilesManager.ruleParamChanged(eq(1), eq(5), eq("format"), eq("abc"), eq((String) null), eq("Nicolas"))).thenReturn(new RuleInheritanceActions()); @@ -377,10 +377,10 @@ public class QProfileActiveRuleOperationsTest { @Test public void revert_active_rule_with_param_to_create() throws Exception { - ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1).setInheritance(ActiveRuleDto.OVERRIDES); + ActiveRuleDto activeRule = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1).setInheritance(ActiveRuleDto.OVERRIDES).setParentId(4); ActiveRuleDto parent = new ActiveRuleDto().setId(4).setProfileId(1).setRuleId(10).setSeverity(1); - when(activeRuleDao.selectParent(5, session)).thenReturn(parent); + when(activeRuleDao.selectById(4, session)).thenReturn(parent); when(activeRuleDao.selectParamsByActiveRuleId(eq(4), eq(session))).thenReturn(newArrayList( new ActiveRuleParamDto().setId(101).setActiveRuleId(5).setKey("minimum").setValue("2")) ); diff --git a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesTest.java b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesTest.java index 461605e6e17..abfd25fe1df 100644 --- a/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesTest.java +++ b/sonar-server/src/test/java/org/sonar/server/qualityprofile/QProfilesTest.java @@ -305,19 +305,12 @@ public class QProfilesTest { @Test public void parent_active_rule() throws Exception { - ActiveRuleDto parent = new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1); - when(activeRuleDao.selectParent(6)).thenReturn(parent); - QProfileRule rule = mock(QProfileRule.class); when(rule.id()).thenReturn(10); - when(rule.activeRuleId()).thenReturn(6); - - QProfileRule ruleResult = mock(QProfileRule.class); - when(rules.getFromActiveRuleId(5)).thenReturn(ruleResult); - - QProfileRule result = qProfiles.parentProfileRule(rule); + when(rule.parentId()).thenReturn(6); - assertThat(result).isEqualTo(ruleResult); + qProfiles.parentProfileRule(rule); + verify(rules).getFromActiveRuleId(6); } @Test @@ -356,6 +349,24 @@ public class QProfilesTest { } @Test + public void activate_rule_with_parent_profile() throws Exception { + QualityProfileDto parentProfile = new QualityProfileDto().setId(2).setName("Parent").setLanguage("java"); + when(qualityProfileDao.selectByNameAndLanguage("Parent", "java")).thenReturn(parentProfile); + QualityProfileDto qualityProfile = new QualityProfileDto().setId(1).setName("My profile").setLanguage("java").setParent("Parent"); + when(qualityProfileDao.selectById(1)).thenReturn(qualityProfile); + RuleDto rule = new RuleDto().setId(10).setRepositoryKey("squid").setRuleKey("AvoidCycle"); + when(ruleDao.selectById(10)).thenReturn(rule); + + when(activeRuleOperations.createActiveRule(eq(qualityProfile), eq(rule), eq(Severity.BLOCKER), any(UserSession.class))) + .thenReturn(new ActiveRuleDto().setId(5).setProfileId(1).setRuleId(10).setSeverity(1)); + + ProfileRuleChanged result = qProfiles.activateRule(1, 10, Severity.BLOCKER); + + assertThat(result.parentProfile()).isNotNull(); + assertThat(result.parentProfile().id()).isEqualTo(2); + } + + @Test public void fail_to_activate_rule_if_rule_not_found() throws Exception { QualityProfileDto qualityProfile = new QualityProfileDto().setId(1).setName("My profile").setLanguage("java"); when(qualityProfileDao.selectById(1)).thenReturn(qualityProfile); @@ -418,20 +429,6 @@ public class QProfilesTest { } @Test - public void active_rule_param() throws Exception { - ActiveRuleParamDto activeRuleParam = new ActiveRuleParamDto().setId(100).setActiveRuleId(5).setKey("max").setValue("20"); - when(activeRuleDao.selectParamByActiveRuleAndKey(5, "max")).thenReturn(activeRuleParam); - - QProfileRule rule = mock(QProfileRule.class); - when(rule.id()).thenReturn(10); - when(rule.activeRuleId()).thenReturn(5); - - ActiveRuleParamDto result = qProfiles.activeRuleParam(rule, "max"); - - assertThat(result).isEqualTo(activeRuleParam); - } - - @Test public void update_active_rule_param() throws Exception { when(qualityProfileDao.selectById(1)).thenReturn(new QualityProfileDto().setId(1).setName("My profile").setLanguage("java")); diff --git a/sonar-server/src/test/java/org/sonar/server/rule/ProfileRulesTest.java b/sonar-server/src/test/java/org/sonar/server/rule/ProfileRulesTest.java index 9dff528e5b0..6ed7a80107d 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule/ProfileRulesTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule/ProfileRulesTest.java @@ -57,7 +57,7 @@ public class ProfileRulesTest { settings.setProperty("sonar.log.profilingLevel", "FULL"); SearchIndex index = new SearchIndex(searchNode, new Profiling(settings)); index.start(); - RuleRegistry registry = new RuleRegistry(index, null, null); + RuleRegistry registry = new RuleRegistry(index, null, null, null); registry.start(); profileRules = new ProfileRules(index); diff --git a/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java index 50c5f6c4b46..320e0c60c70 100644 --- a/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java +++ b/sonar-server/src/test/java/org/sonar/server/rule/RuleRegistryTest.java @@ -26,18 +26,19 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Multimap; import org.apache.commons.io.IOUtils; +import org.apache.ibatis.session.SqlSession; import org.elasticsearch.common.collect.Lists; import org.elasticsearch.search.SearchHit; import org.junit.After; 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.config.Settings; -import org.sonar.api.database.DatabaseSession; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.ActiveRuleParam; -import org.sonar.api.rules.Rule; +import org.sonar.core.persistence.MyBatis; import org.sonar.core.profiling.Profiling; +import org.sonar.core.qualityprofile.db.ActiveRuleDao; import org.sonar.core.qualityprofile.db.ActiveRuleDto; import org.sonar.core.qualityprofile.db.ActiveRuleParamDto; import org.sonar.core.rule.RuleDao; @@ -58,32 +59,46 @@ import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@RunWith(MockitoJUnitRunner.class) public class RuleRegistryTest { - private EsSetup esSetup; - private SearchIndex searchIndex; - private RuleDao ruleDao; - private DatabaseSession session; + EsSetup esSetup; + + SearchIndex searchIndex; + + @Mock + RuleDao ruleDao; + + @Mock + ActiveRuleDao activeRuleDao; + + @Mock + MyBatis myBatis; + + @Mock + SqlSession session; + RuleRegistry registry; @Before public void setUp() throws Exception { - ruleDao = mock(RuleDao.class); + when(myBatis.openSession()).thenReturn(session); esSetup = new EsSetup(); esSetup.execute(EsSetup.deleteAll()); SearchNode node = mock(SearchNode.class); when(node.client()).thenReturn(esSetup.client()); + Settings settings = new Settings(); settings.setProperty("sonar.log.profilingLevel", "FULL"); Profiling profiling = new Profiling(settings); searchIndex = new SearchIndex(node, profiling); searchIndex.start(); - session = mock(DatabaseSession.class); + myBatis = mock(MyBatis.class); - registry = new RuleRegistry(searchIndex, ruleDao, session); + registry = new RuleRegistry(searchIndex, ruleDao, activeRuleDao, myBatis); registry.start(); String source1 = IOUtils.toString(TestUtils.getResource(getClass(), "rules/rule1.json").toURI()); @@ -95,7 +110,6 @@ public class RuleRegistryTest { EsSetup.index("rules", "rule", "2").withSource(source2), EsSetup.index("rules", "rule", "3").withSource(source3) ); - } @After @@ -232,49 +246,13 @@ public class RuleRegistryTest { assertThat(registry.findIds(ImmutableMap.of("repositoryKey", "xoo"))) .hasSize(2) - .containsOnly((int) ruleId1, (int) ruleId2); + .containsOnly(ruleId1, ruleId2); assertThat(esSetup.exists("rules", "rule", "3")).isFalse(); } @Test - public void should_index_all_active_rules() { - int id = 1; - int profileId = 42; - ActiveRule rule = mock(ActiveRule.class); - when(rule.getId()).thenReturn(id); - Rule refRule = Rule.create(); - refRule.setId(1); - when(rule.getRule()).thenReturn(refRule ); - RulesProfile profile = mock(RulesProfile.class); - when(profile.getId()).thenReturn(profileId); - when(rule.getRulesProfile()).thenReturn(profile ); - ActiveRuleParam param = mock(ActiveRuleParam.class); - when(param.getKey()).thenReturn("string"); - when(param.getValue()).thenReturn("polop"); - List<ActiveRuleParam> params = ImmutableList.of(param); - when(rule.getActiveRuleParams()).thenReturn(params ); - List<ActiveRule> rules = ImmutableList.of(rule); - - when(session.getResults(ActiveRule.class)).thenReturn(rules); - registry.bulkRegisterActiveRules(); - assertThat(esSetup.exists("rules", "active_rule", "1")); - - SearchHit[] parentHit = esSetup.client().prepareSearch("rules").setFilter( - hasChildFilter("active_rule", termFilter("profileId", profileId)) - ).execute().actionGet().getHits().getHits(); - assertThat(parentHit).hasSize(1); - assertThat(parentHit[0].getId()).isEqualTo("1"); - - SearchHit[] childHit = esSetup.client().prepareSearch("rules").setFilter( - hasParentFilter("rule", termFilter("key", "RuleWithParameters")) - ).execute().actionGet().getHits().getHits(); - assertThat(childHit).hasSize(1); - assertThat(childHit[0].getId()).isEqualTo("1"); - } - - @Test public void bulk_index_active_rules() throws IOException { - List<ActiveRuleDto> activeRules = newArrayList(new ActiveRuleDto().setId(1).setProfileId(10).setRuleId(1).setSeverity(2)); + List<ActiveRuleDto> activeRules = newArrayList(new ActiveRuleDto().setId(1).setProfileId(10).setRuleId(1).setSeverity(2).setParentId(5)); Multimap<Integer, ActiveRuleParamDto> paramsByActiveRule = ArrayListMultimap.create(); paramsByActiveRule.putAll(1, newArrayList(new ActiveRuleParamDto().setId(1).setActiveRuleId(1).setRulesParameterId(1).setKey("key").setValue("RuleWithParameters"))); |