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 com.google.common.io.Closeables; 024import net.sourceforge.pmd.Report; 025import net.sourceforge.pmd.RuleContext; 026import net.sourceforge.pmd.RuleSet; 027import net.sourceforge.pmd.RuleSetFactory; 028import net.sourceforge.pmd.RuleSets; 029import org.sonar.api.BatchExtension; 030import org.sonar.api.profiles.RulesProfile; 031import org.sonar.api.resources.InputFile; 032import org.sonar.api.resources.Java; 033import org.sonar.api.resources.Project; 034import org.sonar.api.resources.ProjectFileSystem; 035import org.sonar.api.utils.TimeProfiler; 036import org.sonar.java.api.JavaUtils; 037 038import java.io.ByteArrayInputStream; 039import java.io.InputStream; 040import java.nio.charset.Charset; 041import java.util.List; 042 043public class PmdExecutor implements BatchExtension { 044 private final Project project; 045 private final ProjectFileSystem projectFileSystem; 046 private final RulesProfile rulesProfile; 047 private final PmdProfileExporter pmdProfileExporter; 048 private final PmdConfiguration pmdConfiguration; 049 050 public PmdExecutor(Project project, ProjectFileSystem projectFileSystem, RulesProfile rulesProfile, PmdProfileExporter pmdProfileExporter, PmdConfiguration pmdConfiguration) { 051 this.project = project; 052 this.projectFileSystem = projectFileSystem; 053 this.rulesProfile = rulesProfile; 054 this.pmdProfileExporter = pmdProfileExporter; 055 this.pmdConfiguration = pmdConfiguration; 056 } 057 058 public Report execute() { 059 TimeProfiler profiler = new TimeProfiler().start("Execute PMD " + PmdVersion.getVersion()); 060 061 ClassLoader initialClassLoader = Thread.currentThread().getContextClassLoader(); 062 try { 063 Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); 064 065 return executePmd(); 066 } finally { 067 Thread.currentThread().setContextClassLoader(initialClassLoader); 068 profiler.stop(); 069 } 070 } 071 072 private Report executePmd() { 073 Report report = new Report(); 074 075 RuleContext context = new RuleContext(); 076 context.setReport(report); 077 078 PmdTemplate pmdFactory = createPmdTemplate(); 079 executeRules(pmdFactory, context, projectFileSystem.mainFiles(Java.KEY), PmdConstants.REPOSITORY_KEY); 080 executeRules(pmdFactory, context, projectFileSystem.testFiles(Java.KEY), PmdConstants.TEST_REPOSITORY_KEY); 081 082 pmdConfiguration.dumpXmlReport(report); 083 084 return report; 085 } 086 087 public void executeRules(PmdTemplate pmdFactory, RuleContext ruleContext, List<InputFile> files, String repositoryKey) { 088 if (files.isEmpty()) { 089 return; // Nothing to analyse 090 } 091 092 RuleSets rulesets = createRulesets(repositoryKey); 093 if (rulesets.getAllRules().isEmpty()) { 094 return; // No rule 095 } 096 097 Charset encoding = projectFileSystem.getSourceCharset(); 098 099 for (InputFile file : files) { 100 pmdFactory.process(file, encoding, rulesets, ruleContext); 101 } 102 } 103 104 private RuleSets createRulesets(String repositoryKey) { 105 String rulesXml = pmdProfileExporter.exportProfile(repositoryKey, rulesProfile); 106 107 pmdConfiguration.dumpXmlRuleSet(repositoryKey, rulesXml); 108 109 return new RuleSets(readRuleSet(rulesXml)); 110 } 111 112 private static RuleSet readRuleSet(String rulesXml) { 113 InputStream rulesInput = null; 114 try { 115 rulesInput = new ByteArrayInputStream(rulesXml.getBytes()); 116 117 return new RuleSetFactory().createRuleSet(rulesInput); 118 } finally { 119 Closeables.closeQuietly(rulesInput); 120 } 121 } 122 123 @VisibleForTesting 124 PmdTemplate createPmdTemplate() { 125 return new PmdTemplate(JavaUtils.getSourceVersion(project)); 126 } 127}