1 package org.apache.maven.plugin.ear;
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.archiver.MavenArchiveConfiguration;
23 import org.apache.maven.archiver.MavenArchiver;
24 import org.apache.maven.execution.MavenSession;
25 import org.apache.maven.plugin.MojoExecutionException;
26 import org.apache.maven.plugin.MojoFailureException;
27 import org.apache.maven.plugin.ear.util.EarMavenArchiver;
28 import org.apache.maven.plugin.ear.util.JavaEEVersion;
29 import org.apache.maven.project.MavenProjectHelper;
30 import org.apache.maven.shared.filtering.MavenFileFilter;
31 import org.apache.maven.shared.filtering.MavenFilteringException;
32 import org.apache.maven.shared.filtering.MavenResourcesExecution;
33 import org.apache.maven.shared.filtering.MavenResourcesFiltering;
34 import org.codehaus.plexus.archiver.ArchiverException;
35 import org.codehaus.plexus.archiver.UnArchiver;
36 import org.codehaus.plexus.archiver.jar.JarArchiver;
37 import org.codehaus.plexus.archiver.jar.Manifest;
38 import org.codehaus.plexus.archiver.jar.Manifest.Attribute;
39 import org.codehaus.plexus.archiver.jar.ManifestException;
40 import org.codehaus.plexus.archiver.manager.ArchiverManager;
41 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
42 import org.codehaus.plexus.archiver.zip.ZipArchiver;
43 import org.codehaus.plexus.archiver.zip.ZipUnArchiver;
44 import org.codehaus.plexus.util.DirectoryScanner;
45 import org.codehaus.plexus.util.FileUtils;
46 import org.codehaus.plexus.util.StringUtils;
47
48 import java.io.File;
49 import java.io.FileReader;
50 import java.io.IOException;
51 import java.io.PrintWriter;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.List;
55 import java.util.zip.ZipException;
56
57
58
59
60
61
62
63
64
65
66
67 public class EarMojo
68 extends AbstractEarMojo
69 {
70 private static final String[] EMPTY_STRING_ARRAY = { };
71
72
73
74
75
76
77
78
79 private File earSourceDirectory;
80
81
82
83
84
85
86 private String earSourceIncludes;
87
88
89
90
91
92
93 private String earSourceExcludes;
94
95
96
97
98
99
100
101 private boolean filtering;
102
103
104
105
106
107
108
109 private List filters;
110
111
112
113
114
115
116
117
118 private List nonFilteredFileExtensions;
119
120
121
122
123
124
125
126
127 private boolean escapedBackslashesInFilePath;
128
129
130
131
132
133
134
135
136 protected String escapeString;
137
138
139
140
141
142
143
144
145
146 private File manifestFile;
147
148
149
150
151
152
153
154 private String applicationXml;
155
156
157
158
159
160
161
162 private String outputDirectory;
163
164
165
166
167
168
169
170 private String finalName;
171
172
173
174
175
176
177
178 private String unpackTypes;
179
180
181
182
183
184
185
186 private String classifier;
187
188
189
190
191
192
193
194
195
196
197
198 private String packagingExcludes;
199
200
201
202
203
204
205
206
207
208
209 private String packagingIncludes;
210
211
212
213
214
215
216
217
218
219 private boolean skinnyWars;
220
221
222
223
224
225
226 private JarArchiver jarArchiver;
227
228
229
230
231
232
233 private ZipArchiver zipArchiver;
234
235
236
237
238
239
240 private ZipUnArchiver zipUnArchiver;
241
242
243
244
245
246
247
248 private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
249
250
251
252
253 private MavenProjectHelper projectHelper;
254
255
256
257
258
259
260 private ArchiverManager archiverManager;
261
262
263
264
265
266 private MavenFileFilter mavenFileFilter;
267
268
269
270
271
272 private MavenResourcesFiltering mavenResourcesFiltering;
273
274
275
276
277
278
279
280 private MavenSession session;
281
282
283 private List filterWrappers;
284
285
286 public void execute()
287 throws MojoExecutionException, MojoFailureException
288 {
289
290 super.execute();
291
292 final JavaEEVersion javaEEVersion = JavaEEVersion.getJavaEEVersion( version );
293
294
295 List<String> unpackTypesList = new ArrayList<String>();
296 if ( unpackTypes != null )
297 {
298 unpackTypesList = Arrays.asList( unpackTypes.split( "," ) );
299 for ( String type : unpackTypesList )
300 {
301 if ( !EarModuleFactory.standardArtifactTypes.contains( type ) )
302 {
303 throw new MojoExecutionException(
304 "Invalid type [" + type + "] supported types are " + EarModuleFactory.standardArtifactTypes );
305 }
306 }
307 getLog().debug( "Initialized unpack types " + unpackTypesList );
308 }
309
310
311 try
312 {
313 for ( EarModule module: getModules() )
314 {
315 if ( module instanceof JavaModule )
316 {
317 getLog().warn( "JavaModule is deprecated (" + module + "), please use JarModule instead." );
318 }
319 if ( module instanceof Ejb3Module )
320 {
321 getLog().warn( "Ejb3Module is deprecated (" + module + "), please use EjbModule instead." );
322 }
323 final File sourceFile = module.getArtifact().getFile();
324 final File destinationFile = buildDestinationFile( getWorkDirectory(), module.getUri() );
325 if ( !sourceFile.isFile() )
326 {
327 throw new MojoExecutionException(
328 "Cannot copy a directory: " + sourceFile.getAbsolutePath() + "; Did you package/install "
329 + module.getArtifact() + "?" );
330 }
331
332 if ( destinationFile.getCanonicalPath().equals( sourceFile.getCanonicalPath() ) )
333 {
334 getLog().info(
335 "Skipping artifact [" + module + "], as it already exists at [" + module.getUri() + "]" );
336 continue;
337 }
338
339
340
341 if ( ( unpackTypesList.contains( module.getType() )
342 && ( module.shouldUnpack() == null || module.shouldUnpack().booleanValue() ) )
343 || ( module.shouldUnpack() != null && module.shouldUnpack().booleanValue() ) )
344 {
345 getLog().info( "Copying artifact [" + module + "] to [" + module.getUri() + "] (unpacked)" );
346
347 destinationFile.mkdirs();
348 unpack( sourceFile, destinationFile );
349
350 if ( skinnyWars && module.changeManifestClasspath() )
351 {
352 changeManifestClasspath( module, destinationFile );
353 }
354 }
355 else
356 {
357 if ( sourceFile.lastModified() > destinationFile.lastModified() )
358 {
359 getLog().info( "Copying artifact [" + module + "] to [" + module.getUri() + "]" );
360 FileUtils.copyFile( sourceFile, destinationFile );
361
362 if ( skinnyWars && module.changeManifestClasspath() )
363 {
364 changeManifestClasspath( module, destinationFile );
365 }
366 }
367 else
368 {
369 getLog().debug(
370 "Skipping artifact [" + module + "], as it is already up to date at [" + module.getUri()
371 + "]" );
372 }
373 }
374 }
375 }
376 catch ( IOException e )
377 {
378 throw new MojoExecutionException( "Error copying EAR modules", e );
379 }
380 catch ( ArchiverException e )
381 {
382 throw new MojoExecutionException( "Error unpacking EAR modules", e );
383 }
384 catch ( NoSuchArchiverException e )
385 {
386 throw new MojoExecutionException( "No Archiver found for EAR modules", e );
387 }
388
389
390 try
391 {
392 File earSourceDir = earSourceDirectory;
393 if ( earSourceDir.exists() )
394 {
395 getLog().info( "Copy ear sources to " + getWorkDirectory().getAbsolutePath() );
396 String[] fileNames = getEarFiles( earSourceDir );
397 for ( int i = 0; i < fileNames.length; i++ )
398 {
399 copyFile( new File( earSourceDir, fileNames[i] ), new File( getWorkDirectory(), fileNames[i] ) );
400 }
401 }
402
403 if ( applicationXml != null && !"".equals( applicationXml ) )
404 {
405
406 getLog().info( "Including custom application.xml[" + applicationXml + "]" );
407 File metaInfDir = new File( getWorkDirectory(), META_INF );
408 copyFile( new File( applicationXml ), new File( metaInfDir, "/application.xml" ) );
409 }
410
411 }
412 catch ( IOException e )
413 {
414 throw new MojoExecutionException( "Error copying EAR sources", e );
415 }
416 catch ( MavenFilteringException e )
417 {
418 throw new MojoExecutionException( "Error filtering EAR sources", e );
419 }
420
421
422 File ddFile = new File( getWorkDirectory(), APPLICATION_XML_URI );
423 if ( !ddFile.exists() && ( javaEEVersion.lt( JavaEEVersion.Five ) ) )
424 {
425 throw new MojoExecutionException(
426 "Deployment descriptor: " + ddFile.getAbsolutePath() + " does not exist." );
427 }
428
429 try
430 {
431 File earFile = getEarFile( outputDirectory, finalName, classifier );
432 final MavenArchiver archiver = new EarMavenArchiver( getModules() );
433 final JarArchiver jarArchiver = getJarArchiver();
434 getLog().debug( "Jar archiver implementation [" + jarArchiver.getClass().getName() + "]" );
435 archiver.setArchiver( jarArchiver );
436 archiver.setOutputFile( earFile );
437
438
439 includeCustomManifestFile();
440
441 getLog().debug(
442 "Excluding " + Arrays.asList( getPackagingExcludes() ) + " from the generated EAR." );
443 getLog().debug(
444 "Including " + Arrays.asList( getPackagingIncludes() ) + " in the generated EAR." );
445
446 archiver.getArchiver().addDirectory( getWorkDirectory(), getPackagingIncludes(), getPackagingExcludes() );
447 archiver.createArchive( getProject(), archive );
448
449 if ( classifier != null )
450 {
451 projectHelper.attachArtifact( getProject(), "ear", classifier, earFile );
452 }
453 else
454 {
455 getProject().getArtifact().setFile( earFile );
456 }
457 }
458 catch ( Exception e )
459 {
460 throw new MojoExecutionException( "Error assembling EAR", e );
461 }
462 }
463
464 public String getApplicationXml()
465 {
466 return applicationXml;
467 }
468
469 public void setApplicationXml( String applicationXml )
470 {
471 this.applicationXml = applicationXml;
472 }
473
474
475
476
477
478
479
480 protected String[] getExcludes()
481 {
482 @SuppressWarnings( "unchecked" )
483 List<String> excludeList = new ArrayList<String>( FileUtils.getDefaultExcludesAsList() );
484 if ( earSourceExcludes != null && !"".equals( earSourceExcludes ) )
485 {
486 excludeList.addAll( Arrays.asList( StringUtils.split( earSourceExcludes, "," ) ) );
487 }
488
489
490 if ( getApplicationXml() != null && !"".equals( getApplicationXml() ) )
491 {
492 excludeList.add( "**/" + META_INF + "/application.xml" );
493 }
494
495 return (String[]) excludeList.toArray( EMPTY_STRING_ARRAY );
496 }
497
498
499
500
501
502
503
504 protected String[] getIncludes()
505 {
506 return StringUtils.split( StringUtils.defaultString( earSourceIncludes ), "," );
507 }
508
509 public String[] getPackagingExcludes()
510 {
511 if ( StringUtils.isEmpty( packagingExcludes ) )
512 {
513 return new String[0];
514 }
515 else
516 {
517 return StringUtils.split( packagingExcludes, "," );
518 }
519 }
520
521 public void setPackagingExcludes( String packagingExcludes )
522 {
523 this.packagingExcludes = packagingExcludes;
524 }
525
526 public String[] getPackagingIncludes()
527 {
528 if ( StringUtils.isEmpty( packagingIncludes ) )
529 {
530 return new String[]{"**"};
531 }
532 else
533 {
534 return StringUtils.split( packagingIncludes, "," );
535 }
536 }
537
538 public void setPackagingIncludes( String packagingIncludes )
539 {
540 this.packagingIncludes = packagingIncludes;
541 }
542
543 private static File buildDestinationFile( File buildDir, String uri )
544 {
545 return new File( buildDir, uri );
546 }
547
548 private void includeCustomManifestFile()
549 {
550 if ( manifestFile == null )
551 {
552 manifestFile = new File( getWorkDirectory(), "META-INF/MANIFEST.MF" );
553 }
554
555 if ( !manifestFile.exists() )
556 {
557 getLog().info( "Could not find manifest file: " + manifestFile + " - Generating one" );
558 }
559 else
560 {
561 getLog().info( "Including custom manifest file [" + manifestFile + "]" );
562 archive.setManifestFile( manifestFile );
563 }
564 }
565
566
567
568
569
570
571
572
573
574 private static File getEarFile( String basedir, String finalName, String classifier )
575 {
576 if ( classifier == null )
577 {
578 classifier = "";
579 }
580 else if ( classifier.trim().length() > 0 && !classifier.startsWith( "-" ) )
581 {
582 classifier = "-" + classifier;
583 }
584
585 return new File( basedir, finalName + classifier + ".ear" );
586 }
587
588
589
590
591
592
593
594
595 private String[] getEarFiles( File sourceDir )
596 {
597 DirectoryScanner scanner = new DirectoryScanner();
598 scanner.setBasedir( sourceDir );
599 scanner.setExcludes( getExcludes() );
600 scanner.addDefaultExcludes();
601
602 scanner.setIncludes( getIncludes() );
603
604 scanner.scan();
605
606 return scanner.getIncludedFiles();
607 }
608
609
610
611
612
613
614
615 public void unpack( File source, File destDir )
616 throws NoSuchArchiverException, IOException, ArchiverException
617 {
618 UnArchiver unArchiver = archiverManager.getUnArchiver( "zip" );
619 unArchiver.setSourceFile( source );
620 unArchiver.setDestDirectory( destDir );
621
622
623 unArchiver.extract();
624 }
625
626
627
628
629
630
631
632
633
634 protected JarArchiver getJarArchiver()
635 {
636 return jarArchiver;
637 }
638
639 private void copyFile( File source, File target )
640 throws MavenFilteringException, IOException, MojoExecutionException
641 {
642 if ( filtering && !isNonFilteredExtension( source.getName() ) )
643 {
644
645 if ( target.getParentFile() != null && !target.getParentFile().exists() )
646 {
647 target.getParentFile().mkdirs();
648 }
649 mavenFileFilter.copyFile( source, target, true, getFilterWrappers(), null );
650 }
651 else
652 {
653 FileUtils.copyFile( source, target );
654 }
655 }
656
657 public boolean isNonFilteredExtension( String fileName )
658 {
659 return !mavenResourcesFiltering.filteredFileExtension( fileName, nonFilteredFileExtensions );
660 }
661
662 private List getFilterWrappers()
663 throws MojoExecutionException
664 {
665 if ( filterWrappers == null )
666 {
667 try
668 {
669 MavenResourcesExecution mavenResourcesExecution = new MavenResourcesExecution();
670 mavenResourcesExecution.setEscapeString( escapeString );
671 filterWrappers =
672 mavenFileFilter.getDefaultFilterWrappers( project, filters, escapedBackslashesInFilePath,
673 this.session, mavenResourcesExecution );
674 }
675 catch ( MavenFilteringException e )
676 {
677 getLog().error( "Fail to build filtering wrappers " + e.getMessage() );
678 throw new MojoExecutionException( e.getMessage(), e );
679 }
680 }
681 return filterWrappers;
682 }
683
684 private void changeManifestClasspath( EarModule module, File original )
685 throws MojoFailureException
686 {
687 try
688 {
689 File workDirectory;
690
691
692 if ( original.isFile() )
693 {
694
695 workDirectory = new File( new File(
696 generatedDescriptorLocation, "temp" ), module.getArtifact()
697 .getArtifactId() );
698 workDirectory.mkdirs();
699 getLog().debug( "Created a temporary work directory: " + workDirectory.getAbsolutePath() );
700
701
702 zipUnArchiver.setSourceFile( original );
703 zipUnArchiver.setDestDirectory( workDirectory );
704 zipUnArchiver.extract();
705 }
706 else
707 {
708 workDirectory = original;
709 }
710
711
712 File metaInfDirectory = new File( workDirectory, "META-INF" );
713 boolean newMetaInfCreated = metaInfDirectory.mkdirs();
714 if ( newMetaInfCreated )
715 {
716 getLog().debug(
717 "This project did not have a META-INF directory before, so a new directory was created." );
718 }
719 File manifestFile = new File( metaInfDirectory, "MANIFEST.MF" );
720 boolean newManifestCreated = manifestFile.createNewFile();
721 if ( newManifestCreated )
722 {
723 getLog().debug(
724 "This project did not have a META-INF/MANIFEST.MF file before, so a new file was created." );
725 }
726
727
728 Manifest mf = new Manifest( new FileReader( manifestFile ) );
729 Attribute classPath = mf.getMainSection()
730 .getAttribute( "Class-Path" );
731 List<String> classPathElements = new ArrayList<String>();
732
733 if ( classPath != null )
734 {
735 classPathElements.addAll( Arrays.asList( classPath.getValue()
736 .split( " " ) ) );
737 }
738 else
739 {
740 classPath = new Attribute( "Class-Path", "" );
741 mf.getMainSection().addConfiguredAttribute( classPath );
742 }
743
744
745 for ( EarModule o : getModules() )
746 {
747 if ( o instanceof JarModule )
748 {
749 JarModule jm = ( JarModule ) o;
750
751 if ( module.getLibDir() != null )
752 {
753 File artifact = new File( new File(
754 workDirectory, module.getLibDir() ),
755 jm.getBundleFileName() );
756
757 if ( artifact.exists() )
758 {
759 if ( !artifact.delete() )
760 {
761 getLog().error(
762 "Could not delete '" + artifact + "'" );
763 }
764 }
765 }
766
767 if ( classPathElements.contains( jm.getBundleFileName() ) )
768 {
769 classPathElements.set( classPathElements.indexOf( jm
770 .getBundleFileName() ), jm.getUri() );
771 }
772 else
773 {
774 classPathElements.add( jm.getUri() );
775 }
776 }
777 }
778 classPath.setValue( StringUtils.join( classPathElements.iterator(), " " ) );
779
780
781 PrintWriter pw = new PrintWriter( manifestFile );
782 mf.write( pw );
783 pw.close();
784
785 if ( original.isFile() )
786 {
787
788 if ( !original.delete() )
789 {
790 getLog().error( "Could not delete original artifact file " + original );
791 }
792
793 getLog().debug( "Zipping module" );
794 zipArchiver.setDestFile( original );
795 zipArchiver.addDirectory( workDirectory );
796 zipArchiver.createArchive();
797 }
798 }
799 catch ( ManifestException e )
800 {
801 throw new MojoFailureException( e.getMessage() );
802 }
803 catch ( ZipException e )
804 {
805 throw new MojoFailureException( e.getMessage() );
806 }
807 catch ( IOException e )
808 {
809 throw new MojoFailureException( e.getMessage() );
810 }
811 catch ( ArchiverException e )
812 {
813 throw new MojoFailureException( e.getMessage() );
814 }
815 }
816 }