1 package org.apache.maven.plugins.assembly.archive;
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.plugin.DebugConfigurationListener;
23 import org.apache.maven.plugins.assembly.AssemblerConfigurationSource;
24 import org.apache.maven.plugins.assembly.InvalidAssemblerConfigurationException;
25 import org.apache.maven.plugins.assembly.archive.archiver.AssemblyProxyArchiver;
26 import org.apache.maven.plugins.assembly.archive.phase.AssemblyArchiverPhase;
27 import org.apache.maven.plugins.assembly.archive.phase.AssemblyArchiverPhaseComparator;
28 import org.apache.maven.plugins.assembly.artifact.DependencyResolutionException;
29 import org.apache.maven.plugins.assembly.filter.ComponentsXmlArchiverFileFilter;
30 import org.apache.maven.plugins.assembly.filter.ContainerDescriptorHandler;
31 import org.apache.maven.plugins.assembly.format.AssemblyFormattingException;
32 import org.apache.maven.plugins.assembly.interpolation.AssemblyExpressionEvaluator;
33 import org.apache.maven.plugins.assembly.model.Assembly;
34 import org.apache.maven.plugins.assembly.model.ContainerDescriptorHandlerConfig;
35 import org.apache.maven.plugins.assembly.utils.AssemblyFileUtils;
36 import org.apache.maven.plugins.assembly.utils.AssemblyFormatUtils;
37 import org.codehaus.plexus.PlexusConstants;
38 import org.codehaus.plexus.PlexusContainer;
39 import org.codehaus.plexus.archiver.ArchiveFinalizer;
40 import org.codehaus.plexus.archiver.Archiver;
41 import org.codehaus.plexus.archiver.ArchiverException;
42 import org.codehaus.plexus.archiver.diags.DryRunArchiver;
43 import org.codehaus.plexus.archiver.filters.JarSecurityFileSelector;
44 import org.codehaus.plexus.archiver.jar.JarArchiver;
45 import org.codehaus.plexus.archiver.manager.ArchiverManager;
46 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
47 import org.codehaus.plexus.archiver.tar.TarArchiver;
48 import org.codehaus.plexus.archiver.tar.TarLongFileMode;
49 import org.codehaus.plexus.archiver.war.WarArchiver;
50 import org.codehaus.plexus.archiver.zip.AbstractZipArchiver;
51 import org.codehaus.plexus.component.annotations.Component;
52 import org.codehaus.plexus.component.annotations.Requirement;
53 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
54 import org.codehaus.plexus.component.configurator.ComponentConfigurator;
55 import org.codehaus.plexus.component.configurator.ConfigurationListener;
56 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
57 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
58 import org.codehaus.plexus.components.io.fileselectors.FileSelector;
59 import org.codehaus.plexus.configuration.PlexusConfiguration;
60 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
61 import org.codehaus.plexus.context.Context;
62 import org.codehaus.plexus.context.ContextException;
63 import org.codehaus.plexus.logging.AbstractLogEnabled;
64 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
65 import org.codehaus.plexus.util.xml.Xpp3Dom;
66 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
67 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
68
69 import java.io.File;
70 import java.io.IOException;
71 import java.io.StringReader;
72 import java.lang.reflect.InvocationTargetException;
73 import java.lang.reflect.Method;
74 import java.util.ArrayList;
75 import java.util.Collections;
76 import java.util.List;
77 import java.util.Map;
78
79
80
81
82
83
84
85
86
87
88 @Component( role = AssemblyArchiver.class, instantiationStrategy = "per-lookup" )
89 public class DefaultAssemblyArchiver
90 extends AbstractLogEnabled
91 implements AssemblyArchiver, Contextualizable
92 {
93
94 @Requirement
95 private ArchiverManager archiverManager;
96
97 @Requirement( role = AssemblyArchiverPhase.class )
98 private List<AssemblyArchiverPhase> assemblyPhases;
99
100 @SuppressWarnings( "MismatchedQueryAndUpdateOfCollection" )
101 @Requirement( role = ContainerDescriptorHandler.class )
102 private Map<String, ContainerDescriptorHandler> containerDescriptorHandlers;
103
104 private PlexusContainer container;
105
106 @SuppressWarnings( "UnusedDeclaration" )
107 public DefaultAssemblyArchiver()
108 {
109 }
110
111
112
113
114
115
116
117 protected DefaultAssemblyArchiver( final ArchiverManager archiverManager,
118 final List<AssemblyArchiverPhase> assemblyPhases )
119 {
120 this.archiverManager = archiverManager;
121 this.assemblyPhases = assemblyPhases;
122 }
123
124 private List<AssemblyArchiverPhase> sortedPhases()
125 {
126 List<AssemblyArchiverPhase> sorted = new ArrayList<AssemblyArchiverPhase>( assemblyPhases );
127 Collections.sort( sorted, new AssemblyArchiverPhaseComparator() );
128 return sorted;
129 }
130
131
132
133
134 @Override
135 public File createArchive( final Assembly assembly, final String fullName, final String format,
136 final AssemblerConfigurationSource configSource, boolean recompressZippedFiles,
137 String mergeManifestMode )
138 throws ArchiveCreationException, AssemblyFormattingException, InvalidAssemblerConfigurationException
139 {
140 validate( assembly );
141
142 String filename = fullName;
143 if ( !configSource.isIgnoreDirFormatExtensions() || !format.startsWith( "dir" ) )
144 {
145 filename += "." + format;
146 }
147
148 AssemblyFileUtils.verifyTempDirectoryAvailability( configSource.getTemporaryRootDirectory() );
149
150 final File outputDirectory = configSource.getOutputDirectory();
151
152 final File destFile = new File( outputDirectory, filename );
153
154 try
155 {
156 final String finalName = configSource.getFinalName();
157 final String specifiedBasedir = assembly.getBaseDirectory();
158
159 String basedir = finalName;
160
161 if ( specifiedBasedir != null )
162 {
163 basedir = AssemblyFormatUtils.getOutputDirectory( specifiedBasedir, finalName, configSource,
164 AssemblyFormatUtils.moduleProjectInterpolator(
165 configSource.getProject() ),
166 AssemblyFormatUtils.artifactProjectInterpolator(
167 null ) );
168 }
169
170 final List<ContainerDescriptorHandler> containerHandlers =
171 selectContainerDescriptorHandlers( assembly.getContainerDescriptorHandlers(), configSource );
172
173 final Archiver archiver =
174 createArchiver( format, assembly.isIncludeBaseDirectory(), basedir, configSource, containerHandlers,
175 recompressZippedFiles, mergeManifestMode );
176
177 archiver.setDestFile( destFile );
178
179 for ( AssemblyArchiverPhase phase : sortedPhases() )
180 {
181 phase.execute( assembly, archiver, configSource );
182 }
183
184 archiver.createArchive();
185 }
186 catch ( final ArchiverException e )
187 {
188 throw new ArchiveCreationException(
189 "Error creating assembly archive " + assembly.getId() + ": " + e.getMessage(), e );
190 }
191 catch ( final IOException e )
192 {
193 throw new ArchiveCreationException(
194 "Error creating assembly archive " + assembly.getId() + ": " + e.getMessage(), e );
195 }
196 catch ( final NoSuchArchiverException e )
197 {
198 throw new ArchiveCreationException(
199 "Unable to obtain archiver for extension '" + format + "', for assembly: '" + assembly.getId() + "'",
200 e );
201 }
202 catch ( final DependencyResolutionException e )
203 {
204 throw new ArchiveCreationException(
205 "Unable to resolve dependencies for assembly '" + assembly.getId() + "'", e );
206 }
207
208 return destFile;
209 }
210
211 private void validate( final Assembly assembly )
212 throws InvalidAssemblerConfigurationException
213 {
214 if ( assembly.getId() == null || assembly.getId().trim().length() < 1 )
215 {
216 throw new InvalidAssemblerConfigurationException( "Assembly ID must be present and non-empty." );
217 }
218 }
219
220
221 private List<ContainerDescriptorHandler> selectContainerDescriptorHandlers(
222 List<ContainerDescriptorHandlerConfig> requestedContainerDescriptorHandlers,
223 final AssemblerConfigurationSource configSource )
224 throws InvalidAssemblerConfigurationException
225
226 {
227 getLogger().debug( "All known ContainerDescriptorHandler components: " + ( containerDescriptorHandlers == null
228 ? "none; map is null."
229 : "" + containerDescriptorHandlers.keySet() ) );
230
231 if ( requestedContainerDescriptorHandlers == null )
232 {
233 requestedContainerDescriptorHandlers = new ArrayList<ContainerDescriptorHandlerConfig>();
234 }
235
236 final List<ContainerDescriptorHandler> handlers = new ArrayList<ContainerDescriptorHandler>();
237 final List<String> hints = new ArrayList<String>();
238
239 if ( !requestedContainerDescriptorHandlers.isEmpty() )
240 {
241 for ( final ContainerDescriptorHandlerConfig config : requestedContainerDescriptorHandlers )
242 {
243 final String hint = config.getHandlerName();
244 final ContainerDescriptorHandler handler = containerDescriptorHandlers.get( hint );
245
246 if ( handler == null )
247 {
248 throw new InvalidAssemblerConfigurationException(
249 "Cannot find ContainerDescriptorHandler with hint: " + hint );
250 }
251
252 getLogger().debug(
253 "Found container descriptor handler with hint: " + hint + " (component: " + handler + ")" );
254
255 if ( config.getConfiguration() != null )
256 {
257 getLogger().debug( "Configuring handler with:\n\n" + config.getConfiguration() + "\n\n" );
258
259 configureContainerDescriptorHandler( handler, (Xpp3Dom) config.getConfiguration(), configSource );
260 }
261
262 handlers.add( handler );
263 hints.add( hint );
264 }
265 }
266
267 if ( !hints.contains( "plexus" ) )
268 {
269 handlers.add( new ComponentsXmlArchiverFileFilter() );
270 }
271
272 return handlers;
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289 protected Archiver createArchiver( final String format, final boolean includeBaseDir, final String finalName,
290 final AssemblerConfigurationSource configSource,
291 final List<ContainerDescriptorHandler> containerHandlers,
292 boolean recompressZippedFiles, String mergeManifestMode )
293 throws NoSuchArchiverException
294 {
295 Archiver archiver;
296 if ( "txz".equals( format ) || "tgz".equals( format ) || "tbz2".equals( format ) || format.startsWith( "tar" ) )
297 {
298 archiver = createTarArchiver( format, TarLongFileMode.valueOf( configSource.getTarLongFileMode() ) );
299 }
300 else if ( "war".equals( format ) )
301 {
302 archiver = createWarArchiver();
303 }
304 else
305 {
306 archiver = archiverManager.getArchiver( format );
307 }
308
309 if ( archiver instanceof AbstractZipArchiver )
310 {
311 ( (AbstractZipArchiver) archiver ).setRecompressAddedZips( recompressZippedFiles );
312 }
313
314 final List<FileSelector> extraSelectors = new ArrayList<FileSelector>();
315 final List<ArchiveFinalizer> extraFinalizers = new ArrayList<ArchiveFinalizer>();
316 if ( archiver instanceof JarArchiver )
317 {
318 if ( mergeManifestMode != null )
319 {
320 ( (JarArchiver) archiver ).setFilesetmanifest(
321 JarArchiver.FilesetManifestConfig.valueOf( mergeManifestMode ) );
322 }
323
324 extraSelectors.add( new JarSecurityFileSelector() );
325
326 extraFinalizers.add(
327 new ManifestCreationFinalizer( configSource.getMavenSession(), configSource.getProject(),
328 configSource.getJarArchiveConfiguration() ) );
329
330 }
331
332 if ( configSource.getArchiverConfig() != null )
333 {
334 configureArchiver( archiver, configSource );
335 }
336
337 String prefix = "";
338 if ( includeBaseDir )
339 {
340 prefix = finalName;
341 }
342
343 archiver = new AssemblyProxyArchiver( prefix, archiver, containerHandlers, extraSelectors, extraFinalizers,
344 configSource.getWorkingDirectory(), getLogger() );
345 if ( configSource.isDryRun() )
346 {
347 archiver = new DryRunArchiver( archiver, getLogger() );
348 }
349
350 archiver.setUseJvmChmod( configSource.isUpdateOnly() );
351 archiver.setIgnorePermissions( configSource.isIgnorePermissions() );
352 archiver.setForced( !configSource.isUpdateOnly() );
353
354 return archiver;
355 }
356
357 private void configureContainerDescriptorHandler( final ContainerDescriptorHandler handler, final Xpp3Dom config,
358 final AssemblerConfigurationSource configSource )
359 throws InvalidAssemblerConfigurationException
360 {
361 getLogger().debug( "Configuring handler: '" + handler.getClass().getName() + "' -->" );
362
363 try
364 {
365 configureComponent( handler, config, configSource );
366 }
367 catch ( final ComponentConfigurationException e )
368 {
369 throw new InvalidAssemblerConfigurationException(
370 "Failed to configure handler: " + handler.getClass().getName(), e );
371 }
372 catch ( final ComponentLookupException e )
373 {
374 throw new InvalidAssemblerConfigurationException(
375 "Failed to lookup configurator for setup of handler: " + handler.getClass().getName(), e );
376 }
377
378 getLogger().debug( "-- end configuration --" );
379 }
380
381 private void configureArchiver( final Archiver archiver, final AssemblerConfigurationSource configSource )
382 {
383 Xpp3Dom config;
384 try
385 {
386 config = Xpp3DomBuilder.build( new StringReader( configSource.getArchiverConfig() ) );
387 }
388 catch ( final XmlPullParserException e )
389 {
390 throw new ArchiverException( "Failed to parse archiver configuration for: " + archiver.getClass().getName(),
391 e );
392 }
393 catch ( final IOException e )
394 {
395 throw new ArchiverException( "Failed to parse archiver configuration for: " + archiver.getClass().getName(),
396 e );
397 }
398
399 getLogger().debug( "Configuring archiver: '" + archiver.getClass().getName() + "' -->" );
400
401 try
402 {
403 configureComponent( archiver, config, configSource );
404 }
405 catch ( final ComponentConfigurationException e )
406 {
407 throw new ArchiverException( "Failed to configure archiver: " + archiver.getClass().getName(), e );
408 }
409 catch ( final ComponentLookupException e )
410 {
411 throw new ArchiverException(
412 "Failed to lookup configurator for setup of archiver: " + archiver.getClass().getName(), e );
413 }
414
415 getLogger().debug( "-- end configuration --" );
416 }
417
418 private void configureComponent( final Object component, final Xpp3Dom config,
419 final AssemblerConfigurationSource configSource )
420 throws ComponentLookupException, ComponentConfigurationException
421 {
422 final ComponentConfigurator configurator = container.lookup( ComponentConfigurator.class, "basic" );
423
424 final ConfigurationListener listener = new DebugConfigurationListener( getLogger() );
425
426 final ExpressionEvaluator expressionEvaluator = new AssemblyExpressionEvaluator( configSource );
427
428 final XmlPlexusConfiguration configuration = new XmlPlexusConfiguration( config );
429
430 final Object[] containerRealm = getContainerRealm();
431
432
433
434
435
436 try
437 {
438 final Method configureComponent =
439 ComponentConfigurator.class.getMethod( "configureComponent", Object.class, PlexusConfiguration.class,
440 ExpressionEvaluator.class, (Class<?>) containerRealm[1],
441 ConfigurationListener.class );
442
443 configureComponent.invoke( configurator, component, configuration, expressionEvaluator, containerRealm[0],
444 listener );
445 }
446 catch ( final NoSuchMethodException e )
447 {
448 throw new RuntimeException( e );
449 }
450 catch ( final IllegalAccessException e )
451 {
452 throw new RuntimeException( e );
453 }
454 catch ( final InvocationTargetException e )
455 {
456 if ( e.getCause() instanceof ComponentConfigurationException )
457 {
458 throw (ComponentConfigurationException) e.getCause();
459 }
460 throw new RuntimeException( e.getCause() );
461 }
462 }
463
464 private Object[] getContainerRealm()
465 {
466
467
468
469
470 try
471 {
472 final Method getContainerRealm = container.getClass().getMethod( "getContainerRealm" );
473 return new Object[]{ getContainerRealm.invoke( container ), getContainerRealm.getReturnType() };
474 }
475 catch ( final NoSuchMethodException e )
476 {
477 throw new RuntimeException( e );
478 }
479 catch ( final IllegalAccessException e )
480 {
481 throw new RuntimeException( e );
482 }
483 catch ( final InvocationTargetException e )
484 {
485 throw new RuntimeException( e.getCause() );
486 }
487 }
488
489 protected Archiver createWarArchiver()
490 throws NoSuchArchiverException
491 {
492 final WarArchiver warArchiver = (WarArchiver) archiverManager.getArchiver( "war" );
493 warArchiver.setIgnoreWebxml( false );
494
495 return warArchiver;
496 }
497
498 protected Archiver createTarArchiver( final String format, final TarLongFileMode tarLongFileMode )
499 throws NoSuchArchiverException
500 {
501 final TarArchiver tarArchiver = (TarArchiver) archiverManager.getArchiver( "tar" );
502 final int index = format.indexOf( '.' );
503 if ( index >= 0 )
504 {
505 TarArchiver.TarCompressionMethod tarCompressionMethod;
506
507
508 final String compression = format.substring( index + 1 );
509 if ( "gz".equals( compression ) )
510 {
511 tarCompressionMethod = TarArchiver.TarCompressionMethod.gzip;
512 }
513 else if ( "bz2".equals( compression ) )
514 {
515 tarCompressionMethod = TarArchiver.TarCompressionMethod.bzip2;
516 }
517 else if ( "xz".equals( compression ) )
518 {
519 tarCompressionMethod = TarArchiver.TarCompressionMethod.xz;
520 }
521 else if ( "snappy".equals( compression ) )
522 {
523 tarCompressionMethod = TarArchiver.TarCompressionMethod.snappy;
524 }
525 else
526 {
527
528 throw new IllegalArgumentException( "Unknown compression format: " + compression );
529 }
530 tarArchiver.setCompression( tarCompressionMethod );
531 }
532 else if ( "tgz".equals( format ) )
533 {
534 tarArchiver.setCompression( TarArchiver.TarCompressionMethod.gzip );
535 }
536 else if ( "tbz2".equals( format ) )
537 {
538 tarArchiver.setCompression( TarArchiver.TarCompressionMethod.bzip2 );
539 }
540 else if ( "txz".equals( format ) )
541 {
542 tarArchiver.setCompression( TarArchiver.TarCompressionMethod.xz );
543 }
544
545 tarArchiver.setLongfile( tarLongFileMode );
546
547 return tarArchiver;
548 }
549
550 @Override
551 public void contextualize( final Context context )
552 throws ContextException
553 {
554 container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
555 }
556
557 protected void setContainer( final PlexusContainer container )
558 {
559 this.container = container;
560 }
561
562 }