View Javadoc

1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.cpd;
5   
6   import java.io.File;
7   import java.io.FilenameFilter;
8   import java.util.HashSet;
9   import java.util.List;
10  import java.util.Properties;
11  import java.util.Set;
12  
13  import net.sourceforge.pmd.AbstractConfiguration;
14  import net.sourceforge.pmd.util.FileFinder;
15  
16  import com.beust.jcommander.IStringConverter;
17  import com.beust.jcommander.Parameter;
18  import java.io.Reader;
19  
20  /**
21   *
22   * @author Brian Remedios
23   * @author Romain Pelisse - <belaran@gmail.com>
24   */
25  public class CPDConfiguration extends AbstractConfiguration {
26  
27  	public final static String DEFAULT_LANGUAGE = "java";
28  
29  	public final static String DEFAULT_RENDERER = "text";
30  
31  	@Parameter(names = "--language", description = "Sources code language. Default value is "
32  			+ DEFAULT_LANGUAGE, required = false, converter = LanguageConverter.class)
33  	private Language language;
34  
35  	@Parameter(names = "--minimum-tokens", description = "The minimum token length which should be reported as a duplicate.", required = true)
36  	private int minimumTileSize;
37  
38  	@Parameter(names = "--skip-duplicate-files", description = "Ignore multiple copies of files of the same name and length in comparison", required = false)
39  	private boolean skipDuplicates;
40  
41  	@Parameter(names = "--format", description = "Report format. Default value is "
42  		+ DEFAULT_RENDERER, required = false)
43  	private String rendererName;
44  
45  	/**
46  	 * The actual renderer. constructed by using the {@link #rendererName}.
47  	 * This property is only valid after {@link #postContruct()} has been called!
48  	 */
49  	private Renderer renderer;
50  
51  	@Parameter(names = "--encoding", description = "Characterset to use when processing files", required = false)
52  	private String encoding;
53  
54  	@Parameter(names = "--ignore-literals", description = "Ignore number values and string contents when comparing text", required = false)
55  	private boolean ignoreLiterals;
56  
57  	@Parameter(names = "--ignore-identifiers", description = "Ignore constant and variable names when comparing text", required = false)
58  	private boolean ignoreIdentifiers;
59  
60  	@Parameter(names = "--ignore-annotations", description = "Ignore language annotations when comparing text", required = false)
61  	private boolean ignoreAnnotations;
62  
63  	@Parameter(names = "--skip-lexical-errors", description = "Skip files which can't be tokenized due to invalid characters instead of aborting CPD", required = false)
64  	private boolean skipLexicalErrors = false;
65  
66  	@Parameter(names = "--files", variableArity = true, description = "List of files and directories to process", required = false)
67  	private List<String> files;
68  
69  	@Parameter(names = "--exclude", variableArity = true, description = "Files to be excluded from CPD check", required = false)
70  	private List<String> excludes;
71  
72  	@Parameter(names = "--non-recursive", description = "Don't scan subdirectiories", required = false)
73          private boolean nonRecursive;
74  
75  	@Parameter(names = "--uri", description = "URI to process", required = false)
76  	private String uri;
77  
78  	@Parameter(names = { "--help", "-h" }, description = "Print help text", required = false, help = true)
79  	private boolean help;
80  
81  	// this has to be a public static class, so that JCommander can use it!
82  	public static class LanguageConverter implements IStringConverter<Language> {
83  
84  
85  		public Language convert(String languageString) {
86  			if (languageString == null || "".equals(languageString)) {
87  				languageString = DEFAULT_LANGUAGE;
88  			}
89  			return new LanguageFactory().createLanguage(languageString);
90  		}
91  	}
92  
93  	public CPDConfiguration()
94  	{
95  	}
96  
97  	@Deprecated
98  	public CPDConfiguration(int minimumTileSize, Language language, String encoding)
99  	{
100 		setMinimumTileSize(minimumTileSize);
101 		setLanguage(language);
102 		setEncoding(encoding);
103 	}
104 
105 
106 	public void setEncoding(String encoding) {
107 	    this.encoding = encoding;
108 	}
109 
110 	public SourceCode sourceCodeFor(File file) {
111 		return new SourceCode(new SourceCode.FileCodeLoader(file,
112 				getSourceEncoding()));
113 	}
114 
115 	public SourceCode sourceCodeFor(Reader reader, String sourceCodeName ) {
116 		return new SourceCode(new SourceCode.ReaderCodeLoader(reader, sourceCodeName ));
117 	}
118 
119 	public void postContruct() {
120         if (getEncoding() != null) {
121             super.setSourceEncoding(getEncoding());
122             if (!getEncoding().equals(System.getProperty("file.encoding")))
123                 System.setProperty("file.encoding", getEncoding());
124         }
125 		if ( this.getLanguage() == null )
126 			this.setLanguage(CPDConfiguration.getLanguageFromString(DEFAULT_LANGUAGE));
127 		if (this.getRendererName() == null )
128 		    this.setRendererName(DEFAULT_RENDERER);
129 		if ( this.getRenderer() == null )
130 			this.setRenderer(getRendererFromString(getRendererName()));
131 	}
132 
133 	public static Renderer getRendererFromString(String name /* , String encoding */) {
134 		if (name.equalsIgnoreCase(DEFAULT_RENDERER) || name.equals("")) {
135 			return new SimpleRenderer();
136 		} else if ("xml".equals(name)) {
137 			return new XMLRenderer();
138 		} else if ("csv".equals(name)) {
139 			return new CSVRenderer();
140 		} else if ("vs".equals(name)) {
141 			return new VSRenderer();
142 		}
143 		try {
144 			return (Renderer) Class.forName(name).newInstance();
145 		} catch (Exception e) {
146 			System.out.println("Can't find class '" + name
147 					+ "', defaulting to SimpleRenderer.");
148 		}
149 		return new SimpleRenderer();
150 	}
151 
152 	public static Language getLanguageFromString(String languageString) {
153 		return new LanguageFactory().createLanguage(languageString);
154 	}
155 
156 	public static void setSystemProperties(CPDConfiguration configuration) {
157 		Properties properties = System.getProperties();
158 		if (configuration.isIgnoreLiterals()) {
159 			properties.setProperty(JavaTokenizer.IGNORE_LITERALS, "true");
160 		} else {
161 		    properties.remove(JavaTokenizer.IGNORE_LITERALS);
162 		}
163 		if (configuration.isIgnoreIdentifiers()) {
164 			properties.setProperty(JavaTokenizer.IGNORE_IDENTIFIERS, "true");
165         } else {
166             properties.remove(JavaTokenizer.IGNORE_IDENTIFIERS);
167 		}
168 		if (configuration.isIgnoreAnnotations()) {
169 			properties.setProperty(JavaTokenizer.IGNORE_ANNOTATIONS, "true");
170         } else {
171             properties.remove(JavaTokenizer.IGNORE_ANNOTATIONS);
172 		}
173 		System.setProperties(properties);
174 		configuration.getLanguage().setProperties(properties);
175 	}
176 
177 	public Language getLanguage() {
178 		return language;
179 	}
180 
181 	public void setLanguage(Language language) {
182 		this.language = language;
183 	}
184 
185 	public int getMinimumTileSize() {
186 		return minimumTileSize;
187 	}
188 
189 	public void setMinimumTileSize(int minimumTileSize) {
190 		this.minimumTileSize = minimumTileSize;
191 	}
192 
193 	public boolean isSkipDuplicates() {
194 		return skipDuplicates;
195 	}
196 
197 	public void setSkipDuplicates(boolean skipDuplicates) {
198 		this.skipDuplicates = skipDuplicates;
199 	}
200 
201 	public String getRendererName() {
202 	    return rendererName;
203 	}
204 
205 	public void setRendererName(String rendererName) {
206 	    this.rendererName = rendererName;
207 	}
208 
209 	public Renderer getRenderer() {
210 		return renderer;
211 	}
212 
213 	public Tokenizer tokenizer() {
214 		if ( language == null )
215 			throw new IllegalStateException("Language is null.");
216 		return language.getTokenizer();
217 	}
218 
219     public FilenameFilter filenameFilter() {
220         if (language == null)
221             throw new IllegalStateException("Language is null.");
222 
223         final FilenameFilter languageFilter = language.getFileFilter();
224         final Set<String> exclusions = new HashSet<String>();
225 
226         if (excludes != null) {
227             FileFinder finder = new FileFinder();
228             for (String excludedFile : excludes) {
229                 File exFile = new File(excludedFile);
230                 if (exFile.isDirectory()) {
231                     List<File> files = finder.findFilesFrom(excludedFile, languageFilter, true);
232                     for (File f : files) {
233                         exclusions.add(f.getAbsolutePath());
234                     }
235                 } else {
236                     exclusions.add(exFile.getAbsolutePath());
237                 }
238             }
239         }
240 
241         FilenameFilter filter = new FilenameFilter() {
242             public boolean accept(File dir, String name) {
243                 File f = new File(dir, name);
244                 if (exclusions.contains(f.getAbsolutePath())) {
245                     System.err.println("Excluding " + f.getAbsolutePath());
246                     return false;
247                 }
248                 return languageFilter.accept(dir, name);
249             }
250         };
251         return filter;
252     }
253 
254 	public void setRenderer(Renderer renderer) {
255 		this.renderer = renderer;
256 	}
257 
258 	public boolean isIgnoreLiterals() {
259 		return ignoreLiterals;
260 	}
261 
262 	public void setIgnoreLiterals(boolean ignoreLiterals) {
263 		this.ignoreLiterals = ignoreLiterals;
264 	}
265 
266 	public boolean isIgnoreIdentifiers() {
267 		return ignoreIdentifiers;
268 	}
269 
270 	public void setIgnoreIdentifiers(boolean ignoreIdentifiers) {
271 		this.ignoreIdentifiers = ignoreIdentifiers;
272 	}
273 
274 	public boolean isIgnoreAnnotations() {
275 		return ignoreAnnotations;
276 	}
277 
278 	public void setIgnoreAnnotations(boolean ignoreAnnotations) {
279 		this.ignoreAnnotations = ignoreAnnotations;
280 	}
281 
282 	public boolean isSkipLexicalErrors() {
283 	    return skipLexicalErrors;
284 	}
285 
286 	public void setSkipLexicalErrors(boolean skipLexicalErrors) {
287 	    this.skipLexicalErrors = skipLexicalErrors;
288 	}
289 
290 	public List<String> getFiles() {
291 		return files;
292 	}
293 
294 	public void setFiles(List<String> files) {
295 		this.files = files;
296 	}
297 
298 	public String getURI() {
299 		return uri;
300 	}
301 
302 	public void setURI(String uri) {
303 		this.uri = uri;
304 	}
305 
306 	public List<String> getExcludes() {
307 	    return excludes;
308 	}
309 
310 	public void setExcludes(List<String> excludes) {
311 	    this.excludes = excludes;
312 	}
313 
314 	public boolean isNonRecursive() {
315 		return nonRecursive;
316 	}
317 
318 	public void setNonRecursive(boolean nonRecursive) {
319 		this.nonRecursive = nonRecursive;
320 	}
321 
322 	public boolean isHelp() {
323 		return help;
324 	}
325 
326 	public void setHelp(boolean help) {
327 		this.help = help;
328 	}
329 
330 	public String getEncoding() {
331 		return encoding;
332 	}
333 }