View Javadoc

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