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.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 )
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(), getLogger() );
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
172 archiver.setDestFile( destFile );
173
174 final AssemblyContext context = new DefaultAssemblyContext();
175
176 dependencyResolver.resolve( assembly, configSource, context );
177
178 for ( final Iterator<AssemblyArchiverPhase> phaseIterator = assemblyPhases.iterator(); phaseIterator.hasNext(); )
179 {
180 final AssemblyArchiverPhase phase = phaseIterator.next();
181
182 phase.execute( assembly, archiver, configSource, context );
183 }
184
185 archiver.createArchive();
186 }
187 catch ( final ArchiverException e )
188 {
189 throw new ArchiveCreationException( "Error creating assembly archive " + assembly.getId() + ": "
190 + e.getMessage(), e );
191 }
192 catch ( final IOException e )
193 {
194 throw new ArchiveCreationException( "Error creating assembly archive " + assembly.getId() + ": "
195 + e.getMessage(), e );
196 }
197 catch ( final NoSuchArchiverException e )
198 {
199 throw new ArchiveCreationException( "Unable to obtain archiver for extension '" + format
200 + "', for assembly: '" + assembly.getId() + "'", e );
201 }
202 catch ( final DependencyResolutionException e )
203 {
204 throw new ArchiveCreationException( "Unable to resolve dependencies for assembly '" + assembly.getId()
205 + "'", 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 private List<ContainerDescriptorHandler> selectContainerDescriptorHandlers( List<ContainerDescriptorHandlerConfig> requestedContainerDescriptorHandlers,
221 final AssemblerConfigurationSource configSource )
222 throws InvalidAssemblerConfigurationException
223 {
224 getLogger().debug( "All known ContainerDescriptorHandler components: "
225 + ( containerDescriptorHandlers == null ? "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 != null ) && !requestedContainerDescriptorHandlers.isEmpty() )
237 {
238 for ( final Iterator<ContainerDescriptorHandlerConfig> it = requestedContainerDescriptorHandlers.iterator(); it.hasNext(); )
239 {
240 final ContainerDescriptorHandlerConfig config = it.next();
241
242 final String hint = config.getHandlerName();
243 final ContainerDescriptorHandler handler = containerDescriptorHandlers.get( hint );
244
245 if ( handler == null )
246 {
247 throw new InvalidAssemblerConfigurationException(
248 "Cannot find ContainerDescriptorHandler with hint: "
249 + hint );
250 }
251
252 getLogger().debug( "Found container descriptor handler with hint: " + hint + " (component: " + handler
253 + ")" );
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 protected Archiver createArchiver( final String format, final boolean includeBaseDir, final String finalName,
288 final AssemblerConfigurationSource configSource,
289 final List<ContainerDescriptorHandler> containerHandlers )
290 throws ArchiverException, NoSuchArchiverException
291 {
292 Archiver archiver;
293 if ( format.startsWith( "tar" ) )
294 {
295 archiver = createTarArchiver( format, configSource.getTarLongFileMode() );
296 }
297 else if ( "war".equals( format ) )
298 {
299 archiver = createWarArchiver();
300 }
301 else
302 {
303 archiver = archiverManager.getArchiver( format );
304 }
305
306 final List<FileSelector> extraSelectors = new ArrayList<FileSelector>();
307 final List<ArchiveFinalizer> extraFinalizers = new ArrayList<ArchiveFinalizer>();
308 if ( archiver instanceof JarArchiver )
309 {
310 extraSelectors.add( new JarSecurityFileSelector() );
311
312 extraFinalizers.add( new ManifestCreationFinalizer( configSource.getProject(),
313 configSource.getJarArchiveConfiguration() ) );
314
315 }
316
317 if ( configSource.getArchiverConfig() != null )
318 {
319 configureArchiver( archiver, configSource );
320 }
321
322 String prefix = "";
323 if ( includeBaseDir )
324 {
325 prefix = finalName;
326 }
327
328 archiver =
329 new AssemblyProxyArchiver( prefix, archiver, containerHandlers, extraSelectors, extraFinalizers,
330 configSource.getWorkingDirectory(), getLogger(), configSource.isDryRun() );
331
332 archiver.setUseJvmChmod( configSource.isUpdateOnly() );
333 archiver.setIgnorePermissions( configSource.isIgnorePermissions() );
334 archiver.setForced( !configSource.isUpdateOnly() );
335
336 return archiver;
337 }
338
339 private void configureContainerDescriptorHandler( final ContainerDescriptorHandler handler, final Xpp3Dom config,
340 final AssemblerConfigurationSource configSource )
341 throws InvalidAssemblerConfigurationException
342 {
343 getLogger().debug( "Configuring handler: '" + handler.getClass().getName() + "' -->" );
344
345 try
346 {
347 configureComponent( handler, config, configSource );
348 }
349 catch ( final ComponentConfigurationException e )
350 {
351 throw new InvalidAssemblerConfigurationException( "Failed to configure handler: "
352 + handler.getClass().getName(), e );
353 }
354 catch ( final ComponentLookupException e )
355 {
356 throw new InvalidAssemblerConfigurationException( "Failed to lookup configurator for setup of handler: "
357 + handler.getClass().getName(), e );
358 }
359
360 getLogger().debug( "-- end configuration --" );
361 }
362
363 private void configureArchiver( final Archiver archiver, final AssemblerConfigurationSource configSource )
364 throws ArchiverException
365 {
366 Xpp3Dom config;
367 try
368 {
369 config = Xpp3DomBuilder.build( new StringReader( configSource.getArchiverConfig() ) );
370 }
371 catch ( final XmlPullParserException e )
372 {
373 throw new ArchiverException(
374 "Failed to parse archiver configuration for: " + archiver.getClass().getName(),
375 e );
376 }
377 catch ( final IOException e )
378 {
379 throw new ArchiverException(
380 "Failed to parse archiver configuration for: " + archiver.getClass().getName(),
381 e );
382 }
383
384 getLogger().debug( "Configuring archiver: '" + archiver.getClass().getName() + "' -->" );
385
386 try
387 {
388 configureComponent( archiver, config, configSource );
389 }
390 catch ( final ComponentConfigurationException e )
391 {
392 throw new ArchiverException( "Failed to configure archiver: " + archiver.getClass().getName(), e );
393 }
394 catch ( final ComponentLookupException e )
395 {
396 throw new ArchiverException( "Failed to lookup configurator for setup of archiver: "
397 + archiver.getClass().getName(), e );
398 }
399
400 getLogger().debug( "-- end configuration --" );
401 }
402
403 private void configureComponent( final Object component, final Xpp3Dom config,
404 final AssemblerConfigurationSource configSource )
405 throws ComponentLookupException, ComponentConfigurationException
406 {
407 final ComponentConfigurator configurator =
408 (ComponentConfigurator) container.lookup( ComponentConfigurator.ROLE, "basic" );
409
410 final ConfigurationListener listener = new DebugConfigurationListener( getLogger() );
411
412 final ExpressionEvaluator expressionEvaluator = new AssemblyExpressionEvaluator( configSource );
413
414 final XmlPlexusConfiguration configuration = new XmlPlexusConfiguration( config );
415
416 final Object[] containerRealm = getContainerRealm();
417
418
419
420
421
422 try
423 {
424 final Method configureComponent =
425 ComponentConfigurator.class.getMethod( "configureComponent", new Class[] { Object.class,
426 PlexusConfiguration.class, ExpressionEvaluator.class, (Class<?>) containerRealm[1],
427 ConfigurationListener.class } );
428
429 configureComponent.invoke( configurator, new Object[] { component, configuration, expressionEvaluator,
430 containerRealm[0], listener } );
431 }
432 catch ( final NoSuchMethodException e )
433 {
434 throw new RuntimeException( e );
435 }
436 catch ( final 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 e )
462 {
463 throw new RuntimeException( e );
464 }
465 catch ( final IllegalAccessException e )
466 {
467 throw new RuntimeException( e );
468 }
469 catch ( final InvocationTargetException e )
470 {
471 throw new RuntimeException( e.getCause() );
472 }
473 }
474
475 protected Archiver createWarArchiver()
476 throws NoSuchArchiverException
477 {
478 final WarArchiver warArchiver = (WarArchiver) archiverManager.getArchiver( "war" );
479 warArchiver.setIgnoreWebxml( false );
480
481 return warArchiver;
482 }
483
484 protected Archiver createTarArchiver( final String format, final String tarLongFileMode )
485 throws NoSuchArchiverException, ArchiverException
486 {
487 final TarArchiver tarArchiver = (TarArchiver) archiverManager.getArchiver( "tar" );
488 final int index = format.indexOf( '.' );
489 if ( index >= 0 )
490 {
491
492
493 final TarArchiver.TarCompressionMethod tarCompressionMethod = new TarArchiver.TarCompressionMethod();
494
495
496 final String compression = format.substring( index + 1 );
497 if ( "gz".equals( compression ) )
498 {
499 tarCompressionMethod.setValue( "gzip" );
500 }
501 else if ( "bz2".equals( compression ) )
502 {
503 tarCompressionMethod.setValue( "bzip2" );
504 }
505 else
506 {
507
508 throw new IllegalArgumentException( "Unknown compression format: " + compression );
509 }
510 tarArchiver.setCompression( tarCompressionMethod );
511 }
512
513 final TarLongFileMode tarFileMode = new TarLongFileMode();
514
515 tarFileMode.setValue( tarLongFileMode );
516
517 tarArchiver.setLongfile( tarFileMode );
518
519 return tarArchiver;
520 }
521
522 public void contextualize( final Context context )
523 throws ContextException
524 {
525 container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
526 }
527
528 protected void setContainer( final PlexusContainer container )
529 {
530 this.container = container;
531 }
532
533 }