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 org.apache.commons.lang.StringUtils;
024    import org.slf4j.Logger;
025    import org.slf4j.LoggerFactory;
026    import org.sonar.api.database.DatabaseSession;
027    import org.sonar.api.profiles.ProfileDefinition;
028    import org.sonar.api.profiles.RulesProfile;
029    import org.sonar.api.rules.*;
030    import org.sonar.api.utils.TimeProfiler;
031    import org.sonar.api.utils.ValidationMessages;
032    import org.sonar.jpa.session.DatabaseSessionFactory;
033    
034    import java.util.ArrayList;
035    import java.util.Arrays;
036    import java.util.List;
037    
038    public final class RegisterProvidedProfiles {
039    
040      private static final Logger LOGGER = LoggerFactory.getLogger(RegisterProvidedProfiles.class);
041    
042      private DatabaseSessionFactory sessionFactory;
043      private List<ProfileDefinition> definitions = Lists.newArrayList();
044      private RuleFinder ruleFinder;
045    
046      public RegisterProvidedProfiles(RuleFinder ruleFinder, DatabaseSessionFactory sessionFactory,// NOSONAR the parameter registerRulesBefore is unused must be declared for execution order of tasks
047                                      RegisterRules registerRulesBefore,
048                                      ProfileDefinition[] definitions) {
049        this.ruleFinder = ruleFinder;
050        this.sessionFactory = sessionFactory;
051        this.definitions.addAll(Arrays.asList(definitions));
052      }
053    
054      public RegisterProvidedProfiles(RuleFinder ruleFinder, DatabaseSessionFactory sessionFactory,// NOSONAR the parameter registerRulesBefore is unused must be declared for execution order of tasks
055                                      RegisterRules registerRulesBefore) {
056        this.ruleFinder = ruleFinder;
057        this.sessionFactory = sessionFactory;
058      }
059    
060      public void start() {
061        TimeProfiler profiler = new TimeProfiler().start("Load provided profiles");
062    
063        List<RulesProfile> profiles = createProfiles();
064        DatabaseSession session = sessionFactory.getSession();
065        cleanProvidedProfiles(profiles, session);
066        saveProvidedProfiles(profiles, session);
067        session.commit();
068        profiler.stop();
069      }
070    
071      List<RulesProfile> createProfiles() {
072        List<RulesProfile> result = Lists.newArrayList();
073        for (ProfileDefinition definition : definitions) {
074          ValidationMessages validation = ValidationMessages.create();
075          RulesProfile profile = definition.createProfile(validation);
076          validation.log(LOGGER);
077          if (profile != null && !validation.hasErrors()) {
078            result.add(profile);
079          }
080        }
081        return result;
082      }
083    
084      void cleanProvidedProfiles(List<RulesProfile> profiles, DatabaseSession session) {
085        TimeProfiler profiler = new TimeProfiler().start("Clean provided profiles");
086        List<RulesProfile> existingProfiles = session.getResults(RulesProfile.class, "provided", true);
087        for (RulesProfile existingProfile : existingProfiles) {
088          boolean isDeprecated = true;
089          for (RulesProfile profile : profiles) {
090            if (StringUtils.equals(existingProfile.getName(), profile.getName()) && StringUtils.equals(existingProfile.getLanguage(), profile.getLanguage())) {
091              isDeprecated = false;
092              break;
093            }
094          }
095          if (isDeprecated) {
096            session.removeWithoutFlush(existingProfile);
097          } else {
098            for (ActiveRule activeRule : existingProfile.getActiveRules()) {
099              session.removeWithoutFlush(activeRule);
100            }
101            existingProfile.setActiveRules(new ArrayList<ActiveRule>());
102            session.saveWithoutFlush(existingProfile);
103          }
104        }
105        profiler.stop();
106      }
107    
108      void saveProvidedProfiles(List<RulesProfile> profiles, DatabaseSession session) {
109        for (RulesProfile profile : profiles) {
110          TimeProfiler profiler = new TimeProfiler().start("Save profile " + profile);
111          RulesProfile persistedProfile = findOrCreate(profile.getName(), profile.getLanguage(), session);
112    
113          for (ActiveRule activeRule : profile.getActiveRules()) {
114            Rule rule = getPersistedRule(activeRule);
115            ActiveRule persistedRule = persistedProfile.activateRule(rule, activeRule.getSeverity());
116            for (RuleParam param : rule.getParams()) {
117              String value = StringUtils.defaultString(activeRule.getParameter(param.getKey()), param.getDefaultValue());
118              if (value != null) {
119                persistedRule.setParameter(param.getKey(), value);
120              }
121            }
122          }
123    
124          session.saveWithoutFlush(persistedProfile);
125          profiler.stop();
126        }
127    
128      }
129    
130      Rule getPersistedRule(ActiveRule activeRule) {
131        Rule rule = activeRule.getRule();
132        if (rule != null && rule.getId() == null) {
133          if (rule.getKey() != null) {
134            rule = ruleFinder.findByKey(rule.getRepositoryKey(), rule.getKey());
135    
136          } else if (rule.getConfigKey() != null) {
137            rule = ruleFinder.find(RuleQuery.create().withRepositoryKey(rule.getRepositoryKey()).withConfigKey(rule.getConfigKey()));
138          }
139        }
140        return rule;
141      }
142    
143      private RulesProfile findOrCreate(String name, String language, DatabaseSession session) {
144        RulesProfile profile = session.getSingleResult(RulesProfile.class, "name", name, "language", language);
145        if (profile == null) {
146          profile = RulesProfile.create(name, language);
147          profile.setProvided(true);
148          profile.setDefaultProfile(false);
149        }
150        return profile;
151      }
152    
153    }