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