View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
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  package org.eclipse.jetty.webapp;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.net.MalformedURLException;
24  import java.net.URL;
25  import java.security.PermissionCollection;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.Collection;
29  import java.util.Collections;
30  import java.util.EventListener;
31  import java.util.HashMap;
32  import java.util.HashSet;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.Set;
36  
37  import javax.servlet.ServletContext;
38  import javax.servlet.ServletRegistration.Dynamic;
39  import javax.servlet.ServletSecurityElement;
40  import javax.servlet.http.HttpSessionActivationListener;
41  import javax.servlet.http.HttpSessionAttributeListener;
42  import javax.servlet.http.HttpSessionBindingListener;
43  import javax.servlet.http.HttpSessionIdListener;
44  import javax.servlet.http.HttpSessionListener;
45  
46  import org.eclipse.jetty.security.ConstraintAware;
47  import org.eclipse.jetty.security.ConstraintMapping;
48  import org.eclipse.jetty.security.ConstraintSecurityHandler;
49  import org.eclipse.jetty.security.SecurityHandler;
50  import org.eclipse.jetty.server.Connector;
51  import org.eclipse.jetty.server.HandlerContainer;
52  import org.eclipse.jetty.server.Server;
53  import org.eclipse.jetty.server.handler.ContextHandler;
54  import org.eclipse.jetty.server.handler.ErrorHandler;
55  import org.eclipse.jetty.server.session.SessionHandler;
56  import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
57  import org.eclipse.jetty.servlet.ServletContextHandler;
58  import org.eclipse.jetty.servlet.ServletHandler;
59  import org.eclipse.jetty.util.Loader;
60  import org.eclipse.jetty.util.MultiException;
61  import org.eclipse.jetty.util.URIUtil;
62  import org.eclipse.jetty.util.annotation.ManagedAttribute;
63  import org.eclipse.jetty.util.annotation.ManagedObject;
64  import org.eclipse.jetty.util.log.Log;
65  import org.eclipse.jetty.util.log.Logger;
66  import org.eclipse.jetty.util.resource.Resource;
67  import org.eclipse.jetty.util.resource.ResourceCollection;
68  
69  /* ------------------------------------------------------------ */
70  /** Web Application Context Handler.
71   * The WebAppContext handler is an extension of ContextHandler that
72   * coordinates the construction and configuration of nested handlers:
73   * {@link org.eclipse.jetty.security.ConstraintSecurityHandler}, {@link org.eclipse.jetty.server.session.SessionHandler}
74   * and {@link org.eclipse.jetty.servlet.ServletHandler}.
75   * The handlers are configured by pluggable configuration classes, with
76   * the default being  {@link org.eclipse.jetty.webapp.WebXmlConfiguration} and
77   * {@link org.eclipse.jetty.webapp.JettyWebXmlConfiguration}.
78   *
79   * @org.apache.xbean.XBean description="Creates a servlet web application at a given context from a resource base"
80   *
81   */
82  @ManagedObject("Web Application ContextHandler")
83  public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context
84  {
85      private static final Logger LOG = Log.getLogger(WebAppContext.class);
86  
87      public static final String TEMPDIR = "javax.servlet.context.tempdir";
88      public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir";
89      public final static String WEB_DEFAULTS_XML="org/eclipse/jetty/webapp/webdefault.xml";
90      public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
91      public final static String SERVER_SYS_CLASSES = "org.eclipse.jetty.webapp.systemClasses";
92      public final static String SERVER_SRV_CLASSES = "org.eclipse.jetty.webapp.serverClasses";
93  
94      private String[] __dftProtectedTargets = {"/web-inf", "/meta-inf"};
95  
96      public static final String[] DEFAULT_CONFIGURATION_CLASSES =
97      {
98          "org.eclipse.jetty.webapp.WebInfConfiguration",
99          "org.eclipse.jetty.webapp.WebXmlConfiguration",
100         "org.eclipse.jetty.webapp.MetaInfConfiguration",
101         "org.eclipse.jetty.webapp.FragmentConfiguration",
102         "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"
103     } ;
104 
105     // System classes are classes that cannot be replaced by
106     // the web application, and they are *always* loaded via
107     // system classloader.
108     public final static String[] __dftSystemClasses =
109     {
110         "java.",                            // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
111         "javax.",                           // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
112         "org.xml.",                         // needed by javax.xml
113         "org.w3c.",                         // needed by javax.xml
114         "org.eclipse.jetty.jmx.",           // webapp cannot change jmx classes
115         "org.eclipse.jetty.util.annotation.",  // webapp cannot change jmx annotations
116         "org.eclipse.jetty.continuation.",  // webapp cannot change continuation classes
117         "org.eclipse.jetty.jndi.",          // webapp cannot change naming classes
118         "org.eclipse.jetty.jaas.",          // webapp cannot change jaas classes
119         "org.eclipse.jetty.websocket.",     // webapp cannot change / replace websocket classes
120         "org.eclipse.jetty.util.log.",      // webapp should use server log
121         "org.eclipse.jetty.servlet.ServletContextHandler.Decorator", // for CDI / weld use
122         "org.eclipse.jetty.servlet.DefaultServlet", // webapp cannot change default servlets
123         "org.eclipse.jetty.jsp.JettyJspServlet", //webapp cannot change jetty jsp servlet
124         "org.eclipse.jetty.servlets.AsyncGzipFilter" // special case for AsyncGzipFilter
125     } ;
126 
127     // Server classes are classes that are hidden from being
128     // loaded by the web application using system classloader,
129     // so if web application needs to load any of such classes,
130     // it has to include them in its distribution.
131     public final static String[] __dftServerClasses =
132     {
133         "-org.eclipse.jetty.jmx.",          // don't hide jmx classes
134         "-org.eclipse.jetty.util.annotation.", // don't hide jmx annotation
135         "-org.eclipse.jetty.continuation.", // don't hide continuation classes
136         "-org.eclipse.jetty.jndi.",         // don't hide naming classes
137         "-org.eclipse.jetty.jaas.",         // don't hide jaas classes
138         "-org.eclipse.jetty.servlets.",     // don't hide jetty servlets
139         "-org.eclipse.jetty.servlet.DefaultServlet", // don't hide default servlet
140         "-org.eclipse.jetty.jsp.",          //don't hide jsp servlet
141         "-org.eclipse.jetty.servlet.listener.", // don't hide useful listeners
142         "-org.eclipse.jetty.websocket.",    // don't hide websocket classes from webapps (allow webapp to use ones from system classloader)
143         "-org.eclipse.jetty.apache.",       // don't hide jetty apache impls
144         "-org.eclipse.jetty.util.log.",     // don't hide server log 
145         "-org.eclipse.jetty.servlet.ServletContextHandler.Decorator", // don't hide CDI / weld interface  
146         "org.objectweb.asm.",               // hide asm used by jetty
147         "org.eclipse.jdt.",                 // hide jdt used by jetty
148         "org.eclipse.jetty."                // hide other jetty classes
149     } ;
150 
151     private final List<String> _configurationClasses = new ArrayList<>();
152     private ClasspathPattern _systemClasses = null;
153     private ClasspathPattern _serverClasses = null;
154 
155     private final List<Configuration> _configurations = new ArrayList<>();
156     private String _defaultsDescriptor=WEB_DEFAULTS_XML;
157     private String _descriptor=null;
158     private final List<String> _overrideDescriptors = new ArrayList<>();
159     private boolean _distributable=false;
160     private boolean _extractWAR=true;
161     private boolean _copyDir=false;
162     private boolean _copyWebInf=false;
163     private boolean _logUrlOnStart =false;
164     private boolean _parentLoaderPriority= Boolean.getBoolean("org.eclipse.jetty.server.webapp.parentLoaderPriority");
165     private PermissionCollection _permissions;
166 
167     private String[] _contextWhiteList = null;
168 
169     private File _tmpDir;
170     private boolean _persistTmpDir = false;
171  
172     private String _war;
173     private String _extraClasspath;
174     private Throwable _unavailableException;
175 
176     private Map<String, String> _resourceAliases;
177     private boolean _ownClassLoader=false;
178     private boolean _configurationDiscovered=true;
179     private boolean _allowDuplicateFragmentNames = false;
180     private boolean _throwUnavailableOnStartupException = false;
181 
182 
183 
184     private MetaData _metadata=new MetaData();
185 
186     public static WebAppContext getCurrentWebAppContext()
187     {
188         ContextHandler.Context context=ContextHandler.getCurrentContext();
189         if (context!=null)
190         {
191             ContextHandler handler = context.getContextHandler();
192             if (handler instanceof WebAppContext)
193                 return (WebAppContext)handler;
194         }
195         return null;
196     }
197 
198     /* ------------------------------------------------------------ */
199     public WebAppContext()
200     {
201         this(null,null,null,null,null,new ErrorPageErrorHandler(),SESSIONS|SECURITY);
202     }
203 
204     /* ------------------------------------------------------------ */
205     /**
206      * @param contextPath The context path
207      * @param webApp The URL or filename of the webapp directory or war file.
208      */
209     public WebAppContext(String webApp,String contextPath)
210     {
211         this(null,contextPath,null,null,null,new ErrorPageErrorHandler(),SESSIONS|SECURITY);
212         setWar(webApp);
213     }
214 
215     /* ------------------------------------------------------------ */
216     /**
217      * @param parent The parent HandlerContainer.
218      * @param contextPath The context path
219      * @param webApp The URL or filename of the webapp directory or war file.
220      */
221     public WebAppContext(HandlerContainer parent, String webApp, String contextPath)
222     {
223         this(parent,contextPath,null,null,null,new ErrorPageErrorHandler(),SESSIONS|SECURITY);
224         setWar(webApp);
225     }
226 
227     /* ------------------------------------------------------------ */
228 
229     /**
230      * This constructor is used in the geronimo integration.
231      *
232      * @param sessionHandler SessionHandler for this web app
233      * @param securityHandler SecurityHandler for this web app
234      * @param servletHandler ServletHandler for this web app
235      * @param errorHandler ErrorHandler for this web app
236      */
237     public WebAppContext(SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler) 
238     {
239         this(null, null, sessionHandler, securityHandler, servletHandler, errorHandler,0);
240     }
241 
242     /* ------------------------------------------------------------ */
243     /**
244      * This constructor is used in the geronimo integration.
245      *
246      * @param sessionHandler SessionHandler for this web app
247      * @param securityHandler SecurityHandler for this web app
248      * @param servletHandler ServletHandler for this web app
249      * @param errorHandler ErrorHandler for this web app
250      */
251     public WebAppContext(HandlerContainer parent, String contextPath, SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler,int options) 
252     {
253         super(parent, contextPath,sessionHandler, securityHandler, servletHandler, errorHandler,options);
254         _scontext = new Context();
255         setErrorHandler(errorHandler != null ? errorHandler : new ErrorPageErrorHandler());
256         setProtectedTargets(__dftProtectedTargets);
257     }
258 
259     /* ------------------------------------------------------------ */
260     /**
261      * @param servletContextName The servletContextName to set.
262      */
263     @Override
264     public void setDisplayName(String servletContextName)
265     {
266         super.setDisplayName(servletContextName);
267         ClassLoader cl = getClassLoader();
268         if (cl!=null && cl instanceof WebAppClassLoader && servletContextName!=null)
269             ((WebAppClassLoader)cl).setName(servletContextName);
270     }
271 
272     /* ------------------------------------------------------------ */
273     /** Get an exception that caused the webapp to be unavailable
274      * @return A throwable if the webapp is unavailable or null
275      */
276     public Throwable getUnavailableException()
277     {
278         return _unavailableException;
279     }
280 
281 
282     /* ------------------------------------------------------------ */
283     /** Set Resource Alias.
284      * Resource aliases map resource uri's within a context.
285      * They may optionally be used by a handler when looking for
286      * a resource.
287      * @param alias
288      * @param uri
289      */
290     public void setResourceAlias(String alias, String uri)
291     {
292         if (_resourceAliases == null)
293             _resourceAliases= new HashMap<String, String>(5);
294         _resourceAliases.put(alias, uri);
295     }
296 
297     /* ------------------------------------------------------------ */
298     public Map<String, String> getResourceAliases()
299     {
300         if (_resourceAliases == null)
301             return null;
302         return _resourceAliases;
303     }
304 
305     /* ------------------------------------------------------------ */
306     public void setResourceAliases(Map<String, String> map)
307     {
308         _resourceAliases = map;
309     }
310 
311     /* ------------------------------------------------------------ */
312     public String getResourceAlias(String path)
313     {
314         if (_resourceAliases == null)
315             return null;
316         String alias = _resourceAliases.get(path);
317 
318         int slash=path.length();
319         while (alias==null)
320         {
321             slash=path.lastIndexOf("/",slash-1);
322             if (slash<0)
323                 break;
324             String match=_resourceAliases.get(path.substring(0,slash+1));
325             if (match!=null)
326                 alias=match+path.substring(slash+1);
327         }
328         return alias;
329     }
330 
331     /* ------------------------------------------------------------ */
332     public String removeResourceAlias(String alias)
333     {
334         if (_resourceAliases == null)
335             return null;
336         return _resourceAliases.remove(alias);
337     }
338 
339     /* ------------------------------------------------------------ */
340     /* (non-Javadoc)
341      * @see org.eclipse.jetty.server.server.handler.ContextHandler#setClassLoader(java.lang.ClassLoader)
342      */
343     @Override
344     public void setClassLoader(ClassLoader classLoader)
345     {
346         super.setClassLoader(classLoader);
347 
348 //        if ( !(classLoader instanceof WebAppClassLoader) )
349 //        {
350 //            LOG.info("NOTE: detected a classloader which is not an instance of WebAppClassLoader being set on WebAppContext, some typical class and resource locations may be missing on: " + toString() );
351 //        }
352 
353         if (classLoader!=null && classLoader instanceof WebAppClassLoader && getDisplayName()!=null)
354             ((WebAppClassLoader)classLoader).setName(getDisplayName());
355     }
356 
357     /* ------------------------------------------------------------ */
358     @Override
359     public Resource getResource(String uriInContext) throws MalformedURLException
360     {
361         if (uriInContext==null || !uriInContext.startsWith(URIUtil.SLASH))
362             throw new MalformedURLException(uriInContext);
363 
364         IOException ioe= null;
365         Resource resource= null;
366         int loop=0;
367         while (uriInContext!=null && loop++<100)
368         {
369             try
370             {
371                 resource= super.getResource(uriInContext);
372                 if (resource != null && resource.exists())
373                     return resource;
374 
375                 uriInContext = getResourceAlias(uriInContext);
376             }
377             catch (IOException e)
378             {
379                 LOG.ignore(e);
380                 if (ioe==null)
381                     ioe= e;
382             }
383         }
384 
385         if (ioe != null && ioe instanceof MalformedURLException)
386             throw (MalformedURLException)ioe;
387 
388         return resource;
389     }
390 
391 
392     /* ------------------------------------------------------------ */
393     /** Is the context Automatically configured.
394      *
395      * @return true if configuration discovery.
396      */
397     public boolean isConfigurationDiscovered()
398     {
399         return _configurationDiscovered;
400     }
401 
402     /* ------------------------------------------------------------ */
403     /** Set the configuration discovery mode.
404      * If configuration discovery is set to true, then the JSR315
405      * servlet 3.0 discovered configuration features are enabled.
406      * These are:<ul>
407      * <li>Web Fragments</li>
408      * <li>META-INF/resource directories</li>
409      * </ul>
410      * @param discovered true if configuration discovery is enabled for automatic configuration from the context
411      */
412     public void setConfigurationDiscovered(boolean discovered)
413     {
414         _configurationDiscovered = discovered;
415     }
416 
417     /* ------------------------------------------------------------ */
418     /** Pre configure the web application.
419      * <p>
420      * The method is normally called from {@link #start()}. It performs
421      * the discovery of the configurations to be applied to this context,
422      * specifically:<ul>
423      * <li>Instantiate the {@link Configuration} instances with a call to {@link #loadConfigurations()}.
424      * <li>Setup the default System classes by calling {@link #loadSystemClasses()}
425      * <li>Setup the default Server classes by calling <code>loadServerClasses()</code>
426      * <li>Instantiates a classload (if one is not already set)
427      * <li>Calls the {@link Configuration#preConfigure(WebAppContext)} method of all
428      * Configuration instances.
429      * </ul>
430      * @throws Exception
431      */
432     public void preConfigure() throws Exception
433     {
434         // Setup configurations
435         loadConfigurations();
436 
437         // Setup system classes
438         loadSystemClasses();
439 
440         // Setup server classes
441         loadServerClasses();
442 
443         // Configure classloader
444         _ownClassLoader=false;
445         if (getClassLoader()==null)
446         {
447             WebAppClassLoader classLoader = new WebAppClassLoader(this);
448             setClassLoader(classLoader);
449             _ownClassLoader=true;
450         }
451 
452         if (LOG.isDebugEnabled())
453         {
454             ClassLoader loader = getClassLoader();
455             LOG.debug("Thread Context classloader {}",loader);
456             loader=loader.getParent();
457             while(loader!=null)
458             {
459                 LOG.debug("Parent class loader: {} ",loader);
460                 loader=loader.getParent();
461             }
462         }
463 
464         // Prepare for configuration
465         for (Configuration configuration : _configurations)
466         {
467             LOG.debug("preConfigure {} with {}",this,configuration);
468             configuration.preConfigure(this);
469         }
470     }
471 
472     /* ------------------------------------------------------------ */
473     public void configure() throws Exception
474     {
475         // Configure webapp
476         for (Configuration configuration : _configurations)
477         {
478             LOG.debug("configure {} with {}",this,configuration);
479             configuration.configure(this);
480         }
481     }
482 
483     /* ------------------------------------------------------------ */
484     public void postConfigure() throws Exception
485     {
486         // Clean up after configuration
487         for (Configuration configuration : _configurations)
488         {
489             LOG.debug("postConfigure {} with {}",this,configuration);
490             configuration.postConfigure(this);
491         }
492     }
493 
494     /* ------------------------------------------------------------ */
495     /*
496      * @see org.eclipse.thread.AbstractLifeCycle#doStart()
497      */
498     @Override
499     protected void doStart() throws Exception
500     {
501         try
502         {
503             _metadata.setAllowDuplicateFragmentNames(isAllowDuplicateFragmentNames());
504             preConfigure();
505             super.doStart();
506             postConfigure();
507 
508             if (isLogUrlOnStart())
509                 dumpUrl();
510         }
511         catch (Exception e)
512         {
513             //start up of the webapp context failed, make sure it is not started
514             LOG.warn("Failed startup of context "+this, e);
515             _unavailableException=e;
516             setAvailable(false);
517             if (isThrowUnavailableOnStartupException())
518                 throw e;
519         }
520     }
521 
522     /* ------------------------------------------------------------ */
523     /*
524      * @see org.eclipse.thread.AbstractLifeCycle#doStop()
525      */
526     @Override
527     protected void doStop() throws Exception
528     {
529         super.doStop();
530 
531         try
532         {
533             for (int i=_configurations.size();i-->0;)
534                 _configurations.get(i).deconfigure(this);
535 
536             if (_metadata != null)
537                 _metadata.clear();
538             _metadata=new MetaData();
539 
540         }
541         finally
542         {
543             if (_ownClassLoader)
544                 setClassLoader(null);
545 
546             setAvailable(true);
547             _unavailableException=null;
548         }
549     }
550 
551     /* ------------------------------------------------------------ */
552     @Override
553     public void destroy()
554     {
555         // Prepare for configuration
556         MultiException mx=new MultiException();
557         if (_configurations!=null)
558         {
559             for (int i=_configurations.size();i-->0;)
560             {
561                 try
562                 {
563                     _configurations.get(i).destroy(this);
564                 }
565                 catch(Exception e)
566                 {
567                     mx.add(e);
568                 }
569             }
570         }
571         _configurations.clear();
572         super.destroy();
573         mx.ifExceptionThrowRuntime();
574     }
575 
576 
577     /* ------------------------------------------------------------ */
578     /*
579      * Dumps the current web app name and URL to the log
580      */
581     private void dumpUrl()
582     {
583         Connector[] connectors = getServer().getConnectors();
584         for (int i=0;i<connectors.length;i++)
585         {
586             String displayName = getDisplayName();
587             if (displayName == null)
588                 displayName = "WebApp@"+connectors.hashCode();
589 
590             LOG.info(displayName + " at http://" + connectors[i].toString() + getContextPath());
591         }
592     }
593 
594     /* ------------------------------------------------------------ */
595     /**
596      * @return Returns the configurations.
597      */
598     @ManagedAttribute(value="configuration classes used to configure webapp", readonly=true)
599     public String[] getConfigurationClasses()
600     {
601         return _configurationClasses.toArray(new String[_configurationClasses.size()]);
602     }
603 
604     /* ------------------------------------------------------------ */
605     /**
606      * @return Returns the configurations.
607      */
608     public Configuration[] getConfigurations()
609     {
610         return _configurations.toArray(new Configuration[_configurations.size()]);
611     }
612 
613     /* ------------------------------------------------------------ */
614     /**
615      * The default descriptor is a web.xml format file that is applied to the context before the standard WEB-INF/web.xml
616      * @return Returns the defaultsDescriptor.
617      */
618     @ManagedAttribute(value="default web.xml deascriptor applied before standard web.xml", readonly=true)
619     public String getDefaultsDescriptor()
620     {
621         return _defaultsDescriptor;
622     }
623 
624     /* ------------------------------------------------------------ */
625     /**
626      * The override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml
627      * @return Returns the Override Descriptor.
628      */
629     public String getOverrideDescriptor()
630     {
631         if (_overrideDescriptors.size()!=1)
632             return null;
633         return _overrideDescriptors.get(0);
634     }
635 
636     /* ------------------------------------------------------------ */
637     /**
638      * An override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml
639      * @return Returns the Override Descriptor list
640      */
641     @ManagedAttribute(value="web.xml deascriptors applied after standard web.xml", readonly=true)
642     public List<String> getOverrideDescriptors()
643     {
644         return Collections.unmodifiableList(_overrideDescriptors);
645     }
646 
647     /* ------------------------------------------------------------ */
648     /**
649      * @return Returns the permissions.
650      */
651     @Override
652     public PermissionCollection getPermissions()
653     {
654         return _permissions;
655     }
656 
657     /* ------------------------------------------------------------ */
658     /**
659      * @see #setServerClasses(String[])
660      * @return Returns the serverClasses.
661      */
662     @ManagedAttribute(value="classes and packages hidden by the context classloader", readonly=true)
663     public String[] getServerClasses()
664     {
665         if (_serverClasses == null)
666             loadServerClasses();
667 
668         return _serverClasses.getPatterns();
669     }
670 
671     /* ------------------------------------------------------------ */
672     /** Add to the list of Server classes.
673      * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) 
674      * or a qualified package name ending with '.' (eg com.foo.).  If the class 
675      * or package has '-' it is excluded from the server classes and order is thus
676      * important when added system class patterns. This argument may also be a comma 
677      * separated list of classOrPackage patterns.
678      * @see #setServerClasses(String[])
679      * @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
680      */
681     public void addServerClass(String classOrPackage)
682     {
683         if (_serverClasses == null)
684             loadServerClasses();
685 
686         _serverClasses.addPattern(classOrPackage);
687     }
688 
689     /* ------------------------------------------------------------ */
690     /** Prepend to the list of Server classes.
691      * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) 
692      * or a qualified package name ending with '.' (eg com.foo.).  If the class 
693      * or package has '-' it is excluded from the server classes and order is thus
694      * important when added system class patterns. This argument may also be a comma 
695      * separated list of classOrPackage patterns.
696      * @see #setServerClasses(String[])
697      * @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
698      */
699     public void prependServerClass(String classOrPackage)
700     {
701         if (_serverClasses == null)
702             loadServerClasses();
703 
704         _serverClasses.prependPattern(classOrPackage);
705     }
706 
707     /* ------------------------------------------------------------ */
708     /**
709      * @see #setSystemClasses(String[])
710      * @return Returns the systemClasses.
711      */
712     @ManagedAttribute(value="classes and packages given priority by context classloader", readonly=true)
713     public String[] getSystemClasses()
714     {
715         if (_systemClasses == null)
716             loadSystemClasses();
717 
718         return _systemClasses.getPatterns();
719     }
720 
721     /* ------------------------------------------------------------ */
722     /** Add to the list of System classes.
723      * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) 
724      * or a qualified package name ending with '.' (eg com.foo.).  If the class 
725      * or package has '-' it is excluded from the system classes and order is thus
726      * important when added system class patterns.  This argument may also be a comma 
727      * separated list of classOrPackage patterns.
728      * @see #setSystemClasses(String[])
729      * @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
730      */
731     public void addSystemClass(String classOrPackage)
732     {
733         if (_systemClasses == null)
734             loadSystemClasses();
735 
736         _systemClasses.addPattern(classOrPackage);
737     }
738 
739 
740     /* ------------------------------------------------------------ */
741     /** Prepend to the list of System classes.
742      * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) 
743      * or a qualified package name ending with '.' (eg com.foo.).  If the class 
744      * or package has '-' it is excluded from the system classes and order is thus
745      * important when added system class patterns.This argument may also be a comma 
746      * separated list of classOrPackage patterns.
747      * @see #setSystemClasses(String[])
748      * @see <a href="http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html">Jetty Documentation: Classloading</a>
749      */
750     public void prependSystemClass(String classOrPackage)
751     {
752         if (_systemClasses == null)
753             loadSystemClasses();
754 
755         _systemClasses.prependPattern(classOrPackage);
756     }
757 
758     /* ------------------------------------------------------------ */
759     @Override
760     public boolean isServerClass(String name)
761     {
762         if (_serverClasses == null)
763             loadServerClasses();
764 
765         return _serverClasses.match(name);
766     }
767 
768     /* ------------------------------------------------------------ */
769     @Override
770     public boolean isSystemClass(String name)
771     {
772         if (_systemClasses == null)
773             loadSystemClasses();
774 
775         return _systemClasses.match(name);
776     }
777 
778     /* ------------------------------------------------------------ */
779     protected void loadSystemClasses()
780     {
781         if (_systemClasses != null)
782             return;
783 
784         //look for a Server attribute with the list of System classes
785         //to apply to every web application. If not present, use our defaults.
786         Server server = getServer();
787         if (server != null)
788         {
789             Object systemClasses = server.getAttribute(SERVER_SYS_CLASSES);
790             if (systemClasses != null && systemClasses instanceof String[])
791                 _systemClasses = new ClasspathPattern((String[])systemClasses);
792         }
793 
794         if (_systemClasses == null)
795             _systemClasses = new ClasspathPattern(__dftSystemClasses);
796     }
797 
798     /* ------------------------------------------------------------ */
799     private void loadServerClasses()
800     {
801         if (_serverClasses != null)
802         {
803             return;
804         }
805 
806         // look for a Server attribute with the list of Server classes
807         // to apply to every web application. If not present, use our defaults.
808         Server server = getServer();
809         if (server != null)
810         {
811             Object serverClasses = server.getAttribute(SERVER_SRV_CLASSES);
812             if (serverClasses != null && serverClasses instanceof String[])
813             {
814                 _serverClasses = new ClasspathPattern((String[])serverClasses);
815             }
816         }
817 
818         if (_serverClasses == null)
819         {
820             _serverClasses = new ClasspathPattern(__dftServerClasses);
821         }
822     }
823 
824     /* ------------------------------------------------------------ */
825     /**
826      * @return Returns the war as a file or URL string (Resource)
827      */
828     @ManagedAttribute(value="war file location", readonly=true)
829     public String getWar()
830     {
831         if (_war==null)
832             _war=getResourceBase();
833         return _war;
834     }
835 
836     /* ------------------------------------------------------------ */
837     public Resource getWebInf() throws IOException
838     {
839         if (super.getBaseResource() == null)
840             return null;
841 
842         // Iw there a WEB-INF directory?
843         Resource web_inf= super.getBaseResource().addPath("WEB-INF/");
844         if (!web_inf.exists() || !web_inf.isDirectory())
845             return null;
846 
847         return web_inf;
848     }
849 
850     /* ------------------------------------------------------------ */
851     /**
852      * @return Returns the distributable.
853      */
854     @ManagedAttribute("web application distributable")
855     public boolean isDistributable()
856     {
857         return _distributable;
858     }
859 
860     /* ------------------------------------------------------------ */
861     /**
862      * @return Returns the extractWAR.
863      */
864     @ManagedAttribute(value="extract war", readonly=true)
865     public boolean isExtractWAR()
866     {
867         return _extractWAR;
868     }
869 
870     /* ------------------------------------------------------------ */
871     /**
872      * @return True if the webdir is copied (to allow hot replacement of jars on windows)
873      */
874     @ManagedAttribute(value="webdir copied on deploy (allows hot replacement on windows)", readonly=true)
875     public boolean isCopyWebDir()
876     {
877         return _copyDir;
878     }
879 
880     /* ------------------------------------------------------------ */
881     /**
882      * @return True if the web-inf lib and classes directories are copied (to allow hot replacement of jars on windows)
883      */
884     public boolean isCopyWebInf()
885     {
886         return _copyWebInf;
887     }
888 
889     /* ------------------------------------------------------------ */
890     /**
891      * @return True if the classloader should delegate first to the parent
892      * classloader (standard java behaviour) or false if the classloader
893      * should first try to load from WEB-INF/lib or WEB-INF/classes (servlet
894      * spec recommendation). Default is false or can be set by the system 
895      * property org.eclipse.jetty.server.webapp.parentLoaderPriority
896      */
897     @Override
898     @ManagedAttribute(value="parent classloader given priority", readonly=true)
899     public boolean isParentLoaderPriority()
900     {
901         return _parentLoaderPriority;
902     }
903 
904 
905     /* ------------------------------------------------------------ */
906     public static String[] getDefaultConfigurationClasses ()
907     {
908         return DEFAULT_CONFIGURATION_CLASSES;
909     }
910 
911     /* ------------------------------------------------------------ */
912     public String[] getDefaultServerClasses ()
913     {
914         return __dftServerClasses;
915     }
916 
917     /* ------------------------------------------------------------ */
918     public String[] getDefaultSystemClasses ()
919     {
920         return __dftSystemClasses;
921     }
922 
923     /* ------------------------------------------------------------ */
924     protected void loadConfigurations()
925         throws Exception
926     {
927         //if the configuration instances have been set explicitly, use them
928         if (_configurations.size()>0)
929             return;
930         
931         if (_configurationClasses.size()==0)
932             _configurationClasses.addAll(Configuration.ClassList.serverDefault(getServer()));
933         for (String configClass : _configurationClasses)
934             _configurations.add((Configuration)Loader.loadClass(this.getClass(), configClass).newInstance());
935     }
936 
937     /* ------------------------------------------------------------ */
938     @Override
939     public String toString()
940     {
941         if (_war!=null)
942         {
943             String war=_war;
944             if (war.indexOf("/webapps/")>=0)
945                 war=war.substring(war.indexOf("/webapps/")+8);
946             return super.toString()+"{"+war+"}";
947         }
948         return super.toString();
949     }
950 
951     /* ------------------------------------------------------------ */
952     /**
953      * @param configurations The configuration class names.  If setConfigurations is not called
954      * these classes are used to create a configurations array.
955      */
956     public void setConfigurationClasses(String[] configurations)
957     {
958         if (isStarted())
959             throw new IllegalStateException();
960         _configurationClasses.clear();
961         if (configurations!=null)
962             _configurationClasses.addAll(Arrays.asList(configurations));
963         _configurations.clear();
964     }
965 
966     public void setConfigurationClasses(List<String> configurations)
967     {
968         setConfigurationClasses(configurations.toArray(new String[configurations.size()]));
969     }
970     
971     /* ------------------------------------------------------------ */
972     /**
973      * @param configurations The configurations to set.
974      */
975     public void setConfigurations(Configuration[] configurations)
976     {
977         if (isStarted())
978             throw new IllegalStateException();
979         _configurations.clear();
980         if (configurations!=null)
981             _configurations.addAll(Arrays.asList(configurations));
982     }
983 
984     /* ------------------------------------------------------------ */
985     /**
986      * The default descriptor is a web.xml format file that is applied to the context before the standard WEB-INF/web.xml
987      * @param defaultsDescriptor The defaultsDescriptor to set.
988      */
989     public void setDefaultsDescriptor(String defaultsDescriptor)
990     {
991         _defaultsDescriptor = defaultsDescriptor;
992     }
993 
994     /* ------------------------------------------------------------ */
995     /**
996      * The override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml
997      * @param overrideDescriptor The overrideDescritpor to set.
998      */
999     public void setOverrideDescriptor(String overrideDescriptor)
1000     {
1001         _overrideDescriptors.clear();
1002         _overrideDescriptors.add(overrideDescriptor);
1003     }
1004 
1005     /* ------------------------------------------------------------ */
1006     /**
1007      * The override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml
1008      * @param overrideDescriptors The overrideDescriptors (file or URL) to set.
1009      */
1010     public void setOverrideDescriptors(List<String> overrideDescriptors)
1011     {
1012         _overrideDescriptors.clear();
1013         _overrideDescriptors.addAll(overrideDescriptors);
1014     }
1015 
1016     /* ------------------------------------------------------------ */
1017     /**
1018      * The override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml
1019      * @param overrideDescriptor The overrideDescriptor (file or URL) to add.
1020      */
1021     public void addOverrideDescriptor(String overrideDescriptor)
1022     {
1023         _overrideDescriptors.add(overrideDescriptor);
1024     }
1025 
1026     /* ------------------------------------------------------------ */
1027     /**
1028      * @return the web.xml descriptor to use. If set to null, WEB-INF/web.xml is used if it exists.
1029      */
1030     @ManagedAttribute(value="standard web.xml descriptor", readonly=true)
1031     public String getDescriptor()
1032     {
1033         return _descriptor;
1034     }
1035 
1036     /* ------------------------------------------------------------ */
1037     /**
1038      * @param descriptor the web.xml descriptor to use. If set to null, WEB-INF/web.xml is used if it exists.
1039      */
1040     public void setDescriptor(String descriptor)
1041     {
1042         _descriptor=descriptor;
1043     }
1044 
1045     /* ------------------------------------------------------------ */
1046     /**
1047      * @param distributable The distributable to set.
1048      */
1049     public void setDistributable(boolean distributable)
1050     {
1051         this._distributable = distributable;
1052     }
1053 
1054     /* ------------------------------------------------------------ */
1055     @Override
1056     public void setEventListeners(EventListener[] eventListeners)
1057     {
1058         if (_sessionHandler!=null)
1059             _sessionHandler.clearEventListeners();
1060 
1061         super.setEventListeners(eventListeners);
1062     }
1063 
1064     /* ------------------------------------------------------------ */
1065     /** Add EventListener
1066      * Convenience method that calls {@link #setEventListeners(EventListener[])}
1067      * @param listener
1068      */
1069     @Override
1070     public void addEventListener(EventListener listener)
1071     {
1072         super.addEventListener(listener);
1073         if ((listener instanceof HttpSessionActivationListener)
1074             || (listener instanceof HttpSessionAttributeListener)
1075             || (listener instanceof HttpSessionBindingListener)
1076             || (listener instanceof HttpSessionListener)
1077             || (listener instanceof HttpSessionIdListener))
1078         {
1079             if (_sessionHandler!=null)
1080                 _sessionHandler.addEventListener(listener);
1081         }
1082     }
1083     
1084     @Override
1085     public void removeEventListener(EventListener listener)
1086     {
1087         super.removeEventListener(listener);
1088         if ((listener instanceof HttpSessionActivationListener)
1089             || (listener instanceof HttpSessionAttributeListener)
1090             || (listener instanceof HttpSessionBindingListener)
1091             || (listener instanceof HttpSessionListener)
1092             || (listener instanceof HttpSessionIdListener))
1093         {
1094             if (_sessionHandler!=null)
1095                 _sessionHandler.removeEventListener(listener);
1096         }
1097         
1098     }
1099 
1100 
1101     /* ------------------------------------------------------------ */
1102     /**
1103      * @param extractWAR True if war files are extracted
1104      */
1105     public void setExtractWAR(boolean extractWAR)
1106     {
1107         _extractWAR = extractWAR;
1108     }
1109 
1110     /* ------------------------------------------------------------ */
1111     /**
1112      * @param copy True if the webdir is copied (to allow hot replacement of jars)
1113      */
1114     public void setCopyWebDir(boolean copy)
1115     {
1116         _copyDir = copy;
1117     }
1118 
1119     /* ------------------------------------------------------------ */
1120     /**
1121      * @param copyWebInf True if the web-inf lib and classes directories are copied (to allow hot replacement of jars on windows)
1122      */
1123     public void setCopyWebInf(boolean copyWebInf)
1124     {
1125         _copyWebInf = copyWebInf;
1126     }
1127 
1128     /* ------------------------------------------------------------ */
1129     /**
1130      * @param java2compliant True if the classloader should delegate first to the parent
1131      * classloader (standard java behaviour) or false if the classloader
1132      * should first try to load from WEB-INF/lib or WEB-INF/classes (servlet
1133      * spec recommendation).  Default is false or can be set by the system 
1134      * property org.eclipse.jetty.server.webapp.parentLoaderPriority
1135      */
1136     public void setParentLoaderPriority(boolean java2compliant)
1137     {
1138         _parentLoaderPriority = java2compliant;
1139     }
1140 
1141     /* ------------------------------------------------------------ */
1142     /**
1143      * @param permissions The permissions to set.
1144      */
1145     public void setPermissions(PermissionCollection permissions)
1146     {
1147         _permissions = permissions;
1148     }
1149 
1150     /**
1151      * Set the context white list
1152      *
1153      * In certain circumstances you want may want to deny access of one webapp from another
1154      * when you may not fully trust the webapp.  Setting this white list will enable a
1155      * check when a servlet called getContext(String), validating that the uriInPath
1156      * for the given webapp has been declaratively allows access to the context.
1157      * @param contextWhiteList
1158      */
1159     public void setContextWhiteList(String[] contextWhiteList)
1160     {
1161         _contextWhiteList = contextWhiteList;
1162     }
1163 
1164     /* ------------------------------------------------------------ */
1165     /**
1166      * Set the server classes patterns.
1167      * <p>
1168      * Server classes/packages are classes used to implement the server and are hidden
1169      * from the context.  If the context needs to load these classes, it must have its
1170      * own copy of them in WEB-INF/lib or WEB-INF/classes.
1171      * A class pattern is a string of one of the forms:<dl>
1172      * <dt>org.package.Classname</dt><dd>Match a specific class</dd>
1173      * <dt>org.package.</dt><dd>Match a specific package hierarchy</dd>
1174      * <dt>-org.package.Classname</dt><dd>Exclude a specific class</dd>
1175      * <dt>-org.package.</dt><dd>Exclude a specific package hierarchy</dd>
1176      * </dl>
1177      * @param serverClasses The serverClasses to set.
1178      */
1179     public void setServerClasses(String[] serverClasses)
1180     {
1181         _serverClasses = new ClasspathPattern(serverClasses);
1182     }
1183 
1184     /* ------------------------------------------------------------ */
1185     /**
1186      * Set the system classes patterns.
1187      * <p>
1188      * System classes/packages are classes provided by the JVM and that
1189      * cannot be replaced by classes of the same name from WEB-INF,
1190      * regardless of the value of {@link #setParentLoaderPriority(boolean)}.
1191      * A class pattern is a string of one of the forms:<dl>
1192      * <dt>org.package.Classname</dt><dd>Match a specific class</dd>
1193      * <dt>org.package.</dt><dd>Match a specific package hierarchy</dd>
1194      * <dt>-org.package.Classname</dt><dd>Exclude a specific class</dd>
1195      * <dt>-org.package.</dt><dd>Exclude a specific package hierarchy</dd>
1196      * </dl>
1197      * @param systemClasses The systemClasses to set.
1198      */
1199     public void setSystemClasses(String[] systemClasses)
1200     {
1201         _systemClasses = new ClasspathPattern(systemClasses);
1202     }
1203 
1204 
1205     /* ------------------------------------------------------------ */
1206     /** Set temporary directory for context.
1207      * The javax.servlet.context.tempdir attribute is also set.
1208      * @param dir Writable temporary directory.
1209      */
1210     public void setTempDirectory(File dir)
1211     {
1212         if (isStarted())
1213             throw new IllegalStateException("Started");
1214 
1215         if (dir!=null)
1216         {
1217             try{dir=new File(dir.getCanonicalPath());}
1218             catch (IOException e){LOG.warn(Log.EXCEPTION,e);}
1219         }
1220 
1221         _tmpDir=dir;
1222         setAttribute(TEMPDIR,_tmpDir);            
1223     }
1224 
1225     /* ------------------------------------------------------------ */
1226     @ManagedAttribute(value="temporary directory location", readonly=true)
1227     public File getTempDirectory ()
1228     {
1229         return _tmpDir;
1230     }
1231 
1232     /**
1233      * If true the temp directory for this 
1234      * webapp will be kept when the webapp stops. Otherwise,
1235      * it will be deleted.
1236      * 
1237      * @param delete
1238      */
1239     public void setPersistTempDirectory(boolean persist)
1240     {
1241         _persistTmpDir = persist;
1242     }
1243     
1244     /**
1245      * @return
1246      */
1247     public boolean isPersistTempDirectory()
1248     {
1249         return _persistTmpDir;
1250     }
1251     
1252     
1253     /* ------------------------------------------------------------ */
1254     /**
1255      * @param war The war to set as a file name or URL
1256      */
1257     public void setWar(String war)
1258     {
1259         _war = war;
1260     }
1261 
1262     /* ------------------------------------------------------------ */
1263     /**
1264      * @return Comma or semicolon separated path of filenames or URLs
1265      * pointing to directories or jar files. Directories should end
1266      * with '/'.
1267      */
1268     @Override
1269     @ManagedAttribute(value="extra classpath for context classloader", readonly=true)
1270     public String getExtraClasspath()
1271     {
1272         return _extraClasspath;
1273     }
1274 
1275     /* ------------------------------------------------------------ */
1276     /**
1277      * @param extraClasspath Comma or semicolon separated path of filenames or URLs
1278      * pointing to directories or jar files. Directories should end
1279      * with '/'.
1280      */
1281     public void setExtraClasspath(String extraClasspath)
1282     {
1283         _extraClasspath=extraClasspath;
1284     }
1285 
1286     /* ------------------------------------------------------------ */
1287     public boolean isLogUrlOnStart()
1288     {
1289         return _logUrlOnStart;
1290     }
1291 
1292     /* ------------------------------------------------------------ */
1293     /**
1294      * Sets whether or not the web app name and URL is logged on startup
1295      *
1296      * @param logOnStart whether or not the log message is created
1297      */
1298     public void setLogUrlOnStart(boolean logOnStart)
1299     {
1300         this._logUrlOnStart = logOnStart;
1301     }
1302 
1303     /* ------------------------------------------------------------ */
1304     @Override
1305     public void setServer(Server server)
1306     {
1307         super.setServer(server);
1308     }
1309 
1310     /* ------------------------------------------------------------ */
1311     public boolean isAllowDuplicateFragmentNames()
1312     {
1313         return _allowDuplicateFragmentNames;
1314     }
1315 
1316     /* ------------------------------------------------------------ */
1317     public void setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames)
1318     {
1319         _allowDuplicateFragmentNames = allowDuplicateFragmentNames;
1320     }
1321 
1322     /* ------------------------------------------------------------ */
1323     public void setThrowUnavailableOnStartupException (boolean throwIfStartupException) {
1324         _throwUnavailableOnStartupException = throwIfStartupException;
1325     }
1326 
1327     /* ------------------------------------------------------------ */
1328     public boolean isThrowUnavailableOnStartupException () {
1329         return _throwUnavailableOnStartupException;
1330     }
1331 
1332     /* ------------------------------------------------------------ */
1333     @Override
1334     protected void startContext()
1335         throws Exception
1336     {
1337         configure();
1338 
1339         //resolve the metadata
1340         _metadata.resolve(this);
1341 
1342         startWebapp();
1343     }
1344 
1345     /* ------------------------------------------------------------ */
1346     protected void startWebapp()
1347         throws Exception
1348     {
1349         super.startContext();
1350     }
1351     
1352     /* ------------------------------------------------------------ */    
1353     @Override
1354     public Set<String> setServletSecurity(Dynamic registration, ServletSecurityElement servletSecurityElement)
1355     {
1356         Set<String> unchangedURLMappings = new HashSet<String>();
1357         //From javadoc for ServletSecurityElement:
1358         /*
1359         If a URL pattern of this ServletRegistration is an exact target of a security-constraint that 
1360         was established via the portable deployment descriptor, then this method does not change the 
1361         security-constraint for that pattern, and the pattern will be included in the return value.
1362 
1363         If a URL pattern of this ServletRegistration is an exact target of a security constraint 
1364         that was established via the ServletSecurity annotation or a previous call to this method, 
1365         then this method replaces the security constraint for that pattern.
1366 
1367         If a URL pattern of this ServletRegistration is neither the exact target of a security constraint 
1368         that was established via the ServletSecurity annotation or a previous call to this method, 
1369         nor the exact target of a security-constraint in the portable deployment descriptor, then 
1370         this method establishes the security constraint for that pattern from the argument ServletSecurityElement. 
1371          */
1372 
1373         Collection<String> pathMappings = registration.getMappings();
1374         if (pathMappings != null)
1375         {
1376             ConstraintSecurityHandler.createConstraint(registration.getName(), servletSecurityElement);
1377 
1378             for (String pathSpec:pathMappings)
1379             {
1380                 Origin origin = getMetaData().getOrigin("constraint.url."+pathSpec);
1381                
1382                 switch (origin)
1383                 {
1384                     case NotSet:
1385                     {
1386                         //No mapping for this url already established
1387                         List<ConstraintMapping> mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement);
1388                         for (ConstraintMapping m:mappings)
1389                             ((ConstraintAware)getSecurityHandler()).addConstraintMapping(m);
1390                         ((ConstraintAware)getSecurityHandler()).checkPathsWithUncoveredHttpMethods();
1391                         getMetaData().setOriginAPI("constraint.url."+pathSpec);
1392                         break;
1393                     }
1394                     case WebXml:
1395                     case WebDefaults:
1396                     case WebOverride:
1397                     case WebFragment:
1398                     {
1399                         //a mapping for this url was created in a descriptor, which overrides everything
1400                         unchangedURLMappings.add(pathSpec);
1401                         break;
1402                     }
1403                     case Annotation:
1404                     case API:
1405                     {
1406                         //mapping established via an annotation or by previous call to this method,
1407                         //replace the security constraint for this pattern
1408                         List<ConstraintMapping> constraintMappings = ConstraintSecurityHandler.removeConstraintMappingsForPath(pathSpec, ((ConstraintAware)getSecurityHandler()).getConstraintMappings());
1409                        
1410                         List<ConstraintMapping> freshMappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement);
1411                         constraintMappings.addAll(freshMappings);
1412                            
1413                         ((ConstraintSecurityHandler)getSecurityHandler()).setConstraintMappings(constraintMappings);
1414                         ((ConstraintAware)getSecurityHandler()).checkPathsWithUncoveredHttpMethods();
1415                         break;
1416                     }
1417                 }
1418             }
1419         }
1420         
1421         return unchangedURLMappings;
1422     }
1423 
1424 
1425 
1426     /* ------------------------------------------------------------ */
1427     public class Context extends ServletContextHandler.Context
1428     {
1429        
1430         /* ------------------------------------------------------------ */
1431         @Override
1432         public void checkListener(Class<? extends EventListener> listener) throws IllegalStateException
1433         {
1434             try
1435             {
1436                 super.checkListener(listener);
1437             }
1438             catch (IllegalArgumentException e)
1439             {
1440                 //not one of the standard servlet listeners, check our extended session listener types
1441                 boolean ok = false;
1442                 for (Class l:SessionHandler.SESSION_LISTENER_TYPES)
1443                 {
1444                     if (l.isAssignableFrom(listener))
1445                     {
1446                         ok = true;
1447                         break;
1448                     }
1449                 }
1450                 if (!ok)
1451                     throw new IllegalArgumentException("Inappropriate listener type "+listener.getName());
1452             }
1453         }
1454 
1455         /* ------------------------------------------------------------ */
1456         @Override
1457         public URL getResource(String path) throws MalformedURLException
1458         {
1459             Resource resource=WebAppContext.this.getResource(path);
1460             if (resource==null || !resource.exists())
1461                 return null;
1462 
1463             // Should we go to the original war?
1464             if (resource.isDirectory() && resource instanceof ResourceCollection && !WebAppContext.this.isExtractWAR())
1465             {
1466                 Resource[] resources = ((ResourceCollection)resource).getResources();
1467                 for (int i=resources.length;i-->0;)
1468                 {
1469                     if (resources[i].getName().startsWith("jar:file"))
1470                         return resources[i].getURL();
1471                 }
1472             }
1473 
1474             return resource.getURL();
1475         }
1476 
1477         /* ------------------------------------------------------------ */
1478         @Override
1479         public ServletContext getContext(String uripath)
1480         {
1481             ServletContext servletContext = super.getContext(uripath);
1482 
1483             if ( servletContext != null && _contextWhiteList != null )
1484             {
1485                 for ( String context : _contextWhiteList )
1486                 {
1487                     if ( context.equals(uripath) )
1488                     {
1489                         return servletContext;
1490                     }
1491                 }
1492 
1493                 return null;
1494             }
1495             else
1496             {
1497                 return servletContext;
1498             }
1499         }
1500         
1501     }
1502 
1503     /* ------------------------------------------------------------ */
1504     public MetaData getMetaData()
1505     {
1506         return _metadata;
1507     }
1508 }