From 4675e38841ce6067538d57d93e8b1f80c06354ef Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Thu, 28 May 2009 03:51:44 +0000 Subject: [PATCH] Ensure MetaInfConfiguration finds all candidate jars from the container path and also from web-inf, then applies inclusion patterns to them to do an initial ordering. Jetty-8 will modify this ordering based on web-fragment ordering. The list of jars is passed around as a context attribute. The inclusion patterns are specified as context attributes. The ContextDeployer and WebAppDeployer can be configured with context attributes (such as the default inclusion patterns) that are set on every context they deploy. The list of jars are passed around as a List of Resources, and the pattern matching is done based on the URI (ie as a name string) rather than as a jar URL. git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@310 7e9141cc-0065-0410-87d8-b60c137991c4 --- .../annotations/AnnotationConfiguration.java | 116 +++++++++++++----- .../jetty/annotations/AnnotationFinder.java | 37 +++--- .../eclipse/jetty/deploy/ContextDeployer.java | 38 +++++- .../eclipse/jetty/deploy/WebAppDeployer.java | 39 +++++- .../eclipse/jetty/plus/jndi/NamingEntry.java | 1 - .../plus/webapp/AbstractConfiguration.java | 2 +- .../jetty/plus/webapp/Configuration.java | 12 +- .../jetty/plus/webapp/EnvConfiguration.java | 25 ++-- jetty-server/src/main/config/etc/jetty.xml | 8 ++ .../org/eclipse/jetty/util/AttributesMap.java | 5 + .../eclipse/jetty/util/PatternMatcher.java | 86 +++++++++++++ .../util/component/AbstractLifeCycle.java | 1 + .../src/main/config/etc/webdefault.xml | 18 --- .../jetty/webapp/FragmentConfiguration.java | 23 ++-- .../org/eclipse/jetty/webapp/JarScanner.java | 115 +++++------------ .../jetty/webapp/MetaInfConfiguration.java | 89 +++++--------- .../jetty/webapp/TagLibConfiguration.java | 26 +--- .../jetty/webapp/WebInfConfiguration.java | 105 +++++++++++++++- .../jetty/webapp/WebXmlConfiguration.java | 11 +- .../eclipse/jetty/webapp/WebXmlProcessor.java | 7 +- 20 files changed, 479 insertions(+), 285 deletions(-) create mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index afd59ee5c9b..525565373f8 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -13,6 +13,10 @@ package org.eclipse.jetty.annotations; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; import java.util.EventListener; import java.util.List; @@ -25,6 +29,7 @@ import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.WebInfConfiguration; /** * Configuration @@ -33,8 +38,7 @@ import org.eclipse.jetty.webapp.WebAppContext; */ public class AnnotationConfiguration extends org.eclipse.jetty.plus.webapp.Configuration { - public static final String __web_inf_pattern = "org.eclipse.jetty.server.webapp.WebInfIncludeAnnotationJarPattern"; - public static final String __container_pattern = "org.eclipse.jetty.server.webapp.ContainerIncludeAnnotationJarPattern"; + public static final String JAR_RESOURCES = WebInfConfiguration.JAR_RESOURCES; @@ -89,7 +93,25 @@ public class AnnotationConfiguration extends org.eclipse.jetty.plus.webapp.Confi { //if no pattern for the container path is defined, then by default scan NOTHING Log.debug("Scanning container jars"); - parseAnnotationsFromJars(context, finder, context.getClassLoader().getParent(), context.getInitParameter(__container_pattern),true, false, + + //Get the container jar uris + + ArrayList containerCandidateUris = findJars (context.getClassLoader().getParent(), true); + + //Pick out the uris from JAR_RESOURCES that match those uris to be scanned + ArrayList containerUris = new ArrayList(); + List jarResources = (List)context.getAttribute(JAR_RESOURCES); + for (Resource r : jarResources) + { + URI uri = r.getURI(); + if (containerCandidateUris.contains(uri)) + { + containerUris.add(uri); + } + + } + + finder.find (containerUris.toArray(new URI[containerUris.size()]), new ClassNameResolver () { public boolean isExcluded (String name) @@ -114,8 +136,23 @@ public class AnnotationConfiguration extends org.eclipse.jetty.plus.webapp.Confi throws Exception { Log.debug("Scanning WEB-INF/lib jars"); + //Get the uris of jars on the webapp classloader + ArrayList candidateUris = findJars(context.getClassLoader(), false); + + //Pick out the uris from JAR_RESOURCES that match those to be scanned + ArrayList webInfUris = new ArrayList(); + List jarResources = (List)context.getAttribute(JAR_RESOURCES); + for (Resource r : jarResources) + { + URI uri = r.getURI(); + if (candidateUris.contains(uri)) + { + webInfUris.add(uri); + } + } + //if no pattern for web-inf/lib is defined, then by default scan everything in it - parseAnnotationsFromJars (context, finder, context.getClassLoader(), context.getInitParameter(__web_inf_pattern), false, true, + finder.find(webInfUris.toArray(new URI[webInfUris.size()]), new ClassNameResolver() { public boolean isExcluded (String name) @@ -140,37 +177,54 @@ public class AnnotationConfiguration extends org.eclipse.jetty.plus.webapp.Confi throws Exception { Log.debug("Scanning classes in WEB-INF/classes"); - parseAnnotationsFromDir (context, finder, context.getWebInf().addPath("classes/"), - new ClassNameResolver() + finder.find(context.getWebInf().addPath("classes/"), + new ClassNameResolver() + { + public boolean isExcluded (String name) + { + if (context.isSystemClass(name)) return true; + if (context.isServerClass(name)) return false; + return false; + } + + public boolean shouldOverride (String name) + { + //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp? + if (context.isParentLoaderPriority()) + return false; + return true; + } + }); + } + + + + public ArrayList findJars (ClassLoader loader, boolean visitParent) + { + ArrayList uris = new ArrayList(); + + while (loader != null && (loader instanceof URLClassLoader)) + { + URL[] urls = ((URLClassLoader)loader).getURLs(); + if (urls != null) + { + for (URL u : urls) { - public boolean isExcluded (String name) + try { - if (context.isSystemClass(name)) return true; - if (context.isServerClass(name)) return false; - return false; + uris.add(u.toURI()); } - - public boolean shouldOverride (String name) + catch (Exception e) { - //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp? - if (context.isParentLoaderPriority()) - return false; - return true; + Log.warn(e); } - }); - } - - - - public void parseAnnotationsFromJars (final WebAppContext context, final AnnotationFinder finder, final ClassLoader classloader, final String pattern, boolean visitParents, boolean isNullInclusive, ClassNameResolver resolver) - throws Exception - { - finder.find (classloader, visitParents, pattern, isNullInclusive,resolver); - } - - public void parseAnnotationsFromDir (final WebAppContext context, final AnnotationFinder finder, final Resource dir, ClassNameResolver resolver) - throws Exception - { - finder.find(dir, resolver); + } + } + if (visitParent) + loader = loader.getParent(); + else + loader = null; + } + return uris; } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationFinder.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationFinder.java index f3faa9a1463..ab2a5447d99 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationFinder.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationFinder.java @@ -18,6 +18,7 @@ import java.io.InputStream; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -586,7 +587,7 @@ public class AnnotationFinder * @param resolver * @throws Exception */ - public void find (ClassLoader loader, boolean visitParents, String jarNamePattern, boolean nullInclusive, final ClassNameResolver resolver) + public void find (ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver) throws Exception { if (loader==null) @@ -597,7 +598,7 @@ public class AnnotationFinder JarScanner scanner = new JarScanner() { - public void processEntry(URL jarUrl, JarEntry entry) + public void processEntry(URI jarUri, JarEntry entry) { try { @@ -610,7 +611,7 @@ public class AnnotationFinder if ((parsedClasses.get(shortName) == null) || (resolver.shouldOverride(shortName))) { parsedClasses.remove(shortName); - Resource clazz = Resource.newResource("jar:"+jarUrl+"!/"+name); + Resource clazz = Resource.newResource("jar:"+jarUri+"!/"+name); scanClass(clazz.getInputStream()); } } @@ -623,32 +624,26 @@ public class AnnotationFinder } }; - Pattern pattern = null; - if (jarNamePattern!=null) - pattern = Pattern.compile(jarNamePattern); - - scanner.scan(pattern, loader, nullInclusive, visitParents); + + scanner.scan(null, loader, nullInclusive, visitParents); } /** - * Find annotations in classes in classes in the supplied url of jar files. - * @param urls - * @param visitParents - * @param jarNamePattern - * @param nullInclusive + * Find annotations in classes in the supplied url of jar files. + * @param uris * @param resolver * @throws Exception */ - public void find (URL[] urls, boolean visitParents, String jarNamePattern, boolean nullInclusive, final ClassNameResolver resolver) + public void find (URI[] uris, final ClassNameResolver resolver) throws Exception { - if (urls==null) + if (uris==null) return; JarScanner scanner = new JarScanner() { - public void processEntry(URL jarUrl, JarEntry entry) + public void processEntry(URI jarUri, JarEntry entry) { try { @@ -661,7 +656,7 @@ public class AnnotationFinder if ((parsedClasses.get(shortName) == null) || (resolver.shouldOverride(shortName))) { parsedClasses.remove(shortName); - Resource clazz = Resource.newResource("jar:"+jarUrl+"!/"+name); + Resource clazz = Resource.newResource("jar:"+jarUri+"!/"+name); scanClass(clazz.getInputStream()); } } @@ -673,12 +668,8 @@ public class AnnotationFinder } } - }; - Pattern pattern = null; - if (jarNamePattern!=null) - pattern = Pattern.compile(jarNamePattern); - - scanner.scan(pattern, urls, nullInclusive); + }; + scanner.scan(null, uris, true); } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java index 74015e5ecb9..3f767a51235 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/ContextDeployer.java @@ -22,6 +22,7 @@ import java.util.Map; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.Scanner; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.log.Log; @@ -73,7 +74,8 @@ public class ContextDeployer extends AbstractLifeCycle private ContextHandlerCollection _contexts; private ConfigurationManager _configMgr; private boolean _recursive = false; - + private AttributesMap _contextAttributes = new AttributesMap(); + /* ------------------------------------------------------------ */ protected class ScannerListener implements Scanner.DiscreteListener { @@ -255,6 +257,39 @@ public class ContextDeployer extends AbstractLifeCycle { return _recursive; } + + + /** + * Set a contextAttribute that will be set for every Context deployed by this deployer. + * @param name + * @param value + */ + public void setAttribute (String name, Object value) + { + _contextAttributes.setAttribute(name,value); + } + + + /** + * Get a contextAttribute that will be set for every Context deployed by this deployer. + * @param name + * @return + */ + public Object getAttribute (String name) + { + return _contextAttributes.getAttribute(name); + } + + + /** + * Remove a contextAttribute that will be set for every Context deployed by this deployer. + * @param name + */ + public void removeAttribute(String name) + { + _contextAttributes.removeAttribute(name); + } + /* ------------------------------------------------------------ */ private void deploy(String filename) throws Exception { @@ -365,6 +400,7 @@ public class ContextDeployer extends AbstractLifeCycle xmlConfiguration.setProperties(properties); ContextHandler context=(ContextHandler)xmlConfiguration.configure(); + context.setAttributes(new AttributesMap(_contextAttributes)); return context; } diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/WebAppDeployer.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/WebAppDeployer.java index fb5ebae629c..0caabb4f131 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/WebAppDeployer.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/WebAppDeployer.java @@ -16,10 +16,10 @@ package org.eclipse.jetty.deploy; import java.util.ArrayList; import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HandlerContainer; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.resource.Resource; @@ -51,6 +51,7 @@ public class WebAppDeployer extends AbstractLifeCycle private boolean _parentLoaderPriority; private boolean _allowDuplicates; private ArrayList _deployed; + private AttributesMap _contextAttributes = new AttributesMap(); public String[] getConfigurationClasses() { @@ -126,6 +127,38 @@ public class WebAppDeployer extends AbstractLifeCycle _allowDuplicates=allowDuplicates; } + + /** + * Set a contextAttribute that will be set for every Context deployed by this deployer. + * @param name + * @param value + */ + public void setAttribute (String name, Object value) + { + _contextAttributes.setAttribute(name,value); + } + + + /** + * Get a contextAttribute that will be set for every Context deployed by this deployer. + * @param name + * @return + */ + public Object getAttribute (String name) + { + return _contextAttributes.getAttribute(name); + } + + + /** + * Remove a contextAttribute that will be set for every Context deployed by this deployer. + * @param name + */ + public void removeAttribute(String name) + { + _contextAttributes.removeAttribute(name); + } + /* ------------------------------------------------------------ */ /** * @throws Exception @@ -234,6 +267,10 @@ public class WebAppDeployer extends AbstractLifeCycle wah.setExtractWAR(_extract); wah.setWar(app.toString()); wah.setParentLoaderPriority(_parentLoaderPriority); + + //set up any contextAttributes + wah.setAttributes(_contextAttributes); + // add it _contexts.addHandler(wah); _deployed.add(wah); diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java index 4b71f534b7c..2fd2bcd8848 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java @@ -201,7 +201,6 @@ public abstract class NamingEntry objectName.addAll(0, prefix); objectNameString = objectName.toString(); NamingUtil.bind(ic, objectNameString, objectToBind); - System.err.println("Bound: "+objectName.toString()+" to "+objectToBind); } } diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/AbstractConfiguration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/AbstractConfiguration.java index 245342b59ad..27de9d1da5c 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/AbstractConfiguration.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/AbstractConfiguration.java @@ -411,7 +411,7 @@ public abstract class AbstractConfiguration implements Configuration { bindUserTransaction(context); - WebXmlProcessor webXmlProcessor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.__web_processor); + WebXmlProcessor webXmlProcessor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); if (webXmlProcessor == null) throw new IllegalStateException ("No processor for web xml"); diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/Configuration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/Configuration.java index 8f701890600..d024897adaa 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/Configuration.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/Configuration.java @@ -62,8 +62,6 @@ public class Configuration extends AbstractConfiguration EnvEntry ee = (EnvEntry)ne; bound = ee.isOverrideWebXml(); } - - System.err.println("Checked for envEntry already bound for "+name+" and got: "+ne+", bound="+bound); } catch (NameNotFoundException e) { @@ -75,7 +73,6 @@ public class Configuration extends AbstractConfiguration //either nothing was bound or the value from web.xml should override Context envCtx = (Context)ic.lookup("java:comp/env"); NamingUtil.bind(envCtx, name, value); - System.err.println("Bound "+name+"to "+value+" for java:comp/env"); } } @@ -186,7 +183,8 @@ public class Configuration extends AbstractConfiguration */ public void parseAnnotations(WebAppContext context) throws Exception { - //see org.eclipse.jetty.annotations.Configuration instead + //Noop unless you want to do annotation discovery. + //Use org.eclipse.jetty.annotations.Configuration instead. } /** @@ -220,32 +218,26 @@ public class Configuration extends AbstractConfiguration //if we found a mapping, get out name it is mapped to in the environment nameInEnvironment = (String)((Link)ne).getObjectToBind(); Link l = (Link)ne; - System.err.println("Link, with nameInEnvironment="+nameInEnvironment); } //try finding that mapped name in the webapp's environment first - System.err.println("Trying to find "+nameInEnvironment+" in webapp scope"); scope = context; bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment); if (bound) return; - System.err.println("Trying to find "+nameInEnvironment+" in server scope"); //try the server's environment scope = context.getServer(); bound = NamingEntryUtil.bindToENC(scope, name, nameInEnvironment); if (bound) return; - System.err.println("Trying to find "+nameInEnvironment+" in jvm scope"); //try the jvm environment bound = NamingEntryUtil.bindToENC(null, name, nameInEnvironment); if (bound) return; - - System.err.println("Didn't find "+nameInEnvironment+" anywhere - looking for "+typeClass.getName()+"/default in server or jvm scope"); //There is no matching resource so try a default name. //The default name syntax is: the [res-type]/default //eg javax.sql.DataSource/default diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java index ab71920e65c..cb6297a5274 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/EnvConfiguration.java @@ -40,9 +40,6 @@ import org.eclipse.jetty.xml.XmlConfiguration; */ public class EnvConfiguration implements Configuration { - - private Context compCtx; - private Context envCtx; private URL jettyEnvXmlUrl; @@ -96,7 +93,6 @@ public class EnvConfiguration implements Configuration //apply the jetty-env.xml file if (jettyEnvXmlUrl != null) { - System.err.println("Applying "+jettyEnvXmlUrl); XmlConfiguration configuration = new XmlConfiguration(jettyEnvXmlUrl); configuration.configure(context); } @@ -122,8 +118,17 @@ public class EnvConfiguration implements Configuration //get rid of any bindings for comp/env for webapp ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(context.getClassLoader()); - compCtx.destroySubcontext("env"); - + try + { + Context ic = new InitialContext(); + Context compCtx = (Context)ic.lookup ("java:comp"); + compCtx.destroySubcontext("env"); + } + catch (NameNotFoundException e) + { + Log.warn(e); + } + //unbind any NamingEntries that were configured in this webapp's name space try { @@ -149,6 +154,8 @@ public class EnvConfiguration implements Configuration throws NamingException { Log.debug("Binding env entries from the jvm scope"); + InitialContext ic = new InitialContext(); + Context envCtx = (Context)ic.lookup("java:comp/env"); Object scope = null; List list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class); Iterator itor = list.iterator(); @@ -190,9 +197,7 @@ public class EnvConfiguration implements Configuration throws NamingException { Context context = new InitialContext(); - compCtx = (Context)context.lookup ("java:comp"); - envCtx = compCtx.createSubcontext("env"); - - System.err.println("Created comp/env"); + Context compCtx = (Context)context.lookup ("java:comp"); + compCtx.createSubcontext("env"); } } diff --git a/jetty-server/src/main/config/etc/jetty.xml b/jetty-server/src/main/config/etc/jetty.xml index 05524237fac..a558ae18208 100644 --- a/jetty-server/src/main/config/etc/jetty.xml +++ b/jetty-server/src/main/config/etc/jetty.xml @@ -110,6 +110,10 @@ /contexts 5 + + org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern + .*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$ + @@ -136,6 +140,10 @@ true false /etc/webdefault.xml + + org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern + .*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$ + diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java index 9869bed0756..fed60e08336 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/AttributesMap.java @@ -41,6 +41,11 @@ public class AttributesMap implements Attributes _map=map; } + public AttributesMap(AttributesMap map) + { + _map=new HashMap(map._map); + } + /* ------------------------------------------------------------ */ /* * @see org.eclipse.jetty.util.Attributes#removeAttribute(java.lang.String) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java b/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java new file mode 100644 index 00000000000..3d8522e4518 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/PatternMatcher.java @@ -0,0 +1,86 @@ +package org.eclipse.jetty.util; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +public abstract class PatternMatcher +{ + public abstract void matched (URI uri) throws Exception; + + + /** + * Find jar names from the provided list matching a pattern. + * + * If the pattern is null and isNullInclusive is true, then + * all jar names will match. + * + * A pattern is a set of acceptable jar names. Each acceptable + * jar name is a regex. Each regex can be separated by either a + * "," or a "|". If you use a "|" this or's together the jar + * name patterns. This means that ordering of the matches is + * unimportant to you. If instead, you want to match particular + * jar names, and you want to match them in order, you should + * separate the regexs with "," instead. + * + * Eg "aaa-.*\\.jar|bbb-.*\\.jar" + * Will iterate over the jar names and match + * in any order. + * + * Eg "aaa-*\\.jar,bbb-.*\\.jar" + * Will iterate over the jar names, matching + * all those starting with "aaa-" first, then "bbb-". + * + * @param pattern + * @param loader + * @param isNullInclusive if true, an empty pattern means all names match, if false, none match + * @throws Exception + */ + public void match (Pattern pattern, URI[] uris, boolean isNullInclusive) + throws Exception + { + if (uris!=null) + { + String[] patterns = (pattern==null?null:pattern.pattern().split(",")); + + List subPatterns = new ArrayList(); + for (int i=0; patterns!=null && i --> - - - org.eclipse.jetty.server.webapp.ContainerIncludeTLDJarPattern - jsp-api-.*\.jar|jsp-.*\.jar - - - - - - - - - - - org.eclipse.jetty.server.webapp.ContainerIncludeAnnotationJarPattern - - - diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java index a754890db7d..2438d7c8d37 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/FragmentConfiguration.java @@ -35,33 +35,36 @@ public class FragmentConfiguration implements Configuration if (!context.isConfigurationDiscovered()) return; - WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.__web_processor); + WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); if (processor == null) { processor = new WebXmlProcessor (context); - context.setAttribute(WebXmlProcessor.__web_processor, processor); + context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor); } + //parse web-fragment.xmls parseWebFragments(context, processor); - + //TODO for jetty-8/servletspec 3 we will need to merge the parsed web fragments into the //effective pom in this preConfigure step } public void configure(WebAppContext context) throws Exception - { + { if (!context.isConfigurationDiscovered()) return; + //TODO for jetty-8/servletspec3 the fragments will not be separately processed here, but //will be done by webXmlConfiguration when it processes the effective merged web.xml - WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.__web_processor); + WebXmlProcessor processor = (WebXmlProcessor)context.getAttribute(WebXmlProcessor.WEB_PROCESSOR); if (processor == null) { processor = new WebXmlProcessor (context); - context.setAttribute(WebXmlProcessor.__web_processor, processor); + context.setAttribute(WebXmlProcessor.WEB_PROCESSOR, processor); } - processor.processFragments(); + + processor.processFragments(); } public void deconfigure(WebAppContext context) throws Exception @@ -83,11 +86,7 @@ public class FragmentConfiguration implements Configuration */ public void parseWebFragments (final WebAppContext context, final WebXmlProcessor processor) throws Exception { - // Check to see if a specific search pattern has been set. - String tmp = (String) context.getInitParameter("org.eclipse.jetty.webapp.WebXmlFragmentPattern"); - Pattern webFragPattern = (tmp == null ? null : Pattern.compile(tmp)); - - List frags = (List)context.getAttribute(MetaInfConfiguration.METAINF_FRAGMENTS); + List frags = (List)context.getAttribute(FRAGMENT_RESOURCES); if (frags!=null) { for (Resource frag : frags) diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java index 084c838fe26..354aee9b28b 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JarScanner.java @@ -15,6 +15,7 @@ package org.eclipse.jetty.webapp; import java.io.InputStream; +import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -38,10 +39,10 @@ import org.eclipse.jetty.util.resource.Resource; * method to handle entries in jar files whose names match the supplied * pattern. */ -public abstract class JarScanner +public abstract class JarScanner extends org.eclipse.jetty.util.PatternMatcher { - public abstract void processEntry (URL jarUrl, JarEntry entry); + public abstract void processEntry (URI jarUri, JarEntry entry); /** * Find jar names from the provided list matching a pattern. @@ -70,32 +71,10 @@ public abstract class JarScanner * @param isNullInclusive if true, an empty pattern means all names match, if false, none match * @throws Exception */ - public void scan (Pattern pattern, URL[] urls, boolean isNullInclusive) + public void scan (Pattern pattern, URI[] uris, boolean isNullInclusive) throws Exception { - if (urls!=null) - { - String[] patterns = (pattern==null?null:pattern.pattern().split(",")); - - List subPatterns = new ArrayList(); - for (int i=0; patterns!=null && i subPatterns = new ArrayList(); - for (int i=0; patterns!=null && i urls = findJars(context); + - JarScanner fragScanner = new JarScanner() + JarScanner scanner = new JarScanner() { - public void processEntry(URL jarUrl, JarEntry entry) + public void processEntry(URI jarUri, JarEntry entry) { try { - MetaInfConfiguration.this.processEntry(context,jarUrl,entry); + MetaInfConfiguration.this.processEntry(context,jarUri,entry); } catch (Exception e) { @@ -57,26 +59,36 @@ public class MetaInfConfiguration implements Configuration } } }; - fragScanner.scan(null, urls.toArray(new URL[urls.size()]), true); + + List jarResources = (List)context.getAttribute(JAR_RESOURCES); + + //Scan jars for META-INF information + if (jarResources != null) + { + URI[] uris = new URI[jarResources.size()]; + int i=0; + for (Resource r : jarResources) + { + uris[i++] = r.getURI(); + } + scanner.scan(null, uris, true); + } } public void configure(WebAppContext context) throws Exception { - // TODO Auto-generated method stub - + } public void deconfigure(WebAppContext context) throws Exception { - // TODO Auto-generated method stub - + } public void postConfigure(WebAppContext context) throws Exception { - // TODO Auto-generated method stub - + } public void addResource (WebAppContext context, String attribute, Resource jar) @@ -92,74 +104,35 @@ public class MetaInfConfiguration implements Configuration } - protected void processEntry(WebAppContext context, URL jarUrl, JarEntry entry) + protected void processEntry(WebAppContext context, URI jarUri, JarEntry entry) { String name = entry.getName(); + if (!name.startsWith("META-INF/")) return; - + try { if (name.equals("META-INF/web-fragment.xml") && context.isConfigurationDiscovered()) { - addResource(context,METAINF_FRAGMENTS,Resource.newResource(jarUrl)); + addResource(context,METAINF_FRAGMENTS,Resource.newResource(jarUri)); } else if (name.equals("META-INF/resources/") && context.isConfigurationDiscovered()) { - addResource(context,METAINF_RESOURCES,Resource.newResource("jar:"+jarUrl+"!/META-INF/resources")); + addResource(context,METAINF_RESOURCES,Resource.newResource("jar:"+jarUri+"!/META-INF/resources")); } else { String lcname = name.toLowerCase(); if (lcname.endsWith(".tld")) { - addResource(context,METAINF_TLDS,Resource.newResource("jar:"+jarUrl+"!/"+name)); + addResource(context,METAINF_TLDS,Resource.newResource("jar:"+jarUri+"!/"+name)); } } } catch(Exception e) { - context.getServletContext().log(jarUrl+"!/"+name,e); + context.getServletContext().log(jarUri+"!/"+name,e); } } - - /** - * Look for jars in WEB-INF/lib - * @param context - * @return - * @throws Exception - */ - protected List findJars (WebAppContext context) - throws Exception - { - List urls = new ArrayList(); - - Resource web_inf = context.getWebInf(); - Resource web_inf_lib = web_inf.addPath("/lib"); - - - if (web_inf_lib.exists() && web_inf_lib.isDirectory()) - { - String[] files=web_inf_lib.list(); - for (int f=0;files!=null && f tld_resources=(Collection)context.getAttribute(TLD_RESOURCES); if (tld_resources!=null) tlds.addAll(tld_resources); diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index 9668c8e855b..a75df5197d2 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -2,11 +2,16 @@ package org.eclipse.jetty.webapp; import java.io.File; import java.io.IOException; +import java.net.URI; import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.PatternMatcher; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.resource.JarResource; @@ -16,6 +21,9 @@ import org.eclipse.jetty.util.resource.ResourceCollection; public class WebInfConfiguration implements Configuration { public static final String TEMPDIR_CREATED = "org.eclipse.jetty.tmpdirCreated"; + public static final String JAR_RESOURCES = "org.eclipse.jetty.jarList"; + public static final String CONTAINER_JAR_PATTERN = "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern"; + public static final String WEBINF_JAR_PATTERN = "org.eclipse.jetty.server.webapp.WebInfIncludeJarPattern"; /** * If set, to a list of URLs, these resources are added to the context @@ -23,7 +31,10 @@ public class WebInfConfiguration implements Configuration */ public static final String RESOURCE_URLS = "org.eclipse.jetty.resources"; - public void preConfigure(WebAppContext context) throws Exception + + + + public void preConfigure(final WebAppContext context) throws Exception { //Make a temp directory for the webapp if one is not already set resolveTempDirectory(context); @@ -34,6 +45,59 @@ public class WebInfConfiguration implements Configuration File work = findWorkDirectory(context); if (work != null) makeTempDirectory(work, context, false); + + //Apply an initial ordering to the jars which governs which will be scanned for META-INF + //info and annotations. The ordering is based on inclusion patterns. + String tmp = (String)context.getAttribute(WEBINF_JAR_PATTERN); + Pattern webInfPattern = (tmp==null?null:Pattern.compile(tmp)); + tmp = (String)context.getAttribute(CONTAINER_JAR_PATTERN); + Pattern containerPattern = (tmp==null?null:Pattern.compile(tmp)); + + final ArrayList jarResources = new ArrayList(); + context.setAttribute(JAR_RESOURCES, jarResources); + + PatternMatcher jarNameMatcher = new PatternMatcher () + { + public void matched(URI uri) throws Exception + { + jarResources.add(Resource.newResource(uri)); + } + + }; + + //Apply ordering to container jars + ClassLoader loader = context.getClassLoader(); + while (loader != null && (loader instanceof URLClassLoader)) + { + URL[] urls = ((URLClassLoader)loader).getURLs(); + if (urls != null) + { + URI[] containerUris = new URI[urls.length]; + int i=0; + for (URL u : urls) + { + containerUris[i++] = u.toURI(); + } + jarNameMatcher.match(containerPattern, containerUris, false); + } + loader = loader.getParent(); + } + + //Apply ordering to WEB-INF/lib jars + //Find all jars in WEB-INF + List jars = findJars(context); + //Convert to uris for matching + URI[] uris = null; + if (jars != null) + { + uris = new URI[jars.size()]; + int i=0; + for (Resource r: jars) + { + uris[i++] = r.getURI(); + } + } + jarNameMatcher.match(webInfPattern, uris, true); //null is inclusive, no pattern == all jars match } @@ -501,4 +565,43 @@ public class WebInfConfiguration implements Configuration return canonicalName.toString(); } + /** + * Look for jars in WEB-INF/lib + * @param context + * @return + * @throws Exception + */ + protected List findJars (WebAppContext context) + throws Exception + { + List jarResources = new ArrayList(); + + Resource web_inf = context.getWebInf(); + Resource web_inf_lib = web_inf.addPath("/lib"); + + + if (web_inf_lib.exists() && web_inf_lib.isDirectory()) + { + String[] files=web_inf_lib.list(); + for (int f=0;files!=null && f