001/* 002 * The Apache Software License, Version 1.1 003 * 004 * Copyright (C) 2000-2002 The Apache Software Foundation. All rights 005 * reserved. 006 * Copyright (C) 2003 jcoverage ltd. 007 * Copyright (C) 2005 Mark Doliner 008 * Copyright (C) 2005 Joakim Erdfelt 009 * Copyright (C) 2005 Grzegorz Lukasik 010 * Copyright (C) 2006 Srivathsan Varadarajan 011 * Copyright (C) 2008 Matt Cordes 012 * Copyright (C) 2008 John Lewis 013 * Copyright (C) 2010 Piotr Tabor 014 * 015 * Redistribution and use in source and binary forms, with or without 016 * modification, are permitted provided that the following conditions 017 * are met: 018 * 019 * 1. Redistributions of source code must retain the above copyright 020 * notice, this list of conditions and the following disclaimer. 021 * 022 * 2. Redistributions in binary form must reproduce the above copyright 023 * notice, this list of conditions and the following disclaimer in 024 * the documentation and/or other materials provided with the 025 * distribution. 026 * 027 * 3. The end-user documentation included with the redistribution, if 028 * any, must include the following acknowlegement: 029 * "This product includes software developed by the 030 * Apache Software Foundation (http://www.apache.org/)." 031 * Alternately, this acknowlegement may appear in the software itself, 032 * if and wherever such third-party acknowlegements normally appear. 033 * 034 * 4. The names "Ant" and "Apache Software 035 * Foundation" must not be used to endorse or promote products derived 036 * from this software without prior written permission. For written 037 * permission, please contact apache@apache.org. 038 * 039 * 5. Products derived from this software may not be called "Apache" 040 * nor may "Apache" appear in their names without prior written 041 * permission of the Apache Group. 042 * 043 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 044 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 045 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 046 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 047 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 048 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 049 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 050 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 051 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 052 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 053 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 054 * SUCH DAMAGE. 055 * ==================================================================== 056 * 057 * This software consists of voluntary contributions made by many 058 * individuals on behalf of the Apache Software Foundation. For more 059 * information on the Apache Software Foundation, please see 060 * <http://www.apache.org/>. 061 */ 062 063package net.sourceforge.cobertura.ant; 064 065import java.io.File; 066import java.io.IOException; 067import java.net.URL; 068import java.net.URLClassLoader; 069import java.util.LinkedList; 070import java.util.List; 071 072import net.sourceforge.cobertura.util.CommandLineBuilder; 073import net.sourceforge.cobertura.util.StringUtil; 074 075import org.apache.tools.ant.AntClassLoader; 076import org.apache.tools.ant.BuildException; 077import org.apache.tools.ant.DirectoryScanner; 078import org.apache.tools.ant.Project; 079import org.apache.tools.ant.taskdefs.Java; 080import org.apache.tools.ant.taskdefs.MatchingTask; 081import org.apache.tools.ant.types.FileSet; 082import org.apache.tools.ant.types.AbstractFileSet; 083import org.apache.tools.ant.types.DirSet; 084import org.apache.tools.ant.types.Path; 085import org.apache.tools.ant.types.Reference; 086 087public abstract class CommonMatchingTask extends MatchingTask 088{ 089 090 final String className; 091 final List<AbstractFileSet> fileSets = new LinkedList<AbstractFileSet>(); 092 093 private Java java = null; 094 private String maxMemory = null; 095 private int forkedJVMDebugPort; 096 protected boolean failOnError = false; 097 098 public CommonMatchingTask(String className) 099 { 100 this.className = className; 101 } 102 103 private String getClassName() 104 { 105 return className; 106 } 107 108 protected Java getJava() 109 { 110 if (java == null) 111 { 112 java = (Java)getProject().createTask("java"); 113 java.setTaskName(getTaskName()); 114 java.setClassname(getClassName()); 115 java.setFork(true); 116 java.setFailonerror(failOnError); 117 java.setDir(getProject().getBaseDir()); 118 if (maxMemory != null) 119 java.setJvmargs("-Xmx" + maxMemory); 120 if (forkedJVMDebugPort > 0) 121 { 122 java.setJvmargs("-Xdebug"); 123 java.setJvmargs("-Xrunjdwp:transport=dt_socket,address=" + forkedJVMDebugPort + ",server=y,suspend=y"); 124 } 125 126 /** 127 * We replace %20 with a space character because, for some 128 * reason, when we call Cobertura from within CruiseControl, 129 * the classpath here contains %20's instead of spaces. I 130 * don't know if this is our problem, or CruiseControl, or 131 * ant, but this seems to fix it. --Mark 132 */ 133 if (getClass().getClassLoader() instanceof AntClassLoader) 134 { 135 String classpath = ((AntClassLoader)getClass() 136 .getClassLoader()).getClasspath(); 137 createClasspath().setPath( 138 StringUtil.replaceAll(classpath, "%20", " ")); 139 } 140 else if (getClass().getClassLoader() instanceof URLClassLoader) 141 { 142 URL[] earls = ((URLClassLoader)getClass().getClassLoader()) 143 .getURLs(); 144 for (int i = 0; i < earls.length; i++) 145 { 146 String classpath = (new File(earls[i].getFile())).getAbsolutePath(); 147 createClasspath().setPath( 148 StringUtil.replaceAll(classpath, "%20", " ")); 149 } 150 } 151 } 152 153 return java; 154 } 155 156 protected void createArgumentsForFilesets( CommandLineBuilder builder) throws IOException { 157 boolean filesetFound = false; 158 for (AbstractFileSet fileSet : fileSets) 159 { 160 if (fileSet instanceof FileSet) { 161 filesetFound = true; 162 builder.addArg("--basedir", baseDir(fileSet)); 163 createArgumentsForFilenames( builder, getFilenames(fileSet)); 164 } else { 165 if (filesetFound) { 166 /* 167 * Once --basedir has been used, it cannot be undone without changes to the 168 * Main methods. So, any dirsets have to come before filesets. 169 */ 170 throw new BuildException("Dirsets have to come before filesets"); 171 } 172 createArgumentsForFilenames( builder, getDirectoryScanner(fileSet).getIncludedDirectories()); 173 } 174 } 175 } 176 177 private void createArgumentsForFilenames( CommandLineBuilder builder, String[] filenames) throws IOException 178 { 179 for (int i = 0; i < filenames.length; i++) 180 { 181 getProject().log("Adding " + filenames[i] + " to list", 182 Project.MSG_VERBOSE); 183 builder.addArg(filenames[i]); 184 } 185 } 186 187 public Path createClasspath() 188 { 189 return getJava().createClasspath().createPath(); 190 } 191 192 public void setClasspath(Path classpath) 193 { 194 createClasspath().append(classpath); 195 } 196 197 public void setClasspathRef(Reference r) 198 { 199 createClasspath().setRefid(r); 200 } 201 202 DirectoryScanner getDirectoryScanner(AbstractFileSet fileSet) 203 { 204 return fileSet.getDirectoryScanner(getProject()); 205 } 206 207 String[] getIncludedFiles(AbstractFileSet fileSet) 208 { 209 return getDirectoryScanner(fileSet).getIncludedFiles(); 210 } 211 212 String[] getExcludedFiles(FileSet fileSet) 213 { 214 return getDirectoryScanner(fileSet).getExcludedFiles(); 215 } 216 217 String[] getFilenames(AbstractFileSet fileSet) 218 { 219 String[] filesToReturn = getIncludedFiles(fileSet); 220 221 return filesToReturn; 222 } 223 224 String baseDir(AbstractFileSet fileSet) 225 { 226 return fileSet.getDirectoryScanner(getProject()).getBasedir() 227 .toString(); 228 } 229 230 public void addDirSet(DirSet dirSet) 231 { 232 fileSets.add(dirSet); 233 } 234 235 public void addFileset(FileSet fileSet) 236 { 237 fileSets.add(fileSet); 238 } 239 240 /** 241 * @param maxMemory Assumed to be something along the lines of 242 * 100M or 50K or 1G. 243 */ 244 public void setMaxMemory(String maxMemory) 245 { 246 this.maxMemory = maxMemory != null ? maxMemory.trim() : null; 247 } 248 249 /** 250 * Used to debug the process that is forked to perform the operation. 251 * Setting this to a non-zero number will cause the process to open 252 * a debug port on that port number. It will suspend until a 253 * remote debugger is attached to the port. 254 * 255 * @param forkedJVMDebugPort 256 */ 257 public void setForkedJVMDebugPort(int forkedJVMDebugPort) 258 { 259 this.forkedJVMDebugPort = forkedJVMDebugPort; 260 } 261 262 /** 263 * If true, then fail if the command exits with a 264 * returncode other than zero. 265 * 266 * @param fail if true fail the build when the command exits with a 267 * nonzero returncode. 268 */ 269 public void setFailonerror(boolean fail) { 270 failOnError = fail; 271 } 272 273}