416597 Allow classes and jars on the webappcontext extraclasspath to be scanned for annotations

This commit is contained in:
Jan Bartel 2013-09-05 18:24:12 +10:00
parent edaa23b21e
commit b8a4bf37e6
4 changed files with 257 additions and 81 deletions

View File

@ -24,6 +24,7 @@ import java.util.EventListener;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.StringTokenizer;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.annotation.HandlesTypes;
@ -59,6 +60,81 @@ public class AnnotationConfiguration extends AbstractConfiguration
protected List<ContainerInitializerAnnotationHandler> _containerInitializerAnnotationHandlers = new ArrayList<ContainerInitializerAnnotationHandler>();
/**
* WebAppClassNameResolver
*
* Checks to see if a classname belongs to hidden or visible packages when scanning,
* and whether a classname that is a duplicate should override a previously
* scanned classname.
*
* This is analogous to the management of classes that the WebAppClassLoader is doing,
* however we don't want to load the classes at this point so we are doing it on
* the name only.
*
*/
public class WebAppClassNameResolver implements ClassNameResolver
{
private WebAppContext _context;
public WebAppClassNameResolver (WebAppContext context)
{
_context = context;
}
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;
}
}
/**
* ContainerClassNameResolver
*
* Checks to see if a classname belongs to a hidden or visible package
* when scanning for annotations and thus whether it should be excluded from
* consideration or not.
*
* This is analogous to the management of classes that the WebAppClassLoader is doing,
* however we don't want to load the classes at this point so we are doing it on
* the name only.
*
*/
public class ContainerClassNameResolver implements ClassNameResolver
{
private WebAppContext _context;
public ContainerClassNameResolver (WebAppContext context)
{
_context = context;
}
public boolean isExcluded (String name)
{
if (_context.isSystemClass(name)) return false;
if (_context.isServerClass(name)) return true;
return false;
}
public boolean shouldOverride (String name)
{
//visiting the container classpath,
if (_context.isParentLoaderPriority())
return true;
return false;
}
}
@Override
public void preConfigure(final WebAppContext context) throws Exception
{
@ -351,25 +427,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
}
parser.parse (containerUris.toArray(new URI[containerUris.size()]),
new ClassNameResolver ()
{
public boolean isExcluded (String name)
{
if (context.isSystemClass(name)) return false;
if (context.isServerClass(name)) return true;
return false;
}
public boolean shouldOverride (String name)
{
//looking at system classpath
if (context.isParentLoaderPriority())
return true;
return false;
}
});
new ContainerClassNameResolver (context));
}
@ -427,24 +485,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
parser.registerHandlers(_discoverableAnnotationHandlers);
}
parser.parse(uri,
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;
}
});
parser.parse(uri, new WebAppClassNameResolver(context));
}
}
}
@ -460,11 +501,7 @@ public class AnnotationConfiguration extends AbstractConfiguration
throws Exception
{
LOG.debug("Scanning classes in WEB-INF/classes");
if (context.getWebInf() != null)
{
Resource classesDir = context.getWebInf().addPath("classes/");
if (classesDir.exists())
{
parser.clearHandlers();
for (DiscoverableAnnotationHandler h:_discoverableAnnotationHandlers)
{
@ -475,24 +512,9 @@ public class AnnotationConfiguration extends AbstractConfiguration
parser.registerHandler(_classInheritanceHandler);
parser.registerHandlers(_containerInitializerAnnotationHandlers);
parser.parseDir(classesDir,
new ClassNameResolver()
for (Resource dir : context.getMetaData().getWebInfClassesDirs())
{
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;
}
});
}
parser.parseDir(dir, new WebAppClassNameResolver(context));
}
}

View File

@ -860,7 +860,7 @@ public class AnnotationParser
}
/**
* Parse a particular resource
* Parse a particular uri
* @param uri
* @param resolver
* @throws Exception
@ -871,7 +871,24 @@ public class AnnotationParser
if (uri == null)
return;
Resource r = Resource.newResource(uri);
parse (Resource.newResource(uri), resolver);
}
/**
* Parse a resource
* @param r
* @param resolver
* @throws Exception
*/
public void parse (Resource r, final ClassNameResolver resolver)
throws Exception
{
if (r == null)
return;
if (r.exists() && r.isDirectory())
{
parseDir(r, resolver);
@ -891,11 +908,10 @@ public class AnnotationParser
return;
}
if (LOG.isDebugEnabled()) LOG.warn("Resource not scannable for classes: {}", uri);
if (LOG.isDebugEnabled()) LOG.warn("Resource not scannable for classes: {}", r);
}
/**
* Parse a resource that is a jar file.
*
@ -910,7 +926,6 @@ public class AnnotationParser
return;
URI uri = jarResource.getURI();
if (jarResource.toString().endsWith(".jar"))
{
if (LOG.isDebugEnabled()) {LOG.debug("Scanning jar {}", jarResource);};
@ -1037,7 +1052,6 @@ public class AnnotationParser
if (path == null || path.length()==0)
return false;
//skip any classfiles that are in a hidden directory
if (path.startsWith(".") || path.contains("/."))
{

View File

@ -55,6 +55,7 @@ public class MetaData
protected final Map<String,FragmentDescriptor> _webFragmentNameMap = new HashMap<String,FragmentDescriptor>();
protected final Map<Resource, FragmentDescriptor> _webFragmentResourceMap = new HashMap<Resource, FragmentDescriptor>();
protected final Map<Resource, List<DiscoveredAnnotation>> _webFragmentAnnotations = new HashMap<Resource, List<DiscoveredAnnotation>>();
protected final List<Resource> _webInfClasses = new ArrayList<Resource>();
protected final List<Resource> _webInfJars = new ArrayList<Resource>();
protected final List<Resource> _orderedWebInfJars = new ArrayList<Resource>();
protected final List<Resource> _orderedContainerResources = new ArrayList<Resource>();
@ -573,6 +574,17 @@ public class MetaData
{
_orderedContainerResources.add(jar);
}
public void setWebInfClassesDirs (List<Resource> dirs)
{
_webInfClasses.addAll(dirs);
}
public List<Resource> getWebInfClassesDirs ()
{
return _webInfClasses;
}
public boolean isAllowDuplicateFragmentNames()
{
return allowDuplicateFragmentNames;

View File

@ -27,6 +27,7 @@ import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import org.eclipse.jetty.server.Connector;
@ -139,6 +140,9 @@ public class WebInfConfiguration extends AbstractConfiguration
}
}
webInfJarNameMatcher.match(webInfPattern, uris, true); //null is inclusive, no pattern == all jars match
//No pattern to appy to classes, just add to metadata
context.getMetaData().setWebInfClassesDirs(findClassDirs(context));
}
@ -694,8 +698,29 @@ public class WebInfConfiguration extends AbstractConfiguration
return canonicalName.toString();
}
protected List<Resource> findClassDirs (WebAppContext context)
throws Exception
{
if (context == null)
return null;
List<Resource> classDirs = new ArrayList<Resource>();
Resource webInfClasses = findWebInfClassesDir(context);
if (webInfClasses != null)
classDirs.add(webInfClasses);
List<Resource> extraClassDirs = findExtraClasspathDirs(context);
if (extraClassDirs != null)
classDirs.addAll(extraClassDirs);
return classDirs;
}
/**
* Look for jars in WEB-INF/lib
* Look for jars that should be treated as if they are in WEB-INF/lib
*
* @param context
* @return the list of jar resources found within context
* @throws Exception
@ -704,14 +729,31 @@ public class WebInfConfiguration extends AbstractConfiguration
throws Exception
{
List<Resource> jarResources = new ArrayList<Resource>();
List<Resource> webInfLibJars = findWebInfLibJars(context);
if (webInfLibJars != null)
jarResources.addAll(webInfLibJars);
List<Resource> extraClasspathJars = findExtraClasspathJars(context);
if (extraClasspathJars != null)
jarResources.addAll(extraClasspathJars);
return jarResources;
}
/**
* Look for jars in WEB-INF/lib
*
* @param context
* @return
* @throws Exception
*/
protected List<Resource> findWebInfLibJars(WebAppContext context)
throws Exception
{
Resource web_inf = context.getWebInf();
if (web_inf==null || !web_inf.exists())
return null;
List<Resource> jarResources = new ArrayList<Resource>();
Resource web_inf_lib = web_inf.addPath("/lib");
if (web_inf_lib.exists() && web_inf_lib.isDirectory())
{
String[] files=web_inf_lib.list();
@ -736,4 +778,90 @@ public class WebInfConfiguration extends AbstractConfiguration
}
return jarResources;
}
/**
* Get jars from WebAppContext.getExtraClasspath as resources
*
* @param context
* @return
* @throws Exception
*/
protected List<Resource> findExtraClasspathJars(WebAppContext context)
throws Exception
{
if (context == null || context.getExtraClasspath() == null)
return null;
List<Resource> jarResources = new ArrayList<Resource>();
StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
while (tokenizer.hasMoreTokens())
{
Resource resource = context.newResource(tokenizer.nextToken().trim());
String fnlc = resource.getName().toLowerCase(Locale.ENGLISH);
int dot = fnlc.lastIndexOf('.');
String extension = (dot < 0 ? null : fnlc.substring(dot));
if (extension != null && (extension.equals(".jar") || extension.equals(".zip")))
{
jarResources.add(resource);
}
}
return jarResources;
}
/**
* Get WEB-INF/classes dir
*
* @param context
* @return
* @throws Exception
*/
protected Resource findWebInfClassesDir (WebAppContext context)
throws Exception
{
if (context == null)
return null;
Resource web_inf = context.getWebInf();
// Find WEB-INF/classes
if (web_inf != null && web_inf.isDirectory())
{
// Look for classes directory
Resource classes= web_inf.addPath("classes/");
if (classes.exists())
return classes;
}
return null;
}
/**
* Get class dirs from WebAppContext.getExtraClasspath as resources
*
* @param context
* @return
* @throws Exception
*/
protected List<Resource> findExtraClasspathDirs(WebAppContext context)
throws Exception
{
if (context == null || context.getExtraClasspath() == null)
return null;
List<Resource> dirResources = new ArrayList<Resource>();
StringTokenizer tokenizer = new StringTokenizer(context.getExtraClasspath(), ",;");
while (tokenizer.hasMoreTokens())
{
Resource resource = context.newResource(tokenizer.nextToken().trim());
if (resource.exists() && resource.isDirectory())
dirResources.add(resource);
}
return dirResources;
}
}