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.jacoco;
021    
022    import org.apache.commons.lang.StringUtils;
023    import org.jacoco.core.runtime.AgentOptions;
024    import org.sonar.api.BatchExtension;
025    import org.sonar.api.Properties;
026    import org.sonar.api.Property;
027    import org.sonar.api.config.Settings;
028    
029    @Properties({
030        @Property(
031            key = JacocoConfiguration.REPORT_PATH_PROPERTY,
032            name = "File with execution data",
033            defaultValue = JacocoConfiguration.REPORT_PATH_DEFAULT_VALUE,
034            description = "Path (absolute or relative) to the file with execution data.",
035            global = false,
036            module = true,
037            project = true
038        ),
039        @Property(
040            key = JacocoConfiguration.INCLUDES_PROPERTY,
041            name = "Includes",
042            description = "A list of class names that should be included in execution analysis." +
043                " The list entries are separated by a colon (:) and may use wildcard characters (* and ?)." +
044                " Except for performance optimization or technical corner cases this option is normally not required.",
045            global = true,
046            project = true,
047            module = true
048        ),
049        @Property(
050            key = JacocoConfiguration.EXCLUDES_PROPERTY,
051            name = "Excludes",
052            defaultValue = JacocoConfiguration.EXCLUDES_DEFAULT_VALUE,
053            description = "A list of class names that should be excluded from execution analysis." +
054                " The list entries are separated by a colon (:) and may use wildcard characters (* and ?)." +
055                " Except for performance optimization or technical corner cases this option is normally not required.",
056            global = true,
057            project = true,
058            module = true
059        ),
060        @Property(
061            key = JacocoConfiguration.EXCLCLASSLOADER_PROPERTY,
062            name = "Excluded class loaders",
063            description = "A list of class loader names that should be excluded from execution analysis." +
064                " The list entries are separated by a colon (:) and may use wildcard characters (* and ?)." +
065                " This option might be required in case of special frameworks that conflict with JaCoCo code" +
066                " instrumentation, in particular class loaders that do not have access to the Java runtime classes.",
067            global = true,
068            project = true,
069            module = true
070        ),
071        @Property(
072            key = JacocoConfiguration.IT_REPORT_PATH_PROPERTY,
073            name = "File with execution data for integration tests",
074            defaultValue = JacocoConfiguration.IT_REPORT_PATH_DEFAULT_VALUE,
075            description = "Path (absolute or relative) to the file with execution data.",
076            global = false,
077            module = true,
078            project = true
079        ),
080        @Property(
081            key = JacocoConfiguration.ANT_TARGETS_PROPERTY,
082            name = "Ant targets",
083            defaultValue = JacocoConfiguration.ANT_TARGETS_DEFAULT_VALUE,
084            description = "Comma separated list of Ant targets for execution of tests.",
085            global = true,
086            module = true,
087            project = true
088        )})
089    public class JacocoConfiguration implements BatchExtension {
090    
091      public static final String REPORT_PATH_PROPERTY = "sonar.jacoco.reportPath";
092      public static final String REPORT_PATH_DEFAULT_VALUE = "target/jacoco.exec";
093      public static final String IT_REPORT_PATH_PROPERTY = "sonar.jacoco.itReportPath";
094      public static final String IT_REPORT_PATH_DEFAULT_VALUE = "";
095      public static final String INCLUDES_PROPERTY = "sonar.jacoco.includes";
096      public static final String EXCLUDES_PROPERTY = "sonar.jacoco.excludes";
097    
098      /**
099       * Hibernate uses Javassist to modify entity classes and without exclusion of such classes from JaCoCo exception might be thrown:
100       * <pre>
101       * Javassist Enhancement failed: org.sonar.api.profiles.Alert
102       * java.lang.VerifyError: (class: org/sonar/api/profiles/Alert_$$_javassist_3, method: <clinit> signature: ()V) Illegal local variable number
103       * </pre>
104       */
105      public static final String EXCLUDES_DEFAULT_VALUE = "*_javassist_*";
106      public static final String EXCLCLASSLOADER_PROPERTY = "sonar.jacoco.exclclassloader";
107      public static final String ANT_TARGETS_PROPERTY = "sonar.jacoco.antTargets";
108      public static final String ANT_TARGETS_DEFAULT_VALUE = "";
109    
110      private Settings settings;
111      private JaCoCoAgentDownloader downloader;
112    
113      public JacocoConfiguration(Settings settings, JaCoCoAgentDownloader downloader) {
114        this.settings = settings;
115        this.downloader = downloader;
116      }
117    
118      public String getReportPath() {
119        return settings.getString(REPORT_PATH_PROPERTY);
120      }
121    
122      public String getItReportPath() {
123        return settings.getString(IT_REPORT_PATH_PROPERTY);
124      }
125    
126      public String getJvmArgument() {
127        AgentOptions options = new AgentOptions();
128        options.setDestfile(getReportPath());
129        String includes = settings.getString(INCLUDES_PROPERTY);
130        if (StringUtils.isNotBlank(includes)) {
131          options.setIncludes(includes);
132        }
133        String excludes = settings.getString(EXCLUDES_PROPERTY);
134        if (StringUtils.isNotBlank(excludes)) {
135          options.setExcludes(excludes);
136        }
137        String exclclassloader = settings.getString(EXCLCLASSLOADER_PROPERTY);
138        if (StringUtils.isNotBlank(exclclassloader)) {
139          options.setExclClassloader(exclclassloader);
140        }
141        return options.getVMArgument(downloader.getAgentJarFile());
142      }
143    
144      public String[] getAntTargets() {
145        return settings.getStringArray(ANT_TARGETS_PROPERTY);
146      }
147    
148      public String getExcludes() {
149        return settings.getString(EXCLUDES_PROPERTY);
150      }
151    
152    }