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.findbugs;
021
022import org.apache.commons.io.FileUtils;
023import org.apache.commons.io.IOUtils;
024import org.apache.commons.lang.StringUtils;
025import org.sonar.api.BatchExtension;
026import org.sonar.api.CoreProperties;
027import org.sonar.api.batch.ProjectClasspath;
028import org.sonar.api.profiles.RulesProfile;
029import org.sonar.api.resources.Project;
030import org.sonar.api.utils.SonarException;
031import org.sonar.plugins.findbugs.xml.ClassFilter;
032import org.sonar.plugins.findbugs.xml.FindBugsFilter;
033import org.sonar.plugins.findbugs.xml.Match;
034
035import java.io.*;
036import java.util.ArrayList;
037import java.util.List;
038
039/**
040 * @since 2.4
041 */
042public class FindbugsConfiguration implements BatchExtension {
043
044  private Project project;
045  private RulesProfile profile;
046  private FindbugsProfileExporter exporter;
047  private ProjectClasspath projectClasspath;
048
049  public FindbugsConfiguration(Project project, RulesProfile profile, FindbugsProfileExporter exporter, ProjectClasspath classpath) {
050    this.project = project;
051    this.profile = profile;
052    this.exporter = exporter;
053    this.projectClasspath = classpath;
054  }
055
056  public File getTargetXMLReport() {
057    if (project.getConfiguration().getBoolean(FindbugsConstants.GENERATE_XML_KEY, FindbugsConstants.GENERATE_XML_DEFAULT_VALUE)) {
058      return new File(project.getFileSystem().getSonarWorkingDirectory(), "findbugs-result.xml");
059    }
060    return null;
061  }
062
063  public edu.umd.cs.findbugs.Project getFindbugsProject() {
064    File classesDir = project.getFileSystem().getBuildOutputDir();
065    if (classesDir == null || !classesDir.exists()) {
066      throw new SonarException("Findbugs needs sources to be compiled. "
067          + "Please build project before executing sonar and check the location of compiled classes.");
068    }
069
070    edu.umd.cs.findbugs.Project findbugsProject = new edu.umd.cs.findbugs.Project();
071    for (File dir : project.getFileSystem().getSourceDirs()) {
072      findbugsProject.addSourceDir(dir.getAbsolutePath());
073    }
074    findbugsProject.addFile(classesDir.getAbsolutePath());
075    for (File file : projectClasspath.getElements()) {
076      if (!file.equals(classesDir)) {
077        findbugsProject.addAuxClasspathEntry(file.getAbsolutePath());
078      }
079    }
080    findbugsProject.addAuxClasspathEntry(annotationsLib.getAbsolutePath());
081    findbugsProject.addAuxClasspathEntry(jsr305Lib.getAbsolutePath());
082    findbugsProject.setCurrentWorkingDirectory(project.getFileSystem().getBuildDir());
083    return findbugsProject;
084  }
085
086  public File saveIncludeConfigXml() throws IOException {
087    StringWriter conf = new StringWriter();
088    exporter.exportProfile(profile, conf);
089    return project.getFileSystem().writeToWorkingDirectory(conf.toString(), "findbugs-include.xml");
090  }
091
092  public File saveExcludeConfigXml() throws IOException {
093    FindBugsFilter findBugsFilter = new FindBugsFilter();
094    if (project.getExclusionPatterns() != null) {
095      for (String exclusion : project.getExclusionPatterns()) {
096        ClassFilter classFilter = new ClassFilter(FindbugsAntConverter.antToJavaRegexpConvertor(exclusion));
097        findBugsFilter.addMatch(new Match(classFilter));
098      }
099    }
100    return project.getFileSystem().writeToWorkingDirectory(findBugsFilter.toXml(), "findbugs-exclude.xml");
101  }
102
103  public List<File> getExcludesFilters() {
104    List<File> result = new ArrayList<File>();
105    String[] filters = project.getConfiguration().getStringArray(FindbugsConstants.EXCLUDES_FILTERS_PROPERTY);
106    for (String excludesFilterPath : filters) {
107      excludesFilterPath = StringUtils.trim(excludesFilterPath);
108      if (StringUtils.isNotBlank(excludesFilterPath)) {
109        result.add(project.getFileSystem().resolvePath(excludesFilterPath));
110      }
111    }
112    return result;
113  }
114
115  public String getEffort() {
116    return StringUtils.lowerCase(project.getConfiguration().getString(CoreProperties.FINDBUGS_EFFORT_PROPERTY,
117        CoreProperties.FINDBUGS_EFFORT_DEFAULT_VALUE));
118  }
119
120  public long getTimeout() {
121    return project.getConfiguration().getLong(CoreProperties.FINDBUGS_TIMEOUT_PROPERTY, CoreProperties.FINDBUGS_TIMEOUT_DEFAULT_VALUE);
122  }
123
124  private File jsr305Lib;
125  private File annotationsLib;
126
127  /**
128   * Invoked by PicoContainer to extract additional FindBugs libraries into temporary files.
129   */
130  public void start() {
131    jsr305Lib = copyLib("/jsr305-" + FindbugsVersion.getVersion() + ".jar");
132    annotationsLib = copyLib("/annotations-" + FindbugsVersion.getVersion() + ".jar");
133  }
134
135  /**
136   * Invoked by PicoContainer to remove temporary files.
137   */
138  public void stop() {
139    jsr305Lib.delete();
140    annotationsLib.delete();
141  }
142
143  private File copyLib(String name) {
144    try {
145      InputStream is = getClass().getResourceAsStream(name);
146      File temp = File.createTempFile("findbugs", ".jar");
147      OutputStream os = FileUtils.openOutputStream(temp);
148      IOUtils.copy(is, os);
149      return temp;
150    } catch (IOException e) {
151      throw new SonarException(e);
152    }
153  }
154}