/*
* Sonar C# Plugin :: StyleCop
* Copyright (C) 2010 Jose Chillan, Alexandre Victoor and SonarSource
* dev@sonar.codehaus.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/
package org.sonar.plugins.csharp.stylecop.profiles;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.profiles.ProfileExporter;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.rules.ActiveRule;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.XMLRuleParser;
import org.sonar.api.utils.SonarException;
import org.sonar.plugins.csharp.api.CSharpConstants;
import org.sonar.plugins.csharp.stylecop.StyleCopConstants;
import org.sonar.plugins.csharp.stylecop.profiles.utils.StyleCopRule;
import com.google.common.collect.Maps;
/**
* Class that allows to export a Sonar profile into a StyleCop rule definition file.
*/
public class StyleCopProfileExporter extends ProfileExporter {
public StyleCopProfileExporter() {
super(StyleCopConstants.REPOSITORY_KEY, StyleCopConstants.REPOSITORY_NAME);
setSupportedLanguages(CSharpConstants.LANGUAGE_KEY);
setMimeType("application/xml");
}
/**
* {@inheritDoc}
*/
@Override
public void exportProfile(RulesProfile profile, Writer writer) {
try {
printStartOfFile(writer);
printRules(profile, writer);
printEndOfFile(writer);
} catch (IOException e) {
throw new SonarException("Error while generating the StyleCop profile to export: " + profile, e);
}
}
private void printStartOfFile(Writer writer) throws IOException {
writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
writer.append("<StyleCopSettings Version=\"4.3\">\n");
writer.append(" <Analyzers>\n");
}
private void printEndOfFile(Writer writer) throws IOException {
writer.append(" </Analyzers>\n");
writer.append("</StyleCopSettings>");
}
private void printRules(RulesProfile profile, Writer writer) throws IOException {
List<ActiveRule> activeRules = profile.getActiveRulesByRepository(StyleCopConstants.REPOSITORY_KEY);
List<StyleCopRule> rules = transformIntoStyleCopRules(activeRules);
// We group the rules by RuleFile names
Map<String, List<StyleCopRule>> rulesByFile = groupStyleCopRulesByAnalyzer(rules);
// And then print out each rule
for (String fileName : rulesByFile.keySet()) {
printRuleFile(writer, rulesByFile, fileName);
}
}
private List<StyleCopRule> transformIntoStyleCopRules(List<ActiveRule> activeRulesByPlugin) {
List<StyleCopRule> result = new ArrayList<StyleCopRule>();
Map<String, ActiveRule> activeRuleMap = Maps.newHashMap();
for (ActiveRule activeRule : activeRulesByPlugin) {
activeRuleMap.put(activeRule.getRule().getKey(), activeRule);
}
List<Rule> initialRules = new XMLRuleParser().parse(StyleCopProfileExporter.class
.getResourceAsStream("/org/sonar/plugins/csharp/stylecop/rules/rules.xml"));
for (Rule rule : initialRules) {
// Extracts the rule's information
String configKey = rule.getConfigKey();
String analyzerName = StringUtils.substringBefore(configKey, "#");
String name = StringUtils.substringAfter(configKey, "#");
// Creates the StyleCop rule
StyleCopRule styleCopRule = new StyleCopRule();
styleCopRule.setAnalyzerId(analyzerName);
styleCopRule.setName(name);
ActiveRule activeRule = activeRuleMap.get(rule.getKey());
if (activeRule != null) {
styleCopRule.setEnabled(true);
RulePriority priority = activeRule.getSeverity();
if (priority != null) {
styleCopRule.setPriority(priority.name().toLowerCase());
}
}
result.add(styleCopRule);
}
return result;
}
private Map<String, List<StyleCopRule>> groupStyleCopRulesByAnalyzer(List<StyleCopRule> rules) {
Map<String, List<StyleCopRule>> rulesByAnalyzer = new HashMap<String, List<StyleCopRule>>();
for (StyleCopRule styleCopRule : rules) {
String analyzerId = styleCopRule.getAnalyzerId();
List<StyleCopRule> rulesList = rulesByAnalyzer.get(analyzerId);
if (rulesList == null) {
rulesList = new ArrayList<StyleCopRule>();
rulesByAnalyzer.put(analyzerId, rulesList);
}
rulesList.add(styleCopRule);
}
return rulesByAnalyzer;
}
private void printRuleFile(Writer writer, Map<String, List<StyleCopRule>> rulesByAnalyzer, String analyzerId) throws IOException {
writer.append(" <Analyzer AnalyzerId=\"");
StringEscapeUtils.escapeXml(writer, analyzerId);
writer.append("\">\n");
writer.append(" <Rules>\n");
for (StyleCopRule styleCopRule : rulesByAnalyzer.get(analyzerId)) {
printRule(writer, styleCopRule);
}
writer.append(" </Rules>\n");
writer.append(" </Analyzer>\n");
}
private void printRule(Writer writer, StyleCopRule styleCopRule) throws IOException {
writer.append(" <Rule Name=\"");
StringEscapeUtils.escapeXml(writer, styleCopRule.getName());
writer.append("\" SonarPriority=\"");
StringEscapeUtils.escapeXml(writer, styleCopRule.getPriority());
writer.append("\">\n");
writer.append(" <RuleSettings>\n");
writer.append(" <BooleanProperty Name=\"Enabled\">");
writer.append(styleCopRule.isEnabled() ? "True" : "False");
writer.append("</BooleanProperty>\n");
writer.append(" </RuleSettings>\n");
writer.append(" </Rule>\n");
}
}