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    
062    package net.sourceforge.cobertura.ant;
063    
064    import java.io.File;
065    import java.io.IOException;
066    import java.net.URL;
067    import java.net.URLClassLoader;
068    import java.util.Iterator;
069    import java.util.LinkedList;
070    import java.util.List;
071    
072    import net.sourceforge.cobertura.util.CommandLineBuilder;
073    import net.sourceforge.cobertura.util.StringUtil;
074    
075    import org.apache.tools.ant.AntClassLoader;
076    import org.apache.tools.ant.BuildException;
077    import org.apache.tools.ant.DirectoryScanner;
078    import org.apache.tools.ant.Project;
079    import org.apache.tools.ant.taskdefs.Java;
080    import org.apache.tools.ant.taskdefs.MatchingTask;
081    import org.apache.tools.ant.types.FileSet;
082    import org.apache.tools.ant.types.AbstractFileSet;
083    import org.apache.tools.ant.types.DirSet;
084    import org.apache.tools.ant.types.Path;
085    import org.apache.tools.ant.types.Reference;
086    
087    public 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    }