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<>();
98 strategies.add( new RelativeFileLocatorStrategy( configSource.getBasedir() ) );
99 strategies.add( new FileLocatorStrategy() );
100
101 final List<LocatorStrategy> refStrategies = new ArrayList<>();
102 refStrategies.add( new PrefixedClasspathLocatorStrategy( "/assemblies/" ) );
103
104 final List<Assembly> assemblies = new ArrayList<>();
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<>();
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 | XmlPullParserException e )
364 {
365 throw new AssemblyReadException( "Error reading descriptor: " + locationDescription + ": " + e.getMessage(),
366 e );
367 }
368 finally
369 {
370 IOUtil.close( reader );
371 }
372
373 if ( assembly.isIncludeSiteDirectory() )
374 {
375 includeSiteInAssembly( assembly, configSource );
376 }
377
378 return assembly;
379 }
380
381 private void debugPrintAssembly( final String message, final Assembly assembly )
382 {
383 final StringWriter sWriter = new StringWriter();
384 try
385 {
386 new AssemblyXpp3Writer().write( sWriter, assembly );
387 }
388 catch ( final IOException e )
389 {
390 getLogger().debug( "Failed to print debug message with assembly descriptor listing, and message: "
391 + message, e );
392 }
393
394 getLogger().debug( message + "\n\n" + sWriter.toString() + "\n\n" );
395 }
396
397
398
399
400
401
402
403
404
405 protected void mergeComponentsWithMainAssembly( final Assembly assembly, final File assemblyDir,
406 final AssemblerConfigurationSource configSource,
407 ComponentXpp3Reader.ContentTransformer transformer )
408 throws AssemblyReadException
409 {
410 final Locator locator = new Locator();
411
412 if ( assemblyDir != null && assemblyDir.exists() && assemblyDir.isDirectory() )
413 {
414 locator.addStrategy( new RelativeFileLocatorStrategy( assemblyDir ) );
415 }
416
417
418 locator.addStrategy( new RelativeFileLocatorStrategy( configSource.getBasedir() ) );
419 locator.addStrategy( new FileLocatorStrategy() );
420 locator.addStrategy( new ClasspathResourceLocatorStrategy() );
421
422 final AssemblyExpressionEvaluator aee = new AssemblyExpressionEvaluator( configSource );
423
424 final List<String> componentLocations = assembly.getComponentDescriptors();
425
426 for ( String location : componentLocations )
427 {
428
429 try
430 {
431 location = aee.evaluate( location ).toString();
432 }
433 catch ( final Exception eee )
434 {
435 getLogger().error( "Error interpolating componentDescriptor: " + location, eee );
436 }
437
438 final Location resolvedLocation = locator.resolve( location );
439
440 if ( resolvedLocation == null )
441 {
442 throw new AssemblyReadException( "Failed to locate component descriptor: " + location );
443 }
444
445 Component component = null;
446 Reader reader = null;
447 try
448 {
449 reader = new InputStreamReader( resolvedLocation.getInputStream() );
450 component = new ComponentXpp3Reader( transformer ).read( reader );
451 }
452 catch ( final IOException | XmlPullParserException e )
453 {
454 throw new AssemblyReadException( "Error reading component descriptor: " + location + " (resolved to: "
455 + resolvedLocation.getSpecification() + ")", e );
456 }
457 finally
458 {
459 IOUtil.close( reader );
460 }
461
462 mergeComponentWithAssembly( component, assembly );
463 }
464 }
465
466
467
468
469
470
471
472 protected void mergeComponentWithAssembly( final Component component, final Assembly assembly )
473 {
474 final List<ContainerDescriptorHandlerConfig> containerHandlerDescriptors =
475 component.getContainerDescriptorHandlers();
476
477 for ( final ContainerDescriptorHandlerConfig cfg : containerHandlerDescriptors )
478 {
479 assembly.addContainerDescriptorHandler( cfg );
480 }
481
482 final List<DependencySet> dependencySetList = component.getDependencySets();
483
484 for ( final DependencySet dependencySet : dependencySetList )
485 {
486 assembly.addDependencySet( dependencySet );
487 }
488
489 final List<FileSet> fileSetList = component.getFileSets();
490
491 for ( final FileSet fileSet : fileSetList )
492 {
493 assembly.addFileSet( fileSet );
494 }
495
496 final List<FileItem> fileList = component.getFiles();
497
498 for ( final FileItem fileItem : fileList )
499 {
500 assembly.addFile( fileItem );
501 }
502
503 final List<Repository> repositoriesList = component.getRepositories();
504
505 for ( final Repository repository : repositoriesList )
506 {
507 assembly.addRepository( repository );
508 }
509
510 final List<ModuleSet> moduleSets = component.getModuleSets();
511 for ( final ModuleSet moduleSet : moduleSets )
512 {
513 assembly.addModuleSet( moduleSet );
514 }
515 }
516
517 @Override
518 public void includeSiteInAssembly( final Assembly assembly, final AssemblerConfigurationSource configSource )
519 throws InvalidAssemblerConfigurationException
520 {
521 final File siteDirectory = configSource.getSiteDirectory();
522
523 if ( !siteDirectory.exists() )
524 {
525 throw new InvalidAssemblerConfigurationException( "site did not exist in the target directory - "
526 + "please run site:site before creating the assembly" );
527 }
528
529 getLogger().info( "Adding site directory to assembly : " + siteDirectory );
530
531 final FileSet siteFileSet = new FileSet();
532
533 siteFileSet.setDirectory( siteDirectory.getPath() );
534
535 siteFileSet.setOutputDirectory( "/site" );
536
537 assembly.addFileSet( siteFileSet );
538 }
539
540 @Override
541 protected Logger getLogger()
542 {
543 Logger logger = super.getLogger();
544
545 if ( logger == null )
546 {
547 logger = new ConsoleLogger( Logger.LEVEL_INFO, "assemblyReader-internal" );
548 enableLogging( logger );
549 }
550
551 return logger;
552 }
553
554 }