001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
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.api.rules;
021    
022    import org.apache.commons.collections.CollectionUtils;
023    import org.sonar.api.BatchExtension;
024    import org.sonar.api.Plugin;
025    import org.sonar.api.Plugins;
026    import org.sonar.api.database.daos.DaoFacade;
027    import org.sonar.api.database.daos.RulesDao;
028    import org.sonar.api.resources.Language;
029    
030    import java.util.*;
031    
032    /**
033     * A class to manage and access rules defined in Sonar
034     * 
035     */
036    public class RulesManager implements BatchExtension {
037    
038      private final Set<Language> languages;
039      private final RulesRepository<?>[] repositories;
040      private final Map<Language, List<RulesRepository<?>>> rulesByLanguage;
041      private final Map<Language, List<Plugin>> pluginsByLanguage;
042      private final Map<String, Map<String, Rule>> rulesByPluginAndKey = new HashMap<String, Map<String, Rule>>();
043      private final RulesDao rulesDao;
044      private final Plugins plugins;
045    
046      /**
047       * Creates a RuleManager
048       * @param plugins the plugins dictionnary
049       * @param repositories the repositories of rules
050       * @param dao the dao object
051       */
052      public RulesManager(Plugins plugins, RulesRepository[] repositories, DaoFacade dao) {
053        this.plugins = plugins;
054        this.rulesDao = dao.getRulesDao();
055    
056        languages = new HashSet<Language>();
057        rulesByLanguage = new HashMap<Language, List<RulesRepository<?>>>();
058        pluginsByLanguage = new HashMap<Language, List<Plugin>>();
059        this.repositories = repositories;
060    
061        for (RulesRepository<?> repository : repositories) {
062          languages.add(repository.getLanguage());
063    
064          List<RulesRepository<?>> list = rulesByLanguage.get(repository.getLanguage());
065          if (list == null) {
066            list = new ArrayList<RulesRepository<?>>();
067            rulesByLanguage.put(repository.getLanguage(), list);
068          }
069          list.add(repository);
070    
071          List<Plugin> languagePlugins = pluginsByLanguage.get(repository.getLanguage());
072          if (languagePlugins == null) {
073            languagePlugins = new ArrayList<Plugin>();
074            pluginsByLanguage.put(repository.getLanguage(), languagePlugins);
075          }
076          languagePlugins.add(plugins.getPluginByExtension(repository));
077        }
078      }
079    
080      /**
081       * Constructor for tests only
082       *
083       * @param dao the dao
084       */
085      protected RulesManager(DaoFacade dao) {
086        this.rulesDao = dao.getRulesDao();
087        plugins = new Plugins();
088        languages = new HashSet<Language>();
089        rulesByLanguage = new HashMap<Language, List<RulesRepository<?>>>();
090        pluginsByLanguage = new HashMap<Language, List<Plugin>>();
091        repositories = null;
092    
093      }
094    
095      /**
096       * Returns the list of languages for which there is a rule repository
097       *
098       * @return a Set of languages
099       */
100      public Set<Language> getLanguages() {
101        return languages;
102      }
103    
104      /**
105       * Gets the list of Rules Repositories available for a language
106       *
107       * @param language the language
108       * @return the list of rules repositories
109       */
110      public List<RulesRepository<?>> getRulesRepositories(Language language) {
111        List<RulesRepository<?>> rulesRepositories = rulesByLanguage.get(language);
112        if (CollectionUtils.isNotEmpty(rulesRepositories)) {
113          return rulesRepositories;
114        }
115        return Collections.emptyList();
116      }
117    
118      /**
119       * Gets the complete list of Rules Repositories in the Sonar instance
120       *
121       * @return the list of rules repositories
122       */
123      public List<RulesRepository<?>> getRulesRepositories() {
124        return Arrays.asList(repositories);
125      }
126    
127      /**
128       * Gets the list of rules plugins for a given language
129       * @param language  the language
130       * @return the list of plugins
131       */
132      public List<Plugin> getPlugins(Language language) {
133        List<Plugin> result = pluginsByLanguage.get(language);
134        if (!CollectionUtils.isEmpty(result)) {
135          return result;
136        }
137        return Collections.emptyList();
138      }
139    
140      /**
141       * Gets count of rules by categories defined for a given language
142       *
143       * @param language the language
144       * @return a Map with the category as key and the count as value
145       */
146      public Map<String, Long> countRulesByCategory(Language language) {
147        return countRulesByCategory(language, rulesDao);
148      }
149    
150      protected Map<String, Long> countRulesByCategory(Language language, RulesDao rulesDao) {
151        Map<String, Long> countByCategory = new HashMap<String, Long>();
152        List<Plugin> result = getPlugins(language);
153        if (!CollectionUtils.isEmpty(result)) {
154          List<String> keys = getPluginKeys(getPlugins(language));
155          for (RulesCategory rulesCategory : rulesDao.getCategories()) {
156            Long rulesCount = rulesDao.countRules(keys, rulesCategory.getName());
157            countByCategory.put(rulesCategory.getName(), rulesCount);
158          }
159        }
160        return countByCategory;
161      }
162    
163      private List<String> getPluginKeys(List<Plugin> plugins) {
164        ArrayList<String> keys = new ArrayList<String>();
165        for (Plugin plugin : plugins) {
166          keys.add(plugin.getKey());
167        }
168        return keys;
169      }
170    
171      /**
172       * Get the list of rules plugin that implement a mechanism of export for a given language
173       *
174       * @param language the language
175       * @return the list of plugins
176       */
177      public List<Plugin> getExportablePlugins(Language language) {
178        List<Plugin> targets = new ArrayList<Plugin>();
179        List<RulesRepository<?>> rulesRepositories = getRulesRepositories(language);
180        for (RulesRepository<?> repository : rulesRepositories) {
181          if (repository instanceof ConfigurationExportable) {
182            targets.add(plugins.getPluginByExtension(repository));
183          }
184        }
185        return targets;
186      }
187    
188      /**
189       * Get the list of rules plugin that implement a mechanism of import for a given language
190       *
191       * @param language the language
192       * @return the list of plugins
193       */
194      public List<Plugin> getImportablePlugins(Language language) {
195        List<Plugin> targets = new ArrayList<Plugin>();
196        for (RulesRepository<?> repository : getRulesRepositories(language)) {
197          if (repository instanceof ConfigurationImportable) {
198            targets.add(plugins.getPluginByExtension(repository));
199          }
200        }
201        return targets;
202      }
203    
204      /**
205       * Gets a list of rules indexed by their key for a given plugin
206       * @param pluginKey the plugin key
207       * @return a Map with the rule key and the rule
208       */
209      public Map<String, Rule> getPluginRulesIndexedByKey(String pluginKey) {
210        Map<String, Rule> rulesByKey = rulesByPluginAndKey.get(pluginKey);
211        if (rulesByKey == null) {
212          rulesByKey = new HashMap<String, Rule>();
213          List<Rule> rules = rulesDao.getRulesByPlugin(pluginKey);
214          if (rules != null) {
215            for (Rule rule : rules) {
216              rulesByKey.put(rule.getKey(), rule);
217            }
218          }
219          rulesByPluginAndKey.put(pluginKey, rulesByKey);
220        }
221        return rulesByKey;
222      }
223    
224      /**
225       * Gets a collection of rules belonging to a plugin
226       *
227       * @param pluginKey the plugin key
228       * @return the collection of rules
229       */
230      public Collection<Rule> getPluginRules(String pluginKey) {
231        Map<String, Rule> rulesByKey = getPluginRulesIndexedByKey(pluginKey);
232        return rulesByKey.values();
233      }
234    
235      /**
236       * Gets a rule belonging to a defined plugin based on its key
237       *
238       * @param pluginKey the plugin key
239       * @param ruleKey the rule key
240       * @return the rule
241       */
242      public Rule getPluginRule(String pluginKey, String ruleKey) {
243        Map<String, Rule> rulesByKey = getPluginRulesIndexedByKey(pluginKey);
244        return rulesByKey.get(ruleKey);
245      }
246    
247    }