001package org.tynamo.resteasy; 002 003import org.apache.tapestry5.SymbolConstants; 004import org.apache.tapestry5.internal.services.CheckForUpdatesFilter; 005import org.apache.tapestry5.ioc.annotations.Inject; 006import org.apache.tapestry5.ioc.annotations.IntermediateType; 007import org.apache.tapestry5.ioc.annotations.Symbol; 008import org.apache.tapestry5.ioc.services.SymbolSource; 009import org.apache.tapestry5.ioc.util.TimeInterval; 010import org.apache.tapestry5.services.*; 011import org.jboss.resteasy.core.Dispatcher; 012import org.jboss.resteasy.core.SynchronousDispatcher; 013import org.jboss.resteasy.plugins.server.servlet.*; 014import org.jboss.resteasy.specimpl.ResteasyHttpHeaders; 015import org.jboss.resteasy.spi.HttpRequest; 016import org.jboss.resteasy.spi.HttpResponse; 017import org.jboss.resteasy.spi.ResteasyProviderFactory; 018import org.jboss.resteasy.spi.ResteasyUriInfo; 019import org.jboss.resteasy.util.GetRestful; 020import org.slf4j.Logger; 021 022import javax.servlet.ServletException; 023import javax.servlet.http.HttpServletRequest; 024import javax.servlet.http.HttpServletResponse; 025import javax.ws.rs.core.Application; 026import javax.ws.rs.ext.Provider; 027import java.io.IOException; 028import java.util.ArrayList; 029import java.util.regex.Pattern; 030 031public class ResteasyRequestFilter implements HttpServletRequestFilter, HttpRequestFactory, HttpResponseFactory { 032 033 private final ServletContainerDispatcher servletContainerDispatcher; 034 private final Dispatcher dispatcher; 035 private final ResteasyProviderFactory providerFactory; 036 private final ApplicationGlobals globals; 037 038 private final Pattern filterPattern; 039 private final Logger logger; 040 041 private boolean productionMode; 042 private boolean corsEnabled; 043 044 private CheckForUpdatesFilter checkForUpdatesFilter; 045 046 private RequestHandler dummyHandler = new RequestHandler() { 047 @Override 048 public boolean service(Request request, Response response) throws IOException { 049 return false; 050 } 051 }; 052 053 public ResteasyRequestFilter( 054 @Inject @Symbol(ResteasySymbols.MAPPING_PREFIX) String filterPath, 055 Logger logger, 056 ApplicationGlobals globals, 057 Application application, 058 SymbolSource source, 059 @Symbol(SymbolConstants.PRODUCTION_MODE) boolean productionMode, 060 UpdateListenerHub updateListenerHub, 061 @Symbol(SymbolConstants.FILE_CHECK_INTERVAL) @IntermediateType(TimeInterval.class) long checkInterval, 062 @Symbol(SymbolConstants.FILE_CHECK_UPDATE_TIMEOUT) @IntermediateType(TimeInterval.class) long updateTimeout, 063 @Symbol(ResteasySymbols.CORS_ENABLED) boolean corsEnabled 064 ) throws ServletException { 065 066 this.logger = logger; 067 this.filterPattern = Pattern.compile(filterPath + ".*", Pattern.CASE_INSENSITIVE); 068 this.globals = globals; 069 070 ListenerBootstrap bootstrap = new TapestryResteasyBootstrap(globals.getServletContext(), source); 071 072 servletContainerDispatcher = new ServletContainerDispatcher(); 073 servletContainerDispatcher.init(globals.getServletContext(), bootstrap, this, this); 074 dispatcher = servletContainerDispatcher.getDispatcher(); 075 providerFactory = servletContainerDispatcher.getDispatcher().getProviderFactory(); 076 processApplication(application); 077 078 this.productionMode = productionMode; 079 this.corsEnabled = corsEnabled; 080 checkForUpdatesFilter = new CheckForUpdatesFilter(updateListenerHub, checkInterval, updateTimeout); 081 } 082 083 @Override 084 public boolean service(HttpServletRequest request, HttpServletResponse response, 085 HttpServletRequestHandler handler) throws IOException { 086 087 String path = request.getServletPath(); 088 String pathInfo = request.getPathInfo(); 089 090 if (pathInfo != null) path += pathInfo; 091 092 if (filterPattern.matcher(path).matches()) { 093 094 if (!productionMode) { 095 checkForUpdatesFilter.service(null, null, dummyHandler); 096 } 097 098 servletContainerDispatcher.service(request.getMethod(), request, response, true); 099 if (corsEnabled) 100 { 101 response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); 102 } 103 return true; 104 } 105 106 return handler.service(request, response); 107 } 108 109 @Override 110 public HttpRequest createResteasyHttpRequest(String httpMethod, HttpServletRequest request, 111 ResteasyHttpHeaders headers, ResteasyUriInfo uriInfo, 112 HttpResponse theResponse, HttpServletResponse response) { 113 return new HttpServletInputMessage(request, response, globals.getServletContext(), theResponse, headers, uriInfo, httpMethod.toUpperCase(), (SynchronousDispatcher) dispatcher); 114 } 115 116 @Override 117 public HttpResponse createResteasyHttpResponse(HttpServletResponse response) { 118 return createServletResponse(response); 119 } 120 121 protected HttpResponse createServletResponse(HttpServletResponse response) { 122 return new HttpServletResponseWrapper(response, providerFactory); 123 } 124 125 private void processApplication(Application config) { 126 logger.info("Deploying " + Application.class.getName() + ": " + config.getClass()); 127 ArrayList<Class> actualResourceClasses = new ArrayList<Class>(); 128 ArrayList<Class> actualProviderClasses = new ArrayList<Class>(); 129 ArrayList resources = new ArrayList(); 130 ArrayList providers = new ArrayList(); 131 if (config.getClasses() != null) { 132 for (Class clazz : config.getClasses()) { 133 if (GetRestful.isRootResource(clazz)) { 134 actualResourceClasses.add(clazz); 135 } else if (clazz.isAnnotationPresent(Provider.class)) { 136 actualProviderClasses.add(clazz); 137 } else { 138 throw new RuntimeException("Application.getClasses() returned unknown class type: " + clazz.getName()); 139 } 140 } 141 } 142 if (config.getSingletons() != null) { 143 for (Object obj : config.getSingletons()) { 144 if (GetRestful.isRootResource(obj.getClass())) { 145 logger.info("Adding singleton resource " + obj.getClass().getName() + " from Application " + Application.class.getName()); 146 resources.add(obj); 147 } else if (obj.getClass().isAnnotationPresent(Provider.class)) { 148 providers.add(obj); 149 } else { 150 throw new RuntimeException("Application.getSingletons() returned unknown class type: " + obj.getClass().getName()); 151 } 152 } 153 } 154 for (Class clazz : actualProviderClasses) providerFactory.registerProvider(clazz); 155 for (Object obj : providers) providerFactory.registerProviderInstance(obj); 156 for (Class clazz : actualResourceClasses) dispatcher.getRegistry().addPerRequestResource(clazz); 157 for (Object obj : resources) dispatcher.getRegistry().addSingletonResource(obj); 158 } 159}