1 package org.alfresco.maven.plugin.amp;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.alfresco.maven.plugin.amp.overlay.OverlayManager;
23 import org.alfresco.maven.plugin.amp.packaging.AmpPackagingContext;
24 import org.alfresco.maven.plugin.amp.packaging.AmpPackagingTask;
25 import org.alfresco.maven.plugin.amp.packaging.AmpPostPackagingTask;
26 import org.alfresco.maven.plugin.amp.packaging.AmpProjectPackagingTask;
27 import org.alfresco.maven.plugin.amp.packaging.OverlayPackagingTask;
28 import org.alfresco.maven.plugin.amp.packaging.SaveAmpStructurePostPackagingTask;
29 import org.alfresco.maven.plugin.amp.util.AmpStructure;
30 import org.alfresco.maven.plugin.amp.util.AmpStructureSerializer;
31 import org.alfresco.maven.plugin.amp.util.CompositeMap;
32 import org.alfresco.maven.plugin.amp.util.PropertyUtils;
33 import org.alfresco.maven.plugin.amp.util.ReflectionProperties;
34
35
36 import org.apache.maven.archiver.MavenArchiveConfiguration;
37 import org.apache.maven.model.Resource;
38 import org.apache.maven.plugin.AbstractMojo;
39 import org.apache.maven.plugin.MojoExecutionException;
40 import org.apache.maven.plugin.MojoFailureException;
41 import org.apache.maven.plugin.logging.Log;
42 import org.apache.maven.project.MavenProject;
43 import org.codehaus.plexus.archiver.jar.JarArchiver;
44 import org.codehaus.plexus.archiver.manager.ArchiverManager;
45 import org.codehaus.plexus.util.StringUtils;
46
47 import java.io.File;
48 import java.io.IOException;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Iterator;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Properties;
55
56 public abstract class AbstractAmpMojo extends AbstractMojo
57 {
58
59 /***
60 * Returns a string array of the classes and resources to be excluded from the jar excludes to be used
61 * when assembling/copying the AMP.
62 *
63 * @return an array of tokens to exclude
64 */
65 protected String[] getExcludes()
66 {
67 List excludeList = new ArrayList();
68 if ( StringUtils.isNotEmpty( mAmpJarExcludes ) )
69 {
70 excludeList.addAll( Arrays.asList( StringUtils.split( mAmpJarExcludes, "," ) ) );
71 }
72
73 return (String[]) excludeList.toArray( EMPTY_STRING_ARRAY );
74 }
75
76 /***
77 * Returns a string array of the classes and resources to be included from the jar assembling/copying the war.
78 *
79 * @return an array of tokens to include
80 */
81 protected String[] getIncludes()
82 {
83 return StringUtils.split( StringUtils.defaultString( mAmpJarIncludes ), "," );
84 }
85
86 /***
87 * Returns a string array of the resources to be included in the AMP web/ folder.
88 *
89 * @return an array of tokens to include
90 */
91 protected String[] getWebIncludes()
92 {
93 return StringUtils.split( StringUtils.defaultString( mAmpWebIncludes ), "," );
94 }
95
96 /***
97 * Returns a string array of the resources to be excluded in the AMP web/ folder.
98 *
99 * @return an array of tokens to exclude
100 */
101 protected String[] getWebExcludes()
102 {
103 List excludeList = new ArrayList();
104 if ( StringUtils.isNotEmpty( mAmpWebExcludes ) )
105 {
106 excludeList.addAll( Arrays.asList( StringUtils.split( mAmpWebExcludes, "," ) ) );
107 }
108
109 return (String[]) excludeList.toArray( EMPTY_STRING_ARRAY );
110
111 }
112
113
114 /***
115 * Returns a string array of the excludes to be used
116 * when adding dependent AMPs as an overlay onto this AMP.
117 *
118 * @return an array of tokens to exclude
119 */
120 protected String[] getDependentAmpExcludes()
121 {
122 String[] excludes;
123 if ( StringUtils.isNotEmpty( dependentAmpExcludes ) )
124 {
125 excludes = StringUtils.split( dependentAmpExcludes, "," );
126 }
127 else
128 {
129 excludes = EMPTY_STRING_ARRAY;
130 }
131 return excludes;
132 }
133
134 /***
135 * Returns a string array of the includes to be used
136 * when adding dependent AMP as an overlay onto this AMP.
137 *
138 * @return an array of tokens to include
139 */
140 protected String[] getDependentAmpIncludes()
141 {
142 return StringUtils.split( StringUtils.defaultString( dependentAmpIncludes ), "," );
143 }
144
145 public void buildExplodedAmp( File webappDirectory )
146 throws MojoExecutionException, MojoFailureException
147 {
148 webappDirectory.mkdirs();
149
150 try
151 {
152 buildAmp( mProject, webappDirectory );
153 }
154 catch ( IOException e )
155 {
156 throw new MojoExecutionException( "Could not build AMP", e );
157 }
158 }
159
160
161 /***
162 * Builds the webapp for the specified project with the new packaging task
163 * thingy
164 * <p/>
165 * Classes, libraries and tld files are copied to
166 * the <tt>webappDirectory</tt> during this phase.
167 *
168 * @param project the maven project
169 * @param webappDirectory the target directory
170 * @throws MojoExecutionException if an error occured while packaging the webapp
171 * @throws MojoFailureException if an unexpected error occured while packaging the webapp
172 * @throws IOException if an error occured while copying the files
173 */
174 public void buildAmp( MavenProject project, File webappDirectory )
175 throws MojoExecutionException, MojoFailureException, IOException
176 {
177
178 AmpStructure cache;
179 if ( mUseCache && mCacheFile.exists() )
180 {
181 cache = new AmpStructure( webappStructureSerialier.fromXml( mCacheFile ) );
182 }
183 else
184 {
185 cache = new AmpStructure( null );
186 }
187
188 final long startTime = System.currentTimeMillis();
189 getLog().info( "Assembling AMP [" + project.getArtifactId() + "] in [" + webappDirectory + "]" );
190
191 final OverlayManager overlayManager =
192 new OverlayManager( mOverlays, project, dependentAmpIncludes, dependentAmpExcludes );
193 final List packagingTasks = getPackagingTasks( overlayManager );
194 final AmpPackagingContext context = new DefaultAmpPackagingContext( webappDirectory, cache, overlayManager );
195 final Iterator it = packagingTasks.iterator();
196 while ( it.hasNext() )
197 {
198 AmpPackagingTask ampPackagingTask = (AmpPackagingTask) it.next();
199 ampPackagingTask.performPackaging( context );
200 }
201
202
203 final List postPackagingTasks = getPostPackagingTasks();
204 final Iterator it2 = postPackagingTasks.iterator();
205 while ( it2.hasNext() )
206 {
207 AmpPostPackagingTask task = (AmpPostPackagingTask) it2.next();
208 task.performPostPackaging( context );
209
210 }
211 getLog().info( "AMP assembled in[" + ( System.currentTimeMillis() - startTime ) + " msecs]" );
212
213 }
214
215 /***
216 * Returns a <tt>List</tt> of the {@link org.alfresco.maven.plugin.amp.packaging.AmpPackagingTask}
217 * instances to invoke to perform the packaging.
218 *
219 * @param overlayManager the overlay manager
220 * @return the list of packaging tasks
221 * @throws MojoExecutionException if the packaging tasks could not be built
222 */
223 private List getPackagingTasks( OverlayManager overlayManager )
224 throws MojoExecutionException
225 {
226 final List packagingTasks = new ArrayList();
227 final List resolvedOverlays = overlayManager.getOverlays();
228 final Iterator it = resolvedOverlays.iterator();
229 while ( it.hasNext() )
230 {
231 Overlay overlay = (Overlay) it.next();
232 if ( overlay.isCurrentProject() )
233 {
234 packagingTasks.add( new AmpProjectPackagingTask( mAmpResources, mModuleProperties) );
235 }
236 else
237 {
238 packagingTasks.add( new OverlayPackagingTask( overlay ) );
239 }
240 }
241 return packagingTasks;
242 }
243
244
245 /***
246 * Returns a <tt>List</tt> of the {@link org.alfresco.maven.plugin.amp.packaging.AmpPostPackagingTask}
247 * instances to invoke to perform the post-packaging.
248 *
249 * @return the list of post packaging tasks
250 */
251 private List getPostPackagingTasks()
252 {
253 final List postPackagingTasks = new ArrayList();
254 if ( mUseCache )
255 {
256 postPackagingTasks.add( new SaveAmpStructurePostPackagingTask( mCacheFile ) );
257 }
258
259 return postPackagingTasks;
260 }
261
262
263 /***
264 * The maven project.
265 *
266 * @parameter expression="${project}"
267 * @required
268 * @readonly
269 */
270 private MavenProject mProject;
271
272 /***
273 * The directory containing generated classes.
274 *
275 * @parameter expression="${project.build.outputDirectory}"
276 * @required
277 * @readonly
278 */
279 private File mClassesDirectory;
280
281
282 /***
283 * The Jar archiver needed for archiving classes directory into jar file under WEB-INF/lib.
284 *
285 * @parameter expression="${component.org.codehaus.plexus.archiver.Archiver#jar}"
286 * @required
287 */
288 private JarArchiver mJarArchiver;
289
290
291 /***
292 * The directory where the webapp is built.
293 *
294 * @parameter expression="${project.build.directory}/${project.build.finalName}"
295 * @required
296 */
297 private File mAmpDirectory;
298
299 /***
300 * Single directory for extra files to include in the AMP.
301 *
302 * @parameter expression="${project.build.outputDirectory}"
303 * @required
304 */
305 private File mAmpConfigDirectory;
306
307 /***
308 * Single directory for extra files to include in the AMP.
309 *
310 * @parameter expression="${basedir}/src/main/webapp"
311 * @required
312 */
313 private File mAmpWebDirectory;
314
315 /***
316 * The list of webResources we want to transfer.
317 *
318 * @parameter
319 */
320 private Resource[] mAmpResources;
321
322 /***
323 * Filters (property files) to include during the interpolation of the pom.xml.
324 *
325 * @parameter expression="${project.build.filters}"
326 */
327 private List filters;
328
329 /***
330 * The path to the web.xml file to use.
331 *
332 * @parameter expression="${maven.amp.moduleProperties}" default-value="${project.basedir}/module.properties"
333 */
334 private File mModuleProperties;
335
336
337 /***
338 * Directory to unpack dependent AMPs into if needed
339 *
340 * @parameter expression="${project.build.directory}/amp/work"
341 * @required
342 */
343 private File mWorkDirectory;
344
345 /***
346 * The file name mapping to use to copy libraries and tlds. If no file mapping is
347 * set (default) the file is copied with its standard name.
348 *
349 * @parameter
350 * @since 2.0.3
351 */
352 private String mOutputFileNameMapping;
353
354 /***
355 * The file containing the webapp structure cache.
356 *
357 * @parameter expression="${project.build.directory}/amp/work/amp-cache.xml"
358 * @required
359 * @since 2.1
360 */
361 private File mCacheFile;
362
363 /***
364 * Whether the cache should be used to save the status of the webapp
365 * accross multiple runs.
366 *
367 * @parameter expression="${useCache}" default-value="true"
368 * @since 2.1
369 */
370 private boolean mUseCache = true;
371
372
373
374 /***
375 * To look up Archiver/UnArchiver implementations
376 *
377 * @parameter expression="${component.org.codehaus.plexus.archiver.manager.ArchiverManager}"
378 * @required
379 */
380 protected ArchiverManager mArchiverManager;
381
382 private static final String META_INF = "META-INF";
383
384 public static final String DEFAULT_FILE_NAME_MAPPING_CLASSIFIER =
385 "${artifactId}-${version}-${classifier}.${extension}";
386
387 public static final String DEFAULT_FILE_NAME_MAPPING = "${artifactId}-${version}.${extension}";
388
389 /***
390 * The comma separated list of tokens to include in the AMP internal JAR. Default **.
391 * Default is '**'.
392 *
393 * @parameter alias="includes"
394 */
395 private String mAmpJarIncludes = "**";
396
397 /***
398 * The comma separated list of tokens to exclude from the AMP created JAR file. By default module configuration is left outside jars.
399 *
400 * @parameter alias="excludes" default-value="alfresco/module/**"
401 */
402 private String mAmpJarExcludes;
403
404
405 /***
406 * The comma separated list of tokens to include in the AMP internal JAR. Default **.
407 * Default is '**'.
408 *
409 * @parameter alias="webIncludes" default-value="**"
410 */
411 private String mAmpWebIncludes;
412
413 /***
414 * The comma separated list of tokens to exclude from the AMP created JAR file. By default module configuration is left outside jars.
415 *
416 * @parameter alias="webExcludes"
417 */
418 private String mAmpWebExcludes;
419
420 /***
421 * The comma separated list of tokens to include when doing
422 * a AMP overlay.
423 * Default is '**'
424 *
425 * @parameter
426 */
427 private String dependentAmpIncludes = "**/**";
428
429 /***
430 * The comma separated list of tokens to exclude when doing
431 * a AMP overlay.
432 *
433 * @parameter
434 */
435 private String dependentAmpExcludes = "META-INF/**";
436
437 /***
438 * The overlays to apply.
439 *
440 * @parameter
441 * @since 2.1
442 */
443 private List mOverlays = new ArrayList();
444
445 /***
446 * The maven archive configuration to use.
447 *
448 * @parameter
449 */
450 protected MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
451
452 private static final String[] EMPTY_STRING_ARRAY = {};
453
454 private final AmpStructureSerializer webappStructureSerialier = new AmpStructureSerializer();
455
456
457
458
459
460
461 private class DefaultAmpPackagingContext
462 implements AmpPackagingContext
463 {
464
465
466 private final AmpStructure webappStructure;
467
468 private final File mAmpDirectory;
469
470 private final OverlayManager overlayManager;
471
472 public DefaultAmpPackagingContext( File webappDirectory, final AmpStructure webappStructure,
473 final OverlayManager overlayManager )
474 {
475 this.mAmpDirectory = webappDirectory;
476 this.webappStructure = webappStructure;
477 this.overlayManager = overlayManager;
478
479
480
481 final Iterator it = overlayManager.getOverlayIds().iterator();
482 while ( it.hasNext() )
483 {
484 String overlayId = (String) it.next();
485 webappStructure.getStructure( overlayId );
486 }
487 }
488
489 public MavenProject getProject()
490 {
491 return mProject;
492 }
493
494 public File getAmpDirectory()
495 {
496 return mAmpDirectory;
497 }
498
499 public File getClassesDirectory()
500 {
501 return mClassesDirectory;
502 }
503
504 public Log getLog()
505 {
506 return AbstractAmpMojo.this.getLog();
507 }
508
509 public String getOutputFileNameMapping()
510 {
511 return mOutputFileNameMapping;
512 }
513
514 public File getAmpWebDirectory()
515 {
516 return mAmpWebDirectory;
517 }
518
519 public String[] getAmpJarIncludes()
520 {
521 return getIncludes();
522 }
523
524 public String[] getAmpJarExcludes()
525 {
526 return getExcludes();
527 }
528
529 public File getOverlaysWorkDirectory()
530 {
531 return mWorkDirectory;
532 }
533
534 public ArchiverManager getArchiverManager()
535 {
536 return mArchiverManager;
537 }
538
539 public MavenArchiveConfiguration getArchive()
540 {
541 return archive;
542 }
543
544 public JarArchiver getJarArchiver()
545 {
546 return mJarArchiver;
547 }
548
549 public List getFilters()
550 {
551 return filters;
552 }
553
554 public Map getFilterProperties()
555 throws MojoExecutionException
556 {
557 Map filterProperties = new Properties();
558
559
560 filterProperties.putAll( System.getProperties() );
561
562
563 filterProperties.putAll( mProject.getProperties() );
564
565 for ( Iterator i = filters.iterator(); i.hasNext(); )
566 {
567 String filtersfile = (String) i.next();
568
569 try
570 {
571 Properties properties = PropertyUtils.loadPropertyFile( new File( filtersfile ), true, true );
572
573 filterProperties.putAll( properties );
574 }
575 catch ( IOException e )
576 {
577 throw new MojoExecutionException( "Error loading property file '" + filtersfile + "'", e );
578 }
579 }
580
581
582 return new CompositeMap( new ReflectionProperties( mProject ), filterProperties );
583 }
584
585 public AmpStructure getAmpStructure()
586 {
587 return webappStructure;
588 }
589
590 public List getOwnerIds()
591 {
592 return overlayManager.getOverlayIds();
593 }
594
595 /***
596 * @see org.alfresco.maven.plugin.amp.packaging.AmpPackagingContext#getAmpConfigDirectory()
597 */
598 public File getAmpConfigDirectory()
599 {
600 return mAmpConfigDirectory;
601 }
602
603 public String[] getAmpWebExcludes() {
604 return getWebExcludes();
605 }
606
607 public String[] getAmpWebIncludes() {
608 return getWebIncludes();
609 }
610
611 }
612
613 public MavenProject getProject()
614 {
615 return mProject;
616 }
617
618 public void setProject( MavenProject project )
619 {
620 this.mProject = project;
621 }
622
623 public File getClassesDirectory()
624 {
625 return mClassesDirectory;
626 }
627
628 public void setClassesDirectory( File classesDirectory )
629 {
630 this.mClassesDirectory = classesDirectory;
631 }
632
633 public File getAmpDirectory()
634 {
635 return mAmpDirectory;
636 }
637
638 public void setAmpDirectory( File webappDirectory )
639 {
640 this.mAmpDirectory = webappDirectory;
641 }
642
643 public File getAmpSourceDirectory()
644 {
645 return mAmpWebDirectory;
646 }
647
648 public void setAmpSourceDirectory( File ampSourceDirectory )
649 {
650 this.mAmpWebDirectory = ampSourceDirectory;
651 }
652
653 public File getWebXml()
654 {
655 return mModuleProperties;
656 }
657
658 public void setWebXml( File webXml )
659 {
660 this.mModuleProperties = webXml;
661 }
662
663
664 public String getOutputFileNameMapping()
665 {
666 return mOutputFileNameMapping;
667 }
668
669 public void setOutputFileNameMapping( String outputFileNameMapping )
670 {
671 this.mOutputFileNameMapping = outputFileNameMapping;
672 }
673
674 public List getOverlays()
675 {
676 return mOverlays;
677 }
678
679 public void setOverlays( List overlays )
680 {
681 this.mOverlays = overlays;
682 }
683
684 public void addOverlay( Overlay overlay )
685 {
686 mOverlays.add( overlay );
687 }
688
689
690 public JarArchiver getJarArchiver()
691 {
692 return mJarArchiver;
693 }
694
695 public void setJarArchiver( JarArchiver jarArchiver )
696 {
697 this.mJarArchiver = jarArchiver;
698 }
699
700 public Resource[] getAmpResources()
701 {
702 return mAmpResources;
703 }
704
705 public void setAmpResources( Resource[] webResources )
706 {
707 this.mAmpResources = webResources;
708 }
709
710 public List getFilters()
711 {
712 return filters;
713 }
714
715 public void setFilters( List filters )
716 {
717 this.filters = filters;
718 }
719
720 public File getWorkDirectory()
721 {
722 return mWorkDirectory;
723 }
724
725 public void setWorkDirectory( File workDirectory )
726 {
727 this.mWorkDirectory = workDirectory;
728 }
729
730 public File getCacheFile()
731 {
732 return mCacheFile;
733 }
734
735 public void setCacheFile( File cacheFile )
736 {
737 this.mCacheFile = cacheFile;
738 }
739
740 public void setAmpSourceIncludes( String ampSourceIncludes )
741 {
742 this.mAmpJarIncludes = ampSourceIncludes;
743 }
744
745 public String getAmpJarExcludes()
746 {
747 return mAmpJarExcludes;
748 }
749
750 public void setAmpJarExcludes( String ampJarExcludes )
751 {
752 this.mAmpJarExcludes = ampJarExcludes;
753 }
754
755
756 public boolean isUseCache()
757 {
758 return mUseCache;
759 }
760
761 public void setUseCache( boolean useCache )
762 {
763 this.mUseCache = useCache;
764 }
765 }