This commit is contained in:
Oleg Zhurakousky
2023-03-02 20:03:54 +01:00
3 changed files with 158 additions and 1 deletions

View File

@@ -3,4 +3,12 @@
This module represents a concept of a light weight AWS forwarding proxy which deploys and interacts with existing
Spring Boot web application deployed as AWS Lambda.
A sample is provided in `/sample` directory
A sample is provided in [sample](https://github.com/spring-cloud/spring-cloud-function/tree/serverless-web/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/sample/pet-store) directory. It contain README and SAM template file to simplify the deployment. This module is identified as the only additional dependnecy to the existing web-app.
_NOTE: Although this module is AWS specific, this dependency is protocol only (not binary), therefore there is no AWS dependnecies._
The aformentioned proxy is identified as AWS Lambda [handler](https://github.com/spring-cloud/spring-cloud-function/blob/serverless-web/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/sample/pet-store/template.yml#L14)
The main Spring Boot configuration file is identified as [MAIN_CLASS](https://github.com/spring-cloud/spring-cloud-function/blob/serverless-web/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/sample/pet-store/template.yml#L22)

View File

@@ -0,0 +1,71 @@
package org.springframework.web.client;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import org.springframework.cloud.function.adapter.aws.web.FunctionClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class WebProxyUtils {
public static ProxyMvc buildMvcProxy(Class<?>... componentClasses) {
if (ObjectUtils.isEmpty(componentClasses)) {
Class<?> startClass = FunctionClassUtils.getStartClass();
if (startClass != null) {
componentClasses = new Class[] {startClass};
}
else {
throw new IllegalStateException("Failed to discover component classes");
}
}
AnnotationConfigWebApplicationContext applpicationContext = new AnnotationConfigWebApplicationContext();
applpicationContext.register(componentClasses);
ServletContext servletContext = new ProxyServletContext();
ServletConfig servletConfig = new ProxyServletConfig(servletContext);
DispatcherServlet servlet = new DispatcherServlet(applpicationContext);
try {
servlet.init(servletConfig);
return new ProxyMvc(servlet, applpicationContext);
}
catch (Exception e) {
throw new IllegalStateException("Failed to create MVC Proxy", e);
}
}
private static class ProxyServletConfig implements ServletConfig {
private final ServletContext servletContext;
ProxyServletConfig(ServletContext servletContext) {
this.servletContext = servletContext;
}
@Override
public String getServletName() {
return "serverless-proxy";
}
@Override
public ServletContext getServletContext() {
return this.servletContext;
}
@Override
public Enumeration<String> getInitParameterNames() {
return Collections.enumeration(new ArrayList<String>());
}
@Override
public String getInitParameter(String name) {
return null;
}
}
}

View File

@@ -0,0 +1,78 @@
package org.springframework.cloud.function.adapter.aws.web;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.web.client.ProxyHttpServletRequest;
import org.springframework.web.client.ProxyHttpServletResponse;
import org.springframework.web.client.ProxyMvc;
import org.springframework.web.client.WebProxyUtils;
import com.fasterxml.jackson.core.type.ResolvedType;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
public class RequestResponseTests {
private ObjectMapper mapper = new ObjectMapper();
private ProxyMvc mvc;
@BeforeEach
public void before() {
this.mvc = WebProxyUtils.buildMvcProxy(PetStoreSpringAppConfig.class);
}
@AfterEach
public void after() {
this.mvc.stop();
}
@Test
public void validateGetListOfPojos() throws Exception {
HttpServletRequest request = new ProxyHttpServletRequest(null, "GET", "/pets");
ProxyHttpServletResponse response = new ProxyHttpServletResponse();
mvc.service(request, response);
TypeReference<List<Pet>> tr = new TypeReference<List<Pet>>() {
};
List<Pet> pets = mapper.readValue(response.getContentAsByteArray(), tr);
assertThat(pets.size()).isEqualTo(10);
assertThat(pets.get(0)).isInstanceOf(Pet.class);
}
@Test
public void validateGetPojo() throws Exception {
HttpServletRequest request = new ProxyHttpServletRequest(null, "GET", "/pets/6e3cc370-892f-4efe-a9eb-82926ff8cc5b");
ProxyHttpServletResponse response = new ProxyHttpServletResponse();
mvc.service(request, response);
Pet pet = mapper.readValue(response.getContentAsByteArray(), Pet.class);
assertThat(pet).isNotNull();
assertThat(pet.getName()).isNotEmpty();
}
@Test
public void validatePost() throws Exception {
ProxyHttpServletRequest request = new ProxyHttpServletRequest(null, "POST", "/pets/");
String jsonPet = "{\n"
+ " \"id\":\"1234\",\n"
+ " \"breed\":\"Canish\",\n"
+ " \"name\":\"Foo\",\n"
+ " \"date\":\"2012-04-23T18:25:43.511Z\"\n"
+ "}";
request.setContent(jsonPet.getBytes());
request.setContentType("application/json");
ProxyHttpServletResponse response = new ProxyHttpServletResponse();
mvc.service(request, response);
Pet pet = mapper.readValue(response.getContentAsByteArray(), Pet.class);
assertThat(pet).isNotNull();
assertThat(pet.getName()).isNotEmpty();
}
}