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