View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 Sabre Holdings.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  
20  package org.eclipse.jetty.ant;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.net.MalformedURLException;
25  import java.net.URL;
26  import java.net.URLClassLoader;
27  import java.util.Iterator;
28  import java.util.List;
29  import javax.servlet.Servlet;
30  
31  import org.apache.tools.ant.AntClassLoader;
32  import org.eclipse.jetty.annotations.AnnotationConfiguration;
33  import org.eclipse.jetty.ant.types.Attribute;
34  import org.eclipse.jetty.ant.types.FileMatchingConfiguration;
35  import org.eclipse.jetty.ant.utils.TaskLog;
36  import org.eclipse.jetty.ant.utils.WebApplicationProxy;
37  import org.eclipse.jetty.plus.webapp.EnvConfiguration;
38  import org.eclipse.jetty.plus.webapp.PlusConfiguration;
39  import org.eclipse.jetty.security.SecurityHandler;
40  import org.eclipse.jetty.server.HandlerContainer;
41  import org.eclipse.jetty.server.handler.ContextHandler;
42  import org.eclipse.jetty.server.handler.ContextHandlerCollection;
43  import org.eclipse.jetty.server.handler.ErrorHandler;
44  import org.eclipse.jetty.server.session.SessionHandler;
45  import org.eclipse.jetty.servlet.Holder;
46  import org.eclipse.jetty.servlet.ServletHandler;
47  import org.eclipse.jetty.servlet.ServletHolder;
48  import org.eclipse.jetty.util.resource.Resource;
49  import org.eclipse.jetty.webapp.Configuration;
50  import org.eclipse.jetty.webapp.FragmentConfiguration;
51  import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
52  import org.eclipse.jetty.webapp.MetaInfConfiguration;
53  import org.eclipse.jetty.webapp.TagLibConfiguration;
54  import org.eclipse.jetty.webapp.WebAppClassLoader;
55  import org.eclipse.jetty.webapp.WebAppContext;
56  
57  /**
58   * An abstraction layer over Jetty WebAppContext.
59   *
60   */
61  public class WebApplicationProxyImpl implements WebApplicationProxy
62  {
63  
64      /** Common root temp directory for all web applications. */
65      static File baseTempDirectory = new File(".");
66  
67      /** Name of this web application. */
68      private String name;
69  
70      /** Location of WAR file (either expanded or not). */
71      private File warFile;
72  
73      /** Application context path. */
74      private String contextPath;
75  
76      /** Location of web.xml file. */
77      private File webXmlFile;
78  
79      /** Location of jetty-env.xml file. */
80      private File jettyEnvXml;
81  
82      /** List of classpath files. */
83      private List classPathFiles;
84  
85      /** Jetty Web Application Context. */
86      private WebAppContext webAppContext;
87  
88      /** Extra scan targets. */
89      private FileMatchingConfiguration extraScanTargetsConfiguration;
90  
91      /** Extra context handlers. */
92      private List contextHandlers;
93  
94      private List attributes;
95  
96      Configuration[] configurations;
97  
98      private FileMatchingConfiguration librariesConfiguration;
99  
100     public static void setBaseTempDirectory(File tempDirectory)
101     {
102         baseTempDirectory = tempDirectory;
103     }
104 
105 
106     public static class AntServletHolder extends ServletHolder
107     {
108 
109         public AntServletHolder()
110         {
111             super();
112         }
113 
114 
115         public AntServletHolder(Class<? extends Servlet> servlet)
116         {
117             super(servlet);
118         }
119 
120 
121         public AntServletHolder(Servlet servlet)
122         {
123             super(servlet);
124         }
125 
126 
127         public AntServletHolder(String name, Class<? extends Servlet> servlet)
128         {
129             super(name, servlet);
130         }
131 
132 
133         public AntServletHolder(String name, Servlet servlet)
134         {
135             super(name, servlet);
136         }
137 
138 
139         @Override
140         protected void initJspServlet() throws Exception
141         {
142             //super.initJspServlet();
143 
144             ContextHandler ch = ((ContextHandler.Context)getServletHandler().getServletContext()).getContextHandler();
145 
146             /* Set the webapp's classpath for Jasper */
147             ch.setAttribute("org.apache.catalina.jsp_classpath", ch.getClassPath());
148 
149             /* Set the system classpath for Jasper */
150             String sysClassPath = getSystemClassPath(ch.getClassLoader().getParent());
151             setInitParameter("com.sun.appserv.jsp.classpath", sysClassPath);
152 
153             /* Set up other classpath attribute */
154             if ("?".equals(getInitParameter("classpath")))
155             {
156                 String classpath = ch.getClassPath();
157                 if (classpath != null)
158                     setInitParameter("classpath", classpath);
159             }
160         }
161 
162 
163         protected String getSystemClassPath (ClassLoader loader) throws Exception
164         {
165             StringBuilder classpath=new StringBuilder();
166             while (loader != null)
167             {
168                 if (loader instanceof URLClassLoader)
169                 {
170                     URL[] urls = ((URLClassLoader)loader).getURLs();
171                     if (urls != null)
172                     {
173                         for (int i=0;i<urls.length;i++)
174                         {
175                             Resource resource = Resource.newResource(urls[i]);
176                             File file=resource.getFile();
177                             if (file!=null && file.exists())
178                             {
179                                 if (classpath.length()>0)
180                                     classpath.append(File.pathSeparatorChar);
181                                 classpath.append(file.getAbsolutePath());
182                             }
183                         }
184                     }
185                 }
186                 else if (loader instanceof AntClassLoader)
187                 {
188                     classpath.append(((AntClassLoader)loader).getClasspath());
189                 }
190 
191                 loader = loader.getParent();
192             }
193 
194             return classpath.toString();
195         }
196 
197     }
198 
199     public static class AntServletHandler extends ServletHandler
200     {
201 
202         @Override
203         public ServletHolder newServletHolder(Holder.Source source)
204         {
205             return new AntServletHolder();
206         }
207 
208     }
209 
210     public static class AntWebAppContext extends WebAppContext
211     {
212         public AntWebAppContext()
213         {
214             super();
215         }
216 
217         public AntWebAppContext(HandlerContainer parent, String webApp, String contextPath)
218         {
219             super(parent, webApp, contextPath);
220         }
221 
222         public AntWebAppContext(SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler)
223         {
224             super(sessionHandler, securityHandler, servletHandler, errorHandler);
225         }
226 
227         public AntWebAppContext(String webApp, String contextPath)
228         {
229             super(webApp, contextPath);
230         }
231 
232         @Override
233         protected ServletHandler newServletHandler()
234         {
235             return new AntServletHandler();
236         }
237     }
238 
239 
240     /**
241      * Default constructor. Takes application name as an argument
242      *
243      * @param name web application name.
244      */
245     public WebApplicationProxyImpl(String name) throws Exception
246     {
247         this.name = name;
248         TaskLog.log("\nConfiguring Jetty for web application: " + name);
249 
250         this.configurations = new Configuration[]
251                                                 { new AntWebInfConfiguration(),
252                                                   new AntWebXmlConfiguration(),
253                                                   new MetaInfConfiguration(),
254                                                   new FragmentConfiguration(),
255                                                   new EnvConfiguration(),
256                                                   new PlusConfiguration(),
257                                                   new AnnotationConfiguration(),
258                                                   new JettyWebXmlConfiguration(),
259                                                   new TagLibConfiguration() };
260     }
261 
262     public List getClassPathFiles()
263     {
264         return classPathFiles;
265     }
266 
267     public String getContextPath()
268     {
269         return contextPath;
270     }
271 
272     public String getName()
273     {
274         return name;
275     }
276 
277     public File getSourceDirectory()
278     {
279         return warFile;
280     }
281 
282     public File getWebXmlFile()
283     {
284         return webXmlFile;
285     }
286 
287     public void setSourceDirectory(File warFile)
288     {
289         this.warFile = warFile;
290         TaskLog.log("Webapp source directory = " + warFile);
291     }
292 
293     public void setContextPath(String contextPath)
294     {
295         if (!contextPath.startsWith("/"))
296         {
297             contextPath = "/" + contextPath;
298         }
299         this.contextPath = contextPath;
300         TaskLog.log("Context path = " + contextPath);
301 
302     }
303 
304     public void setWebXml(File webXmlFile)
305     {
306         this.webXmlFile = webXmlFile;
307     }
308 
309     public void setJettyEnvXml(File jettyEnvXml)
310     {
311         this.jettyEnvXml = jettyEnvXml;
312         if (this.jettyEnvXml != null)
313         {
314             TaskLog.log("jetty-env.xml file: = " + jettyEnvXml.getAbsolutePath());
315         }
316     }
317 
318     public void setClassPathFiles(List classPathFiles)
319     {
320         this.classPathFiles = classPathFiles;
321         TaskLog.log("Classpath = " + classPathFiles);
322     }
323 
324     /**
325      * Checks if a given file is scanned according to the internal
326      * configuration. This may be difficult due to use of 'includes' and
327      * 'excludes' statements.
328      *
329      * @param pathToFile a fully qualified path to file.
330      * @return true if file is being scanned, false otherwise.
331      */
332     public boolean isFileScanned(String pathToFile)
333     {
334         return librariesConfiguration.isIncluded(pathToFile)
335                 || extraScanTargetsConfiguration.isIncluded(pathToFile);
336     }
337 
338     public void setLibrariesConfiguration(FileMatchingConfiguration classesConfiguration)
339     {
340         TaskLog.log("Default scanned paths = " + classesConfiguration.getBaseDirectories());
341         this.librariesConfiguration = classesConfiguration;
342     }
343 
344     public List getLibraries()
345     {
346         return librariesConfiguration.getBaseDirectories();
347     }
348 
349     public void setExtraScanTargetsConfiguration(
350             FileMatchingConfiguration extraScanTargetsConfiguration)
351     {
352         this.extraScanTargetsConfiguration = extraScanTargetsConfiguration;
353         TaskLog.log("Extra scan targets = " + extraScanTargetsConfiguration.getBaseDirectories());
354     }
355 
356     public void setAttributes(List attributes)
357     {
358         this.attributes = attributes;
359     }
360 
361     public List getExtraScanTargets()
362     {
363         return extraScanTargetsConfiguration.getBaseDirectories();
364     }
365 
366     public List getContextHandlers()
367     {
368         return contextHandlers;
369     }
370 
371     public void setContextHandlers(List contextHandlers)
372     {
373         this.contextHandlers = contextHandlers;
374     }
375 
376     /**
377      * @see WebApplicationProxy#getProxiedObject()
378      */
379     public Object getProxiedObject()
380     {
381         return webAppContext;
382     }
383 
384     /**
385      * @see WebApplicationProxy#start()
386      */
387     public void start()
388     {
389         try
390         {
391             TaskLog.logWithTimestamp("Starting web application " + name + " ...\n");
392             webAppContext.start();
393         }
394         catch (Exception e)
395         {
396             TaskLog.log(e.toString());
397         }
398     }
399 
400     /**
401      * @see WebApplicationProxy#stop()
402      */
403     public void stop()
404     {
405         try
406         {
407             TaskLog.logWithTimestamp("Stopping web application " + name + " ...");
408             Thread.currentThread().sleep(500L);
409             webAppContext.stop();
410         }
411         catch (InterruptedException e)
412         {
413             TaskLog.log(e.toString());
414         }
415         catch (Exception e)
416         {
417             TaskLog.log(e.toString());
418         }
419     }
420 
421     /**
422      * @see WebApplicationProxy#createApplicationContext(org.eclipse.jetty.server.handler.ContextHandlerCollection)
423      */
424     public void createApplicationContext(ContextHandlerCollection contexts)
425     {
426         webAppContext = new AntWebAppContext(contexts, warFile.getAbsolutePath(), contextPath);
427         webAppContext.setDisplayName(name);
428 
429         configurePaths();
430 
431         if ( !attributes.isEmpty() )
432         {
433             for ( Iterator i = attributes.iterator(); i.hasNext(); )
434             {
435                 Attribute attr = (Attribute) i.next();
436 
437                 webAppContext.setAttribute(attr.getName(),attr.getValue());
438             }
439         }
440 
441         configureHandlers(contexts);
442 
443         applyConfiguration();
444     }
445 
446     private void configureHandlers(ContextHandlerCollection contexts)
447     {
448         // adding extra context handlers
449         Iterator handlersIterator = contextHandlers.iterator();
450         while (handlersIterator.hasNext())
451         {
452             ContextHandler contextHandler = (ContextHandler) handlersIterator.next();
453             contexts.addHandler(contextHandler);
454         }
455     }
456 
457     private void configurePaths()
458     {
459         // configuring temp directory
460         File tempDir = new File(baseTempDirectory, contextPath);
461         if (!tempDir.exists())
462         {
463             tempDir.mkdirs();
464         }
465         webAppContext.setTempDirectory(tempDir);
466         tempDir.deleteOnExit();
467         TaskLog.log("Temp directory = " + tempDir.getAbsolutePath());
468 
469         // configuring WAR directory for packaged web applications
470         if (warFile.isFile())
471         {
472             warFile = new File(tempDir, "webapp");
473             webXmlFile = new File(new File(warFile, "WEB-INF"), "web.xml");
474         }
475     }
476 
477     /**
478      * Applies web application configuration at the end of configuration process
479      * or after application restart.
480      */
481     void applyConfiguration()
482     {
483         for (int i = 0; i < configurations.length; i++)
484         {
485             if (configurations[i] instanceof EnvConfiguration)
486             {
487                 try
488                 {
489                     if (jettyEnvXml != null && jettyEnvXml.exists())
490                     {
491                         ((EnvConfiguration) configurations[i]).setJettyEnvXml(Resource.toURL(jettyEnvXml));
492                     }
493                 }
494                 catch (MalformedURLException e)
495                 {
496                     throw new RuntimeException(e);
497                 }
498             }
499             else if (configurations[i] instanceof AntWebXmlConfiguration)
500             {
501                 ((AntWebXmlConfiguration) configurations[i]).setClassPathFiles(classPathFiles);
502                 ((AntWebXmlConfiguration) configurations[i]).setWebAppBaseDir(warFile);
503                 ((AntWebXmlConfiguration) configurations[i]).setWebXmlFile(webXmlFile);
504                 ((AntWebXmlConfiguration) configurations[i]).setWebDefaultXmlFile(webDefaultXmlFile);
505             }
506         }
507 
508         try
509         {
510             ClassLoader loader = new WebAppClassLoader(this.getClass().getClassLoader(),
511                     webAppContext);
512             webAppContext.setParentLoaderPriority(true);
513             webAppContext.setClassLoader(loader);
514             if (webDefaultXmlFile != null)
515                 webAppContext.setDefaultsDescriptor(webDefaultXmlFile.getCanonicalPath());
516 
517         }
518         catch (IOException e)
519         {
520             TaskLog.log(e.toString());
521         }
522 
523         webAppContext.setConfigurations(configurations);
524     }
525 
526     private File webDefaultXmlFile;
527 
528     public File getWebDefaultXmlFile()
529     {
530         return this.webDefaultXmlFile;
531     }
532 
533     public void setWebDefaultXmlFile(File webDefaultXmlfile)
534     {
535         this.webDefaultXmlFile = webDefaultXmlfile;
536     }
537 }