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 = getClass().getResourceAsStream( "/assemblies/" + ref + ".xml" );
199
200 if ( resourceAsStream == null )
201 {
202 if ( configSource.isIgnoreMissingDescriptor() )
203 {
204 getLogger().debug( "Ignoring missing assembly descriptor with ID '" + ref + "' per configuration." );
205 return null;
206 }
207 else
208 {
209 throw new AssemblyReadException( "Descriptor with ID '" + ref + "' not found" );
210 }
211 }
212
213 Reader reader = null;
214 try
215 {
216 reader = ReaderFactory.newXmlReader( resourceAsStream );
217 final Assembly assembly = readAssembly( reader, ref, null, configSource );
218 reader.close();
219 reader = null;
220 assemblies.add( assembly );
221 return assembly;
222 }
223 catch ( final IOException e )
224 {
225 throw new AssemblyReadException( "Problem with descriptor with ID '" + ref + "'", e );
226 }
227 finally
228 {
229 IOUtils.closeQuietly( reader );
230 }
231 }
232
233 private Assembly addAssemblyFromDescriptorFile( final File descriptor,
234 final AssemblerConfigurationSource configSource,
235 final List<Assembly> assemblies )
236 throws AssemblyReadException,
237 InvalidAssemblerConfigurationException
238 {
239 if ( !descriptor.exists() )
240 {
241 if ( configSource.isIgnoreMissingDescriptor() )
242 {
243 getLogger().debug( "Ignoring missing assembly descriptor: '" + descriptor + "' per configuration." );
244 return null;
245 }
246 else
247 {
248 throw new AssemblyReadException( "Descriptor: '" + descriptor + "' not found" );
249 }
250 }
251
252 Reader r = null;
253 try
254 {
255 r = ReaderFactory.newXmlReader( descriptor );
256
257 final Assembly assembly =
258 readAssembly( r, descriptor.getAbsolutePath(), descriptor.getParentFile(), configSource );
259
260 r.close();
261 r = null;
262
263 assemblies.add( assembly );
264
265 return assembly;
266 }
267 catch ( final IOException e )
268 {
269 throw new AssemblyReadException( "Error reading assembly descriptor: " + descriptor, e );
270 }
271 finally
272 {
273 IOUtil.close( r );
274 }
275 }
276
277 private Assembly addAssemblyFromDescriptor( final String spec, final Locator locator,
278 final AssemblerConfigurationSource configSource,
279 final List<Assembly> assemblies )
280 throws AssemblyReadException, InvalidAssemblerConfigurationException
281 {
282 final Location location = locator.resolve( spec );
283
284 if ( location == null )
285 {
286 if ( configSource.isIgnoreMissingDescriptor() )
287 {
288 getLogger().debug( "Ignoring missing assembly descriptor with ID '" + spec
289 + "' per configuration.\nLocator output was:\n\n" + locator.getMessageHolder().render() );
290 return null;
291 }
292 else
293 {
294 throw new AssemblyReadException( "Error locating assembly descriptor: " + spec + "\n\n"
295 + locator.getMessageHolder().render() );
296 }
297 }
298
299 Reader r = null;
300 try
301 {
302 r = ReaderFactory.newXmlReader( location.getInputStream() );
303
304 File dir = null;
305 if ( location.getFile() != null )
306 {
307 dir = location.getFile().getParentFile();
308 }
309
310 final Assembly assembly = readAssembly( r, spec, dir, configSource );
311
312 r.close();
313 r = null;
314
315 assemblies.add( assembly );
316
317 return assembly;
318 }
319 catch ( final IOException e )
320 {
321 throw new AssemblyReadException( "Error reading assembly descriptor: " + spec, e );
322 }
323 finally
324 {
325 IOUtil.close( r );
326 }
327
328 }
329
330 public Assembly readAssembly( Reader reader, final String locationDescription, final File assemblyDir,
331 final AssemblerConfigurationSource configSource )
332 throws AssemblyReadException, InvalidAssemblerConfigurationException
333 {
334 Assembly assembly;
335
336 final MavenProject project = configSource.getProject();
337 try
338 {
339
340 InterpolationState is = new InterpolationState();
341 final RecursionInterceptor interceptor =
342 new PrefixAwareRecursionInterceptor( InterpolationConstants.PROJECT_PREFIXES, true );
343 is.setRecursionInterceptor( interceptor );
344
345 FixedStringSearchInterpolator interpolator =
346 AssemblyInterpolator.fullInterpolator( project, createProjectInterpolator( project ), configSource );
347 AssemblyXpp3Reader.ContentTransformer transformer =
348 AssemblyInterpolator.assemblyInterpolator( interpolator, is, getLogger() );
349
350 final AssemblyXpp3Reader r = new AssemblyXpp3Reader( transformer );
351 assembly = r.read( reader );
352
353 ComponentXpp3Reader.ContentTransformer ctrans =
354 AssemblyInterpolator.componentInterpolator( interpolator, is, getLogger() );
355 mergeComponentsWithMainAssembly( assembly, assemblyDir, configSource, ctrans );
356 debugPrintAssembly( "After assembly is interpolated:", assembly );
357
358 AssemblyInterpolator.checkErrors( AssemblyId.createAssemblyId( assembly ), is, getLogger() );
359
360 reader.close();
361 reader = null;
362 }
363 catch ( final IOException e )
364 {
365 throw new AssemblyReadException( "Error reading descriptor: " + locationDescription + ": " + e.getMessage(),
366 e );
367 }
368 catch ( final XmlPullParserException e )
369 {
370 throw new AssemblyReadException( "Error reading descriptor: " + locationDescription + ": " + e.getMessage(),
371 e );
372 }
373 finally
374 {
375 IOUtil.close( reader );
376 }
377
378 if ( assembly.isIncludeSiteDirectory() )
379 {
380 includeSiteInAssembly( assembly, configSource );
381 }
382
383 return assembly;
384 }
385
386 private void debugPrintAssembly( final String message, final Assembly assembly )
387 {
388 final StringWriter sWriter = new StringWriter();
389 try
390 {
391 new AssemblyXpp3Writer().write( sWriter, assembly );
392 }
393 catch ( final IOException e )
394 {
395 getLogger().debug( "Failed to print debug message with assembly descriptor listing, and message: "
396 + message, e );
397 }
398
399 getLogger().debug( message + "\n\n" + sWriter.toString() + "\n\n" );
400 }
401
402
403
404
405
406
407
408
409
410 protected void mergeComponentsWithMainAssembly( final Assembly assembly, final File assemblyDir,
411 final AssemblerConfigurationSource configSource,
412 ComponentXpp3Reader.ContentTransformer transformer )
413 throws AssemblyReadException
414 {
415 final Locator locator = new Locator();
416
417 if ( assemblyDir != null && assemblyDir.exists() && assemblyDir.isDirectory() )
418 {
419 locator.addStrategy( new RelativeFileLocatorStrategy( assemblyDir ) );
420 }
421
422
423 locator.addStrategy( new RelativeFileLocatorStrategy( configSource.getBasedir() ) );
424 locator.addStrategy( new FileLocatorStrategy() );
425 locator.addStrategy( new ClasspathResourceLocatorStrategy() );
426
427 final AssemblyExpressionEvaluator aee = new AssemblyExpressionEvaluator( configSource );
428
429 final List<String> componentLocations = assembly.getComponentDescriptors();
430
431 for ( String location : componentLocations )
432 {
433
434 try
435 {
436 location = aee.evaluate( location ).toString();
437 }
438 catch ( final Exception eee )
439 {
440 getLogger().error( "Error interpolating componentDescriptor: " + location, eee );
441 }
442
443 final Location resolvedLocation = locator.resolve( location );
444
445 if ( resolvedLocation == null )
446 {
447 throw new AssemblyReadException( "Failed to locate component descriptor: " + location );
448 }
449
450 Component component = null;
451 Reader reader = null;
452 try
453 {
454 reader = new InputStreamReader( resolvedLocation.getInputStream() );
455 component = new ComponentXpp3Reader( transformer ).read( reader );
456 }
457 catch ( final IOException e )
458 {
459 throw new AssemblyReadException( "Error reading component descriptor: " + location + " (resolved to: "
460 + resolvedLocation.getSpecification() + ")", e );
461 }
462 catch ( final XmlPullParserException e )
463 {
464 throw new AssemblyReadException( "Error reading component descriptor: " + location + " (resolved to: "
465 + resolvedLocation.getSpecification() + ")", e );
466 }
467 finally
468 {
469 IOUtil.close( reader );
470 }
471
472 mergeComponentWithAssembly( component, assembly );
473 }
474 }
475
476
477
478
479
480
481
482 protected void mergeComponentWithAssembly( final Component component, final Assembly assembly )
483 {
484 final List<ContainerDescriptorHandlerConfig> containerHandlerDescriptors =
485 component.getContainerDescriptorHandlers();
486
487 for ( final ContainerDescriptorHandlerConfig cfg : containerHandlerDescriptors )
488 {
489 assembly.addContainerDescriptorHandler( cfg );
490 }
491
492 final List<DependencySet> dependencySetList = component.getDependencySets();
493
494 for ( final DependencySet dependencySet : dependencySetList )
495 {
496 assembly.addDependencySet( dependencySet );
497 }
498
499 final List<FileSet> fileSetList = component.getFileSets();
500
501 for ( final FileSet fileSet : fileSetList )
502 {
503 assembly.addFileSet( fileSet );
504 }
505
506 final List<FileItem> fileList = component.getFiles();
507
508 for ( final FileItem fileItem : fileList )
509 {
510 assembly.addFile( fileItem );
511 }
512
513 final List<Repository> repositoriesList = component.getRepositories();
514
515 for ( final Repository repository : repositoriesList )
516 {
517 assembly.addRepository( repository );
518 }
519
520 final List<ModuleSet> moduleSets = component.getModuleSets();
521 for ( final ModuleSet moduleSet : moduleSets )
522 {
523 assembly.addModuleSet( moduleSet );
524 }
525 }
526
527 @Override
528 public void includeSiteInAssembly( final Assembly assembly, final AssemblerConfigurationSource configSource )
529 throws InvalidAssemblerConfigurationException
530 {
531 final File siteDirectory = configSource.getSiteDirectory();
532
533 if ( !siteDirectory.exists() )
534 {
535 throw new InvalidAssemblerConfigurationException( "site did not exist in the target directory - "
536 + "please run site:site before creating the assembly" );
537 }
538
539 getLogger().info( "Adding site directory to assembly : " + siteDirectory );
540
541 final FileSet siteFileSet = new FileSet();
542
543 siteFileSet.setDirectory( siteDirectory.getPath() );
544
545 siteFileSet.setOutputDirectory( "/site" );
546
547 assembly.addFileSet( siteFileSet );
548 }
549
550 @Override
551 protected Logger getLogger()
552 {
553 Logger logger = super.getLogger();
554
555 if ( logger == null )
556 {
557 logger = new ConsoleLogger( Logger.LEVEL_INFO, "assemblyReader-internal" );
558 enableLogging( logger );
559 }
560
561 return logger;
562 }
563
564 }