001/* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020package org.sonar.server.startup; 021 022import com.google.common.collect.Lists; 023import com.google.common.collect.Maps; 024import org.apache.commons.lang.StringUtils; 025import org.sonar.api.database.DatabaseSession; 026import org.sonar.api.rules.ActiveRuleParam; 027import org.sonar.api.rules.Rule; 028import org.sonar.api.rules.RuleParam; 029import org.sonar.api.rules.RuleRepository; 030import org.sonar.api.utils.Logs; 031import org.sonar.api.utils.SonarException; 032import org.sonar.api.utils.TimeProfiler; 033import org.sonar.core.i18n.RuleI18nManager; 034import org.sonar.jpa.session.DatabaseSessionFactory; 035 036import java.util.*; 037 038public final class RegisterRules { 039 040 private final DatabaseSessionFactory sessionFactory; 041 private final List<RuleRepository> repositories; 042 private final RuleI18nManager ruleI18nManager; 043 044 public RegisterRules(DatabaseSessionFactory sessionFactory, RuleRepository[] repos, RuleI18nManager ruleI18nManager) { 045 this.sessionFactory = sessionFactory; 046 this.repositories = Arrays.asList(repos); 047 this.ruleI18nManager = ruleI18nManager; 048 } 049 050 public RegisterRules(DatabaseSessionFactory sessionFactory, RuleI18nManager ruleI18nManager) { 051 this(sessionFactory, new RuleRepository[0], ruleI18nManager); 052 } 053 054 public void start() { 055 TimeProfiler profiler = new TimeProfiler(); 056 057 DatabaseSession session = sessionFactory.getSession(); 058 disableAllRules(session); 059 for (RuleRepository repository : repositories) { 060 profiler.start("Register rules [" + repository.getKey() + "/" + StringUtils.defaultString(repository.getLanguage(), "-") + "]"); 061 registerRepository(repository, session); 062 profiler.stop(); 063 } 064 065 profiler.start("Disable deprecated user rules"); 066 disableDeprecatedUserRules(session); 067 profiler.stop(); 068 069 session.commit(); 070 } 071 072 private void disableDeprecatedUserRules(DatabaseSession session) { 073 List<Integer> deprecatedUserRuleIds = Lists.newLinkedList(); 074 deprecatedUserRuleIds.addAll(session.createQuery( 075 "SELECT r.id FROM " + Rule.class.getSimpleName() + 076 " r WHERE r.parent IS NOT NULL AND NOT EXISTS(FROM " + Rule.class.getSimpleName() + " p WHERE r.parent=p)").getResultList()); 077 078 deprecatedUserRuleIds.addAll(session.createQuery( 079 "SELECT r.id FROM " + Rule.class.getSimpleName() + 080 " r WHERE r.parent IS NOT NULL AND EXISTS(FROM " + Rule.class.getSimpleName() + " p WHERE r.parent=p and p.enabled=false)").getResultList()); 081 082 for (Integer deprecatedUserRuleId : deprecatedUserRuleIds) { 083 Rule rule = session.getSingleResult(Rule.class, "id", deprecatedUserRuleId); 084 rule.setEnabled(false); 085 session.saveWithoutFlush(rule); 086 } 087 088 } 089 090 private void disableAllRules(DatabaseSession session) { 091 // the hardcoded repository "manual" is used for manual violations 092 session.createQuery("UPDATE " + Rule.class.getSimpleName() + " SET enabled=false WHERE parent IS NULL AND pluginName<>'manual'").executeUpdate(); 093 } 094 095 private void registerRepository(RuleRepository repository, DatabaseSession session) { 096 Map<String, Rule> rulesByKey = Maps.newHashMap(); 097 for (Rule rule : repository.createRules()) { 098 validateRule(rule, repository.getKey()); 099 rule.setRepositoryKey(repository.getKey()); 100 rulesByKey.put(rule.getKey(), rule); 101 } 102 Logs.INFO.info(rulesByKey.size() + " rules"); 103 104 List<Rule> persistedRules = session.getResults(Rule.class, "pluginName", repository.getKey()); 105 for (Rule persistedRule : persistedRules) { 106 Rule rule = rulesByKey.get(persistedRule.getKey()); 107 if (rule != null) { 108 updateRule(persistedRule, rule, session); 109 rulesByKey.remove(rule.getKey()); 110 } 111 } 112 113 saveNewRules(rulesByKey.values(), session); 114 } 115 116 private void validateRule(Rule rule, String repositoryKey) { 117 if (rule.getName() == null && ruleI18nManager.getName(repositoryKey, rule.getKey(), Locale.ENGLISH) == null) { 118 throw new SonarException("The following rule (repository: " + repositoryKey + ") must have a name: " + rule); 119 } 120 if (rule.getDescription() == null && ruleI18nManager.getDescription(repositoryKey, rule.getKey(), Locale.ENGLISH) == null) { 121 throw new SonarException("The following rule (repository: " + repositoryKey + ") must have a description: " + rule); 122 } 123 } 124 125 private void updateRule(Rule persistedRule, Rule rule, DatabaseSession session) { 126 persistedRule.setName(rule.getName()); 127 persistedRule.setConfigKey(rule.getConfigKey()); 128 persistedRule.setDescription(rule.getDescription()); 129 persistedRule.setSeverity(rule.getSeverity()); 130 persistedRule.setEnabled(true); 131 persistedRule.setCardinality(rule.getCardinality()); 132 133 // delete deprecated params 134 deleteDeprecatedParameters(persistedRule, rule, session); 135 136 // add new params and update existing params 137 updateParameters(persistedRule, rule); 138 139 session.saveWithoutFlush(persistedRule); 140 } 141 142 private void updateParameters(Rule persistedRule, Rule rule) { 143 if (rule.getParams() != null) { 144 for (RuleParam param : rule.getParams()) { 145 RuleParam persistedParam = persistedRule.getParam(param.getKey()); 146 if (persistedParam == null) { 147 persistedParam = persistedRule.createParameter(param.getKey()); 148 } 149 persistedParam.setDescription(param.getDescription()); 150 persistedParam.setType(param.getType()); 151 persistedParam.setDefaultValue(param.getDefaultValue()); 152 } 153 } 154 } 155 156 private void deleteDeprecatedParameters(Rule persistedRule, Rule rule, DatabaseSession session) { 157 if (persistedRule.getParams() != null && persistedRule.getParams().size() > 0) { 158 for (Iterator<RuleParam> it = persistedRule.getParams().iterator(); it.hasNext();) { 159 RuleParam persistedParam = it.next(); 160 if (rule.getParam(persistedParam.getKey()) == null) { 161 it.remove(); 162 session 163 .createQuery("delete from " + ActiveRuleParam.class.getSimpleName() + " where ruleParam=:param") 164 .setParameter("param", persistedParam) 165 .executeUpdate(); 166 } 167 } 168 } 169 } 170 171 private void saveNewRules(Collection<Rule> rules, DatabaseSession session) { 172 for (Rule rule : rules) { 173 rule.setEnabled(true); 174 session.saveWithoutFlush(rule); 175 } 176 } 177}