From 4cd8b077b5dfc35935d2565337f6671436af437c Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 5 May 2011 03:03:12 +0000 Subject: [PATCH] 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 --- .../jetty/overlays/OverlayedAppProvider.java | 201 +++++++++++++++--- .../templates/myfoo=foo/WEB-INF/jetty-web.xml | 6 + .../myfoo=foo/WEB-INF/web-overlay.xml | 21 +- .../jetty/server/handler/ContextHandler.java | 2 - .../org/eclipse/jetty/webapp/Descriptor.java | 5 + .../webapp/JettyWebXmlConfiguration.java | 10 +- .../org/eclipse/jetty/webapp/MetaData.java | 13 ++ .../eclipse/jetty/webapp/WebAppContext.java | 13 +- .../java/org/eclipse/jetty/TestServer.java | 1 - 9 files changed, 240 insertions(+), 32 deletions(-) create mode 100644 jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/jetty-web.xml diff --git a/jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/OverlayedAppProvider.java b/jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/OverlayedAppProvider.java index 7a5324a25e3..9885cd96ff7 100644 --- a/jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/OverlayedAppProvider.java +++ b/jetty-overlay-deployer/src/main/java/org/eclipse/jetty/overlays/OverlayedAppProvider.java @@ -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; * *

* Each overlays may provide the following files and subdirectories:

- *
lib
- *
The lib directory can contain jars that are applied to a {@link URLClassLoader} that is + *
WEB-INF/lib-overlay
+ *
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.
* - *
overlay.xml
+ *
WEB-INF/overlay.xml
*
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.
* - *
template.xml
+ *
WEB-INF/template.xml
*
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.
* - *
webdefault.xml
+ *
WEB-INF/webdefault.xml
*
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.
* - *
web-overlay.xml
+ *
WEB-INF/web-overlay.xml
*
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.
* - *
webapp
- *
This directory contains static content that overlays the static content of the webapp + *
.
+ *
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.
- * + *
+ *

+ * Any init parameters set on the context, filters or servlets may have parameterized values, with the parameters + * including: + *

+ *
${overlays.dir}
+ *
the root overlay scan directory as a canonical file name.
+ *
${overlay.webapp}
+ *
the webapp name, same as {@link Webapp#getName()}.
+ *
${overlay.template}
+ *
the template name, as {@link Template#getName()}.
+ *
${overlay.template.name}
+ *
the template classifier, as {@link Template#getTemplateName()}.
+ *
${overlay.template.classifier}
+ *
the template classifier, as {@link Template#getClassifier()()}.
+ *
${overlay.node}
+ *
the node name, as {@link Node#getName()}.
+ *
${overlay.instance}
+ *
the instance name, {@link Instance#getName()}.
+ *
${overlay.instance.classifier}
+ *
the instance name, {@link Instance#getClassifier()()}.
+ *
${*}
+ *
Any properties obtained via {@link #getConfigurationManager()}.{@link ConfigurationManager#getProperties()}
+ *
*
*

* 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 params = new HashMap(); + 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 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 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 bases = new ArrayList(); - 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 getLayers(Layer... layers) + { + List resources = new ArrayList(); + for (Layer layer: layers) + { + if (layer==null) + continue; + Resource resource = layer.getBaseResource(); + if (resource.exists()) + resources.add(resource); + } + return resources; + } + /* ------------------------------------------------------------ */ private static List 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 _params; + private final ContextHandler _ctx; + + private ParameterExpander(Map params, ContextHandler ctx) + { + _params = params; + _ctx = ctx; + } + + public void contextInitialized(ServletContextEvent sce) + { + Enumeration 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> holders = new ArrayList>(); + 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) + { + } + } } diff --git a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/jetty-web.xml b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/jetty-web.xml new file mode 100644 index 00000000000..33526645e3c --- /dev/null +++ b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/jetty-web.xml @@ -0,0 +1,6 @@ + + + + + Executing jetty-web.xml for + \ No newline at end of file diff --git a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/web-overlay.xml b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/web-overlay.xml index 44c7878918b..c03f435a740 100644 --- a/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/web-overlay.xml +++ b/jetty-overlay-deployer/src/test/resources/home/overlays/templates/myfoo=foo/WEB-INF/web-overlay.xml @@ -15,7 +15,26 @@ template templates/myfoo/web.xml - + + overlay.template + ${overlay.template} + + + overlay.template.name + ${overlay.template.name} + + + overlay.template.classifier + ${overlay.template.classifier} + + + overlay.instance.classifier + ${overlay.instance.classifier} + + + overlay.instance + ${overlay.instance} + diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 704b6c285eb..7fa375521b0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -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() { diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java index e35210643fa..7bfe2e7fdb8 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java @@ -71,4 +71,9 @@ public abstract class Descriptor { return _root; } + + public String toString() + { + return this.getClass().getSimpleName()+"("+_xml+")"; + } } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java index 19c787684e5..037ed9a2537 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java @@ -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); } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java index 44184898b5e..212a08a0690 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java @@ -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 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(); + } } } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index ddebb549f69..c215e6f1524 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -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; } diff --git a/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java b/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java index 1ae8301bc9a..5182df00a71 100644 --- a/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java +++ b/test-jetty-webapp/src/test/java/org/eclipse/jetty/TestServer.java @@ -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 = "..";