343482 refactored overlay deployer layout to use WAR layout

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@3076 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Greg Wilkins 2011-05-05 03:03:12 +00:00
parent 9f5376269a
commit 4cd8b077b5
9 changed files with 240 additions and 32 deletions

View File

@ -23,16 +23,21 @@ import java.net.URLClassLoader;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.Timer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.AppProvider;
import org.eclipse.jetty.deploy.ConfigurationManager;
@ -42,6 +47,8 @@ import org.eclipse.jetty.jndi.local.localContextRoot;
import org.eclipse.jetty.server.ResourceCache;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.servlet.Holder;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.Scanner;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
@ -49,6 +56,7 @@ import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection;
import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
@ -72,34 +80,57 @@ import org.xml.sax.SAXException;
* </dl>
* <p>
* Each overlays may provide the following files and subdirectories:<dl>
* <dt>lib</dt>
* <dd>The lib directory can contain jars that are applied to a {@link URLClassLoader} that is
* <dt>WEB-INF/lib-overlay</dt>
* <dd>The lib-overlay directory can contain jars that are applied to a {@link URLClassLoader} that is
* available before any overlay.xml files are executed, so that classes from these jars may be used by the
* overlay.xml.</dd>
*
* <dt>overlay.xml</dt>
* <dt>WEB-INF/overlay.xml</dt>
* <dd>This {@link XmlConfiguration} formatted file must exist in the WEB-INF directory of an overlay and is
* used to configure a {@link ContextHandler} or {@link WebAppContext}. The overlay.xml from the template
* overlay can be used to instantiate the ContextHandler instance, so a derived class maybe used.</dd>
*
* <dt>template.xml</dt>
* <dt>WEB-INF/template.xml</dt>
* <dd>This {@link XmlConfiguration} formatted file if it exists in a template or node overlay, is applied to a shared instance of {@link TemplateContext}.
* Any ID's created in a template are available as ID's in overlay.xml for an instance.</dd>
*
* <dt>webdefault.xml</dt>
* <dt>WEB-INF/webdefault.xml</dt>
* <dd>If present in an overlay, then the most specific version is passed to
* {@link WebAppContext#setDefaultsDescriptor(String)}. Typically this is set in the template overlay.</dd>
*
* <dt>web-overlay.xml</dt>
* <dt>WEB-INF/web-overlay.xml</dt>
* <dd>The web-overlay.xml file of an overlay is applied to a web application as
* with {@link WebAppContext#addOverrideDescriptor(String)}. This allows incremental changes to web.xml without
* totally replacing it (see webapp). Typically this is used to set init parameters.</dd>
*
* <dt>webapp</dt>
* <dd>This directory contains static content that overlays the static content of the webapp
* <dt>.</dt>
* <dd>This root directory contains static content that overlays the static content of the webapp
* or earlier overlays. Using this directory, files like index.html or logo.png can be added or replaced. It can
* also be used to replace files within WEB-INF including web.xml classes and libs.</dd>
*
* </dl>
* <p>
* Any init parameters set on the context, filters or servlets may have parameterized values, with the parameters
* including:
* <dl>
* <dt>${overlays.dir}</dt>
* <dd>the root overlay scan directory as a canonical file name.</dd>
* <dt>${overlay.webapp}</dt>
* <dd>the webapp name, same as {@link Webapp#getName()}.</dd>
* <dt>${overlay.template}</dt>
* <dd>the template name, as {@link Template#getName()}.</dd>
* <dt>${overlay.template.name}</dt>
* <dd>the template classifier, as {@link Template#getTemplateName()}.</dd>
* <dt>${overlay.template.classifier}</dt>
* <dd>the template classifier, as {@link Template#getClassifier()()}.</dd>
* <dt>${overlay.node}</dt>
* <dd>the node name, as {@link Node#getName()}.</dd>
* <dt>${overlay.instance}</dt>
* <dd>the instance name, {@link Instance#getName()}.</dd>
* <dt>${overlay.instance.classifier}</dt>
* <dd>the instance name, {@link Instance#getClassifier()()}.</dd>
* <dt>${*}</dt>
* <dd>Any properties obtained via {@link #getConfigurationManager()}.{@link ConfigurationManager#getProperties()}</dd>
* <dd></dd>
* </dl>
* <p>
* The OverlayedAppProvider will scan the "webapps", "templates", "nodes" and "instances" subdirectories of
@ -122,7 +153,7 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
{
private final static Logger __log=org.eclipse.jetty.util.log.Log.getLogger("OverlayedAppProvider");
/**
* Property set for overlay.xml and template.xml files that gives the root overlay scan directory as a canoncial file name.
* Property set for overlay.xml and template.xml files that gives the root overlay scan directory as a canonical file name.
*/
public final static String OVERLAYS_DIR="overlays.dir";
/**
@ -130,9 +161,17 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
*/
public final static String OVERLAY_WEBAPP="overlay.webapp";
/**
* Property set for overlay.xml and template.xml files that gives the current template name, as {@link Template#getTemplateName()}.
* Property set for overlay.xml and template.xml files that gives the current template full name, as {@link Template#getName()}.
*/
public final static String OVERLAY_TEMPLATE="overlay.template";
/**
* Property set for overlay.xml and template.xml files that gives the current template name, as {@link Template#getTemplateName()}.
*/
public final static String OVERLAY_TEMPLATE_NAME="overlay.template.name";
/**
* Property set for overlay.xml and template.xml files that gives the current template classifier, as {@link Template#getClassifier()}.
*/
public final static String OVERLAY_TEMPLATE_CLASSIFIER="overlay.template.classifier";
/**
* Property set for overlay.xml and template.xml files that gives the current node name, as {@link Node#getName()}.
*/
@ -141,6 +180,10 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
* Property set for overlay.xml and template.xml files that gives the current instance name, {@link Instance#getName()}.
*/
public final static String OVERLAY_INSTANCE="overlay.instance";
/**
* Property set for overlay.xml and template.xml files that gives the current instance clasifier, {@link Instance#getClassifier()}.
*/
public final static String OVERLAY_INSTANCE_CLASSIFIER="overlay.instance.classifier";
public final static String WEBAPPS="webapps";
public final static String TEMPLATES="templates";
@ -490,6 +533,14 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
__log.debug("{}: baseResource={}",origin,context.getBaseResource());
Resource jetty_web_xml = context.getResource("/WEB-INF/"+JettyWebXmlConfiguration.JETTY_WEB_XML);
if (jetty_web_xml!=null && jetty_web_xml.exists())
context.setAttribute(JettyWebXmlConfiguration.XML_CONFIGURATION,newXmlConfiguration(jetty_web_xml.getURL(),idMap,template,instance));
// Add listener to expand parameters from descriptors before other listeners execute
Map<String,String> params = new HashMap<String,String>();
populateParameters(params,template,instance);
context.addEventListener(new ParameterExpander(params,context));
System.err.println("created:\n"+context.dump());
@ -505,23 +556,41 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
private XmlConfiguration newXmlConfiguration(URL url, Map<String, Object> idMap, Template template, Instance instance) throws SAXException, IOException
{
XmlConfiguration xmlc = new XmlConfiguration(url);
xmlc.getProperties().put(OVERLAYS_DIR,_scanDir.getCanonicalPath());
if (template!=null)
{
xmlc.getProperties().put(OVERLAY_TEMPLATE,template.getTemplateName());
xmlc.getProperties().put(OVERLAY_WEBAPP,template.getWebapp()==null?null:template.getWebapp().getName());
}
if (_node!=null)
xmlc.getProperties().put(OVERLAY_NODE,_node.getName());
if (instance!=null)
xmlc.getProperties().put(OVERLAY_INSTANCE,instance.getName());
if (getConfigurationManager()!=null)
xmlc.getProperties().putAll(getConfigurationManager().getProperties());
populateParameters(xmlc.getProperties(),template,instance);
xmlc.getIdMap().putAll(idMap);
return xmlc;
}
/* ------------------------------------------------------------ */
private void populateParameters(Map<String,String> params,Template template, Instance instance)
{
try
{
params.put(OVERLAYS_DIR,_scanDir.getCanonicalPath());
if (template!=null)
{
params.put(OVERLAY_TEMPLATE,template.getName());
params.put(OVERLAY_TEMPLATE_NAME,template.getTemplateName());
params.put(OVERLAY_TEMPLATE_CLASSIFIER,template.getClassifier());
params.put(OVERLAY_WEBAPP,template.getWebapp()==null?null:template.getWebapp().getName());
}
if (_node!=null)
params.put(OVERLAY_NODE,_node.getName());
if (instance!=null)
{
params.put(OVERLAY_INSTANCE,instance.getName());
params.put(OVERLAY_INSTANCE_CLASSIFIER,instance.getClassifier());
}
if (getConfigurationManager()!=null)
params.putAll(getConfigurationManager().getProperties());
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}
/* ------------------------------------------------------------ */
private TemplateContext createTemplateContext(final String key, Webapp webapp, Template template, Node node, ClassLoader parent) throws Exception
@ -559,7 +628,7 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
// Make the shared resourceBase
List<Resource> bases = new ArrayList<Resource>();
for (Resource wa : getLayeredResources("webapp",node,template))
for (Resource wa : getLayers(node,template))
bases.add(wa);
if (webapp!=null)
bases.add(webapp.getBaseResource());
@ -1081,6 +1150,21 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
return webapp;
}
/* ------------------------------------------------------------ */
private static List<Resource> getLayers(Layer... layers)
{
List<Resource> resources = new ArrayList<Resource>();
for (Layer layer: layers)
{
if (layer==null)
continue;
Resource resource = layer.getBaseResource();
if (resource.exists())
resources.add(resource);
}
return resources;
}
/* ------------------------------------------------------------ */
private static List<Resource> getLayeredResources(String path, Layer... layers)
{
@ -1359,4 +1443,73 @@ public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvid
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private final class ParameterExpander implements ServletContextListener
{
private final Map<String, String> _params;
private final ContextHandler _ctx;
private ParameterExpander(Map<String, String> params, ContextHandler ctx)
{
_params = params;
_ctx = ctx;
}
public void contextInitialized(ServletContextEvent sce)
{
Enumeration<String> e=_ctx.getInitParameterNames();
while (e.hasMoreElements())
{
String name = e.nextElement();
_ctx.setInitParameter(name,expandParameter(_ctx.getInitParameter(name)));
}
ServletHandler servletHandler = _ctx.getChildHandlerByClass(ServletHandler.class);
if (servletHandler!=null)
{
List<Holder<?>> holders = new ArrayList<Holder<?>>();
holders.addAll(Arrays.asList(servletHandler.getFilters()));
holders.addAll(Arrays.asList(servletHandler.getServlets()));
for (Holder<?> holder: holders)
{
e=holder.getInitParameterNames();
while (e.hasMoreElements())
{
String name = e.nextElement();
holder.setInitParameter(name,expandParameter(holder.getInitParameter(name)));
}
}
}
}
private String expandParameter(String value)
{
int i=0;
while (true)
{
int open=value.indexOf("${",i);
if (open<0)
return value;
int close=value.indexOf("}",open);
if (close<0)
return value;
String param = value.substring(open+2,close);
if (_params.containsKey(param))
{
String tmp=value.substring(0,open)+_params.get(param);
i=tmp.length();
value=tmp+value.substring(close+1);
}
else
i=close+1;
}
}
public void contextDestroyed(ServletContextEvent sce)
{
}
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Call class="org.eclipse.jetty.util.log.Log" name="info"><Arg>Executing jetty-web.xml for <Property name="overlay.instance"/></Arg></Call>
</Configure>

View File

@ -15,7 +15,26 @@
<param-name>template</param-name>
<param-value>templates/myfoo/web.xml</param-value>
</context-param>
<context-param>
<param-name>overlay.template</param-name>
<param-value>${overlay.template}</param-value>
</context-param>
<context-param>
<param-name>overlay.template.name</param-name>
<param-value>${overlay.template.name}</param-value>
</context-param>
<context-param>
<param-name>overlay.template.classifier</param-name>
<param-value>${overlay.template.classifier}</param-value>
</context-param>
<context-param>
<param-name>overlay.instance.classifier</param-name>
<param-value>${overlay.instance.classifier}</param-value>
</context-param>
<context-param>
<param-name>overlay.instance</param-name>
<param-value>${overlay.instance}</param-value>
</context-param>
</web-app>

View File

@ -196,8 +196,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
dump(out,indent,Collections.singletonList(new CLDump(getClassLoader())),TypeUtil.asList(getHandlers()),getBeans(),_initParams.entrySet(), _attributes.getAttributeEntrySet(),_contextAttributes.getAttributeEntrySet());
}
/* ------------------------------------------------------------ */
public Context getServletContext()
{

View File

@ -71,4 +71,9 @@ public abstract class Descriptor
{
return _root;
}
public String toString()
{
return this.getClass().getSimpleName()+"("+_xml+")";
}
}

View File

@ -38,6 +38,8 @@ public class JettyWebXmlConfiguration extends AbstractConfiguration
public static final String PROPERTY_THIS_WEB_INF_URL = "this.web-inf.url";
public static final String XML_CONFIGURATION = "org.eclipse.jetty.webapp.JettyWebXmlConfiguration";
public static final String JETTY_WEB_XML = "jetty-web.xml";
/**
* Configure
@ -64,7 +66,7 @@ public class JettyWebXmlConfiguration extends AbstractConfiguration
// do jetty.xml file
Resource jetty=web_inf.addPath("jetty7-web.xml");
if(!jetty.exists())
jetty=web_inf.addPath("jetty-web.xml");
jetty=web_inf.addPath(JETTY_WEB_XML);
if(!jetty.exists())
jetty=web_inf.addPath("web-jetty.xml");
@ -77,7 +79,11 @@ public class JettyWebXmlConfiguration extends AbstractConfiguration
context.setServerClasses(null);
if(Log.isDebugEnabled())
Log.debug("Configure: "+jetty);
XmlConfiguration jetty_config=new XmlConfiguration(jetty.getURL());
XmlConfiguration jetty_config = (XmlConfiguration)context.getAttribute(XML_CONFIGURATION);
if (jetty_config==null)
jetty_config=new XmlConfiguration(jetty.getURL());
else
context.removeAttribute(XML_CONFIGURATION);
setupXmlConfiguration(context,jetty_config, web_inf);
jetty_config.configure(context);
}

View File

@ -21,6 +21,7 @@ import java.util.Map;
import javax.servlet.ServletContext;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.resource.Resource;
@ -293,6 +294,8 @@ public class MetaData
public void resolve (WebAppContext context)
throws Exception
{
Log.debug("metadata resolve {}",context);
//Ensure origins is fresh
_origins.clear();
@ -316,11 +319,17 @@ public class MetaData
p.process(context,getWebDefault());
p.process(context,getWebXml());
for (WebDescriptor wd : getOverrideWebs())
{
Log.debug("process {} {}",context,wd);
p.process(context,wd);
}
}
for (DiscoveredAnnotation a:_annotations)
{
Log.debug("apply {}",a);
a.apply();
}
List<Resource> resources = getOrderedWebInfJars();
@ -331,6 +340,7 @@ public class MetaData
{
for (DescriptorProcessor p:_descriptorProcessors)
{
Log.debug("process {} {}",context,fd);
p.process(context,fd);
}
}
@ -339,7 +349,10 @@ public class MetaData
if (fragAnnotations != null)
{
for (DiscoveredAnnotation a:fragAnnotations)
{
Log.debug("apply {}",a);
a.apply();
}
}
}

View File

@ -407,7 +407,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
// Prepare for configuration
for (int i=0;i<_configurations.length;i++)
{
Log.debug("preConfigure {} with {}",this,_configurations[i]);
_configurations[i].preConfigure(this);
}
}
/* ------------------------------------------------------------ */
@ -415,7 +418,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
{
// Configure webapp
for (int i=0;i<_configurations.length;i++)
{
Log.debug("configure {} with {}",this,_configurations[i]);
_configurations[i].configure(this);
}
}
/* ------------------------------------------------------------ */
@ -423,7 +429,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
{
// Clean up after configuration
for (int i=0;i<_configurations.length;i++)
{
Log.debug("postConfigure {} with {}",this,_configurations[i]);
_configurations[i].postConfigure(this);
}
}
/* ------------------------------------------------------------ */
@ -1092,7 +1101,6 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
_war = war;
}
/* ------------------------------------------------------------ */
/**
* @return Comma or semicolon separated path of filenames or URLs
@ -1170,7 +1178,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
_throwUnavailableOnStartupException = throwIfStartupException;
}
/* ------------------------------------------------------------ */
public boolean isThrowUnavailableOnStartupException () {
return _throwUnavailableOnStartupException;
}

View File

@ -49,7 +49,6 @@ public class TestServer
{
public static void main(String[] args) throws Exception
{
Log.getLog().setDebugEnabled(false);
((StdErrLog)Log.getLog()).setSource(false);
String jetty_root = "..";