package net.sourceforge.eclipsejetty.starter.jetty8;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.LinkedHashSet;
import org.eclipse.jetty.annotations.AbstractDiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.annotations.AnnotationDecorator;
import org.eclipse.jetty.annotations.AnnotationParser;
import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler;
import org.eclipse.jetty.annotations.ClassNameResolver;
import org.eclipse.jetty.annotations.WebFilterAnnotationHandler;
import org.eclipse.jetty.annotations.WebListenerAnnotationHandler;
import org.eclipse.jetty.annotations.WebServletAnnotationHandler;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
/**
* This class works around a bug in Jetty 8 {@link http://bugs.eclipse.org/bugs/show_bug.cgi?id=404176}, which does not
* scan external directories for annotations. The solution is based on
*
* <pre>
* {@link http://stackoverflow.com/questions/13222071/spring-3-1-webapplicationinitializer-embedded-jetty-8-annotationconfiguration}.
* </pre>
*
* @author Manfred Hantschel
*/
public class ExtendedAnnotationConfiguration extends AnnotationConfiguration
{
public ExtendedAnnotationConfiguration()
{
super();
}
@Override
public void configure(WebAppContext context) throws Exception
{
boolean metadataComplete = context.getMetaData().isMetaDataComplete();
context.addDecorator(new AnnotationDecorator(context));
//Even if metadata is complete, we still need to scan for ServletContainerInitializers - if there are any
AnnotationParser parser = null;
if (!metadataComplete)
{
//If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations
if ((context.getServletContext().getEffectiveMajorVersion() >= 3) || context.isConfigurationDiscovered())
{
_discoverableAnnotationHandlers.add(new WebServletAnnotationHandler(context));
_discoverableAnnotationHandlers.add(new WebFilterAnnotationHandler(context));
_discoverableAnnotationHandlers.add(new WebListenerAnnotationHandler(context));
}
}
//Regardless of metadata, if there are any ServletContainerInitializers with @HandlesTypes, then we need to scan all the
//classes so we can call their onStartup() methods correctly
createServletContainerInitializerAnnotationHandlers(context, getNonExcludedInitializers(context));
if (!_discoverableAnnotationHandlers.isEmpty() || (_classInheritanceHandler != null)
|| !_containerInitializerAnnotationHandlers.isEmpty())
{
parser = createAnnotationParser();
parse(context, parser);
for (DiscoverableAnnotationHandler h : _discoverableAnnotationHandlers)
{
context.getMetaData().addDiscoveredAnnotations(
((AbstractDiscoverableAnnotationHandler) h).getAnnotationList());
}
}
}
private void parse(final WebAppContext context, AnnotationParser parser) throws Exception
{
Collection<Resource> _resources = collectResources(new LinkedHashSet<Resource>(), context.getClassLoader());
for (Resource _resource : _resources)
{
if (_resource == null)
{
return;
}
parser.clearHandlers();
for (DiscoverableAnnotationHandler h : _discoverableAnnotationHandlers)
{
if (h instanceof AbstractDiscoverableAnnotationHandler)
{
((AbstractDiscoverableAnnotationHandler) h).setResource(null); //
}
}
parser.registerHandlers(_discoverableAnnotationHandlers);
parser.registerHandler(_classInheritanceHandler);
parser.registerHandlers(_containerInitializerAnnotationHandlers);
parser.parse(_resource, new ClassNameResolver()
{
@Override
public boolean isExcluded(String name)
{
if (context.isSystemClass(name))
{
return true;
}
if (context.isServerClass(name))
{
return false;
}
return false;
}
@Override
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;
}
});
}
}
private Collection<Resource> collectResources(Collection<Resource> resources, ClassLoader classLoader)
throws IOException
{
if (classLoader instanceof URLClassLoader)
{
URL[] urls = ((URLClassLoader) classLoader).getURLs();
for (URL url : urls)
{
resources.add(Resource.newResource(url));
}
}
return resources;
}
}