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