View Javadoc

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