package com.kryptnostic.rhizome.core; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.ServletContainerInitializer; import javax.servlet.annotation.HandlesTypes; import jersey.repackaged.com.google.common.collect.Lists; import org.eclipse.jetty.annotations.AnnotationConfiguration; import org.eclipse.jetty.annotations.ClassInheritanceHandler; import org.eclipse.jetty.annotations.ContainerInitializerAnnotationHandler; import org.eclipse.jetty.annotations.ServletContainerInitializersStarter; import org.eclipse.jetty.plus.annotation.ContainerInitializer; import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.webapp.WebAppContext; /** * This class contains an exact replica of the annotation configuration class, with the exception that it registers a * {@code RhizomeWebApplicationInitializer} for discovery during class path scanning. * * @author Matthew Tamayo-Rios */ public class JettyAnnotationConfigurationHack extends AnnotationConfiguration { private static final Logger LOG = Log.getLogger( JettyAnnotationConfigurationHack.class ); private static final List<String> additionalInitializers = Lists.newArrayList(); static { additionalInitializers.add( Rhizome.class.getCanonicalName() ); } @Override public void createServletContainerInitializerAnnotationHandlers( WebAppContext context, List<ServletContainerInitializer> scis ) throws Exception { if ( scis == null || scis.isEmpty() ) return; // nothing to do final List<ContainerInitializer> initializers = new ArrayList<ContainerInitializer>(); context.setAttribute( CONTAINER_INITIALIZERS, initializers ); for ( ServletContainerInitializer service : scis ) { HandlesTypes annotation = service.getClass().getAnnotation( HandlesTypes.class ); ContainerInitializer initializer = null; if ( annotation != null ) { // There is a HandlesTypes annotation on the on the ServletContainerInitializer Class<?>[] classes = annotation.value(); if ( classes != null ) { initializer = new ContainerInitializer( service, classes ); /* * Add custom initializer as a work around for https://bugs.eclipse.org/bugs/show_bug.cgi?id=404176 */ for ( String t : additionalInitializers ) { initializer.addApplicableTypeName( t ); } // If we haven't already done so, we need to register a handler that will // process the whole class hierarchy to satisfy the ServletContainerInitializer if ( context.getAttribute( CLASS_INHERITANCE_MAP ) == null ) { // MultiMap<String> map = new MultiMap<>(); ConcurrentHashMap<String, ConcurrentHashSet<String>> map = new ClassInheritanceMap(); context.setAttribute( CLASS_INHERITANCE_MAP, map ); _classInheritanceHandler = new ClassInheritanceHandler( map ); } for ( Class<?> c : classes ) { // The value of one of the HandlesTypes classes is actually an Annotation itself so // register a handler for it if ( c.isAnnotation() ) { if ( LOG.isDebugEnabled() ) LOG.debug( "Registering annotation handler for " + c.getName() ); _containerInitializerAnnotationHandlers.add( new ContainerInitializerAnnotationHandler( initializer, c ) ); } } } else { initializer = new ContainerInitializer( service, null ); if ( LOG.isDebugEnabled() ) LOG.debug( "No classes in HandlesTypes on initializer " + service.getClass() ); } } else { initializer = new ContainerInitializer( service, null ); if ( LOG.isDebugEnabled() ) LOG.debug( "No annotation on initializer " + service.getClass() ); } initializers.add( initializer ); } // add a bean to the context which will call the servletcontainerinitializers when appropriate ServletContainerInitializersStarter starter = (ServletContainerInitializersStarter) context .getAttribute( CONTAINER_INITIALIZER_STARTER ); if ( starter != null ) throw new IllegalStateException( "ServletContainerInitializersStarter already exists" ); starter = new ServletContainerInitializersStarter( context ); context.setAttribute( CONTAINER_INITIALIZER_STARTER, starter ); context.addBean( starter, true ); } public static void registerInitializer( String className ) { additionalInitializers.add( className ); } public static void removeInitializer( String className ) { additionalInitializers.remove( className ); } }