1 package org.codehaus.mojo.apt;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import java.io.File;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.Iterator;
32 import java.util.LinkedHashSet;
33 import java.util.List;
34 import java.util.Set;
35
36 import org.apache.maven.artifact.Artifact;
37 import org.apache.maven.artifact.DependencyResolutionRequiredException;
38 import org.apache.maven.model.Resource;
39 import org.apache.maven.plugin.AbstractMojo;
40 import org.apache.maven.plugin.MojoExecutionException;
41 import org.apache.maven.project.MavenProject;
42 import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
43 import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
44 import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
45 import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
46 import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping;
47 import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
48 import org.codehaus.plexus.util.StringUtils;
49
50
51
52
53
54
55
56
57 public abstract class AbstractAptMojo extends AbstractMojo
58 {
59
60
61
62
63
64
65
66
67
68 private MavenProject project;
69
70
71
72
73
74
75
76
77 private List<Artifact> pluginArtifacts;
78
79
80
81
82
83
84
85
86 private File workingDirectory;
87
88
89
90
91
92
93
94
95 private boolean fork;
96
97
98
99
100
101
102 private String executable;
103
104
105
106
107
108
109 private String meminitial;
110
111
112
113
114
115
116 private String maxmem;
117
118
119
120
121
122
123 private boolean showWarnings;
124
125
126
127
128
129
130
131
132 private String encoding;
133
134
135
136
137
138
139
140 private boolean verbose;
141
142
143
144
145
146
147 private String[] options;
148
149
150
151
152
153
154
155 private String factory;
156
157
158
159
160
161
162 private List<String> additionalSourceRoots;
163
164
165
166
167
168
169 private String resourceTargetPath;
170
171
172
173
174
175
176 private boolean resourceFiltering;
177
178
179
180
181
182
183
184 private boolean force;
185
186
187
188
189
190
191
192
193
194 private Set<String> outputFiles;
195
196
197
198
199
200
201
202
203
204 private Set<String> outputFileEndings;
205
206
207
208
209
210
211
212 private int staleMillis;
213
214
215
216
217
218
219 private boolean skip;
220
221
222
223 private Set<String> includes;
224
225 private Set<String> excludes;
226
227
228
229
230
231
232 public final void execute() throws MojoExecutionException
233 {
234 if ( skip )
235 {
236 getLog().info( "Skipping apt" );
237 }
238 else
239 {
240 executeImpl();
241 }
242 }
243
244
245
246 protected void executeImpl() throws MojoExecutionException
247 {
248
249
250 includes = CollectionUtils.defaultSet( getIncludes(), Collections.singleton( "**/*.java" ) );
251 excludes = CollectionUtils.defaultSet( getExcludes() );
252
253
254
255 List<File> staleSourceFiles = getSourceFiles( getStaleScanner(), "stale sources" );
256
257 if ( staleSourceFiles.isEmpty() )
258 {
259 getLog().info( "Nothing to process - all processor-generated files are up to date" );
260 }
261 else
262 {
263 executeApt();
264 }
265
266
267
268 String sourcePath = getSourceOutputDirectory().getPath();
269
270 if ( !getCompileSourceRoots().contains( sourcePath ) )
271 {
272 getCompileSourceRoots().add( sourcePath );
273 }
274
275
276
277 String resourcePath = getOutputDirectory().getPath();
278
279 if ( !MavenProjectUtils.containsDirectory( getResources(), resourcePath ) )
280 {
281 Resource resource = new Resource();
282
283 resource.setDirectory( resourcePath );
284 resource.addExclude( "**/*.java" );
285 resource.setFiltering( resourceFiltering );
286
287 if ( resourceTargetPath != null )
288 {
289 resource.setTargetPath( resourceTargetPath );
290 }
291
292 getResources().add( resource );
293 }
294 }
295
296
297
298
299
300
301 protected MavenProject getProject()
302 {
303 return project;
304 }
305
306
307
308
309
310
311 protected String[] getOptions()
312 {
313 return options;
314 }
315
316
317
318
319
320
321 protected abstract List<String> getCompileSourceRoots();
322
323
324
325
326
327
328 protected abstract List<Resource> getResources();
329
330
331
332
333
334
335 protected abstract List<String> getClasspathElements();
336
337
338
339
340
341
342 protected abstract Set<String> getIncludes();
343
344
345
346
347
348
349 protected abstract Set<String> getExcludes();
350
351
352
353
354
355
356 protected abstract File getOutputDirectory();
357
358
359
360
361
362
363
364 protected abstract File getSourceOutputDirectory();
365
366
367
368 private void executeApt() throws MojoExecutionException
369 {
370 List<File> sourceFiles = getSourceFiles( getSourceScanner(), "sources" );
371
372 if ( getLog().isInfoEnabled() )
373 {
374 int count = sourceFiles.size();
375
376 getLog().info( "Processing " + count + " source file" + ( count == 1 ? "" : "s" ) );
377 }
378
379 List<String> args = createArgs( sourceFiles );
380
381 boolean success;
382
383 if ( fork )
384 {
385 success = AptUtils.invokeForked( getLog(), workingDirectory, executable, meminitial, maxmem, args );
386 }
387 else
388 {
389 success = AptUtils.invoke( getLog(), args );
390 }
391
392 if ( !success )
393 {
394 throw new MojoExecutionException( "Apt failed" );
395 }
396 }
397
398 private List<String> createArgs( List<File> sourceFiles ) throws MojoExecutionException
399 {
400 List<String> args = new ArrayList<String>();
401
402
403
404 Set<String> classpathElements = new LinkedHashSet<String>();
405 classpathElements.addAll( getPluginClasspathElements() );
406 classpathElements.addAll( getClasspathElements() );
407
408 if ( !classpathElements.isEmpty() )
409 {
410 args.add( "-classpath" );
411 args.add( toPath( classpathElements ) );
412 }
413
414 List<String> sourcePaths = getSourcePaths();
415
416 if ( !sourcePaths.isEmpty() )
417 {
418 args.add( "-sourcepath" );
419 args.add( toPath( sourcePaths ) );
420 }
421
422 args.add( "-d" );
423 args.add( getOutputDirectory().getAbsolutePath() );
424
425 if ( !showWarnings )
426 {
427 args.add( "-nowarn" );
428 }
429
430 if ( encoding != null )
431 {
432 args.add( "-encoding" );
433 args.add( encoding );
434 }
435
436 if ( verbose )
437 {
438 args.add( "-verbose" );
439 }
440
441
442
443 args.add( "-s" );
444 args.add( getSourceOutputDirectory().getAbsolutePath() );
445
446
447 args.add( "-nocompile" );
448
449 if ( options != null )
450 {
451 for ( String option : options )
452 {
453 args.add( "-A" + option.trim() );
454 }
455 }
456
457 if ( StringUtils.isNotEmpty( factory ) )
458 {
459 args.add( "-factory" );
460 args.add( factory );
461 }
462
463
464
465 for ( File file : sourceFiles )
466 {
467 args.add( file.getAbsolutePath() );
468 }
469
470 return args;
471 }
472
473 private static String toPath( Collection<String> paths )
474 {
475 StringBuffer buffer = new StringBuffer();
476
477 for ( Iterator<String> iterator = paths.iterator(); iterator.hasNext(); )
478 {
479 buffer.append( iterator.next() );
480
481 if ( iterator.hasNext() )
482 {
483 buffer.append( File.pathSeparator );
484 }
485 }
486
487 return buffer.toString();
488 }
489
490 private List<String> getPluginClasspathElements() throws MojoExecutionException
491 {
492 try
493 {
494 return MavenProjectUtils.getClasspathElements( project, pluginArtifacts );
495 }
496 catch ( DependencyResolutionRequiredException exception )
497 {
498 throw new MojoExecutionException( "Cannot get plugin classpath elements", exception );
499 }
500 }
501
502 private List<String> getSourcePaths()
503 {
504 List<String> sourcePaths = new ArrayList<String>();
505
506 sourcePaths.addAll( getCompileSourceRoots() );
507
508 if ( additionalSourceRoots != null )
509 {
510 sourcePaths.addAll( additionalSourceRoots );
511 }
512
513 return sourcePaths;
514 }
515
516 private List<File> getSourceFiles( SourceInclusionScanner scanner, String name ) throws MojoExecutionException
517 {
518 List<File> sourceFiles = new ArrayList<File>();
519
520 for ( String path : getSourcePaths() )
521 {
522 File sourceDir = new File( path );
523
524 sourceFiles.addAll( getSourceFiles( scanner, name, sourceDir ) );
525 }
526
527 return sourceFiles;
528 }
529
530 private Set<File> getSourceFiles( SourceInclusionScanner scanner, String name, File sourceDir )
531 throws MojoExecutionException
532 {
533 Set<File> sources;
534
535 if ( sourceDir.isDirectory() )
536 {
537 try
538 {
539 Set<?> rawSources = scanner.getIncludedSources( sourceDir, getOutputDirectory() );
540
541 sources = CollectionUtils.genericSet( rawSources, File.class );
542 }
543 catch ( InclusionScanException exception )
544 {
545 throw new MojoExecutionException( "Error scanning source directory: " + sourceDir, exception );
546 }
547 }
548 else
549 {
550 sources = Collections.emptySet();
551 }
552
553 if ( getLog().isDebugEnabled() )
554 {
555 if ( sources.isEmpty() )
556 {
557 getLog().debug( "No " + name + " found in " + sourceDir );
558 }
559 else
560 {
561 getLog().debug( StringUtils.capitalizeFirstLetter( name ) + " found in " + sourceDir + ":" );
562
563 LogUtils.log( getLog(), LogUtils.LEVEL_DEBUG, sources, " " );
564 }
565 }
566
567 return sources;
568 }
569
570 private SourceInclusionScanner getStaleScanner()
571 {
572
573
574 SourceInclusionScanner scanner;
575
576 if ( force )
577 {
578 if ( !CollectionUtils.isEmpty( outputFiles ) || !CollectionUtils.isEmpty( outputFileEndings ) )
579 {
580 getLog().warn( "Not using staleness checking - ignoring outputFiles and outputFileEndings" );
581 }
582
583 getLog().debug( "Processing all source files" );
584
585 scanner = createSimpleScanner();
586 }
587 else
588 {
589 scanner = new StaleSourceScanner( staleMillis, includes, excludes );
590
591 if ( !CollectionUtils.isEmpty( outputFiles ) )
592 {
593 if ( !CollectionUtils.isEmpty( outputFileEndings ) )
594 {
595 getLog().warn( "Both outputFiles and outputFileEndings specified - using outputFiles" );
596 }
597
598 getLog().debug( "Computing stale sources against target files " + outputFiles );
599
600 for ( String file : outputFiles )
601 {
602 scanner.addSourceMapping( new SingleTargetSourceMapping( ".java", file ) );
603 }
604 }
605 else
606 {
607 Set<String> suffixes = CollectionUtils.defaultSet( outputFileEndings, Collections.singleton( ".java" ) );
608
609 getLog().debug( "Computing stale sources against target file endings " + suffixes );
610
611 scanner.addSourceMapping( new SuffixMapping( ".java", suffixes ) );
612 }
613 }
614
615 return scanner;
616 }
617
618 private SourceInclusionScanner getSourceScanner()
619 {
620 SourceInclusionScanner scanner;
621
622 if ( force || CollectionUtils.isEmpty( outputFiles ) )
623 {
624 scanner = getStaleScanner();
625 }
626 else
627 {
628 scanner = createSimpleScanner();
629 }
630
631 return scanner;
632 }
633
634 private SourceInclusionScanner createSimpleScanner()
635 {
636 SourceInclusionScanner scanner = new SimpleSourceInclusionScanner( includes, excludes );
637
638
639 scanner.addSourceMapping( new SuffixMapping( "", "" ) );
640
641 return scanner;
642 }
643 }