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