All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.webapp.WebAppContext Maven / Gradle / Ivy

//
//  ========================================================================
//  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.webapp;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.PermissionCollection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration.Dynamic;
import javax.servlet.ServletSecurityElement;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionListener;

import org.eclipse.jetty.security.ConstraintAware;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;

/* ------------------------------------------------------------ */
/** Web Application Context Handler.
 * The WebAppContext handler is an extension of ContextHandler that
 * coordinates the construction and configuration of nested handlers:
 * {@link org.eclipse.jetty.security.ConstraintSecurityHandler}, {@link org.eclipse.jetty.server.session.SessionHandler}
 * and {@link org.eclipse.jetty.servlet.ServletHandler}.
 * The handlers are configured by pluggable configuration classes, with
 * the default being  {@link org.eclipse.jetty.webapp.WebXmlConfiguration} and
 * {@link org.eclipse.jetty.webapp.JettyWebXmlConfiguration}.
 *
 * @org.apache.xbean.XBean description="Creates a servlet web application at a given context from a resource base"
 *
 */
@ManagedObject("Web Application ContextHandler")
public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context
{
    private static final Logger LOG = Log.getLogger(WebAppContext.class);

    public static final String TEMPDIR = "javax.servlet.context.tempdir";
    public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir";
    public final static String WEB_DEFAULTS_XML="org/eclipse/jetty/webapp/webdefault.xml";
    public final static String ERROR_PAGE="org.eclipse.jetty.server.error_page";
    public final static String SERVER_SYS_CLASSES = "org.eclipse.jetty.webapp.systemClasses";
    public final static String SERVER_SRV_CLASSES = "org.eclipse.jetty.webapp.serverClasses";

    private String[] __dftProtectedTargets = {"/web-inf", "/meta-inf"};

    public static String[] DEFAULT_CONFIGURATION_CLASSES =
    {
        "org.eclipse.jetty.webapp.WebInfConfiguration",
        "org.eclipse.jetty.webapp.WebXmlConfiguration",
        "org.eclipse.jetty.webapp.MetaInfConfiguration",
        "org.eclipse.jetty.webapp.FragmentConfiguration",
        "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"
    } ;

    // System classes are classes that cannot be replaced by
    // the web application, and they are *always* loaded via
    // system classloader.
    public final static String[] __dftSystemClasses =
    {
        "java.",                            // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
        "javax.",                           // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
        "org.xml.",                         // needed by javax.xml
        "org.w3c.",                         // needed by javax.xml
        "org.eclipse.jetty.continuation.",  // webapp cannot change continuation classes
        "org.eclipse.jetty.jndi.",          // webapp cannot change naming classes
        "org.eclipse.jetty.jaas.",          // webapp cannot change jaas classes
        "org.eclipse.jetty.websocket.",        // WebSocket is a jetty extension
        "org.eclipse.jetty.websocket.WebSocketServlet", // webapp cannot change WebSocketServlet
        "org.eclipse.jetty.servlet.DefaultServlet" // webapp cannot change default servlets
    } ;

    // Server classes are classes that are hidden from being
    // loaded by the web application using system classloader,
    // so if web application needs to load any of such classes,
    // it has to include them in its distribution.
    public final static String[] __dftServerClasses =
    {
        "-org.eclipse.jetty.continuation.", // don't hide continuation classes
        "-org.eclipse.jetty.jndi.",         // don't hide naming classes
        "-org.eclipse.jetty.jaas.",         // don't hide jaas classes
        "-org.eclipse.jetty.servlets.",     // don't hide jetty servlets
        "-org.eclipse.jetty.websocket.WebSocketServlet", // don't hide WebSocketServlet
        "-org.eclipse.jetty.servlet.DefaultServlet", // don't hide default servlet
        "-org.eclipse.jetty.servlet.listener.", // don't hide useful listeners
        "-org.eclipse.jetty.websocket.",    //not a serverclass, is a systemclass
        "org.eclipse.jetty."                // hide other jetty classes
    } ;

    private final List _configurationClasses = new ArrayList<>();
    private ClasspathPattern _systemClasses = null;
    private ClasspathPattern _serverClasses = null;

    private final List _configurations = new ArrayList<>();
    private String _defaultsDescriptor=WEB_DEFAULTS_XML;
    private String _descriptor=null;
    private final List _overrideDescriptors = new ArrayList<>();
    private boolean _distributable=false;
    private boolean _extractWAR=true;
    private boolean _copyDir=false;
    private boolean _copyWebInf=false;
    private boolean _logUrlOnStart =false;
    private boolean _parentLoaderPriority= Boolean.getBoolean("org.eclipse.jetty.server.webapp.parentLoaderPriority");
    private PermissionCollection _permissions;

    private String[] _contextWhiteList = null;

    private File _tmpDir;
    private String _war;
    private String _extraClasspath;
    private Throwable _unavailableException;

    private Map _resourceAliases;
    private boolean _ownClassLoader=false;
    private boolean _configurationDiscovered=true;
    private boolean _allowDuplicateFragmentNames = false;
    private boolean _throwUnavailableOnStartupException = false;



    private MetaData _metadata=new MetaData();

    public static WebAppContext getCurrentWebAppContext()
    {
        ContextHandler.Context context=ContextHandler.getCurrentContext();
        if (context!=null)
        {
            ContextHandler handler = context.getContextHandler();
            if (handler instanceof WebAppContext)
                return (WebAppContext)handler;
        }
        return null;
    }

    /* ------------------------------------------------------------ */
    public WebAppContext()
    {
        this(null,null,null,null,null,new ErrorPageErrorHandler(),SESSIONS|SECURITY);
    }

    /* ------------------------------------------------------------ */
    /**
     * @param contextPath The context path
     * @param webApp The URL or filename of the webapp directory or war file.
     */
    public WebAppContext(String webApp,String contextPath)
    {
        this(null,contextPath,null,null,null,new ErrorPageErrorHandler(),SESSIONS|SECURITY);
        setWar(webApp);
    }

    /* ------------------------------------------------------------ */
    /**
     * @param parent The parent HandlerContainer.
     * @param contextPath The context path
     * @param webApp The URL or filename of the webapp directory or war file.
     */
    public WebAppContext(HandlerContainer parent, String webApp, String contextPath)
    {
        this(parent,contextPath,null,null,null,new ErrorPageErrorHandler(),SESSIONS|SECURITY);
        setWar(webApp);
    }

    /* ------------------------------------------------------------ */

    /**
     * This constructor is used in the geronimo integration.
     *
     * @param sessionHandler SessionHandler for this web app
     * @param securityHandler SecurityHandler for this web app
     * @param servletHandler ServletHandler for this web app
     * @param errorHandler ErrorHandler for this web app
     */
    public WebAppContext(SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler) 
    {
        this(null, null, sessionHandler, securityHandler, servletHandler, errorHandler,0);
    }

    /* ------------------------------------------------------------ */
    /**
     * This constructor is used in the geronimo integration.
     *
     * @param sessionHandler SessionHandler for this web app
     * @param securityHandler SecurityHandler for this web app
     * @param servletHandler ServletHandler for this web app
     * @param errorHandler ErrorHandler for this web app
     */
    public WebAppContext(HandlerContainer parent, String contextPath, SessionHandler sessionHandler, SecurityHandler securityHandler, ServletHandler servletHandler, ErrorHandler errorHandler,int options) 
    {
        super(parent, contextPath,sessionHandler, securityHandler, servletHandler, errorHandler,options);
        _scontext = new Context();
        setErrorHandler(errorHandler != null ? errorHandler : new ErrorPageErrorHandler());
        setProtectedTargets(__dftProtectedTargets);
    }

    /* ------------------------------------------------------------ */
    /**
     * @param servletContextName The servletContextName to set.
     */
    @Override
    public void setDisplayName(String servletContextName)
    {
        super.setDisplayName(servletContextName);
        ClassLoader cl = getClassLoader();
        if (cl!=null && cl instanceof WebAppClassLoader && servletContextName!=null)
            ((WebAppClassLoader)cl).setName(servletContextName);
    }

    /* ------------------------------------------------------------ */
    /** Get an exception that caused the webapp to be unavailable
     * @return A throwable if the webapp is unavailable or null
     */
    public Throwable getUnavailableException()
    {
        return _unavailableException;
    }


    /* ------------------------------------------------------------ */
    /** Set Resource Alias.
     * Resource aliases map resource uri's within a context.
     * They may optionally be used by a handler when looking for
     * a resource.
     * @param alias
     * @param uri
     */
    public void setResourceAlias(String alias, String uri)
    {
        if (_resourceAliases == null)
            _resourceAliases= new HashMap(5);
        _resourceAliases.put(alias, uri);
    }

    /* ------------------------------------------------------------ */
    public Map getResourceAliases()
    {
        if (_resourceAliases == null)
            return null;
        return _resourceAliases;
    }

    /* ------------------------------------------------------------ */
    public void setResourceAliases(Map map)
    {
        _resourceAliases = map;
    }

    /* ------------------------------------------------------------ */
    public String getResourceAlias(String path)
    {
        if (_resourceAliases == null)
            return null;
        String alias = _resourceAliases.get(path);

        int slash=path.length();
        while (alias==null)
        {
            slash=path.lastIndexOf("/",slash-1);
            if (slash<0)
                break;
            String match=_resourceAliases.get(path.substring(0,slash+1));
            if (match!=null)
                alias=match+path.substring(slash+1);
        }
        return alias;
    }

    /* ------------------------------------------------------------ */
    public String removeResourceAlias(String alias)
    {
        if (_resourceAliases == null)
            return null;
        return _resourceAliases.remove(alias);
    }

    /* ------------------------------------------------------------ */
    /* (non-Javadoc)
     * @see org.eclipse.jetty.server.server.handler.ContextHandler#setClassLoader(java.lang.ClassLoader)
     */
    @Override
    public void setClassLoader(ClassLoader classLoader)
    {
        super.setClassLoader(classLoader);

//        if ( !(classLoader instanceof WebAppClassLoader) )
//        {
//            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() );
//        }

        if (classLoader!=null && classLoader instanceof WebAppClassLoader && getDisplayName()!=null)
            ((WebAppClassLoader)classLoader).setName(getDisplayName());
    }

    /* ------------------------------------------------------------ */
    @Override
    public Resource getResource(String uriInContext) throws MalformedURLException
    {
        if (uriInContext==null || !uriInContext.startsWith(URIUtil.SLASH))
            throw new MalformedURLException(uriInContext);

        IOException ioe= null;
        Resource resource= null;
        int loop=0;
        while (uriInContext!=null && loop++<100)
        {
            try
            {
                resource= super.getResource(uriInContext);
                if (resource != null && resource.exists())
                    return resource;

                uriInContext = getResourceAlias(uriInContext);
            }
            catch (IOException e)
            {
                LOG.ignore(e);
                if (ioe==null)
                    ioe= e;
            }
        }

        if (ioe != null && ioe instanceof MalformedURLException)
            throw (MalformedURLException)ioe;

        return resource;
    }


    /* ------------------------------------------------------------ */
    /** Is the context Automatically configured.
     *
     * @return true if configuration discovery.
     */
    public boolean isConfigurationDiscovered()
    {
        return _configurationDiscovered;
    }

    /* ------------------------------------------------------------ */
    /** Set the configuration discovery mode.
     * If configuration discovery is set to true, then the JSR315
     * servlet 3.0 discovered configuration features are enabled.
     * These are:
    *
  • Web Fragments
  • *
  • META-INF/resource directories
  • *
* @param discovered true if configuration discovery is enabled for automatic configuration from the context */ public void setConfigurationDiscovered(boolean discovered) { _configurationDiscovered = discovered; } /* ------------------------------------------------------------ */ /** Pre configure the web application. *

* The method is normally called from {@link #start()}. It performs * the discovery of the configurations to be applied to this context, * specifically:

    *
  • Instantiate the {@link Configuration} instances with a call to {@link #loadConfigurations()}. *
  • Setup the default System classes by calling {@link #loadSystemClasses()} *
  • Setup the default Server classes by calling loadServerClasses() *
  • Instantiates a classload (if one is not already set) *
  • Calls the {@link Configuration#preConfigure(WebAppContext)} method of all * Configuration instances. *
* @throws Exception */ public void preConfigure() throws Exception { // Setup configurations loadConfigurations(); // Setup system classes loadSystemClasses(); // Setup server classes loadServerClasses(); // Configure classloader _ownClassLoader=false; if (getClassLoader()==null) { WebAppClassLoader classLoader = new WebAppClassLoader(this); setClassLoader(classLoader); _ownClassLoader=true; } if (LOG.isDebugEnabled()) { ClassLoader loader = getClassLoader(); LOG.debug("Thread Context classloader {}",loader); loader=loader.getParent(); while(loader!=null) { LOG.debug("Parent class loader: {} ",loader); loader=loader.getParent(); } } // Prepare for configuration for (Configuration configuration : _configurations) { LOG.debug("preConfigure {} with {}",this,configuration); configuration.preConfigure(this); } } /* ------------------------------------------------------------ */ public void configure() throws Exception { // Configure webapp for (Configuration configuration : _configurations) { LOG.debug("configure {} with {}",this,configuration); configuration.configure(this); } } /* ------------------------------------------------------------ */ public void postConfigure() throws Exception { // Clean up after configuration for (Configuration configuration : _configurations) { LOG.debug("postConfigure {} with {}",this,configuration); configuration.postConfigure(this); } } /* ------------------------------------------------------------ */ /* * @see org.eclipse.thread.AbstractLifeCycle#doStart() */ @Override protected void doStart() throws Exception { try { _metadata.setAllowDuplicateFragmentNames(isAllowDuplicateFragmentNames()); preConfigure(); super.doStart(); postConfigure(); if (isLogUrlOnStart()) dumpUrl(); } catch (Exception e) { //start up of the webapp context failed, make sure it is not started LOG.warn("Failed startup of context "+this, e); _unavailableException=e; setAvailable(false); if (isThrowUnavailableOnStartupException()) throw e; } } /* ------------------------------------------------------------ */ /* * @see org.eclipse.thread.AbstractLifeCycle#doStop() */ @Override protected void doStop() throws Exception { super.doStop(); try { for (int i=_configurations.size();i-->0;) _configurations.get(i).deconfigure(this); if (_metadata != null) _metadata.clear(); _metadata=new MetaData(); } finally { if (_ownClassLoader) setClassLoader(null); setAvailable(true); _unavailableException=null; } } /* ------------------------------------------------------------ */ @Override public void destroy() { // Prepare for configuration MultiException mx=new MultiException(); if (_configurations!=null) { for (int i=_configurations.size();i-->0;) { try { _configurations.get(i).destroy(this); } catch(Exception e) { mx.add(e); } } } _configurations.clear(); super.destroy(); mx.ifExceptionThrowRuntime(); } /* ------------------------------------------------------------ */ /* * Dumps the current web app name and URL to the log */ private void dumpUrl() { Connector[] connectors = getServer().getConnectors(); for (int i=0;i getOverrideDescriptors() { return Collections.unmodifiableList(_overrideDescriptors); } /* ------------------------------------------------------------ */ /** * @return Returns the permissions. */ @Override public PermissionCollection getPermissions() { return _permissions; } /* ------------------------------------------------------------ */ /** * @see #setServerClasses(String[]) * @return Returns the serverClasses. */ @ManagedAttribute(value="classes and packages hidden by the context classloader", readonly=true) public String[] getServerClasses() { if (_serverClasses == null) loadServerClasses(); return _serverClasses.getPatterns(); } /* ------------------------------------------------------------ */ /** Add to the list of Server classes. * @see #setServerClasses(String[]) * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) * or a qualified package name ending with '.' (eg com.foo.). If the class * or package has '-' it is excluded from the server classes and order is thus * important when added system class patterns. This argument may also be a comma * separated list of classOrPackage patterns. */ public void addServerClass(String classOrPackage) { if (_serverClasses == null) loadServerClasses(); _serverClasses.addPattern(classOrPackage); } /* ------------------------------------------------------------ */ /** Prepend to the list of Server classes. * @see #setServerClasses(String[]) * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) * or a qualified package name ending with '.' (eg com.foo.). If the class * or package has '-' it is excluded from the server classes and order is thus * important when added system class patterns. This argument may also be a comma * separated list of classOrPackage patterns. */ public void prependServerClass(String classOrPackage) { if (_serverClasses == null) loadServerClasses(); _serverClasses.prependPattern(classOrPackage); } /* ------------------------------------------------------------ */ /** * @see #setSystemClasses(String[]) * @return Returns the systemClasses. */ @ManagedAttribute(value="classes and packages given priority by context classloader", readonly=true) public String[] getSystemClasses() { if (_systemClasses == null) loadSystemClasses(); return _systemClasses.getPatterns(); } /* ------------------------------------------------------------ */ /** Add to the list of System classes. * @see #setSystemClasses(String[]) * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) * or a qualified package name ending with '.' (eg com.foo.). If the class * or package has '-' it is excluded from the system classes and order is thus * important when added system class patterns. This argument may also be a comma * separated list of classOrPackage patterns. */ public void addSystemClass(String classOrPackage) { if (_systemClasses == null) loadSystemClasses(); _systemClasses.addPattern(classOrPackage); } /* ------------------------------------------------------------ */ /** Prepend to the list of System classes. * @see #setSystemClasses(String[]) * @param classOrPackage A fully qualified class name (eg com.foo.MyClass) * or a qualified package name ending with '.' (eg com.foo.). If the class * or package has '-' it is excluded from the system classes and order is thus * important when added system class patterns.This argument may also be a comma * separated list of classOrPackage patterns. */ public void prependSystemClass(String classOrPackage) { if (_systemClasses == null) loadSystemClasses(); _systemClasses.prependPattern(classOrPackage); } /* ------------------------------------------------------------ */ @Override public boolean isServerClass(String name) { if (_serverClasses == null) loadServerClasses(); return _serverClasses.match(name); } /* ------------------------------------------------------------ */ @Override public boolean isSystemClass(String name) { if (_systemClasses == null) loadSystemClasses(); return _systemClasses.match(name); } /* ------------------------------------------------------------ */ protected void loadSystemClasses() { if (_systemClasses != null) return; //look for a Server attribute with the list of System classes //to apply to every web application. If not present, use our defaults. Server server = getServer(); if (server != null) { Object systemClasses = server.getAttribute(SERVER_SYS_CLASSES); if (systemClasses != null && systemClasses instanceof String[]) _systemClasses = new ClasspathPattern((String[])systemClasses); } if (_systemClasses == null) _systemClasses = new ClasspathPattern(__dftSystemClasses); } /* ------------------------------------------------------------ */ private void loadServerClasses() { if (_serverClasses != null) { return; } // look for a Server attribute with the list of Server classes // to apply to every web application. If not present, use our defaults. Server server = getServer(); if (server != null) { Object serverClasses = server.getAttribute(SERVER_SRV_CLASSES); if (serverClasses != null && serverClasses instanceof String[]) { _serverClasses = new ClasspathPattern((String[])serverClasses); } } if (_serverClasses == null) { _serverClasses = new ClasspathPattern(__dftServerClasses); } } /* ------------------------------------------------------------ */ /** * @return Returns the war as a file or URL string (Resource) */ @ManagedAttribute(value="war file location", readonly=true) public String getWar() { if (_war==null) _war=getResourceBase(); return _war; } /* ------------------------------------------------------------ */ public Resource getWebInf() throws IOException { if (super.getBaseResource() == null) return null; // Iw there a WEB-INF directory? Resource web_inf= super.getBaseResource().addPath("WEB-INF/"); if (!web_inf.exists() || !web_inf.isDirectory()) return null; return web_inf; } /* ------------------------------------------------------------ */ /** * @return Returns the distributable. */ @ManagedAttribute("web application distributable") public boolean isDistributable() { return _distributable; } /* ------------------------------------------------------------ */ /** * @return Returns the extractWAR. */ @ManagedAttribute(value="extract war", readonly=true) public boolean isExtractWAR() { return _extractWAR; } /* ------------------------------------------------------------ */ /** * @return True if the webdir is copied (to allow hot replacement of jars on windows) */ @ManagedAttribute(value="webdir copied on deploy (allows hot replacement on windows)", readonly=true) public boolean isCopyWebDir() { return _copyDir; } /* ------------------------------------------------------------ */ /** * @return True if the web-inf lib and classes directories are copied (to allow hot replacement of jars on windows) */ public boolean isCopyWebInf() { return _copyWebInf; } /* ------------------------------------------------------------ */ /** * @return True if the classloader should delegate first to the parent * classloader (standard java behaviour) or false if the classloader * should first try to load from WEB-INF/lib or WEB-INF/classes (servlet * spec recommendation). */ @Override @ManagedAttribute(value="parent classloader given priority", readonly=true) public boolean isParentLoaderPriority() { return _parentLoaderPriority; } /* ------------------------------------------------------------ */ public static String[] getDefaultConfigurationClasses () { return DEFAULT_CONFIGURATION_CLASSES; } /* ------------------------------------------------------------ */ public String[] getDefaultServerClasses () { return __dftServerClasses; } /* ------------------------------------------------------------ */ public String[] getDefaultSystemClasses () { return __dftSystemClasses; } /* ------------------------------------------------------------ */ protected void loadConfigurations() throws Exception { //if the configuration instances have been set explicitly, use them if (_configurations.size()>0) return; if (_configurationClasses.size()==0) _configurationClasses.addAll(Configuration.ClassList.serverDefault(getServer())); for (String configClass : _configurationClasses) _configurations.add((Configuration)Loader.loadClass(this.getClass(), configClass).newInstance()); } /* ------------------------------------------------------------ */ @Override public String toString() { if (_war!=null) { String war=_war; if (war.indexOf("/webapps/")>=0) war=war.substring(war.indexOf("/webapps/")+8); return super.toString()+"{"+war+"}"; } return super.toString(); } /* ------------------------------------------------------------ */ /** * @param configurations The configuration class names. If setConfigurations is not called * these classes are used to create a configurations array. */ public void setConfigurationClasses(String[] configurations) { if (isRunning()) throw new IllegalStateException(); _configurationClasses.clear(); if (configurations!=null) _configurationClasses.addAll(Arrays.asList(configurations)); _configurations.clear(); } public void setConfigurationClasses(List configurations) { setConfigurationClasses(configurations.toArray(new String[configurations.size()])); } /* ------------------------------------------------------------ */ /** * @param configurations The configurations to set. */ public void setConfigurations(Configuration[] configurations) { if (isRunning()) throw new IllegalStateException(); _configurations.clear(); if (configurations!=null) _configurations.addAll(Arrays.asList(configurations)); } /* ------------------------------------------------------------ */ /** * The default descriptor is a web.xml format file that is applied to the context before the standard WEB-INF/web.xml * @param defaultsDescriptor The defaultsDescriptor to set. */ public void setDefaultsDescriptor(String defaultsDescriptor) { _defaultsDescriptor = defaultsDescriptor; } /* ------------------------------------------------------------ */ /** * The override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml * @param overrideDescriptor The overrideDescritpor to set. */ public void setOverrideDescriptor(String overrideDescriptor) { _overrideDescriptors.clear(); _overrideDescriptors.add(overrideDescriptor); } /* ------------------------------------------------------------ */ /** * The override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml * @param overrideDescriptors The overrideDescriptors (file or URL) to set. */ public void setOverrideDescriptors(List overrideDescriptors) { _overrideDescriptors.clear(); _overrideDescriptors.addAll(overrideDescriptors); } /* ------------------------------------------------------------ */ /** * The override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml * @param overrideDescriptor The overrideDescriptor (file or URL) to add. */ public void addOverrideDescriptor(String overrideDescriptor) { _overrideDescriptors.add(overrideDescriptor); } /* ------------------------------------------------------------ */ /** * @return the web.xml descriptor to use. If set to null, WEB-INF/web.xml is used if it exists. */ @ManagedAttribute(value="standard web.xml descriptor", readonly=true) public String getDescriptor() { return _descriptor; } /* ------------------------------------------------------------ */ /** * @param descriptor the web.xml descriptor to use. If set to null, WEB-INF/web.xml is used if it exists. */ public void setDescriptor(String descriptor) { _descriptor=descriptor; } /* ------------------------------------------------------------ */ /** * @param distributable The distributable to set. */ public void setDistributable(boolean distributable) { this._distributable = distributable; } /* ------------------------------------------------------------ */ @Override public void setEventListeners(EventListener[] eventListeners) { if (_sessionHandler!=null) _sessionHandler.clearEventListeners(); super.setEventListeners(eventListeners); } /* ------------------------------------------------------------ */ /** Add EventListener * Convenience method that calls {@link #setEventListeners(EventListener[])} * @param listener */ @Override public void addEventListener(EventListener listener) { super.addEventListener(listener); if ((listener instanceof HttpSessionActivationListener) || (listener instanceof HttpSessionAttributeListener) || (listener instanceof HttpSessionBindingListener) || (listener instanceof HttpSessionListener)) { if (_sessionHandler!=null) _sessionHandler.addEventListener(listener); } } @Override public void removeEventListener(EventListener listener) { super.removeEventListener(listener); if ((listener instanceof HttpSessionActivationListener) || (listener instanceof HttpSessionAttributeListener) || (listener instanceof HttpSessionBindingListener) || (listener instanceof HttpSessionListener)) { if (_sessionHandler!=null) _sessionHandler.removeEventListener(listener); } } /* ------------------------------------------------------------ */ /** * @param extractWAR True if war files are extracted */ public void setExtractWAR(boolean extractWAR) { _extractWAR = extractWAR; } /* ------------------------------------------------------------ */ /** * @param copy True if the webdir is copied (to allow hot replacement of jars) */ public void setCopyWebDir(boolean copy) { _copyDir = copy; } /* ------------------------------------------------------------ */ /** * @param copyWebInf True if the web-inf lib and classes directories are copied (to allow hot replacement of jars on windows) */ public void setCopyWebInf(boolean copyWebInf) { _copyWebInf = copyWebInf; } /* ------------------------------------------------------------ */ /** * @param java2compliant The java2compliant to set. */ public void setParentLoaderPriority(boolean java2compliant) { _parentLoaderPriority = java2compliant; } /* ------------------------------------------------------------ */ /** * @param permissions The permissions to set. */ public void setPermissions(PermissionCollection permissions) { _permissions = permissions; } /** * Set the context white list * * In certain circumstances you want may want to deny access of one webapp from another * when you may not fully trust the webapp. Setting this white list will enable a * check when a servlet called getContext(String), validating that the uriInPath * for the given webapp has been declaratively allows access to the context. * @param contextWhiteList */ public void setContextWhiteList(String[] contextWhiteList) { _contextWhiteList = contextWhiteList; } /* ------------------------------------------------------------ */ /** * Set the server classes patterns. *

* Server classes/packages are classes used to implement the server and are hidden * from the context. If the context needs to load these classes, it must have its * own copy of them in WEB-INF/lib or WEB-INF/classes. * A class pattern is a string of one of the forms:

*
org.package.Classname
Match a specific class
*
org.package.
Match a specific package hierarchy
*
-org.package.Classname
Exclude a specific class
*
-org.package.
Exclude a specific package hierarchy
*
* @param serverClasses The serverClasses to set. */ public void setServerClasses(String[] serverClasses) { _serverClasses = new ClasspathPattern(serverClasses); } /* ------------------------------------------------------------ */ /** * Set the system classes patterns. *

* System classes/packages are classes provided by the JVM and that * cannot be replaced by classes of the same name from WEB-INF, * regardless of the value of {@link #setParentLoaderPriority(boolean)}. * A class pattern is a string of one of the forms:

*
org.package.Classname
Match a specific class
*
org.package.
Match a specific package hierarchy
*
-org.package.Classname
Exclude a specific class
*
-org.package.
Exclude a specific package hierarchy
*
* @param systemClasses The systemClasses to set. */ public void setSystemClasses(String[] systemClasses) { _systemClasses = new ClasspathPattern(systemClasses); } /* ------------------------------------------------------------ */ /** Set temporary directory for context. * The javax.servlet.context.tempdir attribute is also set. * @param dir Writable temporary directory. */ public void setTempDirectory(File dir) { if (isStarted()) throw new IllegalStateException("Started"); if (dir!=null) { try{dir=new File(dir.getCanonicalPath());} catch (IOException e){LOG.warn(Log.EXCEPTION,e);} } if (dir!=null && !dir.exists()) { dir.mkdir(); dir.deleteOnExit(); } if (dir!=null && ( !dir.exists() || !dir.isDirectory() || !dir.canWrite())) throw new IllegalArgumentException("Bad temp directory: "+dir); try { if (dir!=null) dir=dir.getCanonicalFile(); } catch(Exception e) { LOG.warn(e); } _tmpDir=dir; setAttribute(TEMPDIR,_tmpDir); } /* ------------------------------------------------------------ */ @ManagedAttribute(value="temporary directory location", readonly=true) public File getTempDirectory () { return _tmpDir; } /* ------------------------------------------------------------ */ /** * @param war The war to set as a file name or URL */ public void setWar(String war) { _war = war; } /* ------------------------------------------------------------ */ /** * @return Comma or semicolon separated path of filenames or URLs * pointing to directories or jar files. Directories should end * with '/'. */ @Override @ManagedAttribute(value="extra classpath for context classloader", readonly=true) public String getExtraClasspath() { return _extraClasspath; } /* ------------------------------------------------------------ */ /** * @param extraClasspath Comma or semicolon separated path of filenames or URLs * pointing to directories or jar files. Directories should end * with '/'. */ public void setExtraClasspath(String extraClasspath) { _extraClasspath=extraClasspath; } /* ------------------------------------------------------------ */ public boolean isLogUrlOnStart() { return _logUrlOnStart; } /* ------------------------------------------------------------ */ /** * Sets whether or not the web app name and URL is logged on startup * * @param logOnStart whether or not the log message is created */ public void setLogUrlOnStart(boolean logOnStart) { this._logUrlOnStart = logOnStart; } /* ------------------------------------------------------------ */ @Override public void setServer(Server server) { super.setServer(server); } /* ------------------------------------------------------------ */ public boolean isAllowDuplicateFragmentNames() { return _allowDuplicateFragmentNames; } /* ------------------------------------------------------------ */ public void setAllowDuplicateFragmentNames(boolean allowDuplicateFragmentNames) { _allowDuplicateFragmentNames = allowDuplicateFragmentNames; } /* ------------------------------------------------------------ */ public void setThrowUnavailableOnStartupException (boolean throwIfStartupException) { _throwUnavailableOnStartupException = throwIfStartupException; } /* ------------------------------------------------------------ */ public boolean isThrowUnavailableOnStartupException () { return _throwUnavailableOnStartupException; } /* ------------------------------------------------------------ */ @Override protected void startContext() throws Exception { configure(); //resolve the metadata _metadata.resolve(this); super.startContext(); } /* ------------------------------------------------------------ */ @Override public Set setServletSecurity(Dynamic registration, ServletSecurityElement servletSecurityElement) { Set unchangedURLMappings = new HashSet(); //From javadoc for ServletSecurityElement: /* If a URL pattern of this ServletRegistration is an exact target of a security-constraint that was established via the portable deployment descriptor, then this method does not change the security-constraint for that pattern, and the pattern will be included in the return value. If a URL pattern of this ServletRegistration is an exact target of a security constraint that was established via the ServletSecurity annotation or a previous call to this method, then this method replaces the security constraint for that pattern. If a URL pattern of this ServletRegistration is neither the exact target of a security constraint that was established via the ServletSecurity annotation or a previous call to this method, nor the exact target of a security-constraint in the portable deployment descriptor, then this method establishes the security constraint for that pattern from the argument ServletSecurityElement. */ Collection pathMappings = registration.getMappings(); if (pathMappings != null) { ConstraintSecurityHandler.createConstraint(registration.getName(), servletSecurityElement); for (String pathSpec:pathMappings) { Origin origin = getMetaData().getOrigin("constraint.url."+pathSpec); switch (origin) { case NotSet: { //No mapping for this url already established List mappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement); for (ConstraintMapping m:mappings) ((ConstraintAware)getSecurityHandler()).addConstraintMapping(m); getMetaData().setOrigin("constraint.url."+pathSpec, Origin.API); break; } case WebXml: case WebDefaults: case WebOverride: case WebFragment: { //a mapping for this url was created in a descriptor, which overrides everything unchangedURLMappings.add(pathSpec); break; } case Annotation: case API: { //mapping established via an annotation or by previous call to this method, //replace the security constraint for this pattern List constraintMappings = ConstraintSecurityHandler.removeConstraintMappingsForPath(pathSpec, ((ConstraintAware)getSecurityHandler()).getConstraintMappings()); List freshMappings = ConstraintSecurityHandler.createConstraintsWithMappingsForPath(registration.getName(), pathSpec, servletSecurityElement); constraintMappings.addAll(freshMappings); ((ConstraintSecurityHandler)getSecurityHandler()).setConstraintMappings(constraintMappings); break; } } } } return unchangedURLMappings; } /* ------------------------------------------------------------ */ public class Context extends ServletContextHandler.Context { /* ------------------------------------------------------------ */ @Override public URL getResource(String path) throws MalformedURLException { Resource resource=WebAppContext.this.getResource(path); if (resource==null || !resource.exists()) return null; // Should we go to the original war? if (resource.isDirectory() && resource instanceof ResourceCollection && !WebAppContext.this.isExtractWAR()) { Resource[] resources = ((ResourceCollection)resource).getResources(); for (int i=resources.length;i-->0;) { if (resources[i].getName().startsWith("jar:file")) return resources[i].getURL(); } } return resource.getURL(); } /* ------------------------------------------------------------ */ @Override public ServletContext getContext(String uripath) { ServletContext servletContext = super.getContext(uripath); if ( servletContext != null && _contextWhiteList != null ) { for ( String context : _contextWhiteList ) { if ( context.equals(uripath) ) { return servletContext; } } return null; } else { return servletContext; } } } /* ------------------------------------------------------------ */ public MetaData getMetaData() { return _metadata; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy