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<>( 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 | IOException e )
187 {
188 throw new ArchiveCreationException(
189 "Error creating assembly archive " + assembly.getId() + ": " + e.getMessage(), e );
190 }
191 catch ( final NoSuchArchiverException e )
192 {
193 throw new ArchiveCreationException(
194 "Unable to obtain archiver for extension '" + format + "', for assembly: '" + assembly.getId() + "'",
195 e );
196 }
197 catch ( final DependencyResolutionException e )
198 {
199 throw new ArchiveCreationException(
200 "Unable to resolve dependencies for assembly '" + assembly.getId() + "'", e );
201 }
202
203 return destFile;
204 }
205
206 private void validate( final Assembly assembly )
207 throws InvalidAssemblerConfigurationException
208 {
209 if ( assembly.getId() == null || assembly.getId().trim().length() < 1 )
210 {
211 throw new InvalidAssemblerConfigurationException( "Assembly ID must be present and non-empty." );
212 }
213 }
214
215
216 private List<ContainerDescriptorHandler> selectContainerDescriptorHandlers(
217 List<ContainerDescriptorHandlerConfig> requestedContainerDescriptorHandlers,
218 final AssemblerConfigurationSource configSource )
219 throws InvalidAssemblerConfigurationException
220
221 {
222 getLogger().debug( "All known ContainerDescriptorHandler components: " + ( containerDescriptorHandlers == null
223 ? "none; map is null."
224 : "" + containerDescriptorHandlers.keySet() ) );
225
226 if ( requestedContainerDescriptorHandlers == null )
227 {
228 requestedContainerDescriptorHandlers = new ArrayList<>();
229 }
230
231 final List<ContainerDescriptorHandler> handlers = new ArrayList<>();
232 final List<String> hints = new ArrayList<>();
233
234 if ( !requestedContainerDescriptorHandlers.isEmpty() )
235 {
236 for ( final ContainerDescriptorHandlerConfig config : requestedContainerDescriptorHandlers )
237 {
238 final String hint = config.getHandlerName();
239 final ContainerDescriptorHandler handler = containerDescriptorHandlers.get( hint );
240
241 if ( handler == null )
242 {
243 throw new InvalidAssemblerConfigurationException(
244 "Cannot find ContainerDescriptorHandler with hint: " + hint );
245 }
246
247 getLogger().debug(
248 "Found container descriptor handler with hint: " + hint + " (component: " + handler + ")" );
249
250 if ( config.getConfiguration() != null )
251 {
252 getLogger().debug( "Configuring handler with:\n\n" + config.getConfiguration() + "\n\n" );
253
254 configureContainerDescriptorHandler( handler, (Xpp3Dom) config.getConfiguration(), configSource );
255 }
256
257 handlers.add( handler );
258 hints.add( hint );
259 }
260 }
261
262 if ( !hints.contains( "plexus" ) )
263 {
264 handlers.add( new ComponentsXmlArchiverFileFilter() );
265 }
266
267 return handlers;
268 }
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284 protected Archiver createArchiver( final String format, final boolean includeBaseDir, final String finalName,
285 final AssemblerConfigurationSource configSource,
286 final List<ContainerDescriptorHandler> containerHandlers,
287 boolean recompressZippedFiles, String mergeManifestMode )
288 throws NoSuchArchiverException
289 {
290 Archiver archiver;
291 if ( "txz".equals( format ) || "tgz".equals( format ) || "tbz2".equals( format ) || format.startsWith( "tar" ) )
292 {
293 archiver = createTarArchiver( format, TarLongFileMode.valueOf( configSource.getTarLongFileMode() ) );
294 }
295 else if ( "war".equals( format ) )
296 {
297 archiver = createWarArchiver();
298 }
299 else
300 {
301 archiver = archiverManager.getArchiver( format );
302 }
303
304 if ( archiver instanceof AbstractZipArchiver )
305 {
306 ( (AbstractZipArchiver) archiver ).setRecompressAddedZips( recompressZippedFiles );
307 }
308
309 final List<FileSelector> extraSelectors = new ArrayList<>();
310 final List<ArchiveFinalizer> extraFinalizers = new ArrayList<>();
311 if ( archiver instanceof JarArchiver )
312 {
313 if ( mergeManifestMode != null )
314 {
315 ( (JarArchiver) archiver ).setFilesetmanifest(
316 JarArchiver.FilesetManifestConfig.valueOf( mergeManifestMode ) );
317 }
318
319 extraSelectors.add( new JarSecurityFileSelector() );
320
321 extraFinalizers.add(
322 new ManifestCreationFinalizer( configSource.getMavenSession(), configSource.getProject(),
323 configSource.getJarArchiveConfiguration() ) );
324
325 }
326
327 if ( configSource.getArchiverConfig() != null )
328 {
329 configureArchiver( archiver, configSource );
330 }
331
332 String prefix = "";
333 if ( includeBaseDir )
334 {
335 prefix = finalName;
336 }
337
338 archiver = new AssemblyProxyArchiver( prefix, archiver, containerHandlers, extraSelectors, extraFinalizers,
339 configSource.getWorkingDirectory(), getLogger() );
340 if ( configSource.isDryRun() )
341 {
342 archiver = new DryRunArchiver( archiver, getLogger() );
343 }
344
345 archiver.setUseJvmChmod( configSource.isUpdateOnly() );
346 archiver.setIgnorePermissions( configSource.isIgnorePermissions() );
347 archiver.setForced( !configSource.isUpdateOnly() );
348
349 return archiver;
350 }
351
352 private void configureContainerDescriptorHandler( final ContainerDescriptorHandler handler, final Xpp3Dom config,
353 final AssemblerConfigurationSource configSource )
354 throws InvalidAssemblerConfigurationException
355 {
356 getLogger().debug( "Configuring handler: '" + handler.getClass().getName() + "' -->" );
357
358 try
359 {
360 configureComponent( handler, config, configSource );
361 }
362 catch ( final ComponentConfigurationException e )
363 {
364 throw new InvalidAssemblerConfigurationException(
365 "Failed to configure handler: " + handler.getClass().getName(), e );
366 }
367 catch ( final ComponentLookupException e )
368 {
369 throw new InvalidAssemblerConfigurationException(
370 "Failed to lookup configurator for setup of handler: " + handler.getClass().getName(), e );
371 }
372
373 getLogger().debug( "-- end configuration --" );
374 }
375
376 private void configureArchiver( final Archiver archiver, final AssemblerConfigurationSource configSource )
377 {
378 Xpp3Dom config;
379 try
380 {
381 config = Xpp3DomBuilder.build( new StringReader( configSource.getArchiverConfig() ) );
382 }
383 catch ( final XmlPullParserException | 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 = container.lookup( ComponentConfigurator.class, "basic" );
413
414 final ConfigurationListener listener = new DebugConfigurationListener( getLogger() );
415
416 final ExpressionEvaluator expressionEvaluator = new AssemblyExpressionEvaluator( configSource );
417
418 final XmlPlexusConfiguration configuration = new XmlPlexusConfiguration( config );
419
420 final Object[] containerRealm = getContainerRealm();
421
422
423
424
425
426 try
427 {
428 final Method configureComponent =
429 ComponentConfigurator.class.getMethod( "configureComponent", Object.class, PlexusConfiguration.class,
430 ExpressionEvaluator.class, (Class<?>) containerRealm[1],
431 ConfigurationListener.class );
432
433 configureComponent.invoke( configurator, component, configuration, expressionEvaluator, containerRealm[0],
434 listener );
435 }
436 catch ( final NoSuchMethodException | IllegalAccessException e )
437 {
438 throw new RuntimeException( e );
439 }
440 catch ( final InvocationTargetException e )
441 {
442 if ( e.getCause() instanceof ComponentConfigurationException )
443 {
444 throw (ComponentConfigurationException) e.getCause();
445 }
446 throw new RuntimeException( e.getCause() );
447 }
448 }
449
450 private Object[] getContainerRealm()
451 {
452
453
454
455
456 try
457 {
458 final Method getContainerRealm = container.getClass().getMethod( "getContainerRealm" );
459 return new Object[]{ getContainerRealm.invoke( container ), getContainerRealm.getReturnType() };
460 }
461 catch ( final NoSuchMethodException | IllegalAccessException e )
462 {
463 throw new RuntimeException( e );
464 }
465 catch ( final InvocationTargetException e )
466 {
467 throw new RuntimeException( e.getCause() );
468 }
469 }
470
471 protected Archiver createWarArchiver()
472 throws NoSuchArchiverException
473 {
474 final WarArchiver warArchiver = (WarArchiver) archiverManager.getArchiver( "war" );
475 warArchiver.setIgnoreWebxml( false );
476
477 return warArchiver;
478 }
479
480 protected Archiver createTarArchiver( final String format, final TarLongFileMode tarLongFileMode )
481 throws NoSuchArchiverException
482 {
483 final TarArchiver tarArchiver = (TarArchiver) archiverManager.getArchiver( "tar" );
484 final int index = format.indexOf( '.' );
485 if ( index >= 0 )
486 {
487 TarArchiver.TarCompressionMethod tarCompressionMethod;
488
489
490 final String compression = format.substring( index + 1 );
491 if ( "gz".equals( compression ) )
492 {
493 tarCompressionMethod = TarArchiver.TarCompressionMethod.gzip;
494 }
495 else if ( "bz2".equals( compression ) )
496 {
497 tarCompressionMethod = TarArchiver.TarCompressionMethod.bzip2;
498 }
499 else if ( "xz".equals( compression ) )
500 {
501 tarCompressionMethod = TarArchiver.TarCompressionMethod.xz;
502 }
503 else if ( "snappy".equals( compression ) )
504 {
505 tarCompressionMethod = TarArchiver.TarCompressionMethod.snappy;
506 }
507 else
508 {
509
510 throw new IllegalArgumentException( "Unknown compression format: " + compression );
511 }
512 tarArchiver.setCompression( tarCompressionMethod );
513 }
514 else if ( "tgz".equals( format ) )
515 {
516 tarArchiver.setCompression( TarArchiver.TarCompressionMethod.gzip );
517 }
518 else if ( "tbz2".equals( format ) )
519 {
520 tarArchiver.setCompression( TarArchiver.TarCompressionMethod.bzip2 );
521 }
522 else if ( "txz".equals( format ) )
523 {
524 tarArchiver.setCompression( TarArchiver.TarCompressionMethod.xz );
525 }
526
527 tarArchiver.setLongfile( tarLongFileMode );
528
529 return tarArchiver;
530 }
531
532 @Override
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 }