001/* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 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 */ 020package org.sonar.plugins.pmd; 021 022import com.google.common.annotations.VisibleForTesting; 023import org.jdom.CDATA; 024import org.jdom.Document; 025import org.jdom.Element; 026import org.jdom.output.Format; 027import org.jdom.output.XMLOutputter; 028import org.sonar.api.profiles.ProfileExporter; 029import org.sonar.api.profiles.RulesProfile; 030import org.sonar.api.resources.Java; 031import org.sonar.api.rules.ActiveRule; 032import org.sonar.api.rules.ActiveRuleParam; 033import org.sonar.api.utils.SonarException; 034import org.sonar.plugins.pmd.xml.PmdProperty; 035import org.sonar.plugins.pmd.xml.PmdRule; 036import org.sonar.plugins.pmd.xml.PmdRuleset; 037 038import java.io.IOException; 039import java.io.StringWriter; 040import java.io.Writer; 041import java.util.ArrayList; 042import java.util.List; 043 044public class PmdProfileExporter extends ProfileExporter { 045 public PmdProfileExporter() { 046 super(PmdConstants.REPOSITORY_KEY, PmdConstants.PLUGIN_NAME); 047 setSupportedLanguages(Java.KEY); 048 setMimeType("application/xml"); 049 } 050 051 @Override 052 public void exportProfile(RulesProfile profile, Writer writer) { 053 try { 054 String xmlModules = exportProfile(PmdConstants.REPOSITORY_KEY, profile); 055 writer.append(xmlModules); 056 } catch (IOException e) { 057 throw new SonarException("Fail to export the profile " + profile, e); 058 } 059 } 060 061 public String exportProfile(String repositoryKey, RulesProfile profile) { 062 PmdRuleset tree = createPmdRuleset(repositoryKey, profile.getActiveRulesByRepository(repositoryKey), profile.getName()); 063 return exportPmdRulesetToXml(tree); 064 } 065 066 private PmdRuleset createPmdRuleset(String repositoryKey, List<ActiveRule> activeRules, String profileName) { 067 PmdRuleset ruleset = new PmdRuleset(profileName); 068 for (ActiveRule activeRule : activeRules) { 069 if (activeRule.getRule().getRepositoryKey().equals(repositoryKey)) { 070 String configKey = activeRule.getRule().getConfigKey(); 071 PmdRule rule = new PmdRule(configKey, PmdLevelUtils.toLevel(activeRule.getSeverity())); 072 if ((activeRule.getActiveRuleParams() != null) && !activeRule.getActiveRuleParams().isEmpty()) { 073 List<PmdProperty> properties = new ArrayList<PmdProperty>(); 074 for (ActiveRuleParam activeRuleParam : activeRule.getActiveRuleParams()) { 075 properties.add(new PmdProperty(activeRuleParam.getRuleParam().getKey(), activeRuleParam.getValue())); 076 } 077 rule.setProperties(properties); 078 } 079 ruleset.addRule(rule); 080 processXPathRule(activeRule.getRuleKey(), rule); 081 } 082 } 083 return ruleset; 084 } 085 086 @VisibleForTesting 087 void processXPathRule(String sonarRuleKey, PmdRule rule) { 088 if (PmdConstants.XPATH_CLASS.equals(rule.getRef())) { 089 rule.setRef(null); 090 PmdProperty xpathMessage = rule.getProperty(PmdConstants.XPATH_MESSAGE_PARAM); 091 if (xpathMessage == null) { 092 throw new SonarException("Property '" + PmdConstants.XPATH_MESSAGE_PARAM + "' should be set for PMD rule " + sonarRuleKey); 093 } 094 rule.setMessage(xpathMessage.getValue()); 095 rule.removeProperty(PmdConstants.XPATH_MESSAGE_PARAM); 096 PmdProperty xpathExp = rule.getProperty(PmdConstants.XPATH_EXPRESSION_PARAM); 097 if (xpathExp == null) { 098 throw new SonarException("Property '" + PmdConstants.XPATH_EXPRESSION_PARAM + "' should be set for PMD rule " + sonarRuleKey); 099 } 100 xpathExp.setCdataValue(xpathExp.getValue()); 101 rule.setClazz(PmdConstants.XPATH_CLASS); 102 rule.setName(sonarRuleKey); 103 } 104 } 105 106 private String exportPmdRulesetToXml(PmdRuleset pmdRuleset) { 107 Element eltRuleset = new Element("ruleset"); 108 for (PmdRule pmdRule : pmdRuleset.getPmdRules()) { 109 Element eltRule = new Element("rule"); 110 addAttribute(eltRule, "ref", pmdRule.getRef()); 111 addAttribute(eltRule, "class", pmdRule.getClazz()); 112 addAttribute(eltRule, "message", pmdRule.getMessage()); 113 addAttribute(eltRule, "name", pmdRule.getName()); 114 addChild(eltRule, "priority", pmdRule.getPriority()); 115 if (pmdRule.hasProperties()) { 116 Element eltProperties = new Element("properties"); 117 eltRule.addContent(eltProperties); 118 for (PmdProperty prop : pmdRule.getProperties()) { 119 Element eltProperty = new Element("property"); 120 eltProperty.setAttribute("name", prop.getName()); 121 if (prop.isCdataValue()) { 122 Element eltValue = new Element("value"); 123 eltValue.addContent(new CDATA(prop.getCdataValue())); 124 eltProperty.addContent(eltValue); 125 } else { 126 eltProperty.setAttribute("value", prop.getValue()); 127 } 128 eltProperties.addContent(eltProperty); 129 } 130 } 131 eltRuleset.addContent(eltRule); 132 } 133 XMLOutputter serializer = new XMLOutputter(Format.getPrettyFormat()); 134 StringWriter xml = new StringWriter(); 135 try { 136 serializer.output(new Document(eltRuleset), xml); 137 } catch (IOException e) { 138 throw new SonarException("A exception occured while generating the PMD configuration file.", e); 139 } 140 return xml.toString(); 141 } 142 143 private void addChild(Element elt, String name, String text) { 144 if (text != null) { 145 elt.addContent(new Element(name).setText(text)); 146 } 147 } 148 149 private void addAttribute(Element elt, String name, String value) { 150 if (value != null) { 151 elt.setAttribute(name, value); 152 } 153 } 154}