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    }