1 package org.apache.maven.plugins.assembly.io;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.commons.io.IOUtils;
23 import org.apache.maven.plugins.assembly.AssemblerConfigurationSource;
24 import org.apache.maven.plugins.assembly.InvalidAssemblerConfigurationException;
25 import org.apache.maven.plugins.assembly.interpolation.AssemblyExpressionEvaluator;
26 import org.apache.maven.plugins.assembly.interpolation.AssemblyInterpolator;
27 import org.apache.maven.plugins.assembly.model.Assembly;
28 import org.apache.maven.plugins.assembly.model.Component;
29 import org.apache.maven.plugins.assembly.model.ContainerDescriptorHandlerConfig;
30 import org.apache.maven.plugins.assembly.model.DependencySet;
31 import org.apache.maven.plugins.assembly.model.FileItem;
32 import org.apache.maven.plugins.assembly.model.FileSet;
33 import org.apache.maven.plugins.assembly.model.ModuleSet;
34 import org.apache.maven.plugins.assembly.model.Repository;
35 import org.apache.maven.plugins.assembly.model.io.xpp3.AssemblyXpp3Reader;
36 import org.apache.maven.plugins.assembly.model.io.xpp3.AssemblyXpp3Writer;
37 import org.apache.maven.plugins.assembly.model.io.xpp3.ComponentXpp3Reader;
38 import org.apache.maven.plugins.assembly.resolved.AssemblyId;
39 import org.apache.maven.plugins.assembly.utils.InterpolationConstants;
40 import org.apache.maven.project.MavenProject;
41 import org.apache.maven.shared.io.location.ClasspathResourceLocatorStrategy;
42 import org.apache.maven.shared.io.location.FileLocatorStrategy;
43 import org.apache.maven.shared.io.location.Location;
44 import org.apache.maven.shared.io.location.Locator;
45 import org.apache.maven.shared.io.location.LocatorStrategy;
46 import org.apache.maven.shared.utils.ReaderFactory;
47 import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
48 import org.codehaus.plexus.interpolation.RecursionInterceptor;
49 import org.codehaus.plexus.interpolation.fixed.FixedStringSearchInterpolator;
50 import org.codehaus.plexus.interpolation.fixed.InterpolationState;
51 import org.codehaus.plexus.interpolation.fixed.PrefixedObjectValueSource;
52 import org.codehaus.plexus.interpolation.fixed.PrefixedPropertiesValueSource;
53 import org.codehaus.plexus.logging.AbstractLogEnabled;
54 import org.codehaus.plexus.logging.Logger;
55 import org.codehaus.plexus.logging.console.ConsoleLogger;
56 import org.codehaus.plexus.util.DirectoryScanner;
57 import org.codehaus.plexus.util.IOUtil;
58 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
59
60 import java.io.File;
61 import java.io.IOException;
62 import java.io.InputStream;
63 import java.io.InputStreamReader;
64 import java.io.Reader;
65 import java.io.StringWriter;
66 import java.util.ArrayList;
67 import java.util.Collections;
68 import java.util.HashSet;
69 import java.util.List;
70 import java.util.Set;
71
72
73
74
75 @org.codehaus.plexus.component.annotations.Component( role = AssemblyReader.class )
76 public class DefaultAssemblyReader
77 extends AbstractLogEnabled
78 implements AssemblyReader
79 {
80
81 public static FixedStringSearchInterpolator createProjectInterpolator( MavenProject project )
82 {
83
84 return FixedStringSearchInterpolator.create( new PrefixedPropertiesValueSource( InterpolationConstants.PROJECT_PROPERTIES_PREFIXES,
85 project.getProperties(), true ),
86 new PrefixedObjectValueSource( InterpolationConstants.PROJECT_PREFIXES,
87 project, true ) );
88
89 }
90
91 @Override
92 public List<Assembly> readAssemblies( final AssemblerConfigurationSource configSource )
93 throws AssemblyReadException, InvalidAssemblerConfigurationException
94 {
95 final Locator locator = new Locator();
96
97 final List<LocatorStrategy> strategies = new ArrayList<LocatorStrategy>();
98 strategies.add( new RelativeFileLocatorStrategy( configSource.getBasedir() ) );
99 strategies.add( new FileLocatorStrategy() );
100
101 final List<LocatorStrategy> refStrategies = new ArrayList<LocatorStrategy>();
102 refStrategies.add( new PrefixedClasspathLocatorStrategy( "/assemblies/" ) );
103
104 final List<Assembly> assemblies = new ArrayList<Assembly>();
105
106 final String[] descriptors = configSource.getDescriptors();
107 final String[] descriptorRefs = configSource.getDescriptorReferences();
108 final File descriptorSourceDirectory = configSource.getDescriptorSourceDirectory();
109
110 if ( ( descriptors != null ) && ( descriptors.length > 0 ) )
111 {
112 locator.setStrategies( strategies );
113 for ( String descriptor1 : descriptors )
114 {
115 getLogger().info( "Reading assembly descriptor: " + descriptor1 );
116 addAssemblyFromDescriptor( descriptor1, locator, configSource, assemblies );
117 }
118 }
119
120 if ( ( descriptorRefs != null ) && ( descriptorRefs.length > 0 ) )
121 {
122 locator.setStrategies( refStrategies );
123 for ( String descriptorRef : descriptorRefs )
124 {
125 addAssemblyForDescriptorReference( descriptorRef, configSource, assemblies );
126 }
127 }
128
129 if ( ( descriptorSourceDirectory != null ) && descriptorSourceDirectory.isDirectory() )
130 {
131
132 locator.setStrategies( Collections.<LocatorStrategy>singletonList( new RelativeFileLocatorStrategy( descriptorSourceDirectory ) ) );
133
134
135 final DirectoryScanner scanner = new DirectoryScanner();
136 scanner.setBasedir( descriptorSourceDirectory );
137 scanner.setIncludes( new String[] { "**/*.xml" } );
138 scanner.addDefaultExcludes();
139
140 scanner.scan();
141
142 final String[] paths = scanner.getIncludedFiles();
143
144 for ( String path : paths )
145 {
146 addAssemblyFromDescriptor( path, locator, configSource, assemblies );
147 }
148 }
149
150 if ( assemblies.isEmpty() )
151 {
152 if ( configSource.isIgnoreMissingDescriptor() )
153 {
154 getLogger().debug( "Ignoring missing assembly descriptors per configuration. "
155 + "See messages above for specifics." );
156 }
157 else
158 {
159 throw new AssemblyReadException( "No assembly descriptors found." );
160 }
161 }
162
163
164 final Set<String> ids = new HashSet<String>();
165 for ( final Assembly assembly : assemblies )
166 {
167 if ( !ids.add( assembly.getId() ) )
168 {
169 getLogger().warn( "The assembly id " + assembly.getId() + " is used more than once." );
170 }
171
172 }
173 return assemblies;
174 }
175
176 @Override
177 public Assembly getAssemblyForDescriptorReference( final String ref,
178 final AssemblerConfigurationSource configSource )
179 throws AssemblyReadException,
180 InvalidAssemblerConfigurationException
181 {
182 return addAssemblyForDescriptorReference( ref, configSource, new ArrayList<Assembly>( 1 ) );
183 }
184
185 @Override
186 public Assembly getAssemblyFromDescriptorFile( final File file, final AssemblerConfigurationSource configSource )
187 throws AssemblyReadException, InvalidAssemblerConfigurationException
188 {
189 return addAssemblyFromDescriptorFile( file, configSource, new ArrayList<Assembly>( 1 ) );
190 }
191
192 private Assembly addAssemblyForDescriptorReference( final String ref,
193 final AssemblerConfigurationSource configSource,
194 final List<Assembly> assemblies )
195 throws AssemblyReadException,
196 InvalidAssemblerConfigurationException
197 {
198 final InputStream resourceAsStream =
199 Thread.currentThread().getContextClassLoader().getResourceAsStream( "assemblies/" + ref + ".xml" );
200
201 if ( resourceAsStream == null )
202 {
203 if ( configSource.isIgnoreMissingDescriptor() )
204 {
205 getLogger().debug( "Ignoring missing assembly descriptor with ID '" + ref + "' per configuration." );
206 return null;
207 }
208 else
209 {
210 throw new AssemblyReadException( "Descriptor with ID '" + ref + "' not found" );
211 }
212 }
213
214 Reader reader = null;
215 try
216 {
217 reader = ReaderFactory.newXmlReader( resourceAsStream );
218 final Assembly assembly = readAssembly( reader, ref, null, configSource );
219 reader.close();
220 reader = null;
221 assemblies.add( assembly );
222 return assembly;
223 }
224 catch ( final IOException e )
225 {
226 throw new AssemblyReadException( "Problem with descriptor with ID '" + ref + "'", e );
227 }
228 finally
229 {
230 IOUtils.closeQuietly( reader );
231 }
232 }
233
234 private Assembly addAssemblyFromDescriptorFile( final File descriptor,
235 final AssemblerConfigurationSource configSource,
236 final List<Assembly> assemblies )
237 throws AssemblyReadException,
238 InvalidAssemblerConfigurationException
239 {
240 if ( !descriptor.exists() )
241 {
242 if ( configSource.isIgnoreMissingDescriptor() )
243 {
244 getLogger().debug( "Ignoring missing assembly descriptor: '" + descriptor + "' per configuration." );
245 return null;
246 }
247 else
248 {
249 throw new AssemblyReadException( "Descriptor: '" + descriptor + "' not found" );
250 }
251 }
252
253 Reader r = null;
254 try
255 {
256 r = ReaderFactory.newXmlReader( descriptor );
257
258 final Assembly assembly =
259 readAssembly( r, descriptor.getAbsolutePath(), descriptor.getParentFile(), configSource );
260
261 r.close();
262 r = null;
263
264 assemblies.add( assembly );
265
266 return assembly;
267 }
268 catch ( final IOException e )
269 {
270 throw new AssemblyReadException( "Error reading assembly descriptor: " + descriptor, e );
271 }
272 finally
273 {
274 IOUtil.close( r );
275 }
276 }
277
278 private Assembly addAssemblyFromDescriptor( final String spec, final Locator locator,
279 final AssemblerConfigurationSource configSource,
280 final List<Assembly> assemblies )
281 throws AssemblyReadException, InvalidAssemblerConfigurationException
282 {
283 final Location location = locator.resolve( spec );
284
285 if ( location == null )
286 {
287 if ( configSource.isIgnoreMissingDescriptor() )
288 {
289 getLogger().debug( "Ignoring missing assembly descriptor with ID '" + spec
290 + "' per configuration.\nLocator output was:\n\n" + locator.getMessageHolder().render() );
291 return null;
292 }
293 else
294 {
295 throw new AssemblyReadException( "Error locating assembly descriptor: " + spec + "\n\n"
296 + locator.getMessageHolder().render() );
297 }
298 }
299
300 Reader r = null;
301 try
302 {
303 r = ReaderFactory.newXmlReader( location.getInputStream() );
304
305 File dir = null;
306 if ( location.getFile() != null )
307 {
308 dir = location.getFile().getParentFile();
309 }
310
311 final Assembly assembly = readAssembly( r, spec, dir, configSource );
312
313 r.close();
314 r = null;
315
316 assemblies.add( assembly );
317
318 return assembly;
319 }
320 catch ( final IOException e )
321 {
322 throw new AssemblyReadException( "Error reading assembly descriptor: " + spec, e );
323 }
324 finally
325 {
326 IOUtil.close( r );
327 }
328
329 }
330
331 public Assembly readAssembly( Reader reader, final String locationDescription, final File assemblyDir,
332 final AssemblerConfigurationSource configSource )
333 throws AssemblyReadException, InvalidAssemblerConfigurationException
334 {
335 Assembly assembly;
336
337 final MavenProject project = configSource.getProject();
338 try
339 {
340
341 InterpolationState is = new InterpolationState();
342 final RecursionInterceptor interceptor =
343 new PrefixAwareRecursionInterceptor( InterpolationConstants.PROJECT_PREFIXES, true );
344 is.setRecursionInterceptor( interceptor );
345
346 FixedStringSearchInterpolator interpolator =
347 AssemblyInterpolator.fullInterpolator( project, createProjectInterpolator( project ), configSource );
348 AssemblyXpp3Reader.ContentTransformer transformer =
349 AssemblyInterpolator.assemblyInterpolator( interpolator, is, getLogger() );
350
351 final AssemblyXpp3Reader r = new AssemblyXpp3Reader( transformer );
352 assembly = r.read( reader );
353
354 ComponentXpp3Reader.ContentTransformer ctrans =
355 AssemblyInterpolator.componentInterpolator( interpolator, is, getLogger() );
356 mergeComponentsWithMainAssembly( assembly, assemblyDir, configSource, ctrans );
357 debugPrintAssembly( "After assembly is interpolated:", assembly );
358
359 AssemblyInterpolator.checkErrors( AssemblyId.createAssemblyId( assembly ), is, getLogger() );
360
361 reader.close();
362 reader = null;
363 }
364 catch ( final IOException e )
365 {
366 throw new AssemblyReadException( "Error reading descriptor: " + locationDescription + ": " + e.getMessage(),
367 e );
368 }
369 catch ( final XmlPullParserException e )
370 {
371 throw new AssemblyReadException( "Error reading descriptor: " + locationDescription + ": " + e.getMessage(),
372 e );
373 }
374 finally
375 {
376 IOUtil.close( reader );
377 }
378
379 if ( assembly.isIncludeSiteDirectory() )
380 {
381 includeSiteInAssembly( assembly, configSource );
382 }
383
384 return assembly;
385 }
386
387 private void debugPrintAssembly( final String message, final Assembly assembly )
388 {
389 final StringWriter sWriter = new StringWriter();
390 try
391 {
392 new AssemblyXpp3Writer().write( sWriter, assembly );
393 }
394 catch ( final IOException e )
395 {
396 getLogger().debug( "Failed to print debug message with assembly descriptor listing, and message: "
397 + message, e );
398 }
399
400 getLogger().debug( message + "\n\n" + sWriter.toString() + "\n\n" );
401 }
402
403
404
405
406
407
408
409
410
411 protected void mergeComponentsWithMainAssembly( final Assembly assembly, final File assemblyDir,
412 final AssemblerConfigurationSource configSource,
413 ComponentXpp3Reader.ContentTransformer transformer )
414 throws AssemblyReadException
415 {
416 final Locator locator = new Locator();
417
418 if ( assemblyDir != null && assemblyDir.exists() && assemblyDir.isDirectory() )
419 {
420 locator.addStrategy( new RelativeFileLocatorStrategy( assemblyDir ) );
421 }
422
423
424 locator.addStrategy( new RelativeFileLocatorStrategy( configSource.getBasedir() ) );
425 locator.addStrategy( new FileLocatorStrategy() );
426 locator.addStrategy( new ClasspathResourceLocatorStrategy() );
427
428 final AssemblyExpressionEvaluator aee = new AssemblyExpressionEvaluator( configSource );
429
430 final List<String> componentLocations = assembly.getComponentDescriptors();
431
432 for ( String location : componentLocations )
433 {
434
435 try
436 {
437 location = aee.evaluate( location ).toString();
438 }
439 catch ( final Exception eee )
440 {
441 getLogger().error( "Error interpolating componentDescriptor: " + location, eee );
442 }
443
444 final Location resolvedLocation = locator.resolve( location );
445
446 if ( resolvedLocation == null )
447 {
448 throw new AssemblyReadException( "Failed to locate component descriptor: " + location );
449 }
450
451 Component component = null;
452 Reader reader = null;
453 try
454 {
455 reader = new InputStreamReader( resolvedLocation.getInputStream() );
456 component = new ComponentXpp3Reader( transformer ).read( reader );
457 }
458 catch ( final IOException e )
459 {
460 throw new AssemblyReadException( "Error reading component descriptor: " + location + " (resolved to: "
461 + resolvedLocation.getSpecification() + ")", e );
462 }
463 catch ( final XmlPullParserException e )
464 {
465 throw new AssemblyReadException( "Error reading component descriptor: " + location + " (resolved to: "
466 + resolvedLocation.getSpecification() + ")", e );
467 }
468 finally
469 {
470 IOUtil.close( reader );
471 }
472
473 mergeComponentWithAssembly( component, assembly );
474 }
475 }
476
477
478
479
480
481
482
483 protected void mergeComponentWithAssembly( final Component component, final Assembly assembly )
484 {
485 final List<ContainerDescriptorHandlerConfig> containerHandlerDescriptors =
486 component.getContainerDescriptorHandlers();
487
488 for ( final ContainerDescriptorHandlerConfig cfg : containerHandlerDescriptors )
489 {
490 assembly.addContainerDescriptorHandler( cfg );
491 }
492
493 final List<DependencySet> dependencySetList = component.getDependencySets();
494
495 for ( final DependencySet dependencySet : dependencySetList )
496 {
497 assembly.addDependencySet( dependencySet );
498 }
499
500 final List<FileSet> fileSetList = component.getFileSets();
501
502 for ( final FileSet fileSet : fileSetList )
503 {
504 assembly.addFileSet( fileSet );
505 }
506
507 final List<FileItem> fileList = component.getFiles();
508
509 for ( final FileItem fileItem : fileList )
510 {
511 assembly.addFile( fileItem );
512 }
513
514 final List<Repository> repositoriesList = component.getRepositories();
515
516 for ( final Repository repository : repositoriesList )
517 {
518 assembly.addRepository( repository );
519 }
520
521 final List<ModuleSet> moduleSets = component.getModuleSets();
522 for ( final ModuleSet moduleSet : moduleSets )
523 {
524 assembly.addModuleSet( moduleSet );
525 }
526 }
527
528 @Override
529 public void includeSiteInAssembly( final Assembly assembly, final AssemblerConfigurationSource configSource )
530 throws InvalidAssemblerConfigurationException
531 {
532 final File siteDirectory = configSource.getSiteDirectory();
533
534 if ( !siteDirectory.exists() )
535 {
536 throw new InvalidAssemblerConfigurationException( "site did not exist in the target directory - "
537 + "please run site:site before creating the assembly" );
538 }
539
540 getLogger().info( "Adding site directory to assembly : " + siteDirectory );
541
542 final FileSet siteFileSet = new FileSet();
543
544 siteFileSet.setDirectory( siteDirectory.getPath() );
545
546 siteFileSet.setOutputDirectory( "/site" );
547
548 assembly.addFileSet( siteFileSet );
549 }
550
551 @Override
552 protected Logger getLogger()
553 {
554 Logger logger = super.getLogger();
555
556 if ( logger == null )
557 {
558 logger = new ConsoleLogger( Logger.LEVEL_INFO, "assemblyReader-internal" );
559 enableLogging( logger );
560 }
561
562 return logger;
563 }
564
565 }