1 package org.apache.maven.plugins.jarsigner;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.text.MessageFormat;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Properties;
30 import java.util.ResourceBundle;
31 import java.util.zip.ZipEntry;
32 import java.util.zip.ZipInputStream;
33
34 import org.apache.maven.artifact.Artifact;
35 import org.apache.maven.plugin.AbstractMojo;
36 import org.apache.maven.plugin.MojoExecutionException;
37 import org.apache.maven.project.MavenProject;
38
39 import org.codehaus.plexus.util.FileUtils;
40 import org.codehaus.plexus.util.Os;
41 import org.codehaus.plexus.util.StringUtils;
42 import org.codehaus.plexus.util.cli.CommandLineException;
43 import org.codehaus.plexus.util.cli.CommandLineUtils;
44 import org.codehaus.plexus.util.cli.Commandline;
45 import org.codehaus.plexus.util.cli.StreamConsumer;
46
47
48
49
50
51
52
53 public abstract class AbstractJarsignerMojo
54 extends AbstractMojo
55 {
56
57
58
59
60
61
62 private boolean verbose;
63
64
65
66
67
68
69
70 private String maxMemory;
71
72
73
74
75
76
77 private File archive;
78
79
80
81
82
83
84
85 private File archiveDirectory;
86
87
88
89
90
91
92
93
94
95 private String[] includes = { "**/*.?ar" };
96
97
98
99
100
101
102
103
104 private String[] excludes = {};
105
106
107
108
109
110
111 private String[] arguments;
112
113
114
115
116
117
118 private boolean skip;
119
120
121
122
123
124
125
126 private boolean processMainArtifact;
127
128
129
130
131
132
133
134
135 private boolean processAttachedArtifacts;
136
137
138
139
140
141
142
143 private Boolean attachments;
144
145
146
147
148
149
150
151
152 private MavenProject project;
153
154
155
156
157 private String executable;
158
159 public final void execute()
160 throws MojoExecutionException
161 {
162 if ( !this.skip )
163 {
164 this.executable = getExecutable();
165
166 int processed = 0;
167
168 if ( this.archive != null )
169 {
170 processArchive( this.archive );
171 processed++;
172 }
173 else
174 {
175 if ( processMainArtifact )
176 {
177 processed += processArtifact( this.project.getArtifact() ) ? 1 : 0;
178 }
179
180 if ( processAttachedArtifacts && !Boolean.FALSE.equals( attachments ) )
181 {
182 for ( Iterator it = this.project.getAttachedArtifacts().iterator(); it.hasNext(); )
183 {
184 final Artifact artifact = (Artifact) it.next();
185
186 processed += processArtifact( artifact ) ? 1 : 0;
187 }
188 }
189 else
190 {
191 if ( verbose )
192 {
193 getLog().info( getMessage( "ignoringAttachments" ) );
194 }
195 else
196 {
197 getLog().debug( getMessage( "ignoringAttachments" ) );
198 }
199 }
200
201 if ( archiveDirectory != null )
202 {
203 String includeList = ( includes != null ) ? StringUtils.join( includes, "," ) : null;
204 String excludeList = ( excludes != null ) ? StringUtils.join( excludes, "," ) : null;
205
206 List jarFiles;
207 try
208 {
209 jarFiles = FileUtils.getFiles( archiveDirectory, includeList, excludeList );
210 }
211 catch ( IOException e )
212 {
213 throw new MojoExecutionException( "Failed to scan archive directory for JARs: "
214 + e.getMessage(), e );
215 }
216
217 for ( Iterator it = jarFiles.iterator(); it.hasNext(); )
218 {
219 File jarFile = (File) it.next();
220
221 processArchive( jarFile );
222 processed++;
223 }
224 }
225 }
226
227 getLog().info( getMessage( "processed", new Integer( processed ) ) );
228 }
229 else
230 {
231 getLog().info( getMessage( "disabled", null ) );
232 }
233 }
234
235
236
237
238
239
240
241
242
243
244
245
246 protected abstract Commandline getCommandline( final File archive, final Commandline commandLine );
247
248
249
250
251
252
253
254
255
256
257
258 protected String getCommandlineInfo( final Commandline commandLine )
259 {
260 if ( commandLine == null )
261 {
262 throw new NullPointerException( "commandLine" );
263 }
264
265 return commandLine.toString();
266 }
267
268
269
270
271
272
273
274
275 private boolean isJarFile( final Artifact artifact )
276 {
277 return artifact != null && artifact.getFile() != null && isJarFile( artifact.getFile() );
278 }
279
280
281
282
283
284
285
286
287 private boolean isJarFile( final File file )
288 {
289 try
290 {
291
292
293 ZipInputStream zis = new ZipInputStream( new FileInputStream( file ) );
294 try
295 {
296 for ( ZipEntry ze = zis.getNextEntry(); ze != null; ze = zis.getNextEntry() )
297 {
298 if ( ze.getName().startsWith( "META-INF/" ) || ze.getName().endsWith( ".class" ) )
299 {
300 return true;
301 }
302 }
303 }
304 finally
305 {
306 zis.close();
307 }
308 }
309 catch ( Exception e )
310 {
311
312 }
313
314 return false;
315 }
316
317
318
319
320
321
322
323
324
325
326 private boolean processArtifact( final Artifact artifact )
327 throws MojoExecutionException
328 {
329 if ( artifact == null )
330 {
331 throw new NullPointerException( "artifact" );
332 }
333
334 boolean processed = false;
335
336 if ( isJarFile( artifact ) )
337 {
338 processArchive( artifact.getFile() );
339
340 processed = true;
341 }
342 else
343 {
344 if ( this.verbose )
345 {
346 getLog().info( getMessage( "unsupported", artifact ) );
347 }
348 else if ( getLog().isDebugEnabled() )
349 {
350 getLog().debug( getMessage( "unsupported", artifact ) );
351 }
352 }
353
354 return processed;
355 }
356
357
358
359
360
361
362
363 protected void preProcessArchive( final File archive )
364 throws MojoExecutionException
365 {
366
367 }
368
369
370
371
372
373
374
375
376 private void processArchive( final File archive )
377 throws MojoExecutionException
378 {
379 if ( archive == null )
380 {
381 throw new NullPointerException( "archive" );
382 }
383
384 preProcessArchive( archive );
385
386 if ( this.verbose )
387 {
388 getLog().info( getMessage( "processing", archive ) );
389 }
390 else if ( getLog().isDebugEnabled() )
391 {
392 getLog().debug( getMessage( "processing", archive ) );
393 }
394
395 Commandline commandLine = new Commandline();
396
397 commandLine.setExecutable( this.executable );
398
399 commandLine.setWorkingDirectory( this.project.getBasedir() );
400
401 if ( this.verbose )
402 {
403 commandLine.createArg().setValue( "-verbose" );
404 }
405
406 if ( StringUtils.isNotEmpty( maxMemory ) )
407 {
408 commandLine.createArg().setValue( "-J-Xmx" + maxMemory );
409 }
410
411 if ( this.arguments != null )
412 {
413 commandLine.addArguments( this.arguments );
414 }
415
416 commandLine = getCommandline( archive, commandLine );
417
418 try
419 {
420 if ( getLog().isDebugEnabled() )
421 {
422 getLog().debug( getMessage( "command", getCommandlineInfo( commandLine ) ) );
423 }
424
425 final int result = CommandLineUtils.executeCommandLine( commandLine,
426 new InputStream()
427 {
428
429 public int read()
430 {
431 return -1;
432 }
433
434 }, new StreamConsumer()
435 {
436
437 public void consumeLine( final String line )
438 {
439 if ( verbose )
440 {
441 getLog().info( line );
442 }
443 else
444 {
445 getLog().debug( line );
446 }
447 }
448
449 }, new StreamConsumer()
450 {
451
452 public void consumeLine( final String line )
453 {
454 getLog().warn( line );
455 }
456
457 } );
458
459 if ( result != 0 )
460 {
461 throw new MojoExecutionException( getMessage( "failure", getCommandlineInfo( commandLine ),
462 new Integer( result ) ) );
463 }
464 }
465 catch ( CommandLineException e )
466 {
467 throw new MojoExecutionException( getMessage( "commandLineException", getCommandlineInfo( commandLine ) ),
468 e );
469 }
470 }
471
472
473
474
475
476
477 private String getExecutable()
478 {
479 String command = "jarsigner" + ( Os.isFamily( Os.FAMILY_WINDOWS ) ? ".exe" : "" );
480
481 String executable =
482 findExecutable( command, System.getProperty( "java.home" ), new String[] { "../bin", "bin", "../sh" } );
483
484 if ( executable == null )
485 {
486 try
487 {
488 Properties env = CommandLineUtils.getSystemEnvVars();
489
490 String[] variables = { "JDK_HOME", "JAVA_HOME" };
491
492 for ( int i = 0; i < variables.length && executable == null; i++ )
493 {
494 executable =
495 findExecutable( command, env.getProperty( variables[i] ), new String[] { "bin", "sh" } );
496 }
497 }
498 catch ( IOException e )
499 {
500 if ( getLog().isDebugEnabled() )
501 {
502 getLog().warn( "Failed to retrieve environment variables, cannot search for " + command, e );
503 }
504 else
505 {
506 getLog().warn( "Failed to retrieve environment variables, cannot search for " + command );
507 }
508 }
509 }
510
511 if ( executable == null )
512 {
513 executable = command;
514 }
515
516 return executable;
517 }
518
519
520
521
522
523
524
525
526
527 private String findExecutable( String command, String homeDir, String[] subDirs )
528 {
529 if ( StringUtils.isNotEmpty( homeDir ) )
530 {
531 for ( int i = 0; i < subDirs.length; i++ )
532 {
533 File file = new File( new File( homeDir, subDirs[i] ), command );
534
535 if ( file.isFile() )
536 {
537 return file.getAbsolutePath();
538 }
539 }
540 }
541
542 return null;
543 }
544
545
546
547
548
549
550
551
552
553
554
555
556
557 private String getMessage( final String key, final Object[] args )
558 {
559 if ( key == null )
560 {
561 throw new NullPointerException( "key" );
562 }
563
564 return new MessageFormat( ResourceBundle.getBundle( "jarsigner" ).getString( key ) ).format( args );
565 }
566
567 private String getMessage( final String key )
568 {
569 return getMessage( key, null );
570 }
571
572 private String getMessage( final String key, final Object arg )
573 {
574 return getMessage( key, new Object[] { arg } );
575 }
576
577 private String getMessage( final String key, final Object arg1, final Object arg2 )
578 {
579 return getMessage( key, new Object[] { arg1, arg2 } );
580 }
581
582 }