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.plugins.checkstyle; 021 022 import com.google.common.collect.ArrayListMultimap; 023 import com.google.common.collect.ListMultimap; 024 import org.apache.commons.configuration.BaseConfiguration; 025 import org.apache.commons.configuration.Configuration; 026 import org.apache.commons.lang.StringEscapeUtils; 027 import org.apache.commons.lang.StringUtils; 028 import org.sonar.api.profiles.ProfileExporter; 029 import org.sonar.api.profiles.RulesProfile; 030 import org.sonar.api.resources.Java; 031 import org.sonar.api.rules.ActiveRule; 032 import org.sonar.api.rules.RuleParam; 033 import org.sonar.api.utils.SonarException; 034 035 import java.io.IOException; 036 import java.io.Writer; 037 import java.util.List; 038 039 public class CheckstyleProfileExporter extends ProfileExporter { 040 041 static final String DOCTYPE_DECLARATION = "<!DOCTYPE module PUBLIC \"-//Puppy Crawl//DTD Check Configuration 1.2//EN\" \"http://www.puppycrawl.com/dtds/configuration_1_2.dtd\">"; 042 private Configuration conf; 043 044 public CheckstyleProfileExporter(Configuration conf) { 045 super(CheckstyleConstants.REPOSITORY_KEY, CheckstyleConstants.PLUGIN_NAME); 046 this.conf = conf; 047 setSupportedLanguages(Java.KEY); 048 setMimeType("application/xml"); 049 } 050 051 /** 052 * for unit tests 053 */ 054 CheckstyleProfileExporter() { 055 this(new BaseConfiguration()); 056 } 057 058 public void exportProfile(RulesProfile profile, Writer writer) { 059 try { 060 ListMultimap<String, ActiveRule> activeRulesByConfigKey = arrangeByConfigKey(profile.getActiveRulesByRepository(CheckstyleConstants.REPOSITORY_KEY)); 061 generateXML(writer, activeRulesByConfigKey); 062 063 } catch (IOException e) { 064 throw new SonarException("Fail to export the profile " + profile, e); 065 } 066 067 } 068 069 private void generateXML(Writer writer, ListMultimap<String, ActiveRule> activeRulesByConfigKey) throws IOException { 070 appendXmlHeader(writer); 071 appendCustomFilters(writer); 072 appendCheckerModules(writer, activeRulesByConfigKey); 073 appendTreeWalker(writer, activeRulesByConfigKey); 074 appendXmlFooter(writer); 075 } 076 077 private void appendXmlHeader(Writer writer) throws IOException { 078 writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 079 + DOCTYPE_DECLARATION 080 + "<!-- Generated by Sonar -->" 081 + "<module name=\"Checker\">"); 082 } 083 084 private void appendCustomFilters(Writer writer) throws IOException { 085 String filtersXML = conf.getString(CheckstyleConstants.FILTERS_KEY, CheckstyleConstants.FILTERS_DEFAULT_VALUE); 086 if (StringUtils.isNotBlank(filtersXML)) { 087 writer.append(filtersXML); 088 } 089 } 090 091 private void appendCheckerModules(Writer writer, ListMultimap<String, ActiveRule> activeRulesByConfigKey) throws IOException { 092 for (String configKey : activeRulesByConfigKey.keySet()) { 093 if (!isInTreeWalker(configKey)) { 094 List<ActiveRule> activeRules = activeRulesByConfigKey.get(configKey); 095 for (ActiveRule activeRule : activeRules) { 096 appendModule(writer, activeRule); 097 } 098 } 099 } 100 } 101 102 private void appendTreeWalker(Writer writer, ListMultimap<String, ActiveRule> activeRulesByConfigKey) throws IOException { 103 writer.append("<module name=\"TreeWalker\">"); 104 writer.append("<module name=\"FileContentsHolder\"/> "); 105 for (String configKey : activeRulesByConfigKey.keySet()) { 106 if (isInTreeWalker(configKey)) { 107 List<ActiveRule> activeRules = activeRulesByConfigKey.get(configKey); 108 for (ActiveRule activeRule : activeRules) { 109 appendModule(writer, activeRule); 110 } 111 } 112 } 113 writer.append("</module>"); 114 } 115 116 private void appendXmlFooter(Writer writer) throws IOException { 117 writer.append("</module>"); 118 } 119 120 static boolean isInTreeWalker(String configKey) { 121 return StringUtils.startsWithIgnoreCase(configKey, "Checker/TreeWalker/"); 122 } 123 124 private static ListMultimap<String, ActiveRule> arrangeByConfigKey(List<ActiveRule> activeRules) { 125 ListMultimap<String, ActiveRule> result = ArrayListMultimap.create(); 126 if (activeRules != null) { 127 for (ActiveRule activeRule : activeRules) { 128 result.put(activeRule.getConfigKey(), activeRule); 129 } 130 } 131 return result; 132 } 133 134 private void appendModule(Writer writer, ActiveRule activeRule) throws IOException { 135 String moduleName = StringUtils.substringAfterLast(activeRule.getConfigKey(), "/"); 136 writer.append("<module name=\""); 137 StringEscapeUtils.escapeXml(writer, moduleName); 138 writer.append("\">"); 139 if (activeRule.getRule().getParent() != null) { 140 appendModuleProperty(writer, "id", activeRule.getRuleKey()); 141 } 142 appendModuleProperty(writer, "severity", CheckstyleSeverityUtils.toSeverity(activeRule.getSeverity())); 143 appendRuleParameters(writer, activeRule); 144 writer.append("</module>"); 145 } 146 147 private void appendRuleParameters(Writer writer, ActiveRule activeRule) throws IOException { 148 for (RuleParam ruleParam : activeRule.getRule().getParams()) { 149 String value = activeRule.getParameter(ruleParam.getKey()); 150 if (StringUtils.isNotBlank(value)) { 151 appendModuleProperty(writer, ruleParam.getKey(), value); 152 } 153 } 154 } 155 156 private void appendModuleProperty(Writer writer, String propertyKey, String propertyValue) throws IOException { 157 if (StringUtils.isNotBlank(propertyValue)) { 158 writer.append("<property name=\""); 159 StringEscapeUtils.escapeXml(writer, propertyKey); 160 writer.append("\" value=\""); 161 StringEscapeUtils.escapeXml(writer, propertyValue); 162 writer.append("\"/>"); 163 } 164 } 165 166 }