1 package org.apache.maven.plugins.pmd;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.UnsupportedEncodingException;
25 import java.util.Locale;
26 import java.util.Properties;
27 import java.util.ResourceBundle;
28
29 import org.apache.maven.plugins.annotations.Mojo;
30 import org.apache.maven.plugins.annotations.Parameter;
31 import org.apache.maven.plugins.pmd.exec.CpdExecutor;
32 import org.apache.maven.plugins.pmd.exec.CpdRequest;
33 import org.apache.maven.plugins.pmd.exec.CpdResult;
34 import org.apache.maven.reporting.MavenReportException;
35 import org.apache.maven.shared.utils.logging.MessageUtils;
36 import org.apache.maven.toolchain.Toolchain;
37 import org.codehaus.plexus.util.StringUtils;
38 import org.codehaus.plexus.util.WriterFactory;
39
40 import net.sourceforge.pmd.cpd.JavaTokenizer;
41 import net.sourceforge.pmd.cpd.renderer.CPDRenderer;
42
43
44
45
46
47
48
49
50
51
52
53
54 @Mojo( name = "cpd", threadSafe = true )
55 public class CpdReport
56 extends AbstractPmdReport
57 {
58
59
60
61
62
63
64 @Parameter( defaultValue = "java" )
65 private String language;
66
67
68
69
70 @Parameter( property = "minimumTokens", defaultValue = "100" )
71 private int minimumTokens;
72
73
74
75
76
77
78 @Parameter( property = "cpd.skip", defaultValue = "false" )
79 private boolean skip;
80
81
82
83
84
85
86
87
88 @Parameter( property = "cpd.ignoreLiterals", defaultValue = "false" )
89 private boolean ignoreLiterals;
90
91
92
93
94
95
96 @Parameter( property = "cpd.ignoreIdentifiers", defaultValue = "false" )
97 private boolean ignoreIdentifiers;
98
99
100
101
102
103
104 @Parameter( property = "cpd.ignoreAnnotations", defaultValue = "false" )
105 private boolean ignoreAnnotations;
106
107
108
109
110
111
112 private CpdResult cpdResult;
113
114
115
116
117 public String getName( Locale locale )
118 {
119 return getBundle( locale ).getString( "report.cpd.name" );
120 }
121
122
123
124
125 public String getDescription( Locale locale )
126 {
127 return getBundle( locale ).getString( "report.cpd.description" );
128 }
129
130
131
132
133 @Override
134 public void executeReport( Locale locale )
135 throws MavenReportException
136 {
137 try
138 {
139 execute( locale );
140 }
141 finally
142 {
143 if ( getSink() != null )
144 {
145 getSink().close();
146 }
147 }
148 }
149
150 private void execute( Locale locale )
151 throws MavenReportException
152 {
153 if ( !skip && canGenerateReport() )
154 {
155 ClassLoader origLoader = Thread.currentThread().getContextClassLoader();
156 try
157 {
158 Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader() );
159
160 generateMavenSiteReport( locale );
161 }
162 finally
163 {
164 Thread.currentThread().setContextClassLoader( origLoader );
165 }
166
167 }
168 }
169
170 @Override
171 public boolean canGenerateReport()
172 {
173 if ( skip )
174 {
175 getLog().info( "Skipping CPD execution" );
176 return false;
177 }
178
179 boolean result = super.canGenerateReport();
180 if ( result )
181 {
182 try
183 {
184 executeCpd();
185 if ( skipEmptyReport )
186 {
187 result = cpdResult.hasDuplications();
188 if ( !result )
189 {
190 getLog().debug( "Skipping report since skipEmptyReport is true and there are no CPD issues." );
191 }
192 }
193 }
194 catch ( MavenReportException e )
195 {
196 throw new RuntimeException( e );
197 }
198 }
199 return result;
200 }
201
202 private void executeCpd()
203 throws MavenReportException
204 {
205 if ( cpdResult != null )
206 {
207
208 getLog().debug( "CPD has already been run - skipping redundant execution." );
209 return;
210 }
211
212 Properties languageProperties = new Properties();
213 if ( ignoreLiterals )
214 {
215 languageProperties.setProperty( JavaTokenizer.IGNORE_LITERALS, "true" );
216 }
217 if ( ignoreIdentifiers )
218 {
219 languageProperties.setProperty( JavaTokenizer.IGNORE_IDENTIFIERS, "true" );
220 }
221 if ( ignoreAnnotations )
222 {
223 languageProperties.setProperty( JavaTokenizer.IGNORE_ANNOTATIONS, "true" );
224 }
225 try
226 {
227 filesToProcess = getFilesToProcess();
228
229 CpdRequest request = new CpdRequest();
230 request.setMinimumTokens( minimumTokens );
231 request.setLanguage( language );
232 request.setLanguageProperties( languageProperties );
233 request.setSourceEncoding( determineEncoding( !filesToProcess.isEmpty() ) );
234 request.addFiles( filesToProcess.keySet() );
235
236 request.setShowPmdLog( showPmdLog );
237 request.setColorizedLog( MessageUtils.isColorEnabled() );
238 request.setLogLevel( determineCurrentRootLogLevel() );
239
240 request.setExcludeFromFailureFile( excludeFromFailureFile );
241 request.setTargetDirectory( targetDirectory.getAbsolutePath() );
242 request.setOutputEncoding( getOutputEncoding() );
243 request.setFormat( format );
244 request.setIncludeXmlInSite( includeXmlInSite );
245 request.setReportOutputDirectory( getReportOutputDirectory().getAbsolutePath() );
246
247 Toolchain tc = getToolchain();
248 if ( tc != null )
249 {
250 getLog().info( "Toolchain in maven-pmd-plugin: " + tc );
251 String javaExecutable = tc.findTool( "java" );
252 request.setJavaExecutable( javaExecutable );
253 }
254
255 getLog().info( "PMD version: " + AbstractPmdReport.getPmdVersion() );
256 cpdResult = CpdExecutor.execute( request );
257 }
258 catch ( UnsupportedEncodingException e )
259 {
260 throw new MavenReportException( "Encoding '" + getSourceEncoding() + "' is not supported.", e );
261 }
262 catch ( IOException e )
263 {
264 throw new MavenReportException( e.getMessage(), e );
265 }
266 }
267
268 private void generateMavenSiteReport( Locale locale )
269 {
270 CpdReportGenerator gen = new CpdReportGenerator( getSink(), filesToProcess, getBundle( locale ),
271 isAggregator() );
272 gen.generate( cpdResult.getDuplications() );
273 }
274
275 private String determineEncoding( boolean showWarn )
276 throws UnsupportedEncodingException
277 {
278 String encoding = WriterFactory.FILE_ENCODING;
279 if ( StringUtils.isNotEmpty( getSourceEncoding() ) )
280 {
281
282 encoding = getSourceEncoding();
283
284 WriterFactory.newWriter( new ByteArrayOutputStream(), encoding );
285
286 }
287 else if ( showWarn )
288 {
289 getLog().warn( "File encoding has not been set, using platform encoding " + WriterFactory.FILE_ENCODING
290 + ", i.e. build is platform dependent!" );
291 encoding = WriterFactory.FILE_ENCODING;
292 }
293 return encoding;
294 }
295
296
297
298
299 public String getOutputName()
300 {
301 return "cpd";
302 }
303
304 private static ResourceBundle getBundle( Locale locale )
305 {
306 return ResourceBundle.getBundle( "cpd-report", locale, CpdReport.class.getClassLoader() );
307 }
308
309
310
311
312
313
314
315
316 @Deprecated
317 public CPDRenderer createRenderer() throws MavenReportException
318 {
319 return CpdExecutor.createRenderer( format, getOutputEncoding() );
320 }
321 }