root/trunk/src/java/org/jcoderz/phoenix/jcoverage/Instrumenter.java

Revision 1011, 11.7 kB (checked in by amandel, 4 years ago)

Aligned svn keyword settings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.phoenix.jcoverage;
34
35import java.io.File;
36import java.io.FileFilter;
37import java.io.IOException;
38import java.util.ArrayList;
39import java.util.Iterator;
40import java.util.List;
41import java.util.logging.Level;
42import java.util.logging.Logger;
43
44import net.sourceforge.cobertura.instrument.Main;
45
46import org.jcoderz.commons.util.FileUtils;
47import org.jcoderz.commons.util.JarUtils;
48
49
50/**
51 *
52 * @author Michael Griffel
53 */
54public final class Instrumenter
55{
56   private static final String CLASSNAME = Instrumenter.class.getName();
57
58   private static final Logger logger = Logger.getLogger(CLASSNAME);
59
60   private final ConfigurationParameters mConfig;
61
62   private final File mBaseTempDir
63      = new File(System.getProperty("java.io.tmpdir"));
64
65   /**
66    * Constructor.
67    * @param config the configuration parameters.
68    */
69   public Instrumenter (ConfigurationParameters config)
70   {
71      mConfig = config;
72   }
73
74   /**
75    * Main method.
76    * @param args command line arguments.
77    */
78   public static void main (String[] args)
79      throws Exception
80   {
81      Main.main(args); 
82
83      logger.info("Instrumentation of '" + args[0] + "' done.");
84   }
85
86   private static void parseArguments (String[] args)
87   {
88      // final List arguments = new ArrayList();
89      try
90      {
91         for (int i = 0; i < args.length; )
92         {
93            logger.info("Parsing argument '" 
94                  + args[i] + "' = '" + args[i + 1] + "'");
95           
96            if (args[i].equals("-jcoverage"))
97            {
98               // FIXME: result.setJcoverage(new File(args[i + 1]));
99            }
100            else if (args[i].equals("-log4j"))
101            {
102               // FIXME: result.setLog4j(new File(args[i + 1]));
103            }
104            else if (args[i].equals("-archive"))
105            {
106               // FIXME: result.setArchive(new File(args[i + 1]));
107            }
108            else if (args[i].equals("-loglevel"))
109            {
110               Logger.getLogger("").setLevel(Level.parse(args[i + 1]));
111            }
112            else
113            {
114               throw new IllegalArgumentException("Invalid argument '" 
115                     + args[i]  + "'");
116            }
117           
118            ++i;
119            ++i;
120         }
121      }
122      catch (IndexOutOfBoundsException e)
123      {
124         final IllegalArgumentException ex = new IllegalArgumentException(
125               "Missing value for " + args[args.length - 1]);
126         ex.initCause(e);
127         throw ex;
128      }
129     
130      // FIXME: checkFileExists(result.getArchive());
131      // FIXME: checkFileExists(result.getLog4j());
132      // FIXME: checkFileExists(result.getJcoverage());
133     
134   }
135
136   /**
137    * Checks if the given file exists.
138    * @param f the file to check
139    * @throws IllegalArgumentException if the file does not exists.
140    */
141   private static void checkFileExists (File f)
142   {
143      if (!f.exists())
144      {
145         throw new IllegalArgumentException("The file '" 
146               + f.getAbsolutePath() + "' does not exists.");
147      }
148   }
149
150   /**
151    * Run JCoverage instrumentation on the archive file.
152    * @throws IOException in case of an I/O error.
153    */
154   public void instrument () 
155         throws IOException
156   {
157      instrument(mConfig.getArchive());
158   }
159   
160   /**
161    * Run JCoverage instrumentation on file <code>f</code>.
162    * @param f file to instrument.
163    * @throws IOException in case of an I/O error.
164    */
165   public void instrument (File f) 
166         throws IOException
167   {
168      if (isArchive(f))
169      {
170         final File tempDir
171               = FileUtils.createTempDir(mBaseTempDir, f.getName());
172         JarUtils.extractJarArchive(tempDir, f);
173     
174         instrument(tempDir);
175     
176         if (!f.delete())
177         {
178            throw new IOException("Cannot remove file " + f); 
179         }
180                 
181         JarUtils.createJarArchive(tempDir, f);
182         FileUtils.rmdir(tempDir);
183         logger.info("Creating new jar " + f);
184      }
185      else if (f.isDirectory())
186      {
187         instrumentClasses(f);
188         findNestedArchives(f);
189      }
190   }
191
192   /**
193    * @param f
194    */
195   private void instrumentClasses (File f) 
196         throws IOException
197   {
198      final List classPath = new ArrayList();
199      findClassPath(f, classPath);
200      final List classFiles = new ArrayList();
201      for (final Iterator pathEntrys = classPath.iterator(); 
202            pathEntrys.hasNext();)
203      {
204         final File originDir = (File) pathEntrys.next();
205         classFiles.clear();
206         findClassFiles(originDir, originDir, classFiles);
207
208         final File tmpDir = FileUtils.createTempDir(
209               mBaseTempDir, "instrumented-classes");
210
211         instrument(classFiles, originDir, tmpDir);
212
213         // move back to origin basedir
214         FileUtils.copySlashStar(tmpDir, originDir);
215
216         // copy coverage file to jar location
217         // the jcoverage*ser files are written to the current working directory
218         // of the JVM!
219         /*
220         final List jcoverageFiles = FileUtils.findFile(
221               new File("."), "jcoverage.*\\.ser");
222         for (final Iterator iterator = jcoverageFiles.iterator();
223               iterator.hasNext();)
224         {
225            final File file = (File) iterator.next();
226            FileUtils.copy(file, originDir);
227         }
228         */
229         
230         // add jcoverage.jar/log4j classes
231         JarUtils.extractJarArchive(originDir, mConfig.getJcoverage());
232         JarUtils.extractJarArchive(originDir, mConfig.getLog4j());
233
234         FileUtils.rmdir(tmpDir);
235      }     
236   }
237
238   /**
239    * Calls the Instrument class from the jcoverage package.
240    *
241    * @param classFiles
242    * @param classpath
243    * @param destinationDir
244    * @throws IOException
245    */
246   private void instrument (
247         List classFiles, File classpath, File destinationDir) 
248         throws IOException
249   {
250      // Instrumentation
251      final List args = new ArrayList();
252      args.add("-d");
253      args.add(destinationDir.getCanonicalPath());
254      args.add("-ignore");
255      args.add("org.apache.log4j.*");
256      args.add("-basedir");
257      args.add(classpath.getCanonicalPath());
258      args.addAll(classFiles);
259
260      logger.finest("Instrument with the following args: " + args);
261           
262      Main.main((String[]) args.toArray(new String[0]));
263   }
264   
265   /**
266    * @param pathEntry
267    * @param pathEntry2
268    * @param classFiles
269    */
270   private void findClassFiles (File basePath, File file, List classFiles) 
271         throws IOException
272   {
273      if (file.isFile())
274      {
275         final String className = FileUtils.getRelativePath(basePath, file);
276         if (className.endsWith(".class") && className.indexOf('$') == -1
277               && className.matches(".*org.jcoderz.*"))
278         {
279            //className = className.substring(
280            //      0, className.length() - ".class".length());
281            /*
282            if (File.separator.equals("\\"))
283            {
284               className = className.replaceAll("\\\\", ".");
285            }
286            else
287            {   
288               className = className.replaceAll(File.separator, ".");
289            }
290            */
291            classFiles.add(className);
292         }
293      }
294      else if (file.isDirectory())
295      {
296         final File [] files = file.listFiles();
297       
298         for (int i = 0; files != null && i < files.length; i++)
299         {
300            findClassFiles(basePath, files[i], classFiles);
301         }
302      }
303   }
304
305   /**
306    * @param f
307    * @param classPath
308    */
309   private void findClassPath (File f, List classPath)
310   {
311      final File [] files = f.listFiles(new FileFilter()
312            {
313               public boolean accept (File pathname)
314               {
315                  return pathname.isDirectory();
316               }
317            });
318
319      boolean found = false;
320      for (int i = 0; !found && i < files.length; i++)
321      {
322         if (files[i].getName().equals("com") 
323             || files[i].getName().equals("junit"))
324         {
325            classPath.add(files[i].getParentFile());
326            found = true;
327         }
328      }
329      if (!found)
330      {
331         for (int i = 0; i < files.length; i++)
332         {
333            findClassPath(files[i], classPath);
334         }
335      }
336   }
337
338   /**
339    * @param f
340    */
341   private void findNestedArchives (File file) 
342         throws IOException
343   {
344      if (file == null)
345      {
346         // done...
347      }
348      else if (file.isDirectory())
349      {
350         final File [] files = file.listFiles();
351         for (int i = 0; i < files.length; i++)
352         {
353            findNestedArchives(files[i]);
354         }
355      }
356      else 
357      {
358         if (isArchive(file))
359         {
360            instrument(file);
361         }
362      }
363   }
364
365   private boolean isArchive (File file) 
366         throws IOException
367   {
368      return file.getCanonicalPath().matches(".*\\.[jerw]ar");
369   }
370   
371   private static class ConfigurationParameters
372   {
373      private File mArchive = null;
374      private File mLog4j = null;
375      private File mJcoverage = null;     
376
377      /**
378       * Returns the archive.
379       * @return the archive.
380       */
381      public final File getArchive ()
382      {
383         return mArchive;
384      }
385
386      /**
387       * Sets the archive to given <code>archive</code>.
388       * @param archive The archive to set.
389       */
390      public final void setArchive (File archive)
391      {
392         mArchive = archive;
393      }
394
395      /**
396       * Returns the jcoverage.
397       * @return the jcoverage.
398       */
399      public final File getJcoverage ()
400      {
401         return mJcoverage;
402      }
403
404      /**
405       * Sets the jcoverage to given <code>jcoverage</code>.
406       * @param jcoverage The jcoverage to set.
407       */
408      public final void setJcoverage (File jcoverage)
409      {
410         mJcoverage = jcoverage;
411      }
412
413      /**
414       * Returns the log4j.
415       * @return the log4j.
416       */
417      public final File getLog4j ()
418      {
419         return mLog4j;
420      }
421
422      /**
423       * Sets the log4j to given <code>log4j</code>.
424       * @param log4j The log4j to set.
425       */
426      public final void setLog4j (File log4j)
427      {
428         mLog4j = log4j;
429      }
430
431   }
432   
433}
Note: See TracBrowser for help on using the browser.