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.tools.ant.*;
023 import org.sonar.api.batch.CoverageExtension;
024 import org.sonar.api.batch.Initializer;
025 import org.sonar.api.batch.SupportedEnvironment;
026 import org.sonar.api.resources.Project;
027
028 import java.util.Map;
029
030 @SupportedEnvironment("ant")
031 public class JacocoAntInitializer extends Initializer implements CoverageExtension {
032
033 private final TaskEnhancer[] taskEnhancers = new TaskEnhancer[] { new JavaLikeTaskEnhancer("java"), new JavaLikeTaskEnhancer("junit"), new TestngTaskEnhancer() };
034
035 private org.apache.tools.ant.Project antProject;
036 private JacocoConfiguration configuration;
037
038 public JacocoAntInitializer(org.apache.tools.ant.Project antProject, JacocoConfiguration configuration) {
039 this.antProject = antProject;
040 this.configuration = configuration;
041 }
042
043 @Override
044 public boolean shouldExecuteOnProject(org.sonar.api.resources.Project project) {
045 return project.getAnalysisType().equals(Project.AnalysisType.DYNAMIC);
046 }
047
048 @Override
049 public void execute(org.sonar.api.resources.Project project) {
050 Map<String, Target> hastable = antProject.getTargets();
051 String jvmArg = configuration.getJvmArgument();
052 String[] names = configuration.getAntTargets();
053 for (String name : names) {
054 Target target = hastable.get(name);
055 if (target == null) {
056 JaCoCoUtils.LOG.warn("Target '{}' not found", name);
057 } else {
058 // Enhance target
059 for (Task task : target.getTasks()) {
060 for (TaskEnhancer enhancer : taskEnhancers) {
061 if (enhancer.supportsTask(task)) {
062 enhancer.enhanceTask(task, jvmArg);
063 }
064 }
065 }
066 // Execute target
067 target.performTasks();
068 }
069 }
070 }
071
072 private static class TestngTaskEnhancer extends TaskEnhancer {
073 @Override
074 public boolean supportsTask(Task task) {
075 return "testng".equals(task.getTaskName());
076 }
077 }
078
079 /**
080 * Basic task enhancer that can handle all 'java like' tasks. That is, tasks
081 * that have a top level fork attribute and nested jvmargs elements
082 */
083 private static class JavaLikeTaskEnhancer extends TaskEnhancer {
084 private String taskName;
085
086 public JavaLikeTaskEnhancer(String taskName) {
087 this.taskName = taskName;
088 }
089
090 public boolean supportsTask(final Task task) {
091 return taskName.equals(task.getTaskName());
092 }
093
094 @Override
095 public void enhanceTask(final Task task, final String jvmArg) {
096 final RuntimeConfigurable configurableWrapper = task.getRuntimeConfigurableWrapper();
097
098 final String forkValue = (String) configurableWrapper.getAttributeMap().get("fork");
099
100 if (forkValue == null || !org.apache.tools.ant.Project.toBoolean(forkValue)) {
101 throw new BuildException("Coverage can only be applied on a forked VM");
102 }
103
104 super.enhanceTask(task, jvmArg);
105 }
106
107 }
108
109 private abstract static class TaskEnhancer {
110 /**
111 * @param task Task instance to enhance
112 * @return <code>true</code> if this enhancer is capable of enhancing the requested task
113 */
114 public abstract boolean supportsTask(Task task);
115
116 /**
117 * Attempt to enhance the supplied task with coverage information. This
118 * operation may fail if the task is being executed in the current VM
119 *
120 * @param task Task instance to enhance (usually an {@link UnknownElement})
121 * @param jvmArg
122 * @throws BuildException Thrown if this enhancer can handle this type of task, but this instance can not be enhanced for some reason.
123 */
124 public void enhanceTask(Task task, String jvmArg) {
125 addJvmArg((UnknownElement) task, jvmArg);
126 }
127
128 public void addJvmArg(final UnknownElement task, final String jvmArg) {
129 final UnknownElement el = new UnknownElement("jvmarg");
130 el.setTaskName("jvmarg");
131 el.setQName("jvmarg");
132
133 final RuntimeConfigurable runtimeConfigurableWrapper = el.getRuntimeConfigurableWrapper();
134 runtimeConfigurableWrapper.setAttribute("value", jvmArg);
135
136 task.getRuntimeConfigurableWrapper().addChild(runtimeConfigurableWrapper);
137
138 task.addChild(el);
139 }
140 }
141
142 }