1   package org.apache.tomcat.maven.plugin.tomcat7.run;
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  import org.apache.catalina.loader.WebappLoader;
22  import org.apache.commons.io.FileUtils;
23  import org.apache.commons.lang.StringUtils;
24  import org.apache.maven.artifact.Artifact;
25  import org.apache.maven.plugin.MojoExecutionException;
26  import org.apache.maven.plugins.annotations.Component;
27  import org.apache.maven.plugins.annotations.Execute;
28  import org.apache.maven.plugins.annotations.LifecyclePhase;
29  import org.apache.maven.plugins.annotations.Mojo;
30  import org.apache.maven.plugins.annotations.Parameter;
31  import org.apache.maven.plugins.annotations.ResolutionScope;
32  import org.apache.maven.shared.filtering.MavenFileFilter;
33  import org.apache.maven.shared.filtering.MavenFileFilterRequest;
34  import org.apache.maven.shared.filtering.MavenFilteringException;
35  import org.apache.tomcat.maven.common.run.ClassLoaderEntriesCalculator;
36  import org.apache.tomcat.maven.common.run.ClassLoaderEntriesCalculatorRequest;
37  import org.apache.tomcat.maven.common.run.ClassLoaderEntriesCalculatorResult;
38  import org.apache.tomcat.maven.common.run.TomcatRunException;
39  import org.codehaus.plexus.util.IOUtil;
40  import org.codehaus.plexus.util.xml.Xpp3Dom;
41  import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
42  import org.codehaus.plexus.util.xml.Xpp3DomWriter;
43  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
44  
45  import java.io.File;
46  import java.io.FileReader;
47  import java.io.FileWriter;
48  import java.io.IOException;
49  import java.io.StringWriter;
50  import java.util.List;
51  import java.util.Set;
52  
53  
54  
55  
56  
57  
58  
59  @Mojo( name = "run", requiresDependencyResolution = ResolutionScope.TEST )
60  @Execute( phase = LifecyclePhase.COMPILE )
61  public class RunMojo
62      extends AbstractRunMojo
63  {
64      
65      
66      
67  
68  
69      
70  
71  
72      @Parameter( defaultValue = "${project.artifacts}", required = true, readonly = true )
73      private Set<Artifact> dependencies;
74  
75      
76  
77  
78      @Parameter( defaultValue = "${basedir}/src/main/webapp", property = "tomcat.warSourceDirectory" )
79      private File warSourceDirectory;
80  
81  
82      
83  
84  
85  
86  
87  
88      @Parameter( property = "tomcat.delegate", defaultValue = "true" )
89      private boolean delegate = true;
90  
91      
92  
93  
94  
95  
96      @Parameter( property = "maven.tomcat.backgroundProcessorDelay", defaultValue = "-1" )
97      protected int backgroundProcessorDelay = -1;
98  
99      
100 
101 
102     @Component
103     private ClassLoaderEntriesCalculator classLoaderEntriesCalculator;
104 
105     
106 
107 
108 
109 
110     @Parameter( property = "maven.tomcat.addWarDependenciesInClassloader", defaultValue = "true" )
111     private boolean addWarDependenciesInClassloader;
112 
113     
114 
115 
116 
117 
118     @Parameter( property = "maven.tomcat.useTestClasspath", defaultValue = "false" )
119     private boolean useTestClasspath;
120 
121     
122 
123 
124 
125 
126     @Parameter( alias = "additionalClassesDirs" )
127     private List<String> additionalClasspathDirs;
128 
129     @Component( role = MavenFileFilter.class, hint = "default" )
130     private MavenFileFilter mavenFileFilter;
131 
132     
133 
134 
135     @Override
136     protected File getDocBase()
137     {
138         return warSourceDirectory;
139     }
140 
141     
142 
143 
144     @Override
145     protected File getContextFile()
146         throws MojoExecutionException
147     {
148         File temporaryContextFile = null;
149 
150         
151         
152         
153         
154         
155         FileReader fr = null;
156         FileWriter fw = null;
157         StringWriter sw = new StringWriter();
158         try
159         {
160             temporaryContextFile = File.createTempFile( "tomcat-maven-plugin", "temp-ctx-file" );
161             temporaryContextFile.deleteOnExit();
162 
163             
164             if ( contextFile != null && contextFile.exists() )
165             {
166                 MavenFileFilterRequest mavenFileFilterRequest = new MavenFileFilterRequest();
167                 mavenFileFilterRequest.setFrom( contextFile );
168                 mavenFileFilterRequest.setTo( temporaryContextFile );
169                 mavenFileFilterRequest.setMavenProject( project );
170                 mavenFileFilterRequest.setMavenSession( session );
171                 mavenFileFilterRequest.setFiltering( true );
172 
173                 mavenFileFilter.copyFile( mavenFileFilterRequest );
174 
175                 fr = new FileReader( temporaryContextFile );
176                 Xpp3Dom xpp3Dom = Xpp3DomBuilder.build( fr );
177                 xpp3Dom.setAttribute( "backgroundProcessorDelay", Integer.toString( backgroundProcessorDelay ) );
178                 xpp3Dom.setAttribute( "reloadable", Boolean.toString( isContextReloadable() ) );
179                 fw = new FileWriter( temporaryContextFile );
180                 Xpp3DomWriter.write( fw, xpp3Dom );
181                 Xpp3DomWriter.write( sw, xpp3Dom );
182                 getLog().debug( " generated context file " + sw.toString() );
183             }
184             else
185             {
186                 if ( contextReloadable )
187                 {
188                     
189                     StringBuilder sb = new StringBuilder( "<Context " ).append( "backgroundProcessorDelay=\"" ).append(
190                         Integer.toString( backgroundProcessorDelay ) ).append( "\"" ).append(
191                         " reloadable=\"" + Boolean.toString( isContextReloadable() ) + "\"/>" );
192 
193                     getLog().debug( " generated context file " + sb.toString() );
194 
195                     fw.write( sb.toString() );
196                 }
197                 else
198                 {
199                     
200                     return null;
201                 }
202             }
203         }
204         catch ( IOException e )
205         {
206             getLog().error( "error creating fake context.xml : " + e.getMessage(), e );
207             throw new MojoExecutionException( "error creating fake context.xml : " + e.getMessage(), e );
208         }
209         catch ( XmlPullParserException e )
210         {
211             getLog().error( "error creating fake context.xml : " + e.getMessage(), e );
212             throw new MojoExecutionException( "error creating fake context.xml : " + e.getMessage(), e );
213         }
214         catch ( MavenFilteringException e )
215         {
216             getLog().error( "error filtering context.xml : " + e.getMessage(), e );
217             throw new MojoExecutionException( "error filtering context.xml : " + e.getMessage(), e );
218         }
219         finally
220         {
221             IOUtil.close( fw );
222             IOUtil.close( fr );
223             IOUtil.close( sw );
224         }
225 
226         return temporaryContextFile;
227     }
228 
229     
230 
231 
232 
233 
234     @Override
235     protected WebappLoader createWebappLoader()
236         throws IOException, MojoExecutionException
237     {
238         WebappLoader loader = super.createWebappLoader();
239         if ( useSeparateTomcatClassLoader )
240         {
241             loader.setDelegate( delegate );
242         }
243 
244         try
245         {
246             ClassLoaderEntriesCalculatorRequest request =
247                 new ClassLoaderEntriesCalculatorRequest().setDependencies( dependencies ).setLog(
248                     getLog() ).setMavenProject( project ).setAddWarDependenciesInClassloader(
249                     addWarDependenciesInClassloader ).setUseTestClassPath( useTestClasspath );
250             ClassLoaderEntriesCalculatorResult classLoaderEntriesCalculatorResult =
251                 classLoaderEntriesCalculator.calculateClassPathEntries( request );
252             List<String> classLoaderEntries = classLoaderEntriesCalculatorResult.getClassPathEntries();
253             final List<File> tmpDirectories = classLoaderEntriesCalculatorResult.getTmpDirectories();
254 
255             Runtime.getRuntime().addShutdownHook( new Thread()
256             {
257                 @Override
258                 public void run()
259                 {
260                     for ( File tmpDir : tmpDirectories )
261                     {
262                         try
263                         {
264                             FileUtils.deleteDirectory( tmpDir );
265                         }
266                         catch ( IOException e )
267                         {
268                             
269                         }
270                     }
271                 }
272             } );
273 
274             if ( classLoaderEntries != null )
275             {
276                 for ( String classLoaderEntry : classLoaderEntries )
277                 {
278                     loader.addRepository( classLoaderEntry );
279                 }
280             }
281 
282             if ( additionalClasspathDirs != null && !additionalClasspathDirs.isEmpty() )
283             {
284                 for ( String additionalClasspathDir : additionalClasspathDirs )
285                 {
286                     if ( StringUtils.isNotBlank( additionalClasspathDir ) )
287                     {
288                         File file = new File( additionalClasspathDir );
289                         if ( file.exists() )
290                         {
291                             String fileUri = file.toURI().toString();
292                             getLog().debug( "add file:" + fileUri + " as a additionalClasspathDir" );
293                             loader.addRepository( fileUri );
294                         }
295                     }
296                 }
297             }
298         }
299         catch ( TomcatRunException e )
300         {
301             throw new MojoExecutionException( e.getMessage(), e );
302         }
303 
304         return loader;
305     }
306 }