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