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 = new ArrayList<RuleRepository>();
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        session.createQuery("UPDATE " + Rule.class.getSimpleName() + " SET enabled=false WHERE parent IS NULL").executeUpdate();
088      }
089    
090      private void registerRepository(RuleRepository repository, DatabaseSession session) {
091        Map<String, Rule> rulesByKey = Maps.newHashMap();
092        for (Rule rule : repository.createRules()) {
093          rule.setRepositoryKey(repository.getKey());
094          rulesByKey.put(rule.getKey(), rule);
095        }
096        Logs.INFO.info(rulesByKey.size() + " rules");
097    
098        List<Rule> persistedRules = session.getResults(Rule.class, "pluginName", repository.getKey());
099        for (Rule persistedRule : persistedRules) {
100          Rule rule = rulesByKey.get(persistedRule.getKey());
101          if (rule != null) {
102            updateRule(persistedRule, rule, session);
103            rulesByKey.remove(rule.getKey());
104          }
105        }
106    
107        saveNewRules(rulesByKey.values(), session);
108      }
109    
110      private void updateRule(Rule persistedRule, Rule rule, DatabaseSession session) {
111        persistedRule.setName(rule.getName());
112        persistedRule.setConfigKey(rule.getConfigKey());
113        persistedRule.setDescription(rule.getDescription());
114        persistedRule.setSeverity(rule.getSeverity());
115        persistedRule.setEnabled(true);
116        persistedRule.setCardinality(rule.getCardinality());
117    
118        // delete deprecated params
119        deleteDeprecatedParameters(persistedRule, rule, session);
120    
121        // add new params and update existing params
122        updateParameters(persistedRule, rule);
123    
124        session.saveWithoutFlush(persistedRule);
125      }
126    
127      private void updateParameters(Rule persistedRule, Rule rule) {
128        if (rule.getParams() != null) {
129          for (RuleParam param : rule.getParams()) {
130            RuleParam persistedParam = persistedRule.getParam(param.getKey());
131            if (persistedParam == null) {
132              persistedParam = persistedRule.createParameter(param.getKey());
133            }
134            persistedParam.setDescription(param.getDescription());
135            persistedParam.setType(param.getType());
136            persistedParam.setDefaultValue(param.getDefaultValue());
137          }
138        }
139      }
140    
141      private void deleteDeprecatedParameters(Rule persistedRule, Rule rule, DatabaseSession session) {
142        if (persistedRule.getParams() != null && persistedRule.getParams().size() > 0) {
143          for (Iterator<RuleParam> it = persistedRule.getParams().iterator(); it.hasNext(); ) {
144            RuleParam persistedParam = it.next();
145            if (rule.getParam(persistedParam.getKey()) == null) {
146              it.remove();
147              session
148                  .createQuery("delete from " + ActiveRuleParam.class.getSimpleName() + " where ruleParam=:param")
149                  .setParameter("param", persistedParam)
150                  .executeUpdate();
151            }
152          }
153        }
154      }
155    
156      private void saveNewRules(Collection<Rule> rules, DatabaseSession session) {
157        for (Rule rule : rules) {
158          rule.setEnabled(true);
159          session.saveWithoutFlush(rule);
160        }
161      }
162    }