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