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