View Javadoc

1   package org.apache.tomcat.maven.plugin.tomcat7.run;
2   /*
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   */
20  
21  import org.apache.catalina.Context;
22  import org.apache.catalina.LifecycleException;
23  import org.apache.catalina.connector.Connector;
24  import org.apache.catalina.loader.WebappLoader;
25  import org.apache.catalina.realm.MemoryRealm;
26  import org.apache.catalina.startup.Catalina;
27  import org.apache.catalina.startup.CatalinaProperties;
28  import org.apache.catalina.startup.Tomcat;
29  import org.apache.catalina.valves.AccessLogValve;
30  import org.apache.maven.artifact.Artifact;
31  import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
32  import org.apache.maven.plugin.MojoExecutionException;
33  import org.apache.maven.plugin.MojoFailureException;
34  import org.apache.maven.project.MavenProject;
35  import org.apache.tomcat.maven.common.run.EmbeddedRegistry;
36  import org.apache.tomcat.maven.common.run.ExternalRepositoriesReloadableWebappLoader;
37  import org.apache.tomcat.maven.plugin.tomcat7.AbstractTomcat7Mojo;
38  import org.codehaus.plexus.archiver.ArchiverException;
39  import org.codehaus.plexus.archiver.UnArchiver;
40  import org.codehaus.plexus.archiver.manager.ArchiverManager;
41  import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
42  import org.codehaus.plexus.classworlds.ClassWorld;
43  import org.codehaus.plexus.classworlds.realm.ClassRealm;
44  import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
45  import org.codehaus.plexus.util.DirectoryScanner;
46  import org.codehaus.plexus.util.FileUtils;
47  import org.w3c.dom.Document;
48  import org.w3c.dom.NamedNodeMap;
49  import org.w3c.dom.Node;
50  import org.xml.sax.SAXException;
51  
52  import javax.servlet.ServletException;
53  import javax.xml.parsers.DocumentBuilder;
54  import javax.xml.parsers.DocumentBuilderFactory;
55  import javax.xml.parsers.ParserConfigurationException;
56  import java.io.File;
57  import java.io.FileNotFoundException;
58  import java.io.IOException;
59  import java.net.MalformedURLException;
60  import java.net.URL;
61  import java.util.ArrayList;
62  import java.util.Collection;
63  import java.util.Iterator;
64  import java.util.List;
65  import java.util.Map;
66  import java.util.Set;
67  
68  /**
69   * @author Olivier Lamy
70   * @since 2.0
71   */
72  public abstract class AbstractRunMojo
73      extends AbstractTomcat7Mojo             
74  {
75  // ----------------------------------------------------------------------
76      // Mojo Parameters
77      // ----------------------------------------------------------------------
78  
79      /**
80       * The packaging of the Maven project that this goal operates upon.
81       *
82       * @parameter expression = "${project.packaging}"
83       * @required
84       * @readonly
85       */
86      private String packaging;
87  
88      /**
89       * The directory to create the Tomcat server configuration under.
90       *
91       * @parameter expression="${project.build.directory}/tomcat"
92       */
93      private File configurationDir;
94  
95      /**
96       * The port to run the Tomcat server on.
97       *
98       * @parameter expression="${maven.tomcat.port}" default-value="8080"
99       */
100     private int port;
101 
102     /**
103      * The AJP port to run the Tomcat server on.
104      * By default it's 0 this means won't be started.
105      * The ajp connector will be started only for value > 0.
106      *
107      * @parameter expression="${maven.tomcat.ajp.port}" default-value="0"
108      * @since 2.0
109      */
110     private int ajpPort;
111 
112     /**
113      * The AJP protocol to run the Tomcat server on.
114      * By default it's ajp.
115      * NOTE The ajp connector will be started only if {@link #ajpPort} > 0.
116      * possible values are:
117      * <ul>
118      * <li>org.apache.coyote.ajp.AjpProtocol - new blocking Java connector that supports an executor</li>
119      * <li>org.apache.coyote.ajp.AjpAprProtocol - the APR/native connector.</li>
120      * </ul>
121      *
122      * @parameter expression="${maven.tomcat.ajp.protocol}" default-value="org.apache.coyote.ajp.AjpProtocol"
123      * @since 2.0
124      */
125     private String ajpProtocol;
126 
127     /**
128      * The https port to run the Tomcat server on.
129      * By default it's 0 this means won't be started.
130      * The https connector will be started only for value > 0.
131      *
132      * @parameter expression="${maven.tomcat.httpsPort}" default-value="0"
133      * @since 1.0
134      */
135     private int httpsPort;
136 
137     /**
138      * The character encoding to use for decoding URIs.
139      *
140      * @parameter expression="${maven.tomcat.uriEncoding}" default-value="ISO-8859-1"
141      * @since 1.0
142      */
143     private String uriEncoding;
144 
145     /**
146      * List of System properties to pass to the Tomcat Server.
147      *
148      * @parameter
149      * @since 1.0-alpha-2
150      */
151     private Map<String, String> systemProperties;
152 
153     /**
154      * The directory contains additional configuration Files that copied in the Tomcat conf Directory.
155      *
156      * @parameter expression = "${maven.tomcat.additionalConfigFilesDir}" default-value="${basedir}/src/main/tomcatconf"
157      * @since 1.0-alpha-2
158      */
159     private File additionalConfigFilesDir;
160 
161     /**
162      * server.xml to use <b>Note if you use this you must configure in this file your webapp paths</b>.
163      *
164      * @parameter expression="${maven.tomcat.serverXml}"
165      * @since 1.0-alpha-2
166      */
167     private File serverXml;
168 
169     /**
170      * overriding the providing web.xml to run tomcat
171      *
172      * @parameter expression="${maven.tomcat.webXml}"
173      * @since 1.0-alpha-2
174      */
175     private File tomcatWebXml;
176 
177     /**
178      * Set this to true to allow Maven to continue to execute after invoking
179      * the run goal.
180      *
181      * @parameter expression="${maven.tomcat.fork}" default-value="false"
182      * @since 1.0
183      */
184     private boolean fork;
185 
186     /**
187      * Will create a tomcat context for each dependencies of war type with 'scope' set to 'tomcat'.
188      * In other words, dependencies with:
189      * <pre>
190      *    &lt;type&gt;war&lt;/type&gt;
191      *    &lt;scope&gt;tomcat&lt;/scope&gt;
192      * </pre>
193      * To preserve backward compatibility it's false by default.
194      *
195      * @parameter expression="${maven.tomcat.addContextWarDependencies}" default-value="false"
196      * @since 1.0
197      */
198     private boolean addContextWarDependencies;
199 
200     /**
201      * The maven project.
202      *
203      * @parameter expression="${project}"
204      * @required
205      * @readonly
206      * @since 1.0
207      */
208     protected MavenProject project;
209 
210     /**
211      * The archive manager.
212      *
213      * @component
214      * @since 1.0
215      */
216     private ArchiverManager archiverManager;
217 
218     /**
219      * if <code>true</code> a new classLoader separated from maven core will be created to start tomcat.
220      *
221      * @parameter expression="${tomcat.useSeparateTomcatClassLoader}" default-value="false"
222      * @since 1.0
223      */
224     protected boolean useSeparateTomcatClassLoader;
225 
226     /**
227      * @parameter expression="${plugin.artifacts}"
228      * @required
229      * @since 1.0
230      */
231     @SuppressWarnings( "rawtypes" )
232     private List pluginArtifacts;
233 
234     /**
235      * If set to true ignore if packaging of project is not 'war'.
236      *
237      * @parameter expression="${tomcat.ignorePackaging}" default-value="false"
238      * @since 1.0
239      */
240     private boolean ignorePackaging;
241 
242     /**
243      * Override the default keystoreFile for the HTTPS connector (if enabled)
244      *
245      * @parameter
246      * @since 1.1
247      */
248     private String keystoreFile;
249 
250     /**
251      * Override the default keystorePass for the HTTPS connector (if enabled)
252      *
253      * @parameter
254      * @since 1.1
255      */
256     private String keystorePass;
257 
258     /**
259      * <p>
260      * Enables or disables naming support for the embedded Tomcat server.
261      * </p>
262      * <p>
263      * <strong>Note:</strong> This setting is ignored if you provide a <code>server.xml</code> for your
264      * Tomcat. Instead please configure naming in the <code>server.xml</code>.
265      * </p>
266      *
267      * @parameter expression="${maven.tomcat.useNaming}" default-value="true"
268      * @see <a href="http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/startup/Embedded.html">org.apache.catalina.startup.Embedded</a>
269      * @see <a href="http://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/startup/Tomcat.html">org.apache.catalina.startup.Tomcat</a>
270      * @since 2.0
271      */
272     private boolean useNaming;
273 
274     /**
275      * Force context scanning if you don't use a context file with reloadable = "true".
276      * The other way to use contextReloadable is to add attribute reloadable = "true"
277      * in your context file.
278      *
279      * @parameter expression="${maven.tomcat.contextReloadable}" default-value="false"
280      * @since 2.0
281      */
282     protected boolean contextReloadable;
283 
284 
285     /**
286      * The path of the Tomcat context XML file.
287      *
288      * @parameter expression="src/main/webapp/META-INF/context.xml"
289      */
290     protected File contextFile;
291 
292     /**
293      * The protocol to run the Tomcat server on.
294      * By default it's HTTP/1.1.
295      *
296      * @parameter expression="${maven.tomcat.protocol}" default-value="HTTP/1.1"
297      * @since 2.0
298      */
299     private String protocol;
300 
301     /**
302      * The path of the Tomcat users XML file.
303      *
304      * @parameter expression = "${maven.tomcat.tomcatUsers.file}"
305      * @since 2.0
306      */
307     private File tomcatUsers;
308 
309     /**
310      * The path of the Tomcat logging configuration.
311      *
312      * @parameter expression = "${maven.tomcat.tomcatLogging.file}"
313      * @since 2.0
314      */
315     private File tomcatLoggingFile;
316 
317 
318     // ----------------------------------------------------------------------
319     // Fields
320     // ----------------------------------------------------------------------
321 
322     /**
323      * @since 1.0
324      */
325     private ClassRealm tomcatRealm;
326 
327     // ----------------------------------------------------------------------
328     // Mojo Implementation
329     // ----------------------------------------------------------------------
330 
331     /**
332      * {@inheritDoc}
333      */
334     public void execute()
335         throws MojoExecutionException, MojoFailureException
336     {
337         // ensure project is a web application
338         if ( !isWar() )
339         {
340             getLog().info( messagesProvider.getMessage( "AbstractRunMojo.nonWar" ) );
341             return;
342         }
343         ClassLoader originalClassLoaser = Thread.currentThread().getContextClassLoader();
344         try
345         {
346             if ( useSeparateTomcatClassLoader )
347             {
348                 Thread.currentThread().setContextClassLoader( getTomcatClassLoader() );
349             }
350             getLog().info( messagesProvider.getMessage( "AbstractRunMojo.runningWar", getWebappUrl() ) );
351 
352             initConfiguration();
353             startContainer();
354             if ( !fork )
355             {
356                 waitIndefinitely();
357             }
358         }
359         catch ( LifecycleException exception )
360         {
361             throw new MojoExecutionException( messagesProvider.getMessage( "AbstractRunMojo.cannotStart" ), exception );
362         }
363         catch ( IOException exception )
364         {
365             throw new MojoExecutionException(
366                 messagesProvider.getMessage( "AbstractRunMojo.cannotCreateConfiguration" ), exception );
367         }
368         catch ( ServletException e )
369         {
370             throw new MojoExecutionException( e.getMessage(), e );
371         }
372         finally
373         {
374             if ( useSeparateTomcatClassLoader )
375             {
376                 Thread.currentThread().setContextClassLoader( originalClassLoaser );
377             }
378         }
379     }
380 
381     // ----------------------------------------------------------------------
382     // Protected Methods
383     // ----------------------------------------------------------------------
384 
385     /**
386      * Gets the webapp context path to use for the web application being run.
387      *
388      * @return the webapp context path
389      */
390     protected String getPath()
391     {
392         return path;
393     }
394 
395     /**
396      * Gets the context to run this web application under for the specified embedded Tomcat.
397      *
398      * @param container the embedded Tomcat container being used
399      * @return the context to run this web application under
400      * @throws IOException            if the context could not be created
401      * @throws MojoExecutionException in case of an error creating the context
402      */
403     protected Context createContext( Tomcat container )
404         throws IOException, MojoExecutionException, ServletException
405     {
406         String contextPath = getPath();
407         Context context = container.addWebapp( contextPath, getDocBase().getAbsolutePath() );
408         //Tomcat.initWebappDefaults( context );
409 
410         if ( useSeparateTomcatClassLoader )
411         {
412             context.setParentClassLoader( getTomcatClassLoader() );
413         }
414 
415         context.setLoader( createWebappLoader() );
416         File contextFile = getContextFile();
417         if ( contextFile != null )
418         {
419             context.setConfigFile( getContextFile().toURI().toURL() );
420         }
421         return context;
422 
423     }
424 
425     /**
426      * Gets the webapp loader to run this web application under.
427      *
428      * @return the webapp loader to use
429      * @throws IOException            if the webapp loader could not be created
430      * @throws MojoExecutionException in case of an error creating the webapp loader
431      */
432     protected WebappLoader createWebappLoader()
433         throws IOException, MojoExecutionException
434     {
435         if ( useSeparateTomcatClassLoader )
436         {
437             return ( isContextReloadable() )
438                 ? new ExternalRepositoriesReloadableWebappLoader( getTomcatClassLoader(), getLog() )
439                 : new WebappLoader( getTomcatClassLoader() );
440         }
441 
442         return ( isContextReloadable() )
443             ? new ExternalRepositoriesReloadableWebappLoader( Thread.currentThread().getContextClassLoader(), getLog() )
444             : new WebappLoader( Thread.currentThread().getContextClassLoader() );
445     }
446 
447     /**
448      * Determine whether the passed context.xml file declares the context as reloadable or not.
449      *
450      * @return false by default, true if  reloadable="true" in context.xml.
451      */
452     protected boolean isContextReloadable()
453         throws MojoExecutionException
454     {
455         if ( contextReloadable )
456         {
457             return true;
458         }
459         // determine whether to use a reloadable Loader or not (default is false).
460         boolean reloadable = false;
461         try
462         {
463             if ( contextFile != null && contextFile.exists() )
464             {
465                 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
466                 DocumentBuilder builder = builderFactory.newDocumentBuilder();
467                 Document contextDoc = builder.parse( contextFile );
468                 contextDoc.getDocumentElement().normalize();
469 
470                 NamedNodeMap nodeMap = contextDoc.getDocumentElement().getAttributes();
471                 Node reloadableAttribute = nodeMap.getNamedItem( "reloadable" );
472 
473                 reloadable =
474                     ( reloadableAttribute != null ) ? Boolean.valueOf( reloadableAttribute.getNodeValue() ) : false;
475             }
476             getLog().debug( "context reloadable: " + reloadable );
477         }
478         catch ( IOException ioe )
479         {
480             getLog().error( "Could not parse file: [" + contextFile.getAbsolutePath() + "]", ioe );
481         }
482         catch ( ParserConfigurationException pce )
483         {
484             getLog().error( "Could not configure XML parser", pce );
485         }
486         catch ( SAXException se )
487         {
488             getLog().error( "Could not parse file: [" + contextFile.getAbsolutePath() + "]", se );
489         }
490 
491         return reloadable;
492     }
493 
494 
495     /**
496      * Gets the webapp directory to run.
497      *
498      * @return the webapp directory
499      */
500     protected abstract File getDocBase();
501 
502     /**
503      * Gets the Tomcat context XML file to use.
504      *
505      * @return the context XML file
506      */
507     protected abstract File getContextFile()
508         throws MojoExecutionException;
509 
510     // ----------------------------------------------------------------------
511     // Private Methods
512     // ----------------------------------------------------------------------
513 
514     /**
515      * Gets whether this project uses WAR packaging.
516      *
517      * @return whether this project uses WAR packaging
518      */
519     protected boolean isWar()
520     {
521         return "war".equals( packaging ) || ignorePackaging;
522     }
523 
524     /**
525      * Gets the URL of the running webapp.
526      *
527      * @return the URL of the running webapp
528      * @throws java.net.MalformedURLException if the running webapp URL is invalid
529      */
530     private URL getWebappUrl()
531         throws MalformedURLException
532     {
533         return new URL( "http", "localhost", port, getPath() );
534     }
535 
536     /**
537      * FIXME not sure we need all of those files with tomcat7
538      * Creates the Tomcat configuration directory with the necessary resources.
539      *
540      * @throws IOException            if the Tomcat configuration could not be created
541      * @throws MojoExecutionException if the Tomcat configuration could not be created
542      */
543     private void initConfiguration()
544         throws IOException, MojoExecutionException
545     {
546         if ( configurationDir.exists() )
547         {
548             getLog().info( messagesProvider.getMessage( "AbstractRunMojo.usingConfiguration", configurationDir ) );
549         }
550         else
551         {
552             getLog().info( messagesProvider.getMessage( "AbstractRunMojo.creatingConfiguration", configurationDir ) );
553 
554             configurationDir.mkdirs();
555 
556             File confDir = new File( configurationDir, "conf" );
557             confDir.mkdir();
558 
559             if ( tomcatLoggingFile != null )
560             {
561                 FileUtils.copyFile( tomcatLoggingFile, new File( confDir, "logging.properties" ) );
562             }
563             else
564             {
565                 copyFile( "/conf/logging.properties", new File( confDir, "logging.properties" ) );
566             }
567 
568             copyFile( "/conf/tomcat-users.xml", new File( confDir, "tomcat-users.xml" ) );
569             if ( tomcatWebXml != null )
570             {
571                 if ( !tomcatWebXml.exists() )
572                 {
573                     throw new MojoExecutionException( " tomcatWebXml " + tomcatWebXml.getPath() + " not exists" );
574                 }
575                 //MTOMCAT-42  here it's a real file resources not a one coming with the mojo
576                 FileUtils.copyFile( tomcatWebXml, new File( confDir, "web.xml" ) );
577             }
578             else
579             {
580                 copyFile( "/conf/web.xml", new File( confDir, "web.xml" ) );
581             }
582 
583             File logDir = new File( configurationDir, "logs" );
584             logDir.mkdir();
585 
586             File webappsDir = new File( configurationDir, "webapps" );
587             webappsDir.mkdir();
588 
589             if ( additionalConfigFilesDir != null && additionalConfigFilesDir.exists() )
590             {
591                 DirectoryScanner scanner = new DirectoryScanner();
592                 scanner.addDefaultExcludes();
593                 scanner.setBasedir( additionalConfigFilesDir.getPath() );
594                 scanner.scan();
595 
596                 String[] files = scanner.getIncludedFiles();
597 
598                 if ( files != null && files.length > 0 )
599                 {
600                     getLog().info( "Coping additional tomcat config files" );
601 
602                     for ( int i = 0; i < files.length; i++ )
603                     {
604                         File file = new File( additionalConfigFilesDir, files[i] );
605 
606                         getLog().info( " copy " + file.getName() );
607 
608                         FileUtils.copyFileToDirectory( file, confDir );
609                     }
610                 }
611             }
612         }
613     }
614 
615     /**
616      * Copies the specified class resource to the specified file.
617      *
618      * @param fromPath the path of the class resource to copy
619      * @param toFile   the file to copy to
620      * @throws IOException if the file could not be copied
621      */
622     private void copyFile( String fromPath, File toFile )
623         throws IOException
624     {
625         URL fromURL = getClass().getResource( fromPath );
626 
627         if ( fromURL == null )
628         {
629             throw new FileNotFoundException( fromPath );
630         }
631 
632         FileUtils.copyURLToFile( fromURL, toFile );
633     }
634 
635     /**
636      * Starts the embedded Tomcat server.
637      *
638      * @throws IOException            if the server could not be configured
639      * @throws LifecycleException     if the server could not be started
640      * @throws MojoExecutionException if the server could not be configured
641      */
642     private void startContainer()
643         throws IOException, LifecycleException, MojoExecutionException, ServletException
644     {
645         String previousCatalinaBase = System.getProperty( "catalina.base" );
646 
647         try
648         {
649 
650             // Set the system properties
651             setupSystemProperties();
652 
653             System.setProperty( "catalina.base", configurationDir.getAbsolutePath() );
654 
655             if ( serverXml != null )
656             {
657                 if ( !serverXml.exists() )
658                 {
659                     throw new MojoExecutionException( serverXml.getPath() + " not exists" );
660                 }
661 
662                 Catalina container = new Catalina();
663                 container.setUseNaming( this.useNaming );
664                 container.setConfig( serverXml.getAbsolutePath() );
665                 container.start();
666                 EmbeddedRegistry.getInstance().register( container );
667             }
668             else
669             {
670 
671                 System.setProperty( "java.util.logging.manager", "org.apache.juli.ClassLoaderLogManager" );
672                 System.setProperty( "java.util.logging.config.file",
673                                     new File( configurationDir, "conf/logging.properties" ).toString() );
674 
675                 // Trigger loading of catalina.properties
676                 CatalinaProperties.getProperty( "foo" );
677 
678                 Tomcat embeddedTomcat = new Tomcat();
679                 if ( useNaming )
680                 {
681                     embeddedTomcat.enableNaming();
682                 }
683                 embeddedTomcat.setBaseDir( configurationDir.getAbsolutePath() );
684                 MemoryRealm memoryRealm = new MemoryRealm();
685 
686                 if ( tomcatUsers != null )
687                 {
688                     if ( !tomcatUsers.exists() )
689                     {
690                         throw new MojoExecutionException( " tomcatUsers " + tomcatUsers.getPath() + " not exists" );
691                     }
692                     getLog().info( "use tomcat-users.xml from " + tomcatUsers.getAbsolutePath() );
693                     memoryRealm.setPathname( tomcatUsers.getAbsolutePath() );
694                 }
695 
696                 embeddedTomcat.setDefaultRealm( memoryRealm );
697 
698                 embeddedTomcat.getHost().setAppBase( new File( configurationDir, "webapps" ).getAbsolutePath() );
699 
700                 Connector connector = new Connector( protocol );
701                 connector.setPort( port );
702 
703                 if ( httpsPort > 0 )
704                 {
705                     connector.setRedirectPort( httpsPort );
706                 }
707 
708                 connector.setURIEncoding( uriEncoding );
709 
710                 embeddedTomcat.getService().addConnector( connector );
711 
712                 embeddedTomcat.setConnector( connector );
713 
714                 if ( useSeparateTomcatClassLoader )
715                 {
716                     embeddedTomcat.getEngine().setParentClassLoader( getTomcatClassLoader() );
717                 }
718 
719                 Context ctx = createContext( embeddedTomcat );
720 
721                 AccessLogValve alv = new AccessLogValve();
722                 alv.setDirectory( new File( configurationDir, "logs" ).getAbsolutePath() );
723                 alv.setPattern( "%h %l %u %t \"%r\" %s %b %I %D" );
724                 embeddedTomcat.getHost().getPipeline().addValve( alv );
725 
726                 // create https connector
727                 if ( httpsPort > 0 )
728                 {
729                     Connector httpsConnector = new Connector( protocol );
730                     httpsConnector.setPort( httpsPort );
731                     httpsConnector.setSecure( true );
732                     httpsConnector.setProperty( "SSLEnabled", "true" );
733                     // should be default but configure it anyway
734                     httpsConnector.setProperty( "sslProtocol", "TLS" );
735                     if ( keystoreFile != null )
736                     {
737                         httpsConnector.setAttribute( "keystoreFile", keystoreFile );
738                     }
739                     if ( keystorePass != null )
740                     {
741                         httpsConnector.setAttribute( "keystorePass", keystorePass );
742                     }
743                     embeddedTomcat.getEngine().getService().addConnector( httpsConnector );
744 
745                 }
746 
747                 // create ajp connector
748                 if ( ajpPort > 0 )
749                 {
750                     Connector ajpConnector = new Connector( ajpProtocol );
751                     ajpConnector.setPort( ajpPort );
752                     ajpConnector.setURIEncoding( uriEncoding );
753                     embeddedTomcat.getEngine().getService().addConnector( ajpConnector );
754                 }
755 
756                 if ( useSeparateTomcatClassLoader )
757                 {
758                     embeddedTomcat.getEngine().setParentClassLoader( getTomcatClassLoader() );
759                 }
760 
761                 if ( addContextWarDependencies )
762                 {
763                     createDependencyContexts( embeddedTomcat );
764                 }
765 
766                 embeddedTomcat.start();
767                 EmbeddedRegistry.getInstance().register( embeddedTomcat );
768 
769             }
770 
771 
772         }
773         finally
774         {
775             if ( previousCatalinaBase != null )
776             {
777                 System.setProperty( "catalina.base", previousCatalinaBase );
778             }
779         }
780     }
781 
782     protected ClassRealm getTomcatClassLoader()
783         throws MojoExecutionException
784     {
785         if ( this.tomcatRealm != null )
786         {
787             return tomcatRealm;
788         }
789         try
790         {
791             ClassWorld world = new ClassWorld();
792             ClassRealm root = world.newRealm( "tomcat", Thread.currentThread().getContextClassLoader() );
793 
794             for ( @SuppressWarnings( "rawtypes" ) Iterator i = pluginArtifacts.iterator(); i.hasNext(); )
795             {
796                 Artifact pluginArtifact = (Artifact) i.next();
797                 if ( "org.apache.tomcat".equals( pluginArtifact.getGroupId() ) )
798                 {
799                     if ( pluginArtifact.getFile() != null )
800                     {
801                         root.addURL( pluginArtifact.getFile().toURI().toURL() );
802                     }
803                 }
804             }
805             tomcatRealm = root;
806             return root;
807         }
808         catch ( DuplicateRealmException e )
809         {
810             throw new MojoExecutionException( e.getMessage(), e );
811         }
812         catch ( MalformedURLException e )
813         {
814             throw new MojoExecutionException( e.getMessage(), e );
815         }
816     }
817 
818     @SuppressWarnings( "unchecked" )
819     public Set<Artifact> getProjectArtifacts()
820     {
821         return project.getArtifacts();
822     }
823 
824     /**
825      * Causes the current thread to wait indefinitely. This method does not return.
826      */
827     private void waitIndefinitely()
828     {
829         Object lock = new Object();
830 
831         synchronized ( lock )
832         {
833             try
834             {
835                 lock.wait();
836             }
837             catch ( InterruptedException exception )
838             {
839                 getLog().warn( messagesProvider.getMessage( "AbstractRunMojo.interrupted" ), exception );
840             }
841         }
842     }
843 
844 
845     /**
846      * Set the SystemProperties from the configuration.
847      */
848     private void setupSystemProperties()
849     {
850         if ( systemProperties != null && !systemProperties.isEmpty() )
851         {
852             getLog().info( "setting SystemProperties:" );
853 
854             for ( String key : systemProperties.keySet() )
855             {
856                 String value = systemProperties.get( key );
857 
858                 if ( value != null )
859                 {
860                     getLog().info( " " + key + "=" + value );
861                     System.setProperty( key, value );
862                 }
863                 else
864                 {
865                     getLog().info( "skip sysProps " + key + " with empty value" );
866                 }
867             }
868         }
869     }
870 
871 
872     /**
873      * Allows the startup of additional webapps in the tomcat container by declaration with scope
874      * "tomcat".
875      *
876      * @param container tomcat
877      * @return dependency tomcat contexts of warfiles in scope "tomcat"
878      */
879     private Collection<Context> createDependencyContexts( Tomcat container )
880         throws MojoExecutionException, MalformedURLException
881     {
882         getLog().info( "Deploying dependency wars" );
883         // Let's add other modules
884         List<Context> contexts = new ArrayList<Context>();
885 
886         ScopeArtifactFilter filter = new ScopeArtifactFilter( "tomcat" );
887         @SuppressWarnings( "unchecked" ) Set<Artifact> artifacts = project.getArtifacts();
888         for ( Artifact artifact : artifacts )
889         {
890 
891             // Artifact is not yet registered and it has neither test, nor a
892             // provided scope, not is it optional
893             if ( "war".equals( artifact.getType() ) && !artifact.isOptional() && filter.include( artifact ) )
894             {
895                 getLog().info( "Deploy warfile: " + String.valueOf( artifact.getFile() ) );
896                 File webapps = new File( configurationDir, "webapps" );
897                 File artifactWarDir = new File( webapps, artifact.getArtifactId() );
898                 if ( !artifactWarDir.exists() )
899                 {
900                     //dont extract if exists
901                     artifactWarDir.mkdir();
902                     try
903                     {
904                         UnArchiver unArchiver = archiverManager.getUnArchiver( "zip" );
905                         unArchiver.setSourceFile( artifact.getFile() );
906                         unArchiver.setDestDirectory( artifactWarDir );
907 
908                         // Extract the module
909                         unArchiver.extract();
910                     }
911                     catch ( NoSuchArchiverException e )
912                     {
913                         getLog().error( e );
914                         continue;
915                     }
916                     catch ( ArchiverException e )
917                     {
918                         getLog().error( e );
919                         continue;
920                     }
921                 }
922                 WebappLoader webappLoader = new WebappLoader( Thread.currentThread().getContextClassLoader() );
923                 Context context =
924                     container.addContext( "/" + artifact.getArtifactId(), artifactWarDir.getAbsolutePath() );
925                 context.setLoader( webappLoader );
926                 context.setName( artifact.getArtifactId() );
927                 File contextFile = getContextFile();
928                 if ( contextFile != null )
929                 {
930                     context.setConfigFile( getContextFile().toURI().toURL() );
931                 }
932                 contexts.add( context );
933 
934             }
935         }
936         return contexts;
937     }
938 }