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     */
020    package org.sonar.plugins.findbugs;
021    
022    import org.apache.commons.io.FileUtils;
023    import org.apache.commons.io.IOUtils;
024    import org.apache.commons.lang.StringUtils;
025    import org.sonar.api.BatchExtension;
026    import org.sonar.api.CoreProperties;
027    import org.sonar.api.batch.ProjectClasspath;
028    import org.sonar.api.profiles.RulesProfile;
029    import org.sonar.api.resources.Project;
030    import org.sonar.api.utils.SonarException;
031    import org.sonar.plugins.findbugs.xml.ClassFilter;
032    import org.sonar.plugins.findbugs.xml.FindBugsFilter;
033    import org.sonar.plugins.findbugs.xml.Match;
034    
035    import java.io.*;
036    import java.util.ArrayList;
037    import java.util.List;
038    
039    /**
040     * @since 2.4
041     */
042    public 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    }