/* * Sonar PHP Plugin * Copyright (C) 2010 Sonar PHP Plugin * 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.php.pmd; import static org.apache.commons.lang.StringUtils.isBlank; import static org.sonar.plugins.php.pmd.PhpmdRuleRepository.PHPMD_REPOSITORY_KEY; import java.io.IOException; import java.io.Reader; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.rules.ActiveRule; import org.sonar.api.rules.Rule; import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.RuleQuery; import org.sonar.api.utils.ValidationMessages; import org.sonar.plugins.php.api.Php; import org.sonar.plugins.php.core.PhpProfileImporter; import org.sonar.plugins.php.pmd.xml.PmdProperty; import org.sonar.plugins.php.pmd.xml.PmdRule; import org.sonar.plugins.php.pmd.xml.PmdRuleset; /** * * */ public class PhpmdProfileImporter extends PhpProfileImporter { public static final String XPATH_CLASS = "net.sourceforge.pmd.rules.XPathRule"; public static final String XPATH_EXPRESSION_PARAM = "xpath"; public static final String XPATH_MESSAGE_PARAM = "message"; private final RuleFinder ruleFinder; /** * @param ruleFinder */ public PhpmdProfileImporter(RuleFinder ruleFinder) { super(PhpmdRuleRepository.PHPMD_REPOSITORY_KEY, PhpmdRuleRepository.PHPMD_REPOSITORY_NAME); setSupportedLanguages(Php.KEY); this.ruleFinder = ruleFinder; } /** * @see org.sonar.api.profiles.ProfileImporter#importProfile(java.io.Reader, org.sonar.api.utils.ValidationMessages) */ @Override public RulesProfile importProfile(Reader pmdConfigurationFile, ValidationMessages messages) { PmdRuleset pmdRuleset = parsePmdRuleset(pmdConfigurationFile, messages); return createRuleProfile(pmdRuleset, messages); } /** * @param pmdRuleset * @param messages * @return */ protected RulesProfile createRuleProfile(PmdRuleset pmdRuleset, ValidationMessages messages) { RulesProfile profile = RulesProfile.create(); for (PmdRule pmdRule : pmdRuleset.getPmdRules()) { if (XPATH_CLASS.equals(pmdRule.getClazz())) { StringBuilder message = new StringBuilder("PMD XPath rule '").append(pmdRule.getName()); message.append("' can't be imported automatically. The rule must be created manually through the Sonar web interface."); messages.addWarningText(message.toString()); } String configKey = pmdRule.getRef(); if (configKey == null) { StringBuilder message = new StringBuilder("Rule '").append(pmdRule.getClazz()); message.append("' does not have a 'ref' attribute and can't be imported"); messages.addWarningText(message.toString()); } else { Rule rule = ruleFinder.find(RuleQuery.create().withRepositoryKey(PHPMD_REPOSITORY_KEY).withConfigKey(configKey)); if (rule == null) { StringBuilder message = new StringBuilder("Unable to import unknown PMD rule '"); message.append(configKey).append("' consider adding an extension in sonar extenions directory"); messages.addWarningText(message.toString()); } else { createRule(messages, profile, pmdRule, configKey, rule); } } } return profile; } /** * @param messages * @param profile * @param pmdRule * @param configKey * @param rule */ private void createRule(ValidationMessages messages, RulesProfile profile, PmdRule pmdRule, String configKey, Rule rule) { PmdRulePriorityMapper mapper = new PmdRulePriorityMapper(); ActiveRule activeRule = profile.activateRule(rule, mapper.from(pmdRule.getPriority())); if (pmdRule.getProperties() != null) { for (PmdProperty prop : pmdRule.getProperties()) { String name = prop.getName(); if (rule.getParam(name) != null) { String value = prop.getValue(); String ruleValue = prop.isCdataValue() && isBlank(value) ? prop.getCdataValue() : value; activeRule.setParameter(name, ruleValue); } else { StringBuilder message = new StringBuilder("The property '").append(name); message.append("' is not supported in the pmd rule: ").append(configKey); messages.addWarningText(message.toString()); } } } } /** * @param pmdConfigurationFile * @param messages * @return */ protected PmdRuleset parsePmdRuleset(Reader pmdConfigurationFile, ValidationMessages messages) { try { SAXBuilder parser = new SAXBuilder(); Document dom = parser.build(pmdConfigurationFile); Element ruleSetNode = dom.getRootElement(); Namespace namespace = ruleSetNode.getNamespace(); PmdRuleset pmdResultset = new PmdRuleset(); for (Element ruleNode : getChildren(ruleSetNode, "rule", namespace)) { PmdRule pmdRule = new PmdRule(ruleNode.getAttributeValue("ref")); pmdRule.setClazz(ruleNode.getAttributeValue("class")); pmdRule.setName(ruleNode.getAttributeValue("name")); pmdRule.setMessage(ruleNode.getAttributeValue("message")); parsePmdPriority(ruleNode, pmdRule, namespace); parsePmdProperties(ruleNode, pmdRule, namespace); pmdResultset.addRule(pmdRule); } return pmdResultset; } catch (IOException e) { return emptyRuleSetAndLogMessages(messages, e); } catch (JDOMException e) { return emptyRuleSetAndLogMessages(messages, e); } } }