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.URL;
25  import java.net.URLClassLoader;
26  import java.util.ArrayList;
27  import java.util.Iterator;
28  import java.util.List;
29  
30  import javax.servlet.Servlet;
31  
32  import org.apache.tools.ant.AntClassLoader;
33  import org.apache.tools.ant.BuildException;
34  import org.apache.tools.ant.Project;
35  import org.apache.tools.ant.types.FileSet;
36  import org.eclipse.jetty.annotations.AnnotationConfiguration;
37  import org.eclipse.jetty.ant.types.Attribute;
38  import org.eclipse.jetty.ant.types.Attributes;
39  import org.eclipse.jetty.ant.types.FileMatchingConfiguration;
40  import org.eclipse.jetty.ant.utils.TaskLog;
41  import org.eclipse.jetty.plus.webapp.EnvConfiguration;
42  import org.eclipse.jetty.plus.webapp.PlusConfiguration;
43  import org.eclipse.jetty.server.handler.ContextHandler;
44  import org.eclipse.jetty.servlet.Holder;
45  import org.eclipse.jetty.servlet.ServletHandler;
46  import org.eclipse.jetty.servlet.ServletHolder;
47  import org.eclipse.jetty.util.resource.Resource;
48  import org.eclipse.jetty.webapp.Configuration;
49  import org.eclipse.jetty.webapp.FragmentConfiguration;
50  import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
51  import org.eclipse.jetty.webapp.MetaInfConfiguration;
52  import org.eclipse.jetty.webapp.WebAppClassLoader;
53  import org.eclipse.jetty.webapp.WebAppContext;
54  import org.eclipse.jetty.webapp.WebInfConfiguration;
55  import org.eclipse.jetty.webapp.WebXmlConfiguration;
56  import org.eclipse.jetty.xml.XmlConfiguration;
57  
58  
59  
60  /**
61   * AntWebAppContext
62   * 
63   * Extension of WebAppContext to allow configuration via Ant environment.
64   *
65   */
66  public class AntWebAppContext extends WebAppContext
67  {
68      public final AntWebInfConfiguration antWebInfConfiguration = new AntWebInfConfiguration();
69      public final WebXmlConfiguration webXmlConfiguration = new WebXmlConfiguration();
70      public final MetaInfConfiguration metaInfConfiguration = new MetaInfConfiguration();
71      public final FragmentConfiguration fragmentConfiguration = new FragmentConfiguration();
72      public final EnvConfiguration envConfiguration = new EnvConfiguration();
73      public final PlusConfiguration plusConfiguration = new PlusConfiguration();
74      public final AnnotationConfiguration annotationConfiguration = new AnnotationConfiguration();
75      public final JettyWebXmlConfiguration jettyWebXmlConfiguration = new JettyWebXmlConfiguration();
76  
77  
78      public final Configuration[] DEFAULT_CONFIGURATIONS = 
79          { 
80           antWebInfConfiguration,
81           webXmlConfiguration,
82           metaInfConfiguration,
83           fragmentConfiguration,
84           envConfiguration,
85           plusConfiguration,
86           annotationConfiguration,
87           jettyWebXmlConfiguration
88          };
89      
90  
91      public final static String DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN =
92      ".*/.*jsp-api-[^/]*\\.jar$|.*/.*jsp-[^/]*\\.jar$|.*/.*taglibs[^/]*\\.jar$|.*/.*jstl[^/]*\\.jar$|.*/.*jsf-impl-[^/]*\\.jar$|.*/.*javax.faces-[^/]*\\.jar$|.*/.*myfaces-impl-[^/]*\\.jar$";
93  
94  
95      /** Location of jetty-env.xml file. */
96      private File jettyEnvXml;
97      
98      /** List of web application libraries. */
99      private List libraries = new ArrayList();
100 
101     /** List of web application class directories. */
102     private List classes = new ArrayList();
103     
104     /** context xml file to apply to the webapp */
105     private File contextXml;
106     
107     /** List of extra scan targets for this web application. */
108     private FileSet scanTargets;
109     
110     /** context attributes to set **/
111     private Attributes attributes;
112     
113     private Project project;
114     
115     private List<File> scanFiles;
116     
117 
118 
119     /** Extra scan targets. */
120     private FileMatchingConfiguration extraScanTargetsConfiguration;
121 
122 
123     private FileMatchingConfiguration librariesConfiguration;
124     
125 
126     public static void dump(ClassLoader loader)
127     {
128         while (loader != null)
129         {
130             System.err.println(loader);
131             if (loader instanceof URLClassLoader)
132             {
133                 URL[] urls = ((URLClassLoader)loader).getURLs();
134                 if (urls != null)
135                 {
136                     for (URL u:urls)
137                         System.err.println("\t"+u+"\n");
138                 }
139             }
140             loader = loader.getParent();
141         }
142     }
143 
144     
145     
146     /**
147      * AntServletHolder
148      *
149      *
150      */
151     public static class AntServletHolder extends ServletHolder
152     {
153 
154         public AntServletHolder()
155         {
156             super();
157         }
158 
159 
160         public AntServletHolder(Class<? extends Servlet> servlet)
161         {
162             super(servlet);
163         }
164 
165 
166         public AntServletHolder(Servlet servlet)
167         {
168             super(servlet);
169         }
170 
171 
172         public AntServletHolder(String name, Class<? extends Servlet> servlet)
173         {
174             super(name, servlet);
175         }
176 
177 
178         public AntServletHolder(String name, Servlet servlet)
179         {
180             super(name, servlet);
181         }
182 
183 
184         @Override
185         protected void initJspServlet() throws Exception
186         {
187             //super.initJspServlet();
188 
189             ContextHandler ch = ContextHandler.getContextHandler(getServletHandler().getServletContext());
190 
191             /* Set the webapp's classpath for Jasper */
192             ch.setAttribute("org.apache.catalina.jsp_classpath", ch.getClassPath());
193 
194             /* Set the system classpath for Jasper */
195             String sysClassPath = getSystemClassPath(ch.getClassLoader().getParent());
196             setInitParameter("com.sun.appserv.jsp.classpath", sysClassPath);
197 
198             /* Set up other classpath attribute */
199             if ("?".equals(getInitParameter("classpath")))
200             {
201                 String classpath = ch.getClassPath();
202                 if (classpath != null)
203                     setInitParameter("classpath", classpath);
204             }
205         }
206 
207 
208         protected String getSystemClassPath (ClassLoader loader) throws Exception
209         {
210             StringBuilder classpath=new StringBuilder();
211             while (loader != null)
212             {
213                 if (loader instanceof URLClassLoader)
214                 {
215                     URL[] urls = ((URLClassLoader)loader).getURLs();
216                     if (urls != null)
217                     {
218                         for (int i=0;i<urls.length;i++)
219                         {
220                             Resource resource = Resource.newResource(urls[i]);
221                             File file=resource.getFile();
222                             if (file!=null && file.exists())
223                             {
224                                 if (classpath.length()>0)
225                                     classpath.append(File.pathSeparatorChar);
226                                 classpath.append(file.getAbsolutePath());
227                             }
228                         }
229                     }
230                 }
231                 else if (loader instanceof AntClassLoader)
232                 {
233                     classpath.append(((AntClassLoader)loader).getClasspath());
234                 }
235 
236                 loader = loader.getParent();
237             }
238 
239             return classpath.toString();
240         }
241 
242     }
243 
244     
245     
246     /**
247      * AntServletHandler
248      *
249      *
250      */
251     public static class AntServletHandler extends ServletHandler
252     {
253 
254         @Override
255         public ServletHolder newServletHolder(Holder.Source source)
256         {
257             return new AntServletHolder();
258         }
259 
260     }
261 
262 
263 
264     /**
265      * Default constructor. Takes application name as an argument
266      *
267      * @param name web application name.
268      */
269     public AntWebAppContext(Project project) throws Exception
270     {
271         super();
272         this.project = project;
273         setConfigurations(DEFAULT_CONFIGURATIONS);
274         setAttribute(WebInfConfiguration.CONTAINER_JAR_PATTERN, DEFAULT_CONTAINER_INCLUDE_JAR_PATTERN);
275         setParentLoaderPriority(true);
276     }
277     
278 
279     /**
280      * Adds a new Ant's attributes tag object if it have not been created yet.
281      */
282     public void addAttributes(Attributes atts)
283     {
284         if (this.attributes != null)
285         {
286             throw new BuildException("Only one <attributes> tag is allowed!");
287         }
288 
289         this.attributes = atts;
290     }
291 
292     
293     public void addLib(FileSet lib)
294     {
295         libraries.add(lib);
296     }
297 
298 
299     public void addClasses(FileSet classes)
300     {
301         this.classes.add(classes);
302     }
303     
304     
305 
306     @Override
307     protected ServletHandler newServletHandler()
308     {
309         return new AntServletHandler();
310     }
311 
312 
313     public void setJettyEnvXml(File jettyEnvXml)
314     {
315         this.jettyEnvXml = jettyEnvXml;
316         TaskLog.log("jetty-env.xml file: = " + (jettyEnvXml == null ? null : jettyEnvXml.getAbsolutePath()));
317     }
318 
319     public File getJettyEnvXml ()
320     {
321         return this.jettyEnvXml;
322     }
323 
324     
325 
326 
327     public List getLibraries()
328     {
329         return librariesConfiguration.getBaseDirectories();
330     }
331 
332  
333     public void addScanTargets(FileSet scanTargets)
334     {
335         if (this.scanTargets != null)
336         {
337             throw new BuildException("Only one <scanTargets> tag is allowed!");
338         }
339 
340         this.scanTargets = scanTargets;
341     }
342     
343     public List getScanTargetFiles () 
344     {
345         if (this.scanTargets == null)
346             return null;
347         
348       
349         FileMatchingConfiguration configuration = new FileMatchingConfiguration();
350         configuration.addDirectoryScanner(scanTargets.getDirectoryScanner(project));
351         return configuration.getBaseDirectories();
352     }
353     
354     public List<File> getScanFiles()
355     {
356         if (scanFiles == null)
357             scanFiles = initScanFiles();
358         return scanFiles;
359     }
360     
361     
362     public boolean isScanned (File file)
363     {
364        List<File> files = getScanFiles();
365        if (files == null || files.isEmpty())
366            return false;
367        return files.contains(file);
368     }
369     
370     
371     public List<File> initScanFiles ()
372     {
373         List<File> scanList = new ArrayList<File>();
374         
375         if (getDescriptor() != null)
376         {
377             try
378             {
379                 Resource r = Resource.newResource(getDescriptor());
380                 scanList.add(r.getFile());
381             }
382             catch (IOException e)
383             {
384                 throw new BuildException(e);
385             }
386         }
387 
388         if (getJettyEnvXml() != null)
389         {
390             try
391             {
392                 Resource r = Resource.newResource(getJettyEnvXml());
393                 scanList.add(r.getFile());
394             }
395             catch (IOException e)
396             {
397                 throw new BuildException("Problem configuring scanner for jetty-env.xml", e);
398             }
399         }
400 
401         if (getDefaultsDescriptor() != null)
402         {
403             try
404             {
405                 if (!AntWebAppContext.WEB_DEFAULTS_XML.equals(getDefaultsDescriptor()))
406                 {
407                     Resource r = Resource.newResource(getDefaultsDescriptor());
408                     scanList.add(r.getFile());
409                 }
410             }
411             catch (IOException e)
412             {
413                 throw new BuildException("Problem configuring scanner for webdefaults.xml", e);
414             }
415         }
416 
417         if (getOverrideDescriptor() != null)
418         {
419             try
420             {
421                 Resource r = Resource.newResource(getOverrideDescriptor());
422                 scanList.add(r.getFile());
423             }
424             catch (IOException e)
425             {
426                 throw new BuildException("Problem configuring scanner for webdefaults.xml", e);
427             }
428         }
429 
430         //add any extra classpath and libs 
431         List<File> cpFiles = getClassPathFiles();
432         if (cpFiles != null)
433             scanList.addAll(cpFiles);
434         
435         //any extra scan targets
436         @SuppressWarnings("unchecked")
437         List<File> scanFiles = (List<File>)getScanTargetFiles();
438         if (scanFiles != null)
439             scanList.addAll(scanFiles);
440         
441         return scanList;
442     }
443     
444     
445     
446     @Override
447     public void setWar(String path)
448     {
449         super.setWar(path);
450 
451         try
452         {
453             Resource war = Resource.newResource(path);
454             if (war.exists() && war.isDirectory() && getDescriptor() == null)
455             {
456                 Resource webXml = war.addPath("WEB-INF/web.xml");
457                 setDescriptor(webXml.toString());
458             }
459         }
460         catch (IOException e)
461         {
462             throw new BuildException(e);
463         }
464     }
465 
466 
467     /**
468      * @see WebApplicationProxy#start()
469      */
470     public void doStart()
471     {
472         try
473         {
474             TaskLog.logWithTimestamp("Starting web application "+this.getDescriptor());
475             if (jettyEnvXml != null && jettyEnvXml.exists())
476                 envConfiguration.setJettyEnvXml(Resource.toURL(jettyEnvXml));
477             setClassLoader(new WebAppClassLoader(this.getClass().getClassLoader(), this));
478             if (attributes != null && attributes.getAttributes() != null)
479             {
480                 for (Attribute a:attributes.getAttributes())
481                     setAttribute(a.getName(), a.getValue());
482             }
483             
484             //apply a context xml file if one was supplied
485             if (contextXml != null)
486             {
487                 XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(contextXml));
488                 TaskLog.log("Applying context xml file "+contextXml);
489                 xmlConfiguration.configure(this);   
490             }
491             
492             super.doStart();
493         }
494         catch (Exception e)
495         {
496             TaskLog.log(e.toString());
497         }
498     }
499 
500     /**
501      * @see WebApplicationProxy#stop()
502      */
503     public void doStop()
504     {
505         try
506         {
507             scanFiles = null;
508             TaskLog.logWithTimestamp("Stopping web application "+this);
509             Thread.currentThread().sleep(500L);
510             super.doStop();
511         }
512         catch (InterruptedException e)
513         {
514             TaskLog.log(e.toString());
515         }
516         catch (Exception e)
517         {
518             TaskLog.log(e.toString());
519         }
520     }
521 
522 
523     
524     /**
525      * @return a list of classpath files (libraries and class directories).
526      */
527     public List<File> getClassPathFiles()
528     {
529         List<File> classPathFiles = new ArrayList<File>();
530         Iterator classesIterator = classes.iterator();
531         while (classesIterator.hasNext())
532         {
533             FileSet clazz = (FileSet) classesIterator.next();
534             classPathFiles.add(clazz.getDirectoryScanner(project).getBasedir());
535         }
536 
537         Iterator iterator = libraries.iterator();
538         while (iterator.hasNext())
539         {
540             FileSet library = (FileSet) iterator.next();
541             String[] includedFiles = library.getDirectoryScanner(project).getIncludedFiles();
542             File baseDir = library.getDirectoryScanner(project).getBasedir();
543 
544             for (int i = 0; i < includedFiles.length; i++)
545             {
546                 classPathFiles.add(new File(baseDir, includedFiles[i]));
547             }
548         }
549 
550 
551         return classPathFiles;
552     }
553 
554     
555     /**
556      * @return a <code>FileMatchingConfiguration</code> object describing the
557      *         configuration of all libraries added to this particular web app
558      *         (both classes and libraries).
559      */
560     public FileMatchingConfiguration getLibrariesConfiguration()
561     {
562         FileMatchingConfiguration config = new FileMatchingConfiguration();
563 
564         Iterator classesIterator = classes.iterator();
565         while (classesIterator.hasNext())
566         {
567             FileSet clazz = (FileSet) classesIterator.next();
568             config.addDirectoryScanner(clazz.getDirectoryScanner(project));
569         }
570 
571         Iterator librariesIterator = libraries.iterator();
572         while (librariesIterator.hasNext())
573         {
574             FileSet library = (FileSet) librariesIterator.next();
575             config.addDirectoryScanner(library.getDirectoryScanner(project));
576         }
577 
578         return config;
579     }
580 
581 
582     public File getContextXml()
583     {
584         return contextXml;
585     }
586 
587 
588     public void setContextXml(File contextXml)
589     {
590         this.contextXml = contextXml;
591     }
592     
593 }