1 package org.codehaus.mojo.rmic;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import org.apache.maven.plugin.AbstractMojo;
26 import org.apache.maven.plugin.MojoExecutionException;
27 import org.apache.maven.plugins.annotations.Parameter;
28 import org.apache.maven.project.MavenProject;
29 import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
30 import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
31 import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
32 import org.codehaus.plexus.util.StringUtils;
33
34 import java.io.File;
35 import java.net.URI;
36 import java.net.URL;
37 import java.net.URLClassLoader;
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.Collections;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Set;
44
45
46
47
48
49
50
51 public abstract class AbstractRmiMojo
52 extends AbstractMojo
53 {
54 private static final String STUB_CLASS_PATTERN = "**/*_Stub.class";
55
56
57
58
59 private Source source;
60
61
62
63
64 @Parameter
65 private List<Source> sources;
66
67
68
69
70 @Parameter
71 @SuppressWarnings( "unused" )
72 protected Set<String> includes;
73
74
75
76
77 @Parameter
78 @SuppressWarnings( "unused" )
79 protected Set<String> excludes;
80
81
82
83
84 @Parameter( defaultValue = "sun" )
85 protected String compiler;
86
87 private RmiCompiler rmiCompiler = new BuiltInRmiCompiler();
88
89
90
91
92
93
94 @SuppressWarnings( "unused" )
95 @Parameter
96 private String version;
97
98
99
100
101 @SuppressWarnings( "unused" )
102 @Parameter( defaultValue = "false" )
103 private boolean iiop;
104
105
106
107
108 @SuppressWarnings( "unused" )
109 @Parameter( defaultValue = "false" )
110 private boolean noLocalStubs;
111
112
113
114
115 @SuppressWarnings( "unused" )
116 @Parameter( defaultValue = "false" )
117 private boolean idl;
118
119
120
121
122 @SuppressWarnings( "unused" )
123 @Parameter( defaultValue = "false" )
124 private boolean noValueMethods;
125
126
127
128
129 @SuppressWarnings( "unused" )
130 @Parameter( defaultValue = "false" )
131 private boolean keep;
132
133
134
135
136 @SuppressWarnings( "unused" )
137 @Parameter( defaultValue = "false" )
138 private boolean nowarn;
139
140
141
142
143 @SuppressWarnings( "unused" )
144 @Parameter( defaultValue = "false" )
145 private boolean poa;
146
147
148
149
150 @SuppressWarnings( "unused" )
151 @Parameter( defaultValue = "false" )
152 private boolean verbose;
153
154
155
156
157
158 @SuppressWarnings( "unused" )
159 @Parameter( defaultValue = "0" )
160 private int staleMillis;
161
162
163
164
165
166
167
168
169 @Parameter( defaultValue = "${project}", readonly = true )
170 protected MavenProject project;
171
172
173
174
175 private DependenciesFacade dependencies = new DependenciesFacadeImpl();
176
177
178
179
180 private static final DependenciesFacade DEPENDENCIES_FACADE = new DependenciesFacadeImpl();
181
182
183
184
185 AbstractRmiMojo()
186 {
187 this( DEPENDENCIES_FACADE );
188 }
189
190
191
192
193
194
195
196 AbstractRmiMojo( DependenciesFacade dependencies )
197 {
198 this.dependencies = dependencies;
199 }
200
201
202
203
204 List<Source> getSources()
205 {
206 return sources;
207 }
208
209
210
211
212
213
214 public abstract List<String> getProjectClasspathElements();
215
216
217
218
219
220
221 public abstract File getOutputDirectory();
222
223
224
225
226
227
228 public abstract File getClassesDirectory();
229
230
231
232
233
234
235 public void execute() throws MojoExecutionException
236 {
237 if ( sources != null && source != null && source.getConfiguredOptions().length() > 0 )
238 {
239 throw new MojoExecutionException( "May not use <source> elements in addition to switches "
240 + "without a <source> element: " + source.getConfiguredOptions() );
241 }
242 if ( sources == null || sources.isEmpty() )
243 {
244 sources = Collections.singletonList( getSource() );
245 }
246
247 for ( Source source : sources )
248 {
249 doExecute( source );
250 }
251 }
252
253 private void doExecute( Source source ) throws MojoExecutionException
254 {
255 rmiCompiler.setLog( getLog() );
256
257 if ( source.isVerbose() )
258 {
259 getLog().debug( source.toString() );
260 }
261
262
263 if ( !getOutputDirectory().isDirectory() )
264 {
265 if ( !getOutputDirectory().mkdirs() )
266 {
267 throw new MojoExecutionException( "Could not make output directory: " + "'"
268 + getOutputDirectory().getAbsolutePath() + "'." );
269 }
270 }
271
272 try
273 {
274
275 Set<File> remoteClassesToCompile = getRemoteClasses( source );
276
277 if ( remoteClassesToCompile.size() == 0 )
278 {
279 getLog().info( "No out of date rmi classes to process." );
280 return;
281 }
282
283 getLog().info( "Compiling " + remoteClassesToCompile.size() + " remote classes" );
284
285 RmiCompilerConfiguration config = new RmiCompilerConfiguration();
286 config.setClasspathEntries( getRmicClasspathElements() );
287 config.addSourceLocation( getClassesDirectory().getPath() );
288 config.setSourceFiles( remoteClassesToCompile );
289 config.setIdl( source.isIdl() );
290 config.setIiop( source.isIiop() );
291 config.setKeep( source.isKeep() );
292 config.setNoLocalStubs( source.isNoLocalStubs() );
293 config.setNoValueMethods( source.isNoValueMethods() );
294 config.setNowarn( source.isNowarn() );
295 config.setOutputLocation( getOutputDirectory().getAbsolutePath() );
296 config.setPoa( source.isPoa() );
297 config.setVerbose( source.isVerbose() );
298 config.setVersion( source.getVersion() );
299
300 rmiCompiler.execute( config );
301 }
302 catch ( RmiCompilerException e )
303 {
304 throw new MojoExecutionException( "Error while executing the RMI compiler.", e );
305 }
306 }
307
308
309
310
311
312
313
314 private List<String> getRmicClasspathElements()
315 {
316 List<String> classpathElements = getProjectClasspathElements();
317
318 if ( !classpathElements.contains( getClassesDirectory().getAbsolutePath() ) )
319 {
320 classpathElements.add( getClassesDirectory().getAbsolutePath() );
321 }
322
323 return classpathElements;
324 }
325
326
327
328
329
330
331
332 private Set<File> getRemoteClasses( Source source )
333 {
334 Set<File> remoteClasses = new HashSet<>();
335
336 try
337 {
338
339 List<URL> classpathList = generateUrlCompileClasspath();
340 URL[] classpathUrls = new URL[classpathList.size()];
341 classpathUrls[0] = getClassesDirectory().toURI().toURL();
342 classpathUrls = classpathList.toArray( classpathUrls );
343 dependencies.defineUrlClassLoader( classpathUrls );
344
345
346
347 SourceInclusionScanner scanner = createScanner( source.getIncludes(), getExcludes( source ) );
348 scanner.addSourceMapping( new SuffixMapping( ".class", "_Stub.class" ) );
349
350 Collection<File> staleRemoteClasses
351 = scanner.getIncludedSources( getClassesDirectory(), getOutputDirectory() );
352
353 for ( File file : staleRemoteClasses )
354 {
355 URI relativeURI = getClassesDirectory().toURI().relativize( file.toURI() );
356 String className = fileToClassName( relativeURI.toString() );
357 Class<?> candidateClass = dependencies.loadClass( className );
358 if ( isRemoteRmiClass( candidateClass, source.isIiop() ) )
359 {
360
361 remoteClasses.add( new File( relativeURI.toString() ) );
362 }
363 }
364
365
366 for ( String include : source.getIncludes() )
367 {
368 File includeFile = new File( getClassesDirectory(), include );
369 if ( ( include.contains( "*" ) ) || dependencies.fileExists( includeFile ) )
370 {
371 continue;
372 }
373
374 remoteClasses.add( includeFile );
375 }
376 }
377 catch ( Exception e )
378 {
379 getLog().warn( "Problem while scanning for classes: " + e );
380 }
381 return remoteClasses;
382 }
383
384 private SourceInclusionScanner createScanner( Set<String> includes, Set<String> excludes )
385 {
386 return dependencies.createScanner( staleMillis, includes, excludes );
387 }
388
389 private Set<String> getExcludes( Source source )
390 {
391 Set<String> excludes = source.getExcludes();
392 excludes.add( STUB_CLASS_PATTERN );
393 return excludes;
394 }
395
396 private static String fileToClassName( String classFileName )
397 {
398 return StringUtils.replace( StringUtils.replace( classFileName, ".class", "" ), "/", "." );
399 }
400
401
402 private boolean isRemoteRmiClass( Class<?> remoteClass, boolean isIiop )
403 {
404 return java.rmi.Remote.class.isAssignableFrom( remoteClass ) && ( !remoteClass.isInterface() || isIiop );
405 }
406
407
408
409
410
411
412 private List<URL> generateUrlCompileClasspath()
413 throws MojoExecutionException
414 {
415 List<URL> rmiCompileClasspath = new ArrayList<>();
416 try
417 {
418 rmiCompileClasspath.add( getClassesDirectory().toURI().toURL() );
419 for ( String classpathElement : getRmicClasspathElements() )
420 {
421 URL pathUrl = new File( classpathElement ).toURI().toURL();
422 rmiCompileClasspath.add( pathUrl );
423 }
424 }
425 catch ( Exception e )
426 {
427 e.printStackTrace();
428 throw new MojoExecutionException( "Problem while generating classpath: " + e.getMessage() );
429 }
430 return rmiCompileClasspath;
431 }
432
433 private Source getSource()
434 {
435 if ( source == null )
436 {
437 source = new Source();
438 }
439 return source;
440 }
441
442
443
444
445
446
447
448 @SuppressWarnings( "unused" )
449 public void setIncludes( Set<String> includes )
450 {
451 getSource().setIncludes( includes );
452 }
453
454
455
456
457
458 public void setExcludes( Set<String> excludes )
459 {
460 getSource().setExcludes( excludes );
461 }
462
463
464
465
466
467 public void setVersion( String version )
468 {
469 getSource().setVersion( version );
470 }
471
472
473
474
475
476 public void setIiop( Boolean iiop )
477 {
478 getSource().setIiop( iiop );
479 }
480
481
482
483
484
485
486 public void setNoLocalStubs( Boolean noLocalStubs )
487 {
488 getSource().setNoLocalStubs( noLocalStubs );
489 }
490
491
492
493
494
495 @SuppressWarnings( "unused" )
496 public void setIdl( Boolean idl )
497 {
498 getSource().setIdl( idl );
499 }
500
501
502
503
504
505
506 @SuppressWarnings( "unused" )
507 public void setNoValueMethods( Boolean noValueMethods )
508 {
509 getSource().setNoValueMethods( noValueMethods );
510 }
511
512
513
514
515
516 @SuppressWarnings( "unused" )
517 public void setKeep( Boolean keep )
518 {
519 getSource().setKeep( keep );
520 }
521
522
523
524
525
526 @SuppressWarnings( "unused" )
527 public void setNowarn( Boolean nowarn )
528 {
529 getSource().setNowarn( nowarn );
530 }
531
532
533
534
535
536
537 public void setPoa( Boolean poa )
538 {
539 getSource().setPoa( poa );
540 }
541
542
543
544
545
546 public void setVerbose( Boolean verbose )
547 {
548 getSource().setVerbose( verbose );
549 }
550
551
552
553
554
555 interface DependenciesFacade
556 {
557 boolean fileExists( File includeFile );
558
559 SourceInclusionScanner createScanner( int staleMillis, Set<String> includes, Set<String> excludes );
560
561 Class<?> loadClass( String className ) throws ClassNotFoundException;
562
563 void defineUrlClassLoader( URL[] classpathUrls );
564 }
565
566
567
568
569 private static class DependenciesFacadeImpl implements DependenciesFacade
570 {
571 private static URLClassLoader loader;
572
573 public Class<?> loadClass( String className ) throws ClassNotFoundException
574 {
575 return loader.loadClass( className );
576 }
577
578 public void defineUrlClassLoader( URL[] classpathUrls )
579 {
580 loader = new URLClassLoader( classpathUrls );
581 }
582
583 public boolean fileExists( File includeFile )
584 {
585 return includeFile.exists();
586 }
587
588 public SourceInclusionScanner createScanner( int staleMillis, Set<String> includes, Set<String> excludes )
589 {
590 return new StaleSourceScanner( staleMillis, includes, excludes );
591 }
592 }
593 }