org.mortbay.jetty.webapp.WebAppContext Maven / Gradle / Ivy
//========================================================================
//$Id: WebAppContext.java,v 1.5 2005/11/16 22:02:45 gregwilkins Exp $
//Copyright 2004-2006 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================
package org.mortbay.jetty.webapp;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.security.PermissionCollection;
import java.util.EventListener;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionListener;
import org.mortbay.component.AbstractLifeCycle;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.HandlerContainer;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.deployer.ContextDeployer;
import org.mortbay.jetty.deployer.WebAppDeployer;
import org.mortbay.jetty.handler.ContextHandler;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.mortbay.jetty.handler.ErrorHandler;
import org.mortbay.jetty.handler.HandlerCollection;
import org.mortbay.jetty.security.SecurityHandler;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ErrorPageErrorHandler;
import org.mortbay.jetty.servlet.ServletHandler;
import org.mortbay.jetty.servlet.SessionHandler;
import org.mortbay.log.Log;
import org.mortbay.resource.JarResource;
import org.mortbay.resource.Resource;
import org.mortbay.util.IO;
import org.mortbay.util.LazyList;
import org.mortbay.util.Loader;
import org.mortbay.util.StringUtil;
import org.mortbay.util.URIUtil;
import org.mortbay.util.UrlEncoded;
/* ------------------------------------------------------------ */
/** Web Application Context Handler.
* The WebAppContext handler is an extension of ContextHandler that
* coordinates the construction and configuration of nested handlers:
* {@link org.mortbay.jetty.security.SecurityHandler}, {@link org.mortbay.jetty.servlet.SessionHandler}
* and {@link org.mortbay.jetty.servlet.ServletHandler}.
* The handlers are configured by pluggable configuration classes, with
* the default being {@link org.mortbay.jetty.webapp.WebXmlConfiguration} and
* {@link org.mortbay.jetty.webapp.JettyWebXmlConfiguration}.
*
* @org.apache.xbean.XBean description="Creates a servlet web application at a given context from a resource base"
*
* @author gregw
*
*/
public class WebAppContext extends Context
{
public final static String WEB_DEFAULTS_XML="org/mortbay/jetty/webapp/webdefault.xml";
public final static String ERROR_PAGE="org.mortbay.jetty.error_page";
private static String[] __dftConfigurationClasses =
{
"org.mortbay.jetty.webapp.WebInfConfiguration",
"org.mortbay.jetty.webapp.WebXmlConfiguration",
"org.mortbay.jetty.webapp.JettyWebXmlConfiguration",
"org.mortbay.jetty.webapp.TagLibConfiguration"
} ;
private String[] _configurationClasses=__dftConfigurationClasses;
private Configuration[] _configurations;
private String _defaultsDescriptor=WEB_DEFAULTS_XML;
private String _descriptor=null;
private String _overrideDescriptor=null;
private boolean _distributable=false;
private boolean _extractWAR=true;
private boolean _copyDir=false;
private boolean _logUrlOnStart =false;
private boolean _parentLoaderPriority= Boolean.getBoolean("org.mortbay.jetty.webapp.parentLoaderPriority");
private PermissionCollection _permissions;
private String[] _systemClasses = {"java.","javax.servlet.","javax.xml.","org.mortbay.","org.xml.","org.w3c.", "org.apache.commons.logging.", "org.apache.log4j."};
private String[] _serverClasses = {"-org.mortbay.jetty.plus.jaas.", "org.mortbay.jetty.", "org.slf4j."}; // TODO hide all mortbay classes
private File _tmpDir;
private boolean _isExistingTmpDir;
private String _war;
private String _extraClasspath;
private Throwable _unavailableException;
private transient Map _resourceAliases;
private transient boolean _ownClassLoader=false;
private transient boolean _unavailable;
public static ContextHandler getCurrentWebAppContext()
{
ContextHandler.SContext context=ContextHandler.getCurrentContext();
if (context!=null)
{
ContextHandler handler = context.getContextHandler();
if (handler instanceof WebAppContext)
return (ContextHandler)handler;
}
return null;
}
/* ------------------------------------------------------------ */
/** Add Web Applications.
* Add auto webapplications to the server. The name of the
* webapp directory or war is used as the context name. If the
* webapp matches the rootWebApp it is added as the "/" context.
* @param server Must not be null
* @param webapps Directory file name or URL to look for auto
* webapplication.
* @param defaults The defaults xml filename or URL which is
* loaded before any in the web app. Must respect the web.dtd.
* If null the default defaults file is used. If the empty string, then
* no defaults file is used.
* @param extract If true, extract war files
* @param java2CompliantClassLoader True if java2 compliance is applied to all webapplications
* @exception IOException
* @deprecated use {@link org.mortbay.jetty.deployer.WebAppDeployer} or {@link org.mortbay.jetty.deployer.ContextDeployer}
*/
public static void addWebApplications(Server server,
String webapps,
String defaults,
boolean extract,
boolean java2CompliantClassLoader)
throws IOException
{
addWebApplications(server, webapps, defaults, __dftConfigurationClasses, extract, java2CompliantClassLoader);
}
/* ------------------------------------------------------------ */
/** Add Web Applications.
* Add auto webapplications to the server. The name of the
* webapp directory or war is used as the context name. If the
* webapp matches the rootWebApp it is added as the "/" context.
* @param server Must not be null
.
* @param webapps Directory file name or URL to look for auto
* webapplication.
* @param defaults The defaults xml filename or URL which is
* loaded before any in the web app. Must respect the web.dtd.
* If null the default defaults file is used. If the empty string, then
* no defaults file is used.
* @param configurations Array of classnames of {@link Configuration} implementations to apply.
* @param extract If true, extract war files
* @param java2CompliantClassLoader True if java2 compliance is applied to all webapplications
* @exception IOException
* @throws IllegalAccessException
* @throws InstantiationException
* @deprecated use {@link org.mortbay.jetty.deployer.WebAppDeployer} or {@link org.mortbay.jetty.deployer.ContextDeployer}
*/
public static void addWebApplications(Server server,
String webapps,
String defaults,
String[] configurations,
boolean extract,
boolean java2CompliantClassLoader)
throws IOException
{
HandlerCollection contexts = (HandlerCollection)server.getChildHandlerByClass(ContextHandlerCollection.class);
if (contexts==null)
contexts = (HandlerCollection)server.getChildHandlerByClass(HandlerCollection.class);
addWebApplications(contexts,webapps,defaults,configurations,extract,java2CompliantClassLoader);
}
/* ------------------------------------------------------------ */
/** Add Web Applications.
* Add auto webapplications to the server. The name of the
* webapp directory or war is used as the context name. If the
* webapp is called "root" it is added as the "/" context.
* @param contexts A HandlerContainer to which the contexts will be added
* @param webapps Directory file name or URL to look for auto
* webapplication.
* @param defaults The defaults xml filename or URL which is
* loaded before any in the web app. Must respect the web.dtd.
* If null the default defaults file is used. If the empty string, then
* no defaults file is used.
* @param configurations Array of classnames of {@link Configuration} implementations to apply.
* @param extract If true, extract war files
* @param java2CompliantClassLoader True if java2 compliance is applied to all webapplications
* @exception IOException
* @throws IllegalAccessException
* @throws InstantiationException
* @deprecated use {@link WebAppDeployer} or {@link ContextDeployer}
*/
public static void addWebApplications(HandlerContainer contexts,
String webapps,
String defaults,
boolean extract,
boolean java2CompliantClassLoader)
throws IOException
{
addWebApplications(contexts, webapps, defaults, __dftConfigurationClasses, extract, java2CompliantClassLoader);
}
/* ------------------------------------------------------------ */
/** Add Web Applications.
* Add auto webapplications to the server. The name of the
* webapp directory or war is used as the context name. If the
* webapp is called "root" it is added as the "/" context.
* @param contexts A HandlerContainer to which the contexts will be added
* @param webapps Directory file name or URL to look for auto
* webapplication.
* @param defaults The defaults xml filename or URL which is
* loaded before any in the web app. Must respect the web.dtd.
* If null the default defaults file is used. If the empty string, then
* no defaults file is used.
* @param configurations Array of classnames of {@link Configuration} implementations to apply.
* @param extract If true, extract war files
* @param java2CompliantClassLoader True if java2 compliance is applied to all webapplications
* @exception IOException
* @throws IllegalAccessException
* @throws InstantiationException
* @deprecated use {@link WebAppDeployer} or {@link ContextDeployer}
*/
public static void addWebApplications(HandlerContainer contexts,
String webapps,
String defaults,
String[] configurations,
boolean extract,
boolean java2CompliantClassLoader)
throws IOException
{
Log.warn("Deprecated configuration used for "+webapps);
WebAppDeployer deployer = new WebAppDeployer();
deployer.setContexts(contexts);
deployer.setWebAppDir(webapps);
deployer.setConfigurationClasses(configurations);
deployer.setExtract(extract);
deployer.setParentLoaderPriority(java2CompliantClassLoader);
try
{
deployer.start();
}
catch(IOException e)
{
throw e;
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}
/* ------------------------------------------------------------ */
public WebAppContext()
{
this(null,null,null,null);
}
/* ------------------------------------------------------------ */
/**
* @param contextPath The context path
* @param webApp The URL or filename of the webapp directory or war file.
*/
public WebAppContext(String webApp,String contextPath)
{
super(null,contextPath,SESSIONS|SECURITY);
setContextPath(contextPath);
setWar(webApp);
setErrorHandler(new ErrorPageErrorHandler());
}
/* ------------------------------------------------------------ */
/**
* @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)
{
super(parent,contextPath,SESSIONS|SECURITY);
setWar(webApp);
setErrorHandler(new ErrorPageErrorHandler());
}
/* ------------------------------------------------------------ */
/**
*/
public WebAppContext(SecurityHandler securityHandler,SessionHandler sessionHandler, ServletHandler servletHandler, ErrorHandler errorHandler)
{
super(null,
sessionHandler!=null?sessionHandler:new SessionHandler(),
securityHandler!=null?securityHandler:new SecurityHandler(),
servletHandler!=null?servletHandler:new ServletHandler(),
null);
setErrorHandler(errorHandler!=null?errorHandler:new ErrorPageErrorHandler());
}
/* ------------------------------------------------------------ */
/** 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 alias)
{
if (_resourceAliases == null)
return null;
return (String)_resourceAliases.get(alias);
}
/* ------------------------------------------------------------ */
public String removeResourceAlias(String alias)
{
if (_resourceAliases == null)
return null;
return (String)_resourceAliases.remove(alias);
}
/* ------------------------------------------------------------ */
/* (non-Javadoc)
* @see org.mortbay.jetty.handler.ContextHandler#setClassLoader(java.lang.ClassLoader)
*/
public void setClassLoader(ClassLoader classLoader)
{
super.setClassLoader(classLoader);
if (classLoader!=null && classLoader instanceof WebAppClassLoader)
((WebAppClassLoader)classLoader).setName(getDisplayName());
}
/* ------------------------------------------------------------ */
public Resource getResource(String uriInContext) throws MalformedURLException
{
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;
}
/* ------------------------------------------------------------ */
/**
* @see org.mortbay.jetty.handler.ContextHandler#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
*/
public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)
throws IOException, ServletException
{
if (_unavailable)
{
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
}
else
super.handle(target, request, response, dispatch);
}
/* ------------------------------------------------------------ */
/*
* @see org.mortbay.thread.AbstractLifeCycle#doStart()
*/
protected void doStart() throws Exception
{
try
{
// Setup configurations
loadConfigurations();
for (int i=0;i<_configurations.length;i++)
_configurations[i].setWebAppContext(this);
// 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 class loader is: " + loader);
loader=loader.getParent();
while(loader!=null)
{
Log.debug("Parent class loader is: " + loader);
loader=loader.getParent();
}
}
for (int i=0;i<_configurations.length;i++)
_configurations[i].configureClassLoader();
getTempDirectory();
if (_tmpDir!=null && !_isExistingTmpDir && !isTempWorkDirectory())
{
File sentinel = new File(_tmpDir, ".active");
if(!sentinel.exists())
sentinel.mkdir();
}
super.doStart();
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;
_unavailable = true;
}
}
/* ------------------------------------------------------------ */
/*
* Dumps the current web app name and URL to the log
*/
public void dumpUrl()
{
Connector[] connectors = getServer().getConnectors();
for (int i=0;i0;)
_configurations[i].deconfigureWebApp();
_configurations=null;
// restore security handler
if (_securityHandler.getHandler()==null)
{
_sessionHandler.setHandler(_securityHandler);
_securityHandler.setHandler(_servletHandler);
}
// delete temp directory if we had to create it or if it isn't called work
if (_tmpDir!=null && !_isExistingTmpDir && !isTempWorkDirectory()) //_tmpDir!=null && !"work".equals(_tmpDir.getName()))
{
IO.delete(_tmpDir);
_tmpDir=null;
}
}
finally
{
if (_ownClassLoader)
setClassLoader(null);
_unavailable = false;
_unavailableException=null;
}
}
/* ------------------------------------------------------------ */
/**
* @return Returns the configurations.
*/
public String[] getConfigurationClasses()
{
return _configurationClasses;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the configurations.
*/
public Configuration[] getConfigurations()
{
return _configurations;
}
/* ------------------------------------------------------------ */
/**
* The default descriptor is a web.xml format file that is applied to the context before the standard WEB-INF/web.xml
* @return Returns the defaultsDescriptor.
*/
public String getDefaultsDescriptor()
{
return _defaultsDescriptor;
}
/* ------------------------------------------------------------ */
/**
* The override descriptor is a web.xml format file that is applied to the context after the standard WEB-INF/web.xml
* @return Returns the Override Descriptor.
*/
public String getOverrideDescriptor()
{
return _overrideDescriptor;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the permissions.
*/
public PermissionCollection getPermissions()
{
return _permissions;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the serverClasses.
*/
public String[] getServerClasses()
{
return _serverClasses;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the systemClasses.
*/
public String[] getSystemClasses()
{
return _systemClasses;
}
/* ------------------------------------------------------------ */
/**
* Get a temporary directory in which to unpack the war etc etc.
* The algorithm for determining this is to check these alternatives
* in the order shown:
*
* A. Try to use an explicit directory specifically for this webapp:
*
* -
* Iff an explicit directory is set for this webapp, use it. Do NOT set
* delete on exit.
*
* -
* Iff javax.servlet.context.tempdir context attribute is set for
* this webapp && exists && writeable, then use it. Do NOT set delete on exit.
*
*
*
* B. Create a directory based on global settings. The new directory
* will be called "Jetty_"+host+"_"+port+"__"+context+"_"+virtualhost
* Work out where to create this directory:
*
* -
* Iff $(jetty.home)/work exists create the directory there. Do NOT
* set delete on exit. Do NOT delete contents if dir already exists.
*
* -
* Iff WEB-INF/work exists create the directory there. Do NOT set
* delete on exit. Do NOT delete contents if dir already exists.
*
* -
* Else create dir in $(java.io.tmpdir). Set delete on exit. Delete
* contents if dir already exists.
*
*
*
* @return
*/
public File getTempDirectory()
{
if (_tmpDir!=null && _tmpDir.isDirectory() && _tmpDir.canWrite())
return _tmpDir;
// Initialize temporary directory
//
// I'm afraid that this is very much black magic.
// but if you can think of better....
Object t = getAttribute(ServletHandler.__J_S_CONTEXT_TEMPDIR);
if (t!=null && (t instanceof File))
{
_tmpDir=(File)t;
if (_tmpDir.isDirectory() && _tmpDir.canWrite())
return _tmpDir;
}
if (t!=null && (t instanceof String))
{
try
{
_tmpDir=new File((String)t);
if (_tmpDir.isDirectory() && _tmpDir.canWrite())
{
if(Log.isDebugEnabled())Log.debug("Converted to File "+_tmpDir+" for "+this);
setAttribute(ServletHandler.__J_S_CONTEXT_TEMPDIR,_tmpDir);
return _tmpDir;
}
}
catch(Exception e)
{
Log.warn(Log.EXCEPTION,e);
}
}
// No tempdir so look for a work directory to use as tempDir base
File work=null;
try
{
File w=new File(System.getProperty("jetty.home"),"work");
if (w.exists() && w.canWrite() && w.isDirectory())
work=w;
else if (getBaseResource()!=null)
{
Resource web_inf = getWebInf();
if (web_inf !=null && web_inf.exists())
{
w=new File(web_inf.getFile(),"work");
if (w.exists() && w.canWrite() && w.isDirectory())
work=w;
}
}
}
catch(Exception e)
{
Log.ignore(e);
}
// No tempdir set so make one!
try
{
String temp = getCanonicalNameForWebAppTmpDir();
if (work!=null)
_tmpDir=new File(work,temp);
else
{
_tmpDir=new File(System.getProperty("java.io.tmpdir"),temp);
if (_tmpDir.exists())
{
if(Log.isDebugEnabled())Log.debug("Delete existing temp dir "+_tmpDir+" for "+this);
if (!IO.delete(_tmpDir))
{
if(Log.isDebugEnabled())Log.debug("Failed to delete temp dir "+_tmpDir);
}
if (_tmpDir.exists())
{
String old=_tmpDir.toString();
_tmpDir=File.createTempFile(temp+"_","");
if (_tmpDir.exists())
_tmpDir.delete();
Log.warn("Can't reuse "+old+", using "+_tmpDir);
}
}
}
if (!_tmpDir.exists())
_tmpDir.mkdir();
//if not in a dir called "work" then we want to delete it on jvm exit
if (!isTempWorkDirectory())
_tmpDir.deleteOnExit();
if(Log.isDebugEnabled())Log.debug("Created temp dir "+_tmpDir+" for "+this);
}
catch(Exception e)
{
_tmpDir=null;
Log.ignore(e);
}
if (_tmpDir==null)
{
try{
// that didn't work, so try something simpler (ish)
_tmpDir=File.createTempFile("JettyContext","");
if (_tmpDir.exists())
_tmpDir.delete();
_tmpDir.mkdir();
_tmpDir.deleteOnExit();
if(Log.isDebugEnabled())Log.debug("Created temp dir "+_tmpDir+" for "+this);
}
catch(IOException e)
{
Log.warn("tmpdir",e); System.exit(1);
}
}
setAttribute(ServletHandler.__J_S_CONTEXT_TEMPDIR,_tmpDir);
return _tmpDir;
}
/**
* Check if the _tmpDir itself is called "work", or if the _tmpDir
* is in a directory called "work".
* @return
*/
public boolean isTempWorkDirectory ()
{
if (_tmpDir == null)
return false;
if (_tmpDir.getName().equalsIgnoreCase("work"))
return true;
File t = _tmpDir.getParentFile();
if (t == null)
return false;
return (t.getName().equalsIgnoreCase("work"));
}
/* ------------------------------------------------------------ */
/**
* @return Returns the war as a file or URL string (Resource)
*/
public String getWar()
{
if (_war==null)
_war=getResourceBase();
return _war;
}
/* ------------------------------------------------------------ */
public Resource getWebInf() throws IOException
{
resolveWebApp();
// 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.
*/
public boolean isDistributable()
{
return _distributable;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the extractWAR.
*/
public boolean isExtractWAR()
{
return _extractWAR;
}
/* ------------------------------------------------------------ */
/**
* @return True if the webdir is copied (to allow hot replacement of jars)
*/
public boolean isCopyWebDir()
{
return _copyDir;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the java2compliant.
*/
public boolean isParentLoaderPriority()
{
return _parentLoaderPriority;
}
/* ------------------------------------------------------------ */
protected void loadConfigurations()
throws Exception
{
if (_configurations!=null)
return;
if (_configurationClasses==null)
_configurationClasses=__dftConfigurationClasses;
_configurations = new Configuration[_configurationClasses.length];
for (int i=0;i<_configurations.length;i++)
{
_configurations[i]=(Configuration)Loader.loadClass(this.getClass(), _configurationClasses[i]).newInstance();
}
}
/* ------------------------------------------------------------ */
protected boolean isProtectedTarget(String target)
{
while (target.startsWith("//"))
target=URIUtil.compactPath(target);
return StringUtil.startsWithIgnoreCase(target, "/web-inf") || StringUtil.startsWithIgnoreCase(target, "/meta-inf");
}
/* ------------------------------------------------------------ */
public String toString()
{
return this.getClass().getName()+"@"+Integer.toHexString(hashCode())+"{"+getContextPath()+","+(_war==null?getResourceBase():_war)+"}";
}
/* ------------------------------------------------------------ */
/** Resolve Web App directory
* If the BaseResource has not been set, use the war resource to
* derive a webapp resource (expanding WAR if required).
*/
protected void resolveWebApp() throws IOException
{
Resource web_app = super.getBaseResource();
if (web_app == null)
{
if (_war==null || _war.length()==0)
_war=getResourceBase();
// Set dir or WAR
web_app= Resource.newResource(_war);
// Accept aliases for WAR files
if (web_app.getAlias() != null)
{
Log.debug(web_app + " anti-aliased to " + web_app.getAlias());
web_app= Resource.newResource(web_app.getAlias());
}
if (Log.isDebugEnabled())
Log.debug("Try webapp=" + web_app + ", exists=" + web_app.exists() + ", directory=" + web_app.isDirectory());
// Is the WAR usable directly?
if (web_app.exists() && !web_app.isDirectory() && !web_app.toString().startsWith("jar:"))
{
// No - then lets see if it can be turned into a jar URL.
Resource jarWebApp= Resource.newResource("jar:" + web_app + "!/");
if (jarWebApp.exists() && jarWebApp.isDirectory())
{
web_app= jarWebApp;
}
}
// If we should extract or the URL is still not usable
if (web_app.exists() && (
(_copyDir && web_app.getFile()!= null && web_app.getFile().isDirectory())
||
(_extractWAR && web_app.getFile()!= null && !web_app.getFile().isDirectory())
||
(_extractWAR && web_app.getFile() == null)
||
!web_app.isDirectory()
))
{
// Then extract it if necessary.
File extractedWebAppDir= new File(getTempDirectory(), "webapp");
if (web_app.getFile()!=null && web_app.getFile().isDirectory())
{
// Copy directory
Log.info("Copy " + web_app.getFile() + " to " + extractedWebAppDir);
IO.copyDir(web_app.getFile(),extractedWebAppDir);
}
else
{
if (!extractedWebAppDir.exists())
{
//it hasn't been extracted before so extract it
extractedWebAppDir.mkdir();
Log.info("Extract " + _war + " to " + extractedWebAppDir);
JarResource.extract(web_app, extractedWebAppDir, false);
}
else
{
//only extract if the war file is newer
if (web_app.lastModified() > extractedWebAppDir.lastModified())
{
extractedWebAppDir.delete();
extractedWebAppDir.mkdir();
Log.info("Extract " + _war + " to " + extractedWebAppDir);
JarResource.extract(web_app, extractedWebAppDir, false);
}
}
}
web_app= Resource.newResource(extractedWebAppDir.getCanonicalPath());
}
// Now do we have something usable?
if (!web_app.exists() || !web_app.isDirectory())
{
Log.warn("Web application not found " + _war);
throw new java.io.FileNotFoundException(_war);
}
if (Log.isDebugEnabled())
Log.debug("webapp=" + web_app);
// ResourcePath
super.setBaseResource(web_app);
}
}
/* ------------------------------------------------------------ */
/**
* @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("Running");
_configurationClasses = configurations==null?null:(String[])configurations.clone();
}
/* ------------------------------------------------------------ */
/**
* @param configurations The configurations to set.
*/
public void setConfigurations(Configuration[] configurations)
{
if (isRunning())
throw new IllegalStateException("Running");
_configurations = configurations==null?null:(Configuration[])configurations.clone();
}
/* ------------------------------------------------------------ */
/**
* 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)
{
if (isRunning())
throw new IllegalStateException("Running");
_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 defaultsDescriptor The overrideDescritpor to set.
*/
public void setOverrideDescriptor(String overrideDescriptor)
{
if (isRunning())
throw new IllegalStateException("Running");
_overrideDescriptor = overrideDescriptor;
}
/* ------------------------------------------------------------ */
/**
* @return the web.xml descriptor to use. If set to null, WEB-INF/web.xml is used if it exists.
*/
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)
{
if (isRunning())
throw new IllegalStateException("Running");
_descriptor=descriptor;
}
/* ------------------------------------------------------------ */
/**
* @param distributable The distributable to set.
*/
public void setDistributable(boolean distributable)
{
this._distributable = distributable;
}
/* ------------------------------------------------------------ */
public void setEventListeners(EventListener[] eventListeners)
{
if (_sessionHandler!=null)
_sessionHandler.clearEventListeners();
super.setEventListeners(eventListeners);
for (int i=0; eventListeners!=null && i