1 package org.apache.maven.archiver;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.artifact.Artifact;
23 import org.apache.maven.artifact.DependencyResolutionRequiredException;
24 import org.apache.maven.execution.MavenSession;
25 import org.apache.maven.project.MavenProject;
26 import org.codehaus.plexus.archiver.ArchiverException;
27 import org.codehaus.plexus.archiver.jar.JarArchiver;
28 import org.codehaus.plexus.archiver.jar.Manifest;
29 import org.codehaus.plexus.archiver.jar.ManifestException;
30 import org.codehaus.plexus.interpolation.InterpolationException;
31 import org.codehaus.plexus.interpolation.Interpolator;
32 import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
33 import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
34 import org.codehaus.plexus.interpolation.PrefixedPropertiesValueSource;
35 import org.codehaus.plexus.interpolation.RecursionInterceptor;
36 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
37 import org.codehaus.plexus.interpolation.ValueSource;
38 import org.apache.maven.shared.utils.StringUtils;
39
40 import java.io.File;
41 import java.io.IOException;
42 import java.util.ArrayList;
43 import java.util.Collections;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Properties;
47 import java.util.Set;
48
49
50
51
52
53
54 public class MavenArchiver
55 {
56
57
58
59
60 public static final String SIMPLE_LAYOUT =
61 "${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}";
62
63
64
65
66 public static final String REPOSITORY_LAYOUT =
67 "${artifact.groupIdPath}/${artifact.artifactId}/" + "${artifact.baseVersion}/${artifact.artifactId}-"
68 + "${artifact.version}${dashClassifier?}.${artifact.extension}";
69
70
71
72
73 public static final String SIMPLE_LAYOUT_NONUNIQUE =
74 "${artifact.artifactId}-${artifact.baseVersion}${dashClassifier?}.${artifact.extension}";
75
76
77
78
79 public static final String REPOSITORY_LAYOUT_NONUNIQUE =
80 "${artifact.groupIdPath}/${artifact.artifactId}/" + "${artifact.baseVersion}/${artifact.artifactId}-"
81 + "${artifact.baseVersion}${dashClassifier?}.${artifact.extension}";
82
83 private static final List<String> ARTIFACT_EXPRESSION_PREFIXES;
84
85 static
86 {
87 List<String> artifactExpressionPrefixes = new ArrayList<String>();
88 artifactExpressionPrefixes.add( "artifact." );
89
90 ARTIFACT_EXPRESSION_PREFIXES = artifactExpressionPrefixes;
91 }
92
93 private JarArchiver archiver;
94
95 private File archiveFile;
96
97
98
99
100
101
102
103
104
105
106
107
108 @SuppressWarnings( "UnusedDeclaration" )
109 public Manifest getManifest( MavenProject project, MavenArchiveConfiguration config )
110 throws ManifestException, DependencyResolutionRequiredException
111 {
112 return getManifest( null, project, config );
113 }
114
115
116
117
118
119
120
121
122
123 public Manifest getManifest( MavenSession session, MavenProject project, MavenArchiveConfiguration config )
124 throws ManifestException, DependencyResolutionRequiredException
125 {
126 boolean hasManifestEntries = !config.isManifestEntriesEmpty();
127 Map<String, String> entries =
128 hasManifestEntries ? config.getManifestEntries() : Collections.<String, String>emptyMap();
129
130 Manifest manifest = getManifest( session, project, config.getManifest(), entries );
131
132
133 if ( hasManifestEntries )
134 {
135
136 for ( Map.Entry<String, String> entry : entries.entrySet() )
137 {
138 String key = entry.getKey();
139 String value = entry.getValue();
140 Manifest.Attribute attr = manifest.getMainSection().getAttribute( key );
141 if ( key.equals( "Class-Path" ) && attr != null )
142 {
143
144
145
146 attr.setValue( value + " " + attr.getValue() );
147 }
148 else
149 {
150 addManifestAttribute( manifest, key, value );
151 }
152 }
153 }
154
155
156 if ( !config.isManifestSectionsEmpty() )
157 {
158 for ( ManifestSection section : config.getManifestSections() )
159 {
160 Manifest.Section theSection = new Manifest.Section();
161 theSection.setName( section.getName() );
162
163 if ( !section.isManifestEntriesEmpty() )
164 {
165 Map<String, String> sectionEntries = section.getManifestEntries();
166
167 for ( Map.Entry<String, String> entry : sectionEntries.entrySet() )
168 {
169 String key = entry.getKey();
170 String value = entry.getValue();
171 Manifest.Attribute attr = new Manifest.Attribute( key, value );
172 theSection.addConfiguredAttribute( attr );
173 }
174 }
175
176 manifest.addConfiguredSection( theSection );
177 }
178 }
179
180 return manifest;
181 }
182
183
184
185
186
187
188
189
190
191
192
193 public Manifest getManifest( MavenProject project, ManifestConfiguration config )
194 throws ManifestException, DependencyResolutionRequiredException
195 {
196 return getManifest( null, project, config, Collections.<String, String>emptyMap() );
197 }
198
199
200
201
202
203
204
205
206
207 public Manifest getManifest( MavenSession mavenSession, MavenProject project, ManifestConfiguration config )
208 throws ManifestException, DependencyResolutionRequiredException
209 {
210 return getManifest( mavenSession, project, config, Collections.<String, String>emptyMap() );
211 }
212
213 private void addManifestAttribute( Manifest manifest, Map<String, String> map, String key, String value )
214 throws ManifestException
215 {
216 if ( map.containsKey( key ) )
217 {
218 return;
219 }
220 addManifestAttribute( manifest, key, value );
221 }
222
223 private void addManifestAttribute( Manifest manifest, String key, String value )
224 throws ManifestException
225 {
226 if ( !StringUtils.isEmpty( value ) )
227 {
228 Manifest.Attribute attr = new Manifest.Attribute( key, value );
229 manifest.addConfiguredAttribute( attr );
230 }
231 else
232 {
233
234
235 Manifest.Attribute attr = new Manifest.Attribute( key, "" );
236 manifest.addConfiguredAttribute( attr );
237 }
238 }
239
240
241
242
243
244
245
246
247
248
249 protected Manifest getManifest( MavenSession session, MavenProject project, ManifestConfiguration config,
250 Map<String, String> entries )
251 throws ManifestException, DependencyResolutionRequiredException
252 {
253
254
255
256 Manifest m = new Manifest();
257 addCreatedByEntry( session, m, entries );
258
259 addCustomEntries( m, entries, config );
260
261 if ( config.isAddClasspath() )
262 {
263 StringBuilder classpath = new StringBuilder();
264
265 List<String> artifacts = project.getRuntimeClasspathElements();
266 String classpathPrefix = config.getClasspathPrefix();
267 String layoutType = config.getClasspathLayoutType();
268 String layout = config.getCustomClasspathLayout();
269
270 Interpolator interpolator = new StringSearchInterpolator();
271
272 for ( String artifactFile : artifacts )
273 {
274 File f = new File( artifactFile );
275 if ( f.getAbsoluteFile().isFile() )
276 {
277 Artifact artifact = findArtifactWithFile( project.getArtifacts(), f );
278
279 if ( classpath.length() > 0 )
280 {
281 classpath.append( " " );
282 }
283 classpath.append( classpathPrefix );
284
285
286
287 if ( artifact == null || layoutType == null )
288 {
289 classpath.append( f.getName() );
290 }
291 else
292 {
293 List<ValueSource> valueSources = new ArrayList<ValueSource>();
294
295 valueSources.add( new PrefixedObjectValueSource( ARTIFACT_EXPRESSION_PREFIXES, artifact,
296 true ) );
297 valueSources.add( new PrefixedObjectValueSource( ARTIFACT_EXPRESSION_PREFIXES,
298 artifact.getArtifactHandler(), true ) );
299
300 Properties extraExpressions = new Properties();
301
302
303 if ( !artifact.isSnapshot() )
304 {
305 extraExpressions.setProperty( "baseVersion", artifact.getVersion() );
306 }
307
308 extraExpressions.setProperty( "groupIdPath", artifact.getGroupId().replace( '.', '/' ) );
309 if ( StringUtils.isNotEmpty( artifact.getClassifier() ) )
310 {
311 extraExpressions.setProperty( "dashClassifier", "-" + artifact.getClassifier() );
312 extraExpressions.setProperty( "dashClassifier?", "-" + artifact.getClassifier() );
313 }
314 else
315 {
316 extraExpressions.setProperty( "dashClassifier", "" );
317 extraExpressions.setProperty( "dashClassifier?", "" );
318 }
319 valueSources.add( new PrefixedPropertiesValueSource( ARTIFACT_EXPRESSION_PREFIXES,
320 extraExpressions, true ) );
321
322 for ( ValueSource vs : valueSources )
323 {
324 interpolator.addValueSource( vs );
325 }
326
327 RecursionInterceptor recursionInterceptor =
328 new PrefixAwareRecursionInterceptor( ARTIFACT_EXPRESSION_PREFIXES );
329
330 try
331 {
332 if ( ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_SIMPLE.equals( layoutType ) )
333 {
334 if ( config.isUseUniqueVersions() )
335 {
336 classpath.append( interpolator.interpolate( SIMPLE_LAYOUT, recursionInterceptor ) );
337 }
338 else
339 {
340 classpath.append( interpolator.interpolate( SIMPLE_LAYOUT_NONUNIQUE,
341 recursionInterceptor ) );
342 }
343 }
344 else if ( ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_REPOSITORY.equals( layoutType ) )
345 {
346
347
348 if ( config.isUseUniqueVersions() )
349 {
350 classpath.append( interpolator.interpolate( REPOSITORY_LAYOUT,
351 recursionInterceptor ) );
352 }
353 else
354 {
355 classpath.append( interpolator.interpolate( REPOSITORY_LAYOUT_NONUNIQUE,
356 recursionInterceptor ) );
357 }
358 }
359 else if ( ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_CUSTOM.equals( layoutType ) )
360 {
361 if ( layout == null )
362 {
363 throw new ManifestException( ManifestConfiguration.CLASSPATH_LAYOUT_TYPE_CUSTOM
364 + " layout type was declared, but custom layout expression was not"
365 + " specified. Check your <archive><manifest><customLayout/> element." );
366 }
367
368 classpath.append( interpolator.interpolate( layout, recursionInterceptor ) );
369 }
370 else
371 {
372 throw new ManifestException( "Unknown classpath layout type: '" + layoutType
373 + "'. Check your <archive><manifest><layoutType/> element." );
374 }
375 }
376 catch ( InterpolationException e )
377 {
378 ManifestException error =
379 new ManifestException( "Error interpolating artifact path for classpath entry: "
380 + e.getMessage() );
381
382 error.initCause( e );
383 throw error;
384 }
385 finally
386 {
387 for ( ValueSource vs : valueSources )
388 {
389 interpolator.removeValuesSource( vs );
390 }
391 }
392 }
393 }
394 }
395
396 if ( classpath.length() > 0 )
397 {
398
399
400 addManifestAttribute( m, "Class-Path", classpath.toString() );
401 }
402 }
403
404 if ( config.isAddDefaultSpecificationEntries() )
405 {
406 addManifestAttribute( m, entries, "Specification-Title", project.getName() );
407 addManifestAttribute( m, entries, "Specification-Version", project.getVersion() );
408
409 if ( project.getOrganization() != null )
410 {
411 addManifestAttribute( m, entries, "Specification-Vendor", project.getOrganization().getName() );
412 }
413 }
414
415 if ( config.isAddDefaultImplementationEntries() )
416 {
417 addManifestAttribute( m, entries, "Implementation-Title", project.getName() );
418 addManifestAttribute( m, entries, "Implementation-Version", project.getVersion() );
419
420 addManifestAttribute( m, entries, "Implementation-Vendor-Id", project.getGroupId() );
421
422 if ( project.getOrganization() != null )
423 {
424 addManifestAttribute( m, entries, "Implementation-Vendor", project.getOrganization().getName() );
425 }
426
427 if ( project.getUrl() != null )
428 {
429 addManifestAttribute( m, entries, "Implementation-URL", project.getUrl() );
430 }
431 }
432
433 String mainClass = config.getMainClass();
434 if ( mainClass != null && !"".equals( mainClass ) )
435 {
436 addManifestAttribute( m, entries, "Main-Class", mainClass );
437 }
438
439
440 if ( config.isAddExtensions() )
441 {
442
443 StringBuilder extensionsList = new StringBuilder();
444 Set<Artifact> artifacts = (Set<Artifact>) project.getArtifacts();
445
446 for ( Artifact artifact : artifacts )
447 {
448 if ( !Artifact.SCOPE_TEST.equals( artifact.getScope() ) )
449 {
450 if ( "jar".equals( artifact.getType() ) )
451 {
452 if ( extensionsList.length() > 0 )
453 {
454 extensionsList.append( " " );
455 }
456 extensionsList.append( artifact.getArtifactId() );
457 }
458 }
459 }
460
461 if ( extensionsList.length() > 0 )
462 {
463 addManifestAttribute( m, entries, "Extension-List", extensionsList.toString() );
464 }
465
466 for ( Object artifact1 : artifacts )
467 {
468
469
470 Artifact artifact = (Artifact) artifact1;
471 if ( "jar".equals( artifact.getType() ) )
472 {
473 String artifactId = artifact.getArtifactId().replace( '.', '_' );
474 String ename = artifactId + "-Extension-Name";
475 addManifestAttribute( m, entries, ename, artifact.getArtifactId() );
476 String iname = artifactId + "-Implementation-Version";
477 addManifestAttribute( m, entries, iname, artifact.getVersion() );
478
479 if ( artifact.getRepository() != null )
480 {
481 iname = artifactId + "-Implementation-URL";
482 String url = artifact.getRepository().getUrl() + "/" + artifact.toString();
483 addManifestAttribute( m, entries, iname, url );
484 }
485 }
486 }
487 }
488
489 return m;
490 }
491
492 private void addCustomEntries( Manifest m, Map<String, String> entries, ManifestConfiguration config )
493 throws ManifestException
494 {
495 addManifestAttribute( m, entries, "Built-By", System.getProperty( "user.name" ) );
496 addManifestAttribute( m, entries, "Build-Jdk", System.getProperty( "java.version" ) );
497
498
499
500
501
502
503 if ( config.getPackageName() != null )
504 {
505 addManifestAttribute( m, entries, "Package", config.getPackageName() );
506 }
507 }
508
509
510
511
512 public JarArchiver getArchiver()
513 {
514 return archiver;
515 }
516
517
518
519
520 public void setArchiver( JarArchiver archiver )
521 {
522 this.archiver = archiver;
523 }
524
525
526
527
528 public void setOutputFile( File outputFile )
529 {
530 archiveFile = outputFile;
531 }
532
533
534
535
536
537
538
539
540
541
542 @SuppressWarnings( "JavaDoc" )
543 public void createArchive( MavenProject project, MavenArchiveConfiguration archiveConfiguration )
544 throws ArchiverException, ManifestException, IOException, DependencyResolutionRequiredException
545 {
546 createArchive( null, project, archiveConfiguration );
547 }
548
549
550
551
552
553
554
555
556
557
558 public void createArchive( MavenSession session, MavenProject project,
559 MavenArchiveConfiguration archiveConfiguration )
560 throws ArchiverException, ManifestException, IOException,
561 DependencyResolutionRequiredException
562 {
563
564
565 MavenProject workingProject = null;
566 workingProject = (MavenProject) project.clone();
567
568 boolean forced = archiveConfiguration.isForced();
569 if ( archiveConfiguration.isAddMavenDescriptor() )
570 {
571
572
573
574
575
576
577
578
579
580
581
582 if ( workingProject.getArtifact().isSnapshot() )
583 {
584 workingProject.setVersion( workingProject.getArtifact().getVersion() );
585 }
586
587 String groupId = workingProject.getGroupId();
588
589 String artifactId = workingProject.getArtifactId();
590
591 archiver.addFile( project.getFile(), "META-INF/maven/" + groupId + "/" + artifactId + "/pom.xml" );
592
593
594
595
596
597 File pomPropertiesFile = archiveConfiguration.getPomPropertiesFile();
598 if ( pomPropertiesFile == null )
599 {
600 File dir = new File( workingProject.getBuild().getDirectory(), "maven-archiver" );
601 pomPropertiesFile = new File( dir, "pom.properties" );
602 }
603 new PomPropertiesUtil().createPomProperties( workingProject, archiver, pomPropertiesFile, forced );
604 }
605
606
607
608
609
610 File manifestFile = archiveConfiguration.getManifestFile();
611
612 if ( manifestFile != null )
613 {
614 archiver.setManifest( manifestFile );
615 }
616
617 Manifest manifest = getManifest( session, workingProject, archiveConfiguration );
618
619
620 archiver.addConfiguredManifest( manifest );
621
622 archiver.setCompress( archiveConfiguration.isCompress() );
623
624 archiver.setRecompressAddedZips( archiveConfiguration.isRecompressAddedZips() );
625
626 archiver.setIndex( archiveConfiguration.isIndex() );
627
628 archiver.setDestFile( archiveFile );
629
630
631 if ( archiveConfiguration.getManifest().isAddClasspath() )
632 {
633 List<String> artifacts = project.getRuntimeClasspathElements();
634 for ( String artifact : artifacts )
635 {
636 File f = new File( artifact );
637 archiver.addConfiguredIndexJars( f );
638 }
639 }
640
641 archiver.setForced( forced );
642 if ( !archiveConfiguration.isForced() && archiver.isSupportingForced() )
643 {
644
645
646
647 }
648
649
650 archiver.createArchive();
651 }
652
653 private void addCreatedByEntry( MavenSession session, Manifest m, Map<String, String> entries )
654 throws ManifestException
655 {
656 String createdBy = "Apache Maven";
657 if ( session != null )
658 {
659 String mavenVersion = session.getUserProperties().getProperty( "maven.version" );
660 if ( mavenVersion != null )
661 {
662 createdBy += " " + mavenVersion;
663 }
664 }
665 addManifestAttribute( m, entries, "Created-By", createdBy );
666 }
667
668 private Artifact findArtifactWithFile( Set<Artifact> artifacts, File file )
669 {
670 for ( Artifact artifact : artifacts )
671 {
672
673 if ( artifact.getFile() != null )
674 {
675 if ( artifact.getFile().equals( file ) )
676 {
677 return artifact;
678 }
679 }
680 }
681 return null;
682 }
683 }