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