18
18
19
19
import static de .thetaphi .forbiddenapis .Checker .Option .*;
20
20
21
+ import org .apache .maven .artifact .Artifact ;
22
+ import org .apache .maven .artifact .factory .ArtifactFactory ;
23
+ import org .apache .maven .artifact .repository .ArtifactRepository ;
24
+ import org .apache .maven .artifact .resolver .ArtifactNotFoundException ;
25
+ import org .apache .maven .artifact .resolver .ArtifactResolutionException ;
26
+ import org .apache .maven .artifact .resolver .ArtifactResolver ;
21
27
import org .apache .maven .plugin .AbstractMojo ;
22
28
import org .apache .maven .plugin .MojoExecutionException ;
23
- import org .apache .maven .plugin . logging . Log ;
29
+ import org .apache .maven .plugins . annotations . Component ;
24
30
import org .apache .maven .plugins .annotations .Parameter ;
25
31
import org .codehaus .plexus .util .DirectoryScanner ;
26
32
33
39
import java .io .File ;
34
40
import java .io .IOException ;
35
41
import java .lang .annotation .RetentionPolicy ;
42
+ import java .net .URI ;
43
+ import java .net .URISyntaxException ;
36
44
import java .net .URLClassLoader ;
37
45
import java .net .MalformedURLException ;
38
46
import java .net .URL ;
41
49
import java .util .LinkedHashSet ;
42
50
import java .util .List ;
43
51
import java .util .Locale ;
52
+ import java .util .Set ;
44
53
45
54
/**
46
55
* Base class for forbiddenapis Mojos.
@@ -56,6 +65,36 @@ public abstract class AbstractCheckMojo extends AbstractMojo {
56
65
@ Parameter (required = false )
57
66
private File [] signaturesFiles ;
58
67
68
+ /**
69
+ * Lists all Maven artifacts, which contain signatures and comments for forbidden API calls.
70
+ * The artifact needs to be specified like a Maven dependency. Resolution is not transitive.
71
+ * You can refer to plain text Maven artifacts ({@code type="txt"}, e.g., with a separate {@code classifier}):
72
+ * <pre>
73
+ * <signaturesArtifact>
74
+ * <groupId>org.apache.foobar</groupId>
75
+ * <artifactId>example</artifactId>
76
+ * <version>1.0</version>
77
+ * <classifier>signatures</classifier>
78
+ * <type>txt</type>
79
+ * </signaturesArtifact>
80
+ * </pre>
81
+ * Alternatively, refer to signatures files inside JAR artifacts. In that case, the additional
82
+ * parameter {@code path} has to be given:
83
+ * <pre>
84
+ * <signaturesArtifact>
85
+ * <groupId>org.apache.foobar</groupId>
86
+ * <artifactId>example</artifactId>
87
+ * <version>1.0</version>
88
+ * <type>jar</type>
89
+ * <path>path/inside/jar/file/signatures.txt</path>
90
+ * </signaturesArtifact>
91
+ * </pre>
92
+ * <p>The signatures are resolved against the compile classpath.
93
+ * @since 2.0
94
+ */
95
+ @ Parameter (required = false )
96
+ private SignaturesArtifact [] signaturesArtifacts ;
97
+
59
98
/**
60
99
* Gives a multiline list of signatures, inline in the pom.xml. Use an XML CDATA section to do that!
61
100
* The signatures are resolved against the compile classpath.
@@ -163,6 +202,18 @@ public abstract class AbstractCheckMojo extends AbstractMojo {
163
202
/** The project packaging (pom, jar, etc.). */
164
203
@ Parameter (defaultValue = "${project.packaging}" , readonly = true , required = true )
165
204
private String packaging ;
205
+
206
+ @ Component
207
+ private ArtifactFactory artifactFactory ;
208
+
209
+ @ Component
210
+ private ArtifactResolver artifactResolver ;
211
+
212
+ @ Parameter (defaultValue = "${project.remoteArtifactRepositories}" , readonly = true , required = true )
213
+ private List <ArtifactRepository > remoteRepositories ;
214
+
215
+ @ Parameter (defaultValue = "${localRepository}" , readonly = true , required = true )
216
+ private ArtifactRepository localRepository ;
166
217
167
218
/** provided by the concrete Mojos for compile and test classes processing */
168
219
protected abstract List <String > getClassPathElements ();
@@ -174,10 +225,46 @@ public abstract class AbstractCheckMojo extends AbstractMojo {
174
225
protected String getTargetVersion () {
175
226
return targetVersion ;
176
227
}
228
+
229
+ private File resolveSignaturesArtifact (SignaturesArtifact signaturesArtifact ) throws ArtifactResolutionException , ArtifactNotFoundException {
230
+ final Artifact artifact = signaturesArtifact .createArtifact (artifactFactory );
231
+ artifactResolver .resolve (artifact , this .remoteRepositories , this .localRepository );
232
+ return artifact .getFile ();
233
+ }
234
+
235
+ private String encodeUrlPath (String path ) {
236
+ try {
237
+ // hack to encode the URL path by misusing URI class:
238
+ return new URI (null , path , null ).toASCIIString ();
239
+ } catch (URISyntaxException e ) {
240
+ throw new IllegalArgumentException (e .getMessage ());
241
+ }
242
+ }
243
+
244
+ private URL createJarUrl (File f , String jarPath ) throws MalformedURLException {
245
+ final URL fileUrl = f .toURI ().toURL ();
246
+ final URL jarBaseUrl = new URL ("jar" , null , fileUrl .toExternalForm () + "!/" );
247
+ return new URL (jarBaseUrl , encodeUrlPath (jarPath ));
248
+ }
177
249
178
250
@ Override
179
251
public void execute () throws MojoExecutionException {
180
- final Log log = getLog ();
252
+ final Logger log = new Logger () {
253
+ @ Override
254
+ public void error (String msg ) {
255
+ getLog ().error (msg );
256
+ }
257
+
258
+ @ Override
259
+ public void warn (String msg ) {
260
+ getLog ().warn (msg );
261
+ }
262
+
263
+ @ Override
264
+ public void info (String msg ) {
265
+ getLog ().info (msg );
266
+ }
267
+ };
181
268
182
269
if (skip ) {
183
270
log .info ("Skipping forbidden-apis checks." );
@@ -202,7 +289,6 @@ public void execute() throws MojoExecutionException {
202
289
urls [i ++] = new File (cpElement ).toURI ().toURL ();
203
290
}
204
291
assert i == urls .length ;
205
- if (log .isDebugEnabled ()) log .debug ("Compile Classpath: " + Arrays .toString (urls ));
206
292
} catch (MalformedURLException e ) {
207
293
throw new MojoExecutionException ("Failed to build classpath." , e );
208
294
}
@@ -218,22 +304,7 @@ public void execute() throws MojoExecutionException {
218
304
if (failOnMissingClasses ) options .add (FAIL_ON_MISSING_CLASSES );
219
305
if (failOnViolation ) options .add (FAIL_ON_VIOLATION );
220
306
if (failOnUnresolvableSignatures ) options .add (FAIL_ON_UNRESOLVABLE_SIGNATURES );
221
- final Checker checker = new Checker (new Logger () {
222
- @ Override
223
- public void error (String msg ) {
224
- log .error (msg );
225
- }
226
-
227
- @ Override
228
- public void warn (String msg ) {
229
- log .warn (msg );
230
- }
231
-
232
- @ Override
233
- public void info (String msg ) {
234
- log .info (msg );
235
- }
236
- }, loader , options );
307
+ final Checker checker = new Checker (log , loader , options );
237
308
238
309
if (!checker .isSupportedJDK ) {
239
310
final String msg = String .format (Locale .ENGLISH ,
@@ -287,9 +358,27 @@ public void info(String msg) {
287
358
checker .parseBundledSignatures (bs , targetVersion );
288
359
}
289
360
}
290
- if (signaturesFiles != null ) for (final File f : new LinkedHashSet <File >(Arrays .asList (signaturesFiles ))) {
361
+ final Set <File > sigFiles = new LinkedHashSet <File >();
362
+ final Set <URL > sigUrls = new LinkedHashSet <URL >();
363
+ if (signaturesFiles != null ) {
364
+ sigFiles .addAll (Arrays .asList (signaturesFiles ));
365
+ }
366
+ if (signaturesArtifacts != null ) {
367
+ for (final SignaturesArtifact artifact : signaturesArtifacts ) {
368
+ final File f = resolveSignaturesArtifact (artifact );
369
+ if (artifact .path != null ) {
370
+ sigUrls .add (createJarUrl (f , artifact .path ));
371
+ } else {
372
+ sigFiles .add (f );
373
+ }
374
+ }
375
+ }
376
+ for (final File f : sigFiles ) {
291
377
checker .parseSignaturesFile (f );
292
378
}
379
+ for (final URL u : sigUrls ) {
380
+ checker .parseSignaturesFile (u );
381
+ }
293
382
final String sig = (signatures != null ) ? signatures .trim () : null ;
294
383
if (sig != null && sig .length () != 0 ) {
295
384
checker .parseSignaturesString (sig );
@@ -298,11 +387,15 @@ public void info(String msg) {
298
387
throw new MojoExecutionException ("IO problem while reading files with API signatures." , ioe );
299
388
} catch (ParseException pe ) {
300
389
throw new MojoExecutionException ("Parsing signatures failed: " + pe .getMessage (), pe );
390
+ } catch (ArtifactResolutionException e ) {
391
+ throw new MojoExecutionException ("Problem while resolving Maven artifact." , e );
392
+ } catch (ArtifactNotFoundException e ) {
393
+ throw new MojoExecutionException ("Maven artifact does not exist." , e );
301
394
}
302
395
303
396
if (checker .hasNoSignatures ()) {
304
397
if (failOnUnresolvableSignatures ) {
305
- throw new MojoExecutionException ("No API signatures found; use parameters 'signatures', 'bundledSignatures', and/or 'signaturesFiles ' to define those!" );
398
+ throw new MojoExecutionException ("No API signatures found; use parameters 'signatures', 'bundledSignatures', 'signaturesFiles', and/or 'signaturesArtifacts ' to define those!" );
306
399
} else {
307
400
log .info ("Skipping execution because no API signatures are available." );
308
401
return ;
0 commit comments