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