1 package org.apache.tomcat.maven.plugin.tomcat7.run;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import org.apache.catalina.Context;
22 import org.apache.catalina.Host;
23 import org.apache.catalina.LifecycleException;
24 import org.apache.catalina.Wrapper;
25 import org.apache.catalina.connector.Connector;
26 import org.apache.catalina.core.StandardContext;
27 import org.apache.catalina.loader.WebappLoader;
28 import org.apache.catalina.realm.MemoryRealm;
29 import org.apache.catalina.servlets.DefaultServlet;
30 import org.apache.catalina.startup.Catalina;
31 import org.apache.catalina.startup.CatalinaProperties;
32 import org.apache.catalina.startup.Tomcat;
33 import org.apache.catalina.valves.AccessLogValve;
34 import org.apache.commons.io.IOUtils;
35 import org.apache.commons.lang.StringUtils;
36 import org.apache.maven.artifact.Artifact;
37 import org.apache.maven.artifact.factory.ArtifactFactory;
38 import org.apache.maven.artifact.repository.ArtifactRepository;
39 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
40 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
41 import org.apache.maven.artifact.resolver.ArtifactResolver;
42 import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
43 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
44 import org.apache.maven.artifact.versioning.VersionRange;
45 import org.apache.maven.execution.MavenSession;
46 import org.apache.maven.plugin.MojoExecutionException;
47 import org.apache.maven.plugin.MojoFailureException;
48 import org.apache.maven.plugins.annotations.Component;
49 import org.apache.maven.plugins.annotations.Parameter;
50 import org.apache.maven.project.MavenProject;
51 import org.apache.maven.shared.filtering.MavenFileFilter;
52 import org.apache.maven.shared.filtering.MavenFileFilterRequest;
53 import org.apache.maven.shared.filtering.MavenFilteringException;
54 import org.apache.naming.NamingEntry;
55 import org.apache.naming.resources.FileDirContext;
56 import org.apache.tomcat.maven.common.config.AbstractWebapp;
57 import org.apache.tomcat.maven.common.run.EmbeddedRegistry;
58 import org.apache.tomcat.maven.common.run.ExternalRepositoriesReloadableWebappLoader;
59 import org.apache.tomcat.maven.plugin.tomcat7.AbstractTomcat7Mojo;
60 import org.codehaus.plexus.archiver.ArchiverException;
61 import org.codehaus.plexus.archiver.UnArchiver;
62 import org.codehaus.plexus.archiver.manager.ArchiverManager;
63 import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
64 import org.codehaus.plexus.classworlds.ClassWorld;
65 import org.codehaus.plexus.classworlds.realm.ClassRealm;
66 import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
67 import org.codehaus.plexus.util.DirectoryScanner;
68 import org.codehaus.plexus.util.FileUtils;
69 import org.w3c.dom.Document;
70 import org.w3c.dom.NamedNodeMap;
71 import org.w3c.dom.Node;
72 import org.xml.sax.SAXException;
73
74 import javax.naming.NamingException;
75 import javax.servlet.ServletException;
76 import javax.xml.parsers.DocumentBuilder;
77 import javax.xml.parsers.DocumentBuilderFactory;
78 import javax.xml.parsers.ParserConfigurationException;
79 import javax.xml.stream.XMLInputFactory;
80 import javax.xml.stream.XMLStreamConstants;
81 import javax.xml.stream.XMLStreamException;
82 import javax.xml.stream.XMLStreamReader;
83 import java.io.File;
84 import java.io.FileInputStream;
85 import java.io.FileNotFoundException;
86 import java.io.FileOutputStream;
87 import java.io.IOException;
88 import java.net.MalformedURLException;
89 import java.net.URL;
90 import java.util.ArrayList;
91 import java.util.Collection;
92 import java.util.Collections;
93 import java.util.Iterator;
94 import java.util.List;
95 import java.util.Map;
96 import java.util.Properties;
97 import java.util.Set;
98
99
100
101
102
103 public abstract class AbstractRunMojo
104 extends AbstractTomcat7Mojo
105 {
106
107
108
109
110
111
112
113 @Component
114 protected ArtifactFactory factory;
115
116
117
118
119 @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
120 private ArtifactRepository local;
121
122
123
124
125 @Component
126 protected ArtifactResolver resolver;
127
128
129
130
131
132
133
134
135 @Parameter( defaultValue = "${project.packaging}", required = true, readonly = true )
136 private String packaging;
137
138
139
140
141 @Parameter( defaultValue = "${project.build.directory}/tomcat" )
142 private File configurationDir;
143
144
145
146
147
148 @Parameter( property = "maven.tomcat.port", defaultValue = "8080" )
149 private int port;
150
151
152
153
154
155
156
157
158
159 @Parameter( property = "maven.tomcat.ajp.port", defaultValue = "0" )
160 private int ajpPort;
161
162
163
164
165
166
167
168
169
170
171
172
173
174 @Parameter( property = "maven.tomcat.ajp.protocol", defaultValue = "org.apache.coyote.ajp.AjpProtocol" )
175 private String ajpProtocol;
176
177
178
179
180
181
182
183
184
185 @Parameter( property = "maven.tomcat.httpsPort", defaultValue = "0" )
186 private int httpsPort;
187
188
189
190
191
192
193 @Parameter( property = "maven.tomcat.uriEncoding", defaultValue = "ISO-8859-1" )
194 private String uriEncoding;
195
196
197
198
199
200
201 @Parameter
202 private Map<String, String> systemProperties;
203
204
205
206
207
208
209 @Parameter( property = "maven.tomcat.additionalConfigFilesDir", defaultValue = "${basedir}/src/main/tomcatconf" )
210 private File additionalConfigFilesDir;
211
212
213
214
215
216
217 @Parameter( property = "maven.tomcat.serverXml" )
218 private File serverXml;
219
220
221
222
223
224
225
226 @Parameter( property = "maven.tomcat.webXml" )
227 private File tomcatWebXml;
228
229
230
231
232
233
234
235 @Parameter( property = "maven.tomcat.fork", defaultValue = "false" )
236 private boolean fork;
237
238
239
240
241
242
243
244
245
246
247
248
249
250 @Parameter( property = "maven.tomcat.addContextWarDependencies", defaultValue = "false" )
251 private boolean addContextWarDependencies;
252
253
254
255
256
257
258 @Component
259 protected MavenProject project;
260
261
262
263
264
265
266 @Component
267 private ArchiverManager archiverManager;
268
269
270
271
272
273
274 @Parameter( property = "tomcat.useSeparateTomcatClassLoader", defaultValue = "false" )
275 protected boolean useSeparateTomcatClassLoader;
276
277
278
279
280 @Parameter( defaultValue = "${plugin.artifacts}", required = true )
281 private List<Artifact> pluginArtifacts;
282
283
284
285
286
287
288 @Parameter( property = "tomcat.ignorePackaging", defaultValue = "false" )
289 private boolean ignorePackaging;
290
291
292
293
294
295
296 @Parameter
297 private String keystoreFile;
298
299
300
301
302
303
304 @Parameter
305 private String keystorePass;
306
307
308
309
310
311
312 @Parameter( defaultValue = "JKS" )
313 private String keystoreType;
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328 @Parameter( property = "maven.tomcat.useNaming", defaultValue = "true" )
329 private boolean useNaming;
330
331
332
333
334
335
336
337
338 @Parameter( property = "maven.tomcat.contextReloadable", defaultValue = "false" )
339 protected boolean contextReloadable;
340
341
342
343
344
345
346 @Parameter( property = "maven.tomcat.backgroundProcessorDelay", defaultValue = "-1" )
347 protected int backgroundProcessorDelay = -1;
348
349
350
351
352
353
354
355 @Parameter( property = "maven.tomcat.contextFile" )
356 protected File contextFile;
357
358
359
360
361
362
363
364 @Parameter( defaultValue = "${project.build.directory}/${project.build.finalName}/META-INF/context.xml",
365 readonly = true )
366 private File defaultContextFile;
367
368
369
370
371
372
373
374 @Parameter( property = "maven.tomcat.protocol", defaultValue = "HTTP/1.1" )
375 private String protocol;
376
377
378
379
380
381
382 @Parameter( property = "maven.tomcat.tomcatUsers.file" )
383 private File tomcatUsers;
384
385
386
387
388
389
390 @Parameter( property = "maven.tomcat.tomcatLogging.file" )
391 private File tomcatLoggingFile;
392
393
394
395
396
397
398 @Parameter( property = "maven.tomcat.skip", defaultValue = "false" )
399 protected boolean skip;
400
401
402
403
404
405 @Parameter
406 private List<Webapp> webapps;
407
408
409
410
411
412
413 @Parameter( property = "maven.tomcat.staticContextPath", defaultValue = "/" )
414 private String staticContextPath;
415
416
417
418
419
420
421
422 @Parameter( property = "maven.tomcat.staticContextDocbase" )
423 private String staticContextDocbase;
424
425
426
427
428
429
430 @Parameter
431 protected String classLoaderClass;
432
433 @Parameter( defaultValue = "${session}", readonly = true, required = true )
434 protected MavenSession session;
435
436
437
438
439
440 @Parameter( property = "maven.tomcat.propertiesPortFilePath" )
441 protected String propertiesPortFilePath;
442
443
444
445
446
447
448 @Parameter( property = "maven.tomcat.hostName", defaultValue = "localhost" )
449 protected String hostName;
450
451
452
453
454
455
456
457 @Parameter
458 protected String[] aliases;
459
460
461
462
463
464
465
466 @Parameter( property = "maven.tomcat.https.clientAuth", defaultValue = "false" )
467 protected String clientAuth = "false";
468
469 @Component( role = MavenFileFilter.class, hint = "default" )
470 protected MavenFileFilter mavenFileFilter;
471
472
473
474
475
476
477
478
479 private ClassRealm tomcatRealm;
480
481
482
483
484
485
486
487
488 public void execute()
489 throws MojoExecutionException, MojoFailureException
490 {
491 if ( skip )
492 {
493 getLog().info( "skip execution" );
494 return;
495 }
496
497 if ( !isWar() && !addContextWarDependencies && getAdditionalWebapps().isEmpty() )
498 {
499 getLog().info( messagesProvider.getMessage( "AbstractRunMojo.nonWar" ) );
500 return;
501 }
502 ClassLoader originalClassLoader = null;
503 if ( useSeparateTomcatClassLoader )
504 {
505 originalClassLoader = Thread.currentThread().getContextClassLoader();
506 }
507 try
508 {
509 getLog().info( messagesProvider.getMessage( "AbstractRunMojo.runningWar", getWebappUrl() ) );
510
511 initConfiguration();
512 startContainer();
513 if ( !fork )
514 {
515 waitIndefinitely();
516 }
517 }
518 catch ( LifecycleException exception )
519 {
520 throw new MojoExecutionException( messagesProvider.getMessage( "AbstractRunMojo.cannotStart" ), exception );
521 }
522 catch ( IOException exception )
523 {
524 throw new MojoExecutionException(
525 messagesProvider.getMessage( "AbstractRunMojo.cannotCreateConfiguration" ), exception );
526 }
527 catch ( ServletException e )
528 {
529 throw new MojoExecutionException( e.getMessage(), e );
530 }
531 catch ( MavenFilteringException e )
532 {
533 throw new MojoExecutionException( "filtering issue: " + e.getMessage(), e );
534 }
535 finally
536 {
537 if ( useSeparateTomcatClassLoader )
538 {
539 Thread.currentThread().setContextClassLoader( originalClassLoader );
540 }
541 }
542 }
543
544
545
546
547
548
549
550
551
552
553 protected String getPath()
554 {
555 return path;
556 }
557
558
559
560
561
562
563
564
565
566 protected Context createContext( Tomcat container )
567 throws IOException, MojoExecutionException, ServletException
568 {
569 String contextPath = getPath();
570
571 String baseDir = getDocBase().getAbsolutePath();
572
573 File overriddenContextFile = getContextFile();
574
575 StandardContext standardContext = null;
576
577 if ( overriddenContextFile != null && overriddenContextFile.exists() )
578 {
579 standardContext = parseContextFile( overriddenContextFile );
580 }
581 else if ( defaultContextFile.exists() )
582 {
583 standardContext = parseContextFile( defaultContextFile );
584 }
585
586 if ( standardContext != null )
587 {
588 if ( standardContext.getPath() != null )
589 {
590 contextPath = standardContext.getPath();
591 }
592 if ( standardContext.getDocBase() != null )
593 {
594 baseDir = standardContext.getDocBase();
595 }
596 }
597
598 contextPath = "/".equals( contextPath ) ? "" : contextPath;
599
600 getLog().info( "create webapp with contextPath: " + contextPath );
601
602 Context context = container.addWebapp( contextPath, baseDir );
603
604 context.setResources(
605 new MyDirContext( new File( project.getBuild().getOutputDirectory() ).getAbsolutePath() ) );
606
607 if ( useSeparateTomcatClassLoader )
608 {
609 context.setParentClassLoader( getTomcatClassLoader() );
610 }
611
612 final WebappLoader loader = createWebappLoader();
613
614 context.setLoader( loader );
615
616 if ( overriddenContextFile != null )
617 {
618
619 context.setConfigFile( overriddenContextFile.toURI().toURL() );
620 }
621 else if ( defaultContextFile.exists() )
622 {
623
624
625 context.setConfigFile( defaultContextFile.toURI().toURL() );
626 }
627
628 if ( classLoaderClass != null )
629 {
630 loader.setLoaderClass( classLoaderClass );
631 }
632
633 return context;
634
635 }
636
637 protected StandardContext parseContextFile( File file )
638 throws MojoExecutionException
639 {
640 try
641 {
642 StandardContext standardContext = new StandardContext();
643 XMLStreamReader reader = XMLInputFactory.newFactory().createXMLStreamReader( new FileInputStream( file ) );
644
645 int tag = reader.next();
646
647 while ( true )
648 {
649 if ( tag == XMLStreamConstants.START_ELEMENT && StringUtils.equals( "Context", reader.getLocalName() ) )
650 {
651 String path = reader.getAttributeValue( null, "path" );
652 if ( StringUtils.isNotBlank( path ) )
653 {
654 standardContext.setPath( path );
655 }
656
657 String docBase = reader.getAttributeValue( null, "docBase" );
658 if ( StringUtils.isNotBlank( docBase ) )
659 {
660 standardContext.setDocBase( docBase );
661 }
662 }
663 if ( !reader.hasNext() )
664 {
665 break;
666 }
667 tag = reader.next();
668 }
669
670 return standardContext;
671 }
672 catch ( XMLStreamException e )
673 {
674 throw new MojoExecutionException( e.getMessage(), e );
675 }
676 catch ( FileNotFoundException e )
677 {
678 throw new MojoExecutionException( e.getMessage(), e );
679 }
680 }
681
682
683 private static class MyDirContext
684 extends FileDirContext
685 {
686 String buildOutputDirectory;
687
688 MyDirContext( String buildOutputDirectory )
689 {
690 this.buildOutputDirectory = buildOutputDirectory;
691 }
692
693 @Override
694 protected List<NamingEntry> doListBindings( String name )
695 throws NamingException
696 {
697 if ( "/WEB-INF/classes".equals( name ) )
698 {
699 if ( !new File( buildOutputDirectory ).exists() )
700 {
701 return Collections.emptyList();
702 }
703 FileDirContext fileDirContext = new FileDirContext();
704 fileDirContext.setDocBase( buildOutputDirectory );
705 NamingEntry namingEntry = new NamingEntry( "/WEB-INF/classes", fileDirContext, -1 );
706 return Collections.singletonList( namingEntry );
707 }
708
709 return super.doListBindings( name );
710 }
711 }
712
713
714
715
716
717
718
719
720 protected WebappLoader createWebappLoader()
721 throws IOException, MojoExecutionException
722 {
723 if ( useSeparateTomcatClassLoader )
724 {
725 return ( isContextReloadable() )
726 ? new ExternalRepositoriesReloadableWebappLoader( getTomcatClassLoader(), getLog() )
727 : new WebappLoader( getTomcatClassLoader() );
728 }
729
730 return ( isContextReloadable() )
731 ? new ExternalRepositoriesReloadableWebappLoader( Thread.currentThread().getContextClassLoader(), getLog() )
732 : new WebappLoader( Thread.currentThread().getContextClassLoader() );
733 }
734
735
736
737
738
739
740 protected boolean isContextReloadable()
741 throws MojoExecutionException
742 {
743 if ( contextReloadable || backgroundProcessorDelay > 0 )
744 {
745 return true;
746 }
747
748 boolean reloadable = false;
749 try
750 {
751 if ( contextFile != null && contextFile.exists() )
752 {
753 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
754 DocumentBuilder builder = builderFactory.newDocumentBuilder();
755 Document contextDoc = builder.parse( contextFile );
756 contextDoc.getDocumentElement().normalize();
757
758 NamedNodeMap nodeMap = contextDoc.getDocumentElement().getAttributes();
759 Node reloadableAttribute = nodeMap.getNamedItem( "reloadable" );
760
761 reloadable =
762 ( reloadableAttribute != null ) ? Boolean.valueOf( reloadableAttribute.getNodeValue() ) : false;
763 }
764 getLog().debug( "context reloadable: " + reloadable );
765 }
766 catch ( IOException ioe )
767 {
768 getLog().error( "Could not parse file: [" + contextFile.getAbsolutePath() + "]", ioe );
769 }
770 catch ( ParserConfigurationException pce )
771 {
772 getLog().error( "Could not configure XML parser", pce );
773 }
774 catch ( SAXException se )
775 {
776 getLog().error( "Could not parse file: [" + contextFile.getAbsolutePath() + "]", se );
777 }
778
779 return reloadable;
780 }
781
782
783
784
785
786
787
788 protected abstract File getDocBase();
789
790
791
792
793
794
795 protected abstract File getContextFile()
796 throws MojoExecutionException;
797
798
799
800
801
802
803
804
805
806
807 protected boolean isWar()
808 {
809 return "war".equals( packaging ) || ignorePackaging;
810 }
811
812
813
814
815
816
817
818 private URL getWebappUrl()
819 throws MalformedURLException
820 {
821 return new URL( "http", "localhost", port, getPath() );
822 }
823
824
825
826
827
828
829
830
831 private void initConfiguration()
832 throws IOException, MojoExecutionException, MavenFilteringException
833 {
834 if ( configurationDir.exists() )
835 {
836 getLog().info( messagesProvider.getMessage( "AbstractRunMojo.usingConfiguration", configurationDir ) );
837 }
838 else
839 {
840 getLog().info( messagesProvider.getMessage( "AbstractRunMojo.creatingConfiguration", configurationDir ) );
841
842 configurationDir.mkdirs();
843
844 File confDir = new File( configurationDir, "conf" );
845 confDir.mkdir();
846
847 if ( tomcatLoggingFile != null )
848 {
849 FileUtils.copyFile( tomcatLoggingFile, new File( confDir, "logging.properties" ) );
850 }
851 else
852 {
853 copyFile( "/conf/logging.properties", new File( confDir, "logging.properties" ) );
854 }
855
856 copyFile( "/conf/tomcat-users.xml", new File( confDir, "tomcat-users.xml" ) );
857 if ( tomcatWebXml != null )
858 {
859 if ( !tomcatWebXml.exists() )
860 {
861 throw new MojoExecutionException( " tomcatWebXml " + tomcatWebXml.getPath() + " not exists" );
862 }
863
864
865 MavenFileFilterRequest mavenFileFilterRequest = new MavenFileFilterRequest();
866 mavenFileFilterRequest.setFrom( tomcatWebXml );
867 mavenFileFilterRequest.setTo( new File( confDir, "web.xml" ) );
868 mavenFileFilterRequest.setMavenProject( project );
869 mavenFileFilterRequest.setMavenSession( session );
870 mavenFileFilterRequest.setFiltering( true );
871
872 mavenFileFilter.copyFile( mavenFileFilterRequest );
873
874 }
875 else
876 {
877 copyFile( "/conf/web.xml", new File( confDir, "web.xml" ) );
878 }
879
880 File logDir = new File( configurationDir, "logs" );
881 logDir.mkdir();
882
883 File webappsDir = new File( configurationDir, "webapps" );
884 webappsDir.mkdir();
885
886 if ( additionalConfigFilesDir != null && additionalConfigFilesDir.exists() )
887 {
888 DirectoryScanner scanner = new DirectoryScanner();
889 scanner.addDefaultExcludes();
890 scanner.setBasedir( additionalConfigFilesDir.getPath() );
891 scanner.scan();
892
893 String[] files = scanner.getIncludedFiles();
894
895 if ( files != null && files.length > 0 )
896 {
897 getLog().info( "Coping additional tomcat config files" );
898
899 for ( int i = 0; i < files.length; i++ )
900 {
901 File file = new File( additionalConfigFilesDir, files[i] );
902
903 getLog().info( " copy " + file.getName() );
904
905 FileUtils.copyFileToDirectory( file, confDir );
906 }
907 }
908 }
909 }
910 }
911
912
913
914
915
916
917
918
919 private void copyFile( String fromPath, File toFile )
920 throws IOException
921 {
922 URL fromURL = getClass().getResource( fromPath );
923
924 if ( fromURL == null )
925 {
926 throw new FileNotFoundException( fromPath );
927 }
928
929 FileUtils.copyURLToFile( fromURL, toFile );
930 }
931
932
933
934
935
936
937
938
939 private void startContainer()
940 throws IOException, LifecycleException, MojoExecutionException, ServletException
941 {
942 String previousCatalinaBase = System.getProperty( "catalina.base" );
943
944 try
945 {
946
947
948 setupSystemProperties();
949
950 System.setProperty( "catalina.base", configurationDir.getAbsolutePath() );
951
952 if ( serverXml != null )
953 {
954 if ( !serverXml.exists() )
955 {
956 throw new MojoExecutionException( serverXml.getPath() + " not exists" );
957 }
958
959 Catalina container = new Catalina();
960
961 if ( useSeparateTomcatClassLoader )
962 {
963 Thread.currentThread().setContextClassLoader( getTomcatClassLoader() );
964 container.setParentClassLoader( getTomcatClassLoader() );
965 }
966
967 container.setUseNaming( this.useNaming );
968 container.setConfig( serverXml.getAbsolutePath() );
969 container.start();
970 EmbeddedRegistry.getInstance().register( container );
971 }
972 else
973 {
974
975 System.setProperty( "java.util.logging.manager", "org.apache.juli.ClassLoaderLogManager" );
976 System.setProperty( "java.util.logging.config.file",
977 new File( configurationDir, "conf/logging.properties" ).toString() );
978
979
980 CatalinaProperties.getProperty( "foo" );
981
982 Tomcat embeddedTomcat = new ExtendedTomcat( configurationDir );
983
984 embeddedTomcat.setBaseDir( configurationDir.getAbsolutePath() );
985 MemoryRealm memoryRealm = new MemoryRealm();
986
987 if ( tomcatUsers != null )
988 {
989 if ( !tomcatUsers.exists() )
990 {
991 throw new MojoExecutionException( " tomcatUsers " + tomcatUsers.getPath() + " not exists" );
992 }
993 getLog().info( "use tomcat-users.xml from " + tomcatUsers.getAbsolutePath() );
994 memoryRealm.setPathname( tomcatUsers.getAbsolutePath() );
995 }
996
997 embeddedTomcat.setDefaultRealm( memoryRealm );
998
999 Context ctx = createContext( embeddedTomcat );
1000
1001 if ( useNaming )
1002 {
1003 embeddedTomcat.enableNaming();
1004 }
1005
1006 embeddedTomcat.getHost().setAppBase( new File( configurationDir, "webapps" ).getAbsolutePath() );
1007
1008 if ( hostName != null )
1009 {
1010 embeddedTomcat.getHost().setName( hostName );
1011 }
1012 if ( aliases != null )
1013 {
1014 for ( String alias : aliases )
1015 {
1016 embeddedTomcat.getHost().addAlias( alias );
1017 }
1018
1019 }
1020 createStaticContext( embeddedTomcat, ctx, embeddedTomcat.getHost() );
1021
1022 Connector connector = new Connector( protocol );
1023 connector.setPort( port );
1024
1025 if ( httpsPort > 0 )
1026 {
1027 connector.setRedirectPort( httpsPort );
1028 }
1029
1030 connector.setURIEncoding( uriEncoding );
1031
1032 embeddedTomcat.getService().addConnector( connector );
1033
1034 embeddedTomcat.setConnector( connector );
1035
1036 AccessLogValve alv = new AccessLogValve();
1037 alv.setDirectory( new File( configurationDir, "logs" ).getAbsolutePath() );
1038 alv.setPattern( "%h %l %u %t \"%r\" %s %b %I %D" );
1039 embeddedTomcat.getHost().getPipeline().addValve( alv );
1040
1041
1042 Connector httpsConnector = null;
1043 if ( httpsPort > 0 )
1044 {
1045 httpsConnector = new Connector( protocol );
1046 httpsConnector.setPort( httpsPort );
1047 httpsConnector.setSecure( true );
1048 httpsConnector.setProperty( "SSLEnabled", "true" );
1049
1050 httpsConnector.setProperty( "sslProtocol", "TLS" );
1051 if ( keystoreFile != null )
1052 {
1053 httpsConnector.setAttribute( "keystoreFile", keystoreFile );
1054 }
1055 if ( keystorePass != null )
1056 {
1057 httpsConnector.setAttribute( "keystorePass", keystorePass );
1058 }
1059 if ( keystoreType != null )
1060 {
1061 httpsConnector.setAttribute( "keystoreType", keystoreType );
1062 }
1063
1064 httpsConnector.setAttribute( "clientAuth", clientAuth );
1065
1066 embeddedTomcat.getEngine().getService().addConnector( httpsConnector );
1067
1068 }
1069
1070
1071 Connector ajpConnector = null;
1072 if ( ajpPort > 0 )
1073 {
1074 ajpConnector = new Connector( ajpProtocol );
1075 ajpConnector.setPort( ajpPort );
1076 ajpConnector.setURIEncoding( uriEncoding );
1077 embeddedTomcat.getEngine().getService().addConnector( ajpConnector );
1078 }
1079
1080 if ( addContextWarDependencies || !getAdditionalWebapps().isEmpty() )
1081 {
1082 createDependencyContexts( embeddedTomcat );
1083 }
1084
1085 if ( useSeparateTomcatClassLoader )
1086 {
1087 Thread.currentThread().setContextClassLoader( getTomcatClassLoader() );
1088 embeddedTomcat.getEngine().setParentClassLoader( getTomcatClassLoader() );
1089 }
1090
1091 embeddedTomcat.start();
1092
1093 Properties portProperties = new Properties();
1094
1095 portProperties.put( "tomcat.maven.http.port", Integer.toString( connector.getLocalPort() ) );
1096
1097 session.getExecutionProperties().put( "tomcat.maven.http.port",
1098 Integer.toString( connector.getLocalPort() ) );
1099 System.setProperty( "tomcat.maven.http.port", Integer.toString( connector.getLocalPort() ) );
1100
1101 if ( httpsConnector != null )
1102 {
1103 session.getExecutionProperties().put( "tomcat.maven.https.port",
1104 Integer.toString( httpsConnector.getLocalPort() ) );
1105 portProperties.put( "tomcat.maven.https.port", Integer.toString( httpsConnector.getLocalPort() ) );
1106 System.setProperty( "tomcat.maven.https.port", Integer.toString( httpsConnector.getLocalPort() ) );
1107 }
1108
1109 if ( ajpConnector != null )
1110 {
1111 session.getExecutionProperties().put( "tomcat.maven.ajp.port",
1112 Integer.toString( ajpConnector.getLocalPort() ) );
1113 portProperties.put( "tomcat.maven.ajp.port", Integer.toString( ajpConnector.getLocalPort() ) );
1114 System.setProperty( "tomcat.maven.ajp.port", Integer.toString( ajpConnector.getLocalPort() ) );
1115 }
1116 if ( propertiesPortFilePath != null )
1117 {
1118 File propertiesPortsFile = new File( propertiesPortFilePath );
1119 if ( propertiesPortsFile.exists() )
1120 {
1121 propertiesPortsFile.delete();
1122 }
1123 FileOutputStream fileOutputStream = new FileOutputStream( propertiesPortsFile );
1124 try
1125 {
1126 portProperties.store( fileOutputStream, "Apache Tomcat Maven plugin port used" );
1127 }
1128 finally
1129 {
1130 IOUtils.closeQuietly( fileOutputStream );
1131 }
1132 }
1133
1134 EmbeddedRegistry.getInstance().register( embeddedTomcat );
1135
1136 }
1137
1138
1139 }
1140 finally
1141 {
1142 if ( previousCatalinaBase != null )
1143 {
1144 System.setProperty( "catalina.base", previousCatalinaBase );
1145 }
1146 }
1147 }
1148
1149 private List<Webapp> getAdditionalWebapps()
1150 {
1151 if ( webapps == null )
1152 {
1153 return Collections.emptyList();
1154 }
1155 return webapps;
1156 }
1157
1158 protected ClassRealm getTomcatClassLoader()
1159 throws MojoExecutionException
1160 {
1161 if ( this.tomcatRealm != null )
1162 {
1163 return tomcatRealm;
1164 }
1165 try
1166 {
1167 ClassWorld world = new ClassWorld();
1168 ClassRealm root = world.newRealm( "tomcat", Thread.currentThread().getContextClassLoader() );
1169
1170 for ( @SuppressWarnings( "rawtypes" ) Iterator i = pluginArtifacts.iterator(); i.hasNext(); )
1171 {
1172 Artifact pluginArtifact = (Artifact) i.next();
1173
1174 if ( pluginArtifact.getFile() != null )
1175 {
1176 root.addURL( pluginArtifact.getFile().toURI().toURL() );
1177 }
1178
1179 }
1180 tomcatRealm = root;
1181 return root;
1182 }
1183 catch ( DuplicateRealmException e )
1184 {
1185 throw new MojoExecutionException( e.getMessage(), e );
1186 }
1187 catch ( MalformedURLException e )
1188 {
1189 throw new MojoExecutionException( e.getMessage(), e );
1190 }
1191 }
1192
1193 @SuppressWarnings( "unchecked" )
1194 public Set<Artifact> getProjectArtifacts()
1195 {
1196 return project.getArtifacts();
1197 }
1198
1199
1200
1201
1202 private void waitIndefinitely()
1203 {
1204 Object lock = new Object();
1205
1206 synchronized ( lock )
1207 {
1208 try
1209 {
1210 lock.wait();
1211 }
1212 catch ( InterruptedException exception )
1213 {
1214 getLog().warn( messagesProvider.getMessage( "AbstractRunMojo.interrupted" ), exception );
1215 }
1216 }
1217 }
1218
1219
1220
1221
1222
1223 private void setupSystemProperties()
1224 {
1225 if ( systemProperties != null && !systemProperties.isEmpty() )
1226 {
1227 getLog().info( "setting SystemProperties:" );
1228
1229 for ( String key : systemProperties.keySet() )
1230 {
1231 String value = systemProperties.get( key );
1232
1233 if ( value != null )
1234 {
1235 getLog().info( " " + key + "=" + value );
1236 System.setProperty( key, value );
1237 }
1238 else
1239 {
1240 getLog().info( "skip sysProps " + key + " with empty value" );
1241 }
1242 }
1243 }
1244 }
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254 private Collection<Context> createDependencyContexts( Tomcat container )
1255 throws MojoExecutionException, MalformedURLException, ServletException, IOException
1256 {
1257 getLog().info( "Deploying dependency wars" );
1258
1259 List<Context> contexts = new ArrayList<Context>();
1260
1261 ScopeArtifactFilter filter = new ScopeArtifactFilter( "tomcat" );
1262 @SuppressWarnings( "unchecked" ) Set<Artifact> artifacts = project.getArtifacts();
1263 for ( Artifact artifact : artifacts )
1264 {
1265
1266
1267
1268 if ( "war".equals( artifact.getType() ) && !artifact.isOptional() && filter.include( artifact ) )
1269 {
1270 addContextFromArtifact( container, contexts, artifact, "/" + artifact.getArtifactId(), null, false );
1271 }
1272 }
1273
1274 for ( AbstractWebapp additionalWebapp : getAdditionalWebapps() )
1275 {
1276 String contextPath = additionalWebapp.getContextPath();
1277 if ( !contextPath.startsWith( "/" ) )
1278 {
1279 contextPath = "/" + contextPath;
1280 }
1281 addContextFromArtifact( container, contexts, getArtifact( additionalWebapp ), contextPath,
1282 additionalWebapp.getContextFile(), additionalWebapp.isAsWebapp() );
1283 }
1284 return contexts;
1285 }
1286
1287
1288 private void addContextFromArtifact( Tomcat container, List<Context> contexts, Artifact artifact,
1289 String contextPath, File contextXml, boolean asWebApp )
1290 throws MojoExecutionException, MalformedURLException, ServletException, IOException
1291 {
1292 getLog().info( "Deploy warfile: " + String.valueOf( artifact.getFile() ) + " to contextPath: " + contextPath );
1293 File webapps = new File( configurationDir, "webapps" );
1294 File artifactWarDir = new File( webapps, artifact.getArtifactId() );
1295 if ( !artifactWarDir.exists() )
1296 {
1297
1298 artifactWarDir.mkdir();
1299 try
1300 {
1301 UnArchiver unArchiver = archiverManager.getUnArchiver( "zip" );
1302 unArchiver.setSourceFile( artifact.getFile() );
1303 unArchiver.setDestDirectory( artifactWarDir );
1304
1305
1306 unArchiver.extract();
1307 }
1308 catch ( NoSuchArchiverException e )
1309 {
1310 getLog().error( e );
1311 return;
1312 }
1313 catch ( ArchiverException e )
1314 {
1315 getLog().error( e );
1316 return;
1317 }
1318 }
1319
1320
1321 WebappLoader webappLoader = createWebappLoader();
1322 Context context = null;
1323 if ( asWebApp )
1324 {
1325 context = container.addWebapp( contextPath, artifactWarDir.getAbsolutePath() );
1326 }
1327 else
1328 {
1329 context = container.addContext( contextPath, artifactWarDir.getAbsolutePath() );
1330 }
1331 context.setLoader( webappLoader );
1332
1333 File contextFile = contextXml != null ? contextXml : getContextFile();
1334 if ( contextFile != null )
1335 {
1336 context.setConfigFile( contextFile.toURI().toURL() );
1337 }
1338
1339 contexts.add( context );
1340
1341 }
1342
1343 private void createStaticContext( final Tomcat container, Context context, Host host )
1344 {
1345 if ( staticContextDocbase != null )
1346 {
1347 Context staticContext = container.addContext( staticContextPath, staticContextDocbase );
1348 staticContext.setPrivileged( true );
1349 Wrapper servlet = context.createWrapper();
1350 servlet.setServletClass( DefaultServlet.class.getName() );
1351 servlet.setName( "staticContent" );
1352 staticContext.addChild( servlet );
1353 staticContext.addServletMapping( "/", "staticContent" );
1354 host.addChild( staticContext );
1355 }
1356 }
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367 protected Artifact getArtifact( AbstractWebapp additionalWebapp )
1368 throws MojoExecutionException
1369 {
1370
1371 Artifact artifact;
1372 VersionRange vr;
1373 try
1374 {
1375 vr = VersionRange.createFromVersionSpec( additionalWebapp.getVersion() );
1376 }
1377 catch ( InvalidVersionSpecificationException e )
1378 {
1379 getLog().warn( "fail to create versionRange from version: " + additionalWebapp.getVersion(), e );
1380 vr = VersionRange.createFromVersion( additionalWebapp.getVersion() );
1381 }
1382
1383 if ( StringUtils.isEmpty( additionalWebapp.getClassifier() ) )
1384 {
1385 artifact =
1386 factory.createDependencyArtifact( additionalWebapp.getGroupId(), additionalWebapp.getArtifactId(), vr,
1387 additionalWebapp.getType(), null, Artifact.SCOPE_COMPILE );
1388 }
1389 else
1390 {
1391 artifact =
1392 factory.createDependencyArtifact( additionalWebapp.getGroupId(), additionalWebapp.getArtifactId(), vr,
1393 additionalWebapp.getType(), additionalWebapp.getClassifier(),
1394 Artifact.SCOPE_COMPILE );
1395 }
1396
1397 try
1398 {
1399 resolver.resolve( artifact, project.getRemoteArtifactRepositories(), this.local );
1400 }
1401 catch ( ArtifactResolutionException e )
1402 {
1403 throw new MojoExecutionException( "Unable to resolve artifact.", e );
1404 }
1405 catch ( ArtifactNotFoundException e )
1406 {
1407 throw new MojoExecutionException( "Unable to find artifact.", e );
1408 }
1409
1410 return artifact;
1411 }
1412 }