001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2011 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 */
020 package org.sonar.server.startup;
021
022 import com.google.common.collect.Lists;
023 import com.google.common.collect.Maps;
024 import org.apache.commons.lang.StringUtils;
025 import org.sonar.api.database.DatabaseSession;
026 import org.sonar.api.rules.ActiveRuleParam;
027 import org.sonar.api.rules.Rule;
028 import org.sonar.api.rules.RuleParam;
029 import org.sonar.api.rules.RuleRepository;
030 import org.sonar.api.utils.Logs;
031 import org.sonar.api.utils.TimeProfiler;
032 import org.sonar.jpa.session.DatabaseSessionFactory;
033
034 import java.util.*;
035
036 public final class RegisterRules {
037
038 private DatabaseSessionFactory sessionFactory;
039 private List<RuleRepository> repositories = Lists.newArrayList();
040
041 public RegisterRules(DatabaseSessionFactory sessionFactory, RuleRepository[] repos) {
042 this.sessionFactory = sessionFactory;
043 this.repositories.addAll(Arrays.asList(repos));
044 }
045
046 public RegisterRules(DatabaseSessionFactory sessionFactory) {
047 this(sessionFactory, new RuleRepository[0]);
048 }
049
050 public void start() {
051 TimeProfiler profiler = new TimeProfiler();
052
053 DatabaseSession session = sessionFactory.getSession();
054 disableAllRules(session);
055 for (RuleRepository repository : repositories) {
056 profiler.start("Register rules [" + repository.getKey() + "/" + StringUtils.defaultString(repository.getLanguage(), "-") + "]");
057 registerRepository(repository, session);
058 profiler.stop();
059 }
060
061 profiler.start("Disable deprecated user rules");
062 disableDeprecatedUserRules(session);
063 profiler.stop();
064
065 session.commit();
066 }
067
068 private void disableDeprecatedUserRules(DatabaseSession session) {
069 List<Integer> deprecatedUserRuleIds = Lists.newLinkedList();
070 deprecatedUserRuleIds.addAll(session.createQuery(
071 "SELECT r.id FROM " + Rule.class.getSimpleName() +
072 " r WHERE r.parent IS NOT NULL AND NOT EXISTS(FROM " + Rule.class.getSimpleName() + " p WHERE r.parent=p)").getResultList());
073
074 deprecatedUserRuleIds.addAll(session.createQuery(
075 "SELECT r.id FROM " + Rule.class.getSimpleName() +
076 " r WHERE r.parent IS NOT NULL AND EXISTS(FROM " + Rule.class.getSimpleName() + " p WHERE r.parent=p and p.enabled=false)").getResultList());
077
078 for (Integer deprecatedUserRuleId : deprecatedUserRuleIds) {
079 Rule rule = session.getSingleResult(Rule.class, "id", deprecatedUserRuleId);
080 rule.setEnabled(false);
081 session.saveWithoutFlush(rule);
082 }
083
084 }
085
086 private void disableAllRules(DatabaseSession session) {
087 // the hardcoded repository "manual" is used for manual violations
088 session.createQuery("UPDATE " + Rule.class.getSimpleName() + " SET enabled=false WHERE parent IS NULL AND pluginName<>'manual'").executeUpdate();
089 }
090
091 private void registerRepository(RuleRepository repository, DatabaseSession session) {
092 Map<String, Rule> rulesByKey = Maps.newHashMap();
093 for (Rule rule : repository.createRules()) {
094 rule.setRepositoryKey(repository.getKey());
095 rulesByKey.put(rule.getKey(), rule);
096 }
097 Logs.INFO.info(rulesByKey.size() + " rules");
098
099 List<Rule> persistedRules = session.getResults(Rule.class, "pluginName", repository.getKey());
100 for (Rule persistedRule : persistedRules) {
101 Rule rule = rulesByKey.get(persistedRule.getKey());
102 if (rule != null) {
103 updateRule(persistedRule, rule, session);
104 rulesByKey.remove(rule.getKey());
105 }
106 }
107
108 saveNewRules(rulesByKey.values(), session);
109 }
110
111 private void updateRule(Rule persistedRule, Rule rule, DatabaseSession session) {
112 persistedRule.setName(rule.getName());
113 persistedRule.setConfigKey(rule.getConfigKey());
114 persistedRule.setDescription(rule.getDescription());
115 persistedRule.setSeverity(rule.getSeverity());
116 persistedRule.setEnabled(true);
117 persistedRule.setCardinality(rule.getCardinality());
118
119 // delete deprecated params
120 deleteDeprecatedParameters(persistedRule, rule, session);
121
122 // add new params and update existing params
123 updateParameters(persistedRule, rule);
124
125 session.saveWithoutFlush(persistedRule);
126 }
127
128 private void updateParameters(Rule persistedRule, Rule rule) {
129 if (rule.getParams() != null) {
130 for (RuleParam param : rule.getParams()) {
131 RuleParam persistedParam = persistedRule.getParam(param.getKey());
132 if (persistedParam == null) {
133 persistedParam = persistedRule.createParameter(param.getKey());
134 }
135 persistedParam.setDescription(param.getDescription());
136 persistedParam.setType(param.getType());
137 persistedParam.setDefaultValue(param.getDefaultValue());
138 }
139 }
140 }
141
142 private void deleteDeprecatedParameters(Rule persistedRule, Rule rule, DatabaseSession session) {
143 if (persistedRule.getParams() != null && persistedRule.getParams().size() > 0) {
144 for (Iterator<RuleParam> it = persistedRule.getParams().iterator(); it.hasNext(); ) {
145 RuleParam persistedParam = it.next();
146 if (rule.getParam(persistedParam.getKey()) == null) {
147 it.remove();
148 session
149 .createQuery("delete from " + ActiveRuleParam.class.getSimpleName() + " where ruleParam=:param")
150 .setParameter("param", persistedParam)
151 .executeUpdate();
152 }
153 }
154 }
155 }
156
157 private void saveNewRules(Collection<Rule> rules, DatabaseSession session) {
158 for (Rule rule : rules) {
159 rule.setEnabled(true);
160 session.saveWithoutFlush(rule);
161 }
162 }
163 }