package org.jboss.resteasy.plugins.servlet;
import org.jboss.resteasy.core.AsynchronousDispatcher;
import org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher;
import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters;
import org.jboss.resteasy.plugins.servlet.i18n.Messages;
import org.jboss.resteasy.spi.NotImplementedYetException;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.HandlesTypes;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.ext.Provider;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
@HandlesTypes({Application.class, Path.class, Provider.class})
public class ResteasyServletInitializer implements ServletContainerInitializer
{
final static Set<String> ignoredPackages = new HashSet<String>();
static
{
ignoredPackages.add(AsynchronousDispatcher.class.getPackage().getName());
}
@Override
public void onStartup(Set<Class<?>> classes, ServletContext servletContext) throws ServletException
{
if (classes == null || classes.size() == 0) return;
for (ServletRegistration reg : servletContext.getServletRegistrations().values())
{
if (reg.getInitParameter("javax.ws.rs.Application") != null)
{
return; // there's already a servlet mapping, do nothing
}
}
Set<Class<?>> appClasses = new HashSet<Class<?>>();
Set<Class<?>> providers = new HashSet<Class<?>>();
Set<Class<?>> resources = new HashSet<Class<?>>();
for (Class<?> clazz : classes)
{
if (ignoredPackages.contains(clazz.getPackage().getName())) continue;
if (clazz.isAnnotationPresent(Path.class))
{
resources.add(clazz);
}
else if (clazz.isAnnotationPresent(Provider.class))
{
providers.add(clazz);
}
else
{
appClasses.add(clazz);
}
}
if (appClasses.size() == 0 && resources.size() == 0) return;
if (appClasses.size() == 0)
{
// todo make sure we can do this on all servlet containers
//handleNoApplicationClass(providers, resources, servletContext);
return;
}
for (Class<?> app : appClasses)
{
register(app, providers, resources, servletContext);
}
}
protected void handleNoApplicationClass(Set<Class<?>> providers, Set<Class<?>> resources, ServletContext servletContext)
{
ServletRegistration defaultApp = null;
for (ServletRegistration reg : servletContext.getServletRegistrations().values())
{
if (reg.getName().equals(Application.class.getName()))
{
defaultApp = reg;
}
}
if (defaultApp == null) return;
throw new NotImplementedYetException(Messages.MESSAGES.defaultApplicationNotImplemented());
}
protected void register(Class<?> applicationClass, Set<Class<?>> providers, Set<Class<?>> resources, ServletContext servletContext)
{
ApplicationPath path = applicationClass.getAnnotation(ApplicationPath.class);
if (path == null)
{
// todo we don't support this yet, i'm not sure if partial deployments are supported in all servlet containers
return;
}
ServletRegistration.Dynamic reg = servletContext.addServlet(applicationClass.getName(), HttpServlet30Dispatcher.class);
reg.setLoadOnStartup(1);
reg.setAsyncSupported(true);
reg.setInitParameter("javax.ws.rs.Application", applicationClass.getName());
if (path != null)
{
String mapping = path.value();
if (!mapping.startsWith("/")) mapping = "/" + mapping;
String prefix = mapping;
if (!prefix.equals("/") && prefix.endsWith("/")) prefix = prefix.substring(0, prefix.length() - 1);
if (mapping.endsWith("/")) mapping += "*";
else mapping += "/*";
// resteasy.servlet.mapping.prefix
reg.setInitParameter("resteasy.servlet.mapping.prefix", prefix);
reg.addMapping(mapping);
}
if (resources.size() > 0)
{
StringBuilder builder = new StringBuilder();
boolean first = true;
for (Class resource : resources)
{
if (first)
{
first = false;
}
else
{
builder.append(",");
}
builder.append(resource.getName());
}
reg.setInitParameter(ResteasyContextParameters.RESTEASY_SCANNED_RESOURCES, builder.toString());
}
if (providers.size() > 0)
{
StringBuilder builder = new StringBuilder();
boolean first = true;
for (Class provider : providers)
{
if (first)
{
first = false;
}
else
{
builder.append(",");
}
builder.append(provider.getName());
}
reg.setInitParameter(ResteasyContextParameters.RESTEASY_SCANNED_PROVIDERS, builder.toString());
}
}
}