View Javadoc

1   package org.naftulin.classpathexplorer;
2   
3   
4   import java.io.File;
5   import java.util.Arrays;
6   import java.util.Iterator;
7   import java.util.LinkedList;
8   import java.util.List;
9   
10  import org.apache.tools.ant.BuildException;
11  import org.apache.tools.ant.Project;
12  import org.apache.tools.ant.Task;
13  import org.apache.tools.ant.types.Path;
14  
15  
16  /***
17   * Ant task that detects and reports dublicate resources. This task has the following 
18   * properties:
19   * Path - either an inline path or path like structure that tell the task which
20   *  direcotries or jar (zip) files to scan for dublicate resrources. Required 
21   *  attribute.
22   * AccetedExtensions - tells which files to consider when reporting dublicates.
23   *  By default, all files are considered, but you might want to limit it to
24   *  .class and .xml. Accepts a comma separated list of extensions. Not required.
25   * NumDublicateThreshold - how many dublicates should the task ignore, before 
26   *  reporing problem. Default is 0.
27   * FailOnError - if there are more dublicate files than threshold alows, should
28   *  the build fail. Default is true.
29   *   
30   * @author henry naftulin
31   * @version 1.0
32   */
33  public class DublicateResourceDetectorAntTask  extends Task {
34  	private static final String[] NO_FILTER = new String[0];
35  	private final List libSet = new LinkedList();
36  	private int numDublicateThreshold;
37  	private boolean failOnError = true;
38  	private String[] acceptedExtensions = NO_FILTER; 
39  	
40  	/***
41  	 * Path - either an inline path or path like structure that tell the task which
42  	 *  direcotries or jar (zip) files to scan for dublicate resrources. Required 
43  	 *  attribute.
44  	 * @param p path
45  	 */
46  	public void setPath(Path p) {
47  		log("setting path " + p, Project.MSG_DEBUG);
48  		libSet.add(p);
49  	}
50  	
51  	/***
52  	 * AccetedExtensions - tells which files to consider when reporting dublicates.
53  	 *  By default, all files are considered, but you might want to limit it to
54  	 *  .class and .xml. Accepts a comma separated list of extensions. Not required.
55  	 * @param extensions
56  	 */
57  	public void setAcceptedExtensions(String extensions) {
58  		if (extensions != null) {
59  			acceptedExtensions = extensions.split(",");
60  		}
61  	}
62  	
63  	/***
64  	 * Path - either an inline path or path like structure that tell the task which
65  	 *  direcotries or jar (zip) files to scan for dublicate resrources. Required 
66  	 *  attribute.
67  	 * @return path.
68  	 */
69  	public Path createPath() {		
70  		Path path = new Path(getProject());
71          libSet.add(path);
72          log("adding a path " + path, Project.MSG_DEBUG);
73          return path;
74  	}
75  	
76  	/***
77  	 * FailOnError - if there are more dublicate files than threshold alows, should
78  	 *  the build fail. Default is true.
79  	 * @param failOnError
80  	 */
81  	public void setFailOnError(boolean failOnError) {
82  		this.failOnError = failOnError;
83  	}
84  
85  	/***
86  	 * NumDublicateThreshold - how many dublicates should the task ignore, before 
87  	 *  reporing problem. Default is 0.
88  	 * @param numDublicateThreshold
89  	 */
90  	public void setNumDublicateThreshold(int numDublicateThreshold) {
91  		this.numDublicateThreshold = numDublicateThreshold;
92  	}
93  	
94  	/***
95  	 * Ant task that detects and reports dublicate resources.
96  	 */	
97  	public void execute() throws BuildException {
98  		if (libSet.size() == 0) {
99  			throw new BuildException("Error: you have to specify path (like classpath) to search for dublicate resources.");
100 		}		
101 		Iterator it = libSet.iterator();
102 		Path tempPath;
103 		List archivesList = new LinkedList();
104 		while(it.hasNext()) {
105 			tempPath = (Path) it.next();
106 			archivesList.addAll(Arrays.asList(tempPath.list()));
107 		}
108 		String[] archivesArray = new String[archivesList.size()];
109 		archivesArray = (String[]) archivesList.toArray(archivesArray);
110 		for(int i=0; i < archivesArray.length; ++i) {
111 			File f = new File(archivesArray[i]);
112 			if (!f.exists()) {
113 				throw new BuildException("Error: Archive " + archivesArray[i] + " does not exist. Please remove it from the path before running this task.");
114 			}
115 			if (!f.isDirectory() && !archivesArray[i].endsWith(".jar") && !archivesArray[i].endsWith(".zip")) {
116 				throw new BuildException("Error: Archive " + archivesArray[i] + " does not a directory or .jar or .zip. Please remove it from the path before running this task");
117 			}
118 		}
119 		ClassPathExplorerFacade facade = new ClassPathExplorerFacade();
120 		AccessibleResource[] dups = facade.getFileteredDublicateResourcesBasedOnPath(acceptedExtensions, archivesArray);
121 		if (dups.length >0) {			
122 			if (dups.length > this.numDublicateThreshold) {
123 				logDublicates(dups, failOnError ? Project.MSG_ERR : Project.MSG_WARN);
124 				if (failOnError) {
125 					throw new BuildException("Error: found " + dups.length + " dublicate.");
126 				}
127 			} else {
128 				log(dups.length + " dublicates found, to see all dublicates configure ant logging to INFO level", Project.MSG_WARN);
129 				logDublicates(dups, Project.MSG_INFO);
130 			}
131 		} else {
132 			log("No dublicates found.", Project.MSG_INFO);
133 		}
134 	}
135 	
136 	private void logDublicates(AccessibleResource[] dups, int logLevel) {
137 		for(int i=0; i < dups.length; ++i) {
138 			log("Resource dublicated: " + dups[i], logLevel);
139 		}
140 	}
141 }