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