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