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