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