Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide ApplicationContext instead of Config classes #3

Merged
merged 3 commits into from
Jan 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions aws-serverless-java-container-spring/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@
<version>${spring.version}</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
*/
package com.amazonaws.serverless.proxy.spring;

import com.amazonaws.serverless.exceptions.InvalidResponseObjectException;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.context.support.ServletRequestHandledEvent;
Expand Down Expand Up @@ -44,11 +44,11 @@ public class LambdaSpringApplicationInitializer implements WebApplicationInitial
private static final String DEFAULT_SERVLET_NAME = "aws-servless-java-container";

// Configuration variables that can be passed in
private List<Class> configurationClasses;
private ConfigurableWebApplicationContext applicationContext;
private boolean refreshContext = true;
private List<ServletContextListener> contextListeners;

// Dynamically instantiated properties
private AnnotationConfigWebApplicationContext applicationContext;
private ServletConfig dispatcherConfig;
private DispatcherServlet dispatcherServlet;

Expand All @@ -57,31 +57,11 @@ public class LambdaSpringApplicationInitializer implements WebApplicationInitial

/**
* Creates a new instance of the WebApplicationInitializer
* @param applicationContext A custom ConfigurableWebApplicationContext to be used
*/
public LambdaSpringApplicationInitializer() {
configurationClasses = new ArrayList<>();
contextListeners = new ArrayList<>();
}

/**
* Adds a configuration class to the Spring startup process. This should be called at least once with an annotated
* class that contains the @Configuration annotations. The simplest possible class uses the @ComponentScan
* annocation to load all controllers.
*
* <pre>
* {@Code
* @Configuration
* @ComponentScan("com.amazonaws.serverless.proxy.spring.echoapp")
* public class EchoSpringAppConfig {
* }
* }
* </pre>
* @param configuration A set of configuration classes
*/
public void addConfigurationClasses(Class... configuration) {
for (Class config : configuration) {
configurationClasses.add(config);
}
public LambdaSpringApplicationInitializer(ConfigurableWebApplicationContext applicationContext) {
this.contextListeners = new ArrayList<>();
this.applicationContext = applicationContext;
}

/**
Expand All @@ -94,27 +74,18 @@ public void addListener(ServletContextListener listener) {
contextListeners.add(listener);
}

public void setRefreshContext(boolean refreshContext) {
this.refreshContext = refreshContext;
}

public void dispatch(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
currentResponse = response;
dispatcherServlet.service(request, response);
}

/**
* Returns the application context initialized in the library
* @return
*/
public AnnotationConfigWebApplicationContext getApplicationContext() {
return applicationContext;
}

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Create the 'root' Spring application context
applicationContext = new AnnotationConfigWebApplicationContext();
for (Class config : configurationClasses) {
applicationContext.register(config);
}
applicationContext.setServletContext(servletContext);

dispatcherConfig = new DefaultDispatcherConfig(servletContext);
Expand All @@ -138,7 +109,11 @@ public void onApplicationEvent(ServletRequestHandledEvent servletRequestHandledE

// Register and map the dispatcher servlet
dispatcherServlet = new DispatcherServlet(applicationContext);
dispatcherServlet.refresh();

if (refreshContext) {
dispatcherServlet.refresh();
}

dispatcherServlet.onApplicationEvent(new ContextRefreshedEvent(applicationContext));
dispatcherServlet.init(dispatcherConfig);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader;
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletResponseWriter;
import com.amazonaws.services.lambda.runtime.Context;
import org.springframework.web.context.ConfigurableWebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;

import javax.servlet.ServletContext;
import java.util.concurrent.CountDownLatch;
Expand All @@ -44,19 +46,34 @@ public class SpringLambdaContainerHandler<RequestType, ResponseType> extends Lam
* @return An initialized instance of the `SpringLambdaContainerHandler`
* @throws ContainerInitializationException
*/
public static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> getAwsProxyHandler(Class... config)
throws ContainerInitializationException {
SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler =
new SpringLambdaContainerHandler<>(
new AwsProxyHttpServletRequestReader(),
new AwsProxyHttpServletResponseWriter(),
new AwsProxySecurityContextWriter(),
new AwsProxyExceptionHandler()
);
public static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> getAwsProxyHandler(Class... config) throws ContainerInitializationException {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(config);

handler.addConfiguration(config);
return new SpringLambdaContainerHandler<>(
new AwsProxyHttpServletRequestReader(),
new AwsProxyHttpServletResponseWriter(),
new AwsProxySecurityContextWriter(),
new AwsProxyExceptionHandler(),
applicationContext
);
}

return handler;
/**
* Creates a default SpringLambdaContainerHandler initialized with the `AwsProxyRequest` and `AwsProxyResponse` objects
* @param applicationContext A custom ConfigurableWebApplicationContext to be used
* @return An initialized instance of the `SpringLambdaContainerHandler`
* @throws ContainerInitializationException
*/
public static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> getAwsProxyHandler(ConfigurableWebApplicationContext applicationContext)
throws ContainerInitializationException {
return new SpringLambdaContainerHandler<>(
new AwsProxyHttpServletRequestReader(),
new AwsProxyHttpServletResponseWriter(),
new AwsProxySecurityContextWriter(),
new AwsProxyExceptionHandler(),
applicationContext
);
}

/**
Expand All @@ -69,20 +86,17 @@ public static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> ge
* @throws ContainerInitializationException
*/
public SpringLambdaContainerHandler(RequestReader<RequestType, AwsProxyHttpServletRequest> requestReader,
ResponseWriter<AwsHttpServletResponse, ResponseType> responseWriter,
SecurityContextWriter<RequestType> securityContextWriter,
ExceptionHandler<ResponseType> exceptionHandler)
ResponseWriter<AwsHttpServletResponse, ResponseType> responseWriter,
SecurityContextWriter<RequestType> securityContextWriter,
ExceptionHandler<ResponseType> exceptionHandler,
ConfigurableWebApplicationContext applicationContext)
throws ContainerInitializationException {
super(requestReader, responseWriter, securityContextWriter, exceptionHandler);
initializer = new LambdaSpringApplicationInitializer();
initializer = new LambdaSpringApplicationInitializer(applicationContext);
}

/**
* Registers a set of classes with the underlying Spring application context
* @param config Spring annotated classes to be registered with the application context
*/
public void addConfiguration(Class... config) {
initializer.addConfigurationClasses(config);
public void setRefreshContext(boolean refreshContext) {
this.initializer.setRefreshContext(refreshContext);
}

@Override
Expand All @@ -98,6 +112,7 @@ protected void handleRequest(AwsProxyHttpServletRequest containerRequest, AwsHtt
initializer.onStartup(context);
initialized = true;
}

initializer.dispatch(containerRequest, containerResponse);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.amazonaws.serverless.proxy.spring;

import com.amazonaws.serverless.exceptions.ContainerInitializationException;
import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.internal.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
Expand All @@ -12,36 +11,66 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.junit.BeforeClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.ConfigurableWebApplicationContext;

import java.io.IOException;
import java.util.UUID;

import static org.junit.Assert.*;

import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.internal.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
import com.amazonaws.serverless.proxy.spring.echoapp.EchoSpringAppConfig;
import com.amazonaws.serverless.proxy.spring.echoapp.model.MapResponseModel;
import com.amazonaws.serverless.proxy.spring.echoapp.model.SingleValueModel;
import com.amazonaws.services.lambda.runtime.Context;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.binary.Base64;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.ConfigurableWebApplicationContext;

public class SpringAwsProxyTest {
import java.io.IOException;
import java.util.UUID;

import static org.junit.Assert.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {EchoSpringAppConfig.class})
@WebAppConfiguration
@TestExecutionListeners(inheritListeners = false, listeners = {DependencyInjectionTestExecutionListener.class})
public class SpringAwsProxyTest {
private static final String CUSTOM_HEADER_KEY = "x-custom-header";
private static final String CUSTOM_HEADER_VALUE = "my-custom-value";
private static final String AUTHORIZER_PRINCIPAL_ID = "test-principal-" + UUID.randomUUID().toString();

@Autowired
private ObjectMapper objectMapper;

private static ObjectMapper objectMapper = new ObjectMapper();
private static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = null;
@Autowired
private MockLambdaContext lambdaContext;

private static Context lambdaContext = new MockLambdaContext();

@BeforeClass
public static void init() {
try {
handler = SpringLambdaContainerHandler.getAwsProxyHandler(EchoSpringAppConfig.class);
} catch (ContainerInitializationException e) {
e.printStackTrace();
fail();
}
}
@Autowired
private SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;

@Test
public void headers_getHeaders_echo() {
Expand Down Expand Up @@ -188,3 +217,4 @@ private void validateSingleValueModel(AwsProxyResponse output, String value) {
}
}
}

Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@
package com.amazonaws.serverless.proxy.spring.echoapp;

import com.amazonaws.serverless.exceptions.ContainerInitializationException;
import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
import com.amazonaws.serverless.proxy.spring.LambdaSpringApplicationInitializer;
import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
import com.amazonaws.services.lambda.runtime.Context;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.ConfigurableWebApplicationContext;

@Configuration
@ComponentScan("com.amazonaws.serverless.proxy.spring.echoapp")
public class EchoSpringAppConfig {

@Autowired
private ConfigurableWebApplicationContext applicationContext;

@Bean
public SpringLambdaContainerHandler springLambdaContainerHandler() throws ContainerInitializationException {
SpringLambdaContainerHandler handler = SpringLambdaContainerHandler.getAwsProxyHandler(applicationContext);
handler.setRefreshContext(false);
return handler;
}

@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}

@Bean
public MockLambdaContext lambdaContext() {
return new MockLambdaContext();
}

}