Add integration with AWS API latch
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package org.springframework.cloud.function.serverless.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterRegistration;
|
||||
|
||||
public class ProxyFilterRegistration implements FilterRegistration, FilterRegistration.Dynamic {
|
||||
|
||||
public Filter getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
private final String name;
|
||||
|
||||
private final Filter filter;
|
||||
|
||||
public ProxyFilterRegistration(String name, Filter filter) {
|
||||
this.name = name;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return this.filter.getClass().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setInitParameter(String name, String value) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitParameter(String name) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> setInitParameters(Map<String, String> initParameters) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getInitParameters() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsyncSupported(boolean isAsyncSupported) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter,
|
||||
String... servletNames) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getServletNameMappings() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter,
|
||||
String... urlPatterns) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getUrlPatternMappings() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
@@ -32,14 +33,14 @@ import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRegistration;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -65,41 +66,49 @@ public class ProxyMvc {
|
||||
|
||||
static final String MVC_RESULT_ATTRIBUTE = ProxyMvc.class.getName().concat(".MVC_RESULT_ATTRIBUTE");
|
||||
|
||||
private final DispatcherServlet servlet;
|
||||
|
||||
private final Filter[] filters;
|
||||
private final DispatcherServlet dispatcher;
|
||||
|
||||
private final ConfigurableWebApplicationContext applicationContext;
|
||||
|
||||
public static ProxyMvc INSTANCE(Class<?>... componentClasses) {
|
||||
Assert.notEmpty(componentClasses, "'componentClasses' must not be null or empty");
|
||||
private ServletContext servletContext;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
public ConfigurableWebApplicationContext getApplicationContext() {
|
||||
return this.applicationContext;
|
||||
}
|
||||
|
||||
public ServletContext getServletContext() {
|
||||
return this.servletContext;
|
||||
}
|
||||
|
||||
public static ProxyMvc INSTANCE(ConfigurableWebApplicationContext applpicationContext) {
|
||||
ProxyServletContext servletContext = new ProxyServletContext();
|
||||
GenericWebApplicationContext applpicationContext = new GenericWebApplicationContext(servletContext);
|
||||
applpicationContext.setServletContext(servletContext);
|
||||
DispatcherServlet dispatcher = new DispatcherServlet(applpicationContext);
|
||||
ServletRegistration.Dynamic reg = servletContext.addServlet("dispatcherServlet", dispatcher);
|
||||
reg.setLoadOnStartup(1);
|
||||
|
||||
ProxyMvc mvc = new ProxyMvc(dispatcher, applpicationContext);
|
||||
mvc.servletContext = servletContext;
|
||||
return mvc;
|
||||
}
|
||||
|
||||
public static ProxyMvc INSTANCE(Class<?>... componentClasses) {
|
||||
GenericWebApplicationContext applpicationContext = new GenericWebApplicationContext();
|
||||
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(applpicationContext);
|
||||
reader.register(componentClasses);
|
||||
|
||||
reader.register(ProxyErrorController.class);
|
||||
|
||||
try {
|
||||
DispatcherServlet servlet = new DispatcherServlet(applpicationContext);
|
||||
servlet.init(new ProxyServletConfig(servletContext));
|
||||
applpicationContext.registerBean(DispatcherServlet.class, servlet);
|
||||
|
||||
return new ProxyMvc(servlet, applpicationContext);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to create MVC Proxy", e);
|
||||
if (!ObjectUtils.isEmpty(componentClasses)) {
|
||||
reader.register(componentClasses);
|
||||
}
|
||||
return INSTANCE(applpicationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor, not for direct instantiation.
|
||||
*/
|
||||
ProxyMvc(DispatcherServlet servlet, ConfigurableWebApplicationContext applicationContext) {
|
||||
ProxyMvc(DispatcherServlet dispatcher, ConfigurableWebApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
this.servlet = servlet;
|
||||
this.filters = applicationContext.getBeansOfType(Filter.class).values().toArray(new Filter[0]);
|
||||
this.dispatcher = dispatcher;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
@@ -118,8 +127,23 @@ public class ProxyMvc {
|
||||
* @see org.springframework.test.web.servlet.result.MockMvcResultMatchers
|
||||
*/
|
||||
public void service(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
ProxyFilterChain filterChain = new ProxyFilterChain(this.servlet, this.filters);
|
||||
this.service(request, response, (CountDownLatch) null);
|
||||
}
|
||||
|
||||
public void service(HttpServletRequest request, HttpServletResponse response, CountDownLatch latch) throws Exception {
|
||||
synchronized (this) {
|
||||
if (!this.initialized) {
|
||||
this.dispatcher.init(new ProxyServletConfig(this.servletContext));
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
ProxyFilterChain filterChain = new ProxyFilterChain(this.dispatcher);
|
||||
filterChain.doFilter(request, response);
|
||||
|
||||
if (latch != null) {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ProxyFilterChain implements FilterChain {
|
||||
@@ -143,10 +167,12 @@ public class ProxyMvc {
|
||||
* @param filters the {@link Filter}'s to invoke in this {@link FilterChain}
|
||||
* @since 3.2
|
||||
*/
|
||||
ProxyFilterChain(Servlet servlet, Filter... filters) {
|
||||
ProxyFilterChain(DispatcherServlet servlet) {
|
||||
List<Filter> filters = new ArrayList<>();
|
||||
servlet.getServletContext().getFilterRegistrations().values().forEach(fr -> filters.add(((ProxyFilterRegistration)fr).getFilter()));
|
||||
Assert.notNull(filters, "filters cannot be null");
|
||||
Assert.noNullElements(filters, "filters cannot contain null values");
|
||||
this.filters = initFilterList(servlet, filters);
|
||||
this.filters = initFilterList(servlet, filters.toArray(new Filter[] {}));
|
||||
}
|
||||
|
||||
private static List<Filter> initFilterList(Servlet servlet, Filter... filters) {
|
||||
@@ -210,24 +236,37 @@ public class ProxyMvc {
|
||||
throws IOException, ServletException {
|
||||
|
||||
try {
|
||||
this.delegateServlet.service(request, response);
|
||||
if (((HttpServletResponse) response).getStatus() != HttpStatus.OK.value()) {
|
||||
((ProxyHttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_STATUS_CODE, ((HttpServletResponse) response).getStatus());
|
||||
if (((HttpServletResponse) response).getStatus() != HttpStatus.OK.value() && request instanceof ProxyHttpServletRequest) {
|
||||
((HttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_STATUS_CODE, ((HttpServletResponse) response).getStatus());
|
||||
this.setErrorMessageAttribute((ProxyHttpServletRequest) request, (ProxyHttpServletResponse) response, null);
|
||||
((ProxyHttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_REQUEST_URI, ((ProxyHttpServletRequest) request).getRequestURI());
|
||||
((HttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_REQUEST_URI, ((HttpServletRequest) request).getRequestURI());
|
||||
|
||||
((ProxyHttpServletRequest) request).setRequestURI("/error");
|
||||
this.delegateServlet.service(request, response);
|
||||
}
|
||||
else {
|
||||
this.delegateServlet.service(request, response);
|
||||
if (((HttpServletResponse) response).getStatus() != HttpStatus.OK.value() && request instanceof ProxyHttpServletRequest) {
|
||||
((HttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_STATUS_CODE, ((HttpServletResponse) response).getStatus());
|
||||
this.setErrorMessageAttribute((ProxyHttpServletRequest) request, (ProxyHttpServletResponse) response, null);
|
||||
((HttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_REQUEST_URI, ((HttpServletRequest) request).getRequestURI());
|
||||
|
||||
((ProxyHttpServletRequest) request).setRequestURI("/error");
|
||||
this.delegateServlet.service(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
((ProxyHttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_STATUS_CODE, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
this.setErrorMessageAttribute((ProxyHttpServletRequest) request, (ProxyHttpServletResponse) response, e);
|
||||
((ProxyHttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, e);
|
||||
((ProxyHttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_REQUEST_URI, ((ProxyHttpServletRequest) request).getRequestURI());
|
||||
if (request instanceof ProxyHttpServletRequest) {
|
||||
((HttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_STATUS_CODE, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
this.setErrorMessageAttribute((ProxyHttpServletRequest) request, (ProxyHttpServletResponse) response, e);
|
||||
((HttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, e);
|
||||
((HttpServletRequest) request).setAttribute(RequestDispatcher.ERROR_REQUEST_URI, ((HttpServletRequest) request).getRequestURI());
|
||||
((ProxyHttpServletRequest) request).setRequestURI("/error");
|
||||
}
|
||||
|
||||
LOG.error("Failed processing the request to: " + ((HttpServletRequest) request).getRequestURI(), e);
|
||||
|
||||
LOG.error("Failed processing the request to: " + ((ProxyHttpServletRequest) request).getRequestURI(), e);
|
||||
((ProxyHttpServletRequest) request).setRequestURI("/error");
|
||||
this.delegateServlet.service(request, response);
|
||||
}
|
||||
}
|
||||
@@ -270,7 +309,7 @@ public class ProxyMvc {
|
||||
|
||||
@Override
|
||||
public String getServletName() {
|
||||
return "serverless-proxy";
|
||||
return "spring-serverless-proxy";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,12 +20,17 @@ import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Enumeration;
|
||||
import java.util.EventListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterRegistration;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
@@ -200,9 +205,14 @@ public class ProxyServletContext implements ServletContext {
|
||||
throw new UnsupportedOperationException("This ServletContext does not represent a running web container");
|
||||
}
|
||||
|
||||
Map<String, ServletRegistration> registrations = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public Dynamic addServlet(String servletName, Servlet servlet) {
|
||||
throw new UnsupportedOperationException("This ServletContext does not represent a running web container");
|
||||
|
||||
ProxyServletRegistration registration = new ProxyServletRegistration(servletName, servlet, this);
|
||||
this.registrations.put(servletName, registration);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,7 +232,7 @@ public class ProxyServletContext implements ServletContext {
|
||||
|
||||
@Override
|
||||
public ServletRegistration getServletRegistration(String servletName) {
|
||||
throw new UnsupportedOperationException("This ServletContext does not represent a running web container");
|
||||
return this.registrations.get(servletName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -240,9 +250,18 @@ public class ProxyServletContext implements ServletContext {
|
||||
throw new UnsupportedOperationException("This ServletContext does not represent a running web container");
|
||||
}
|
||||
|
||||
Map<String, FilterRegistration> filterRegistrations = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public javax.servlet.FilterRegistration.Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
|
||||
throw new UnsupportedOperationException("This ServletContext does not represent a running web container");
|
||||
try {
|
||||
Filter filter = filterClass.getDeclaredConstructor().newInstance();
|
||||
ProxyFilterRegistration registration = new ProxyFilterRegistration(filterName, filter);
|
||||
filterRegistrations.put(filterName, registration);
|
||||
return registration;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -252,12 +271,12 @@ public class ProxyServletContext implements ServletContext {
|
||||
|
||||
@Override
|
||||
public FilterRegistration getFilterRegistration(String filterName) {
|
||||
throw new UnsupportedOperationException("This ServletContext does not represent a running web container");
|
||||
return this.filterRegistrations.get(filterName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
|
||||
throw new UnsupportedOperationException("This ServletContext does not represent a running web container");
|
||||
return this.filterRegistrations;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
package org.springframework.cloud.function.serverless.web;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRegistration;
|
||||
import javax.servlet.ServletSecurityElement;
|
||||
|
||||
public class ProxyServletRegistration implements ServletRegistration, ServletRegistration.Dynamic, Comparable<ProxyServletRegistration> {
|
||||
|
||||
private final String servletName;
|
||||
|
||||
private final Servlet servlet;
|
||||
|
||||
private final ServletContext servletContext;
|
||||
|
||||
private int loadOnStartup;
|
||||
|
||||
public ProxyServletRegistration(String servletName, Servlet servlet, ServletContext servletContext) {
|
||||
this.servlet = servlet;
|
||||
this.servletName = servletName;
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.servletName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setInitParameter(String name, String value) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getInitParameter(String name) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> setInitParameters(Map<String, String> initParameters) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getInitParameters() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsyncSupported(boolean isAsyncSupported) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoadOnStartup(int loadOnStartup) {
|
||||
this.loadOnStartup = loadOnStartup;
|
||||
}
|
||||
|
||||
public int getLoadOnStartup() {
|
||||
return this.loadOnStartup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> setServletSecurity(ServletSecurityElement constraint) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMultipartConfig(MultipartConfigElement multipartConfig) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRunAsRole(String roleName) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> addMapping(String... urlPatterns) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getMappings() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRunAsRole() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ProxyServletRegistration o) {
|
||||
return Integer.compare(this.loadOnStartup, o.getLoadOnStartup());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user