Skip to content

Commit 7205220

Browse files
authored
Merge pull request #2 from mattcorey/profile-support
Profile support
2 parents 1682ba8 + 1af0f7c commit 7205220

File tree

12 files changed

+168
-7
lines changed

12 files changed

+168
-7
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class LambdaHandler implements RequestHandler<AwsProxyRequest, AwsProxyRe
3636
```
3737

3838
### Spring support
39-
The library supports Spring applications that are configured using annotations (in code) rather than in an XML file. The simplest possible configuration uses the `@ComponentScan` annotation to load all controller classes from a package. For example, our unit test application has the following configuuration class.
39+
The library supports Spring applications that are configured using annotations (in code) rather than in an XML file. The simplest possible configuration uses the `@ComponentScan` annotation to load all controller classes from a package. For example, our unit test application has the following configuration class.
4040

4141
```java
4242
@Configuration
@@ -57,6 +57,9 @@ public class LambdaHandler implements RequestHandler<AwsProxyRequest, AwsProxyRe
5757
}
5858
```
5959

60+
#### Spring Profiles
61+
You can enable Spring Profiles (as defined with the `@Profile` annotation) by deploying your Lambda under a stage name that matches the profile name. This will allow you to create a single package with support for different resources for dev, test, prod, etc. See [@Profile documentation](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Profile.html) for details.
62+
6063
### Spark support
6164
The library also supports applications written with the [Spark framework](http://sparkjava.com/). When using the library with Spark, it's important to initialize the `SparkLambdaContainerHandler` before defining routes.
6265

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyServletContext.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,9 @@ public String getVirtualServerName() {
410410
return null;
411411
}
412412

413+
public String getStage() {
414+
return awsProxyRequest.getRequestContext().getStage();
415+
}
413416

414417
public static ServletContext getInstance(AwsProxyRequest request, Context lambdaContext) {
415418
if (instance == null) {
@@ -418,4 +421,8 @@ public static ServletContext getInstance(AwsProxyRequest request, Context lambda
418421

419422
return instance;
420423
}
424+
425+
public static void clearServletContextCache() {
426+
instance = null;
427+
}
421428
}

aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/LambdaSpringApplicationInitializer.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class LambdaSpringApplicationInitializer implements WebApplicationInitial
4747
private ConfigurableWebApplicationContext applicationContext;
4848
private boolean refreshContext = true;
4949
private List<ServletContextListener> contextListeners;
50+
private String lambdaStage;
5051

5152
// Dynamically instantiated properties
5253
private ServletConfig dispatcherConfig;
@@ -84,8 +85,13 @@ public void dispatch(HttpServletRequest request, HttpServletResponse response)
8485
dispatcherServlet.service(request, response);
8586
}
8687

88+
public void setLambdaStage(String lambdaStage) {
89+
this.lambdaStage = lambdaStage;
90+
}
91+
8792
@Override
8893
public void onStartup(ServletContext servletContext) throws ServletException {
94+
applicationContext.getEnvironment().setActiveProfiles(lambdaStage);
8995
applicationContext.setServletContext(servletContext);
9096

9197
dispatcherConfig = new DefaultDispatcherConfig(servletContext);

aws-serverless-java-container-spring/src/main/java/com/amazonaws/serverless/proxy/spring/SpringLambdaContainerHandler.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@
1616
import com.amazonaws.serverless.proxy.internal.*;
1717
import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
1818
import com.amazonaws.serverless.proxy.internal.model.AwsProxyResponse;
19-
import com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletResponse;
20-
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest;
21-
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader;
22-
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletResponseWriter;
19+
import com.amazonaws.serverless.proxy.internal.servlet.*;
2320
import com.amazonaws.services.lambda.runtime.Context;
2421
import org.springframework.web.context.ConfigurableWebApplicationContext;
2522
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
@@ -112,6 +109,7 @@ protected void handleRequest(AwsProxyHttpServletRequest containerRequest, AwsHtt
112109

113110
// wire up the application context on the first invocation
114111
if (!initialized) {
112+
initializer.setLambdaStage(((AwsProxyServletContext) containerRequest.getServletContext()).getStage());
115113
ServletContext context = containerRequest.getServletContext();
116114
initializer.onStartup(context);
117115
initialized = true;

aws-serverless-java-container-spring/src/test/java/com/amazonaws/serverless/proxy/spring/echoapp/EchoSpringAppConfig.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
import com.amazonaws.serverless.exceptions.ContainerInitializationException;
44
import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
5-
import com.amazonaws.serverless.proxy.spring.LambdaSpringApplicationInitializer;
65
import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
7-
import com.amazonaws.services.lambda.runtime.Context;
86
import com.fasterxml.jackson.databind.ObjectMapper;
97
import org.springframework.beans.factory.annotation.Autowired;
108
import org.springframework.context.annotation.Bean;
119
import org.springframework.context.annotation.ComponentScan;
1210
import org.springframework.context.annotation.Configuration;
11+
import org.springframework.context.annotation.PropertySource;
1312
import org.springframework.web.context.ConfigurableWebApplicationContext;
1413

1514
@Configuration
1615
@ComponentScan("com.amazonaws.serverless.proxy.spring.echoapp")
16+
@PropertySource("classpath:application.properties")
1717
public class EchoSpringAppConfig {
1818

1919
@Autowired
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.amazonaws.serverless.proxy.spring.echoapp;
2+
3+
import org.springframework.context.annotation.Configuration;
4+
import org.springframework.context.annotation.Profile;
5+
import org.springframework.context.annotation.PropertySource;
6+
7+
/**
8+
* Created by matthewcorey on 2/20/17.
9+
*/
10+
@Configuration
11+
@Profile("override")
12+
@PropertySource("classpath:/application-override.properties")
13+
public class ProfileOverrideConfig {
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.amazonaws.serverless.proxy.spring.echoapp.profile;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
6+
@Configuration
7+
public class DefaultProfileConfiguration {
8+
@Bean
9+
public String beanInjectedValue() {
10+
return "default-profile-from-bean";
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.amazonaws.serverless.proxy.spring.echoapp.profile;
2+
3+
import com.amazonaws.serverless.proxy.spring.echoapp.model.MapResponseModel;
4+
import org.springframework.beans.factory.annotation.Autowired;
5+
import org.springframework.beans.factory.annotation.Value;
6+
import org.springframework.web.bind.annotation.RequestMapping;
7+
import org.springframework.web.bind.annotation.RequestMethod;
8+
import org.springframework.web.bind.annotation.RestController;
9+
10+
@RestController
11+
@RequestMapping("/profile")
12+
public class DefaultProfileResource {
13+
@Value("${spring-proxy.profile-test}")
14+
private String profileTest;
15+
16+
@Value("${spring-proxy.not-overridden-test}")
17+
private String noOverride;
18+
19+
@Autowired
20+
private String beanInjectedValue;
21+
22+
@RequestMapping(path = "/spring-properties", method = RequestMethod.GET)
23+
public MapResponseModel loadProperties() {
24+
MapResponseModel model = new MapResponseModel();
25+
26+
model.addValue("profileTest", profileTest);
27+
model.addValue("noOverride", noOverride);
28+
model.addValue("beanInjectedValue", beanInjectedValue);
29+
return model;
30+
}
31+
}
32+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.amazonaws.serverless.proxy.spring.echoapp.profile;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.context.annotation.Profile;
6+
7+
@Configuration
8+
@Profile("override")
9+
public class OverrideProfileConfiguration {
10+
@Bean
11+
public String beanInjectedValue() {
12+
return "override-profile-from-bean";
13+
}
14+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.amazonaws.serverless.proxy.spring.profile;
2+
3+
import com.amazonaws.serverless.proxy.internal.model.AwsProxyRequest;
4+
import com.amazonaws.serverless.proxy.internal.model.AwsProxyResponse;
5+
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyServletContext;
6+
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
7+
import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
8+
import com.amazonaws.serverless.proxy.spring.SpringLambdaContainerHandler;
9+
import com.amazonaws.serverless.proxy.spring.echoapp.EchoSpringAppConfig;
10+
import com.amazonaws.serverless.proxy.spring.echoapp.model.MapResponseModel;
11+
import com.fasterxml.jackson.databind.ObjectMapper;
12+
import org.junit.Before;
13+
import org.junit.Test;
14+
import org.junit.runner.RunWith;
15+
import org.springframework.beans.factory.annotation.Autowired;
16+
import org.springframework.test.context.ContextConfiguration;
17+
import org.springframework.test.context.TestExecutionListeners;
18+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
19+
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
20+
import org.springframework.test.context.web.WebAppConfiguration;
21+
22+
import static org.junit.Assert.assertEquals;
23+
24+
@RunWith(SpringJUnit4ClassRunner.class)
25+
@ContextConfiguration(classes = EchoSpringAppConfig.class)
26+
@WebAppConfiguration
27+
@TestExecutionListeners(inheritListeners = false, listeners = {DependencyInjectionTestExecutionListener.class})
28+
public class SpringProfileTest {
29+
@Autowired
30+
private ObjectMapper objectMapper;
31+
32+
@Autowired
33+
private MockLambdaContext lambdaContext;
34+
35+
@Before
36+
public void clearServletContextCache() {
37+
AwsProxyServletContext.clearServletContextCache();
38+
}
39+
40+
@Test
41+
public void profile_defaultProfile() throws Exception {
42+
AwsProxyRequest request = new AwsProxyRequestBuilder("/profile/spring-properties", "GET")
43+
.build();
44+
45+
SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = SpringLambdaContainerHandler.getAwsProxyHandler(EchoSpringAppConfig.class);
46+
AwsProxyResponse output = handler.proxy(request, lambdaContext);
47+
assertEquals(200, output.getStatusCode());
48+
49+
MapResponseModel response = objectMapper.readValue(output.getBody(), MapResponseModel.class);
50+
assertEquals(3, response.getValues().size());
51+
assertEquals("default-profile", response.getValues().get("profileTest"));
52+
assertEquals("not-overridden", response.getValues().get("noOverride"));
53+
assertEquals("default-profile-from-bean", response.getValues().get("beanInjectedValue"));
54+
}
55+
56+
@Test
57+
public void profile_overrideProfile() throws Exception {
58+
AwsProxyRequest request = new AwsProxyRequestBuilder("/profile/spring-properties", "GET")
59+
.stage("override")
60+
.build();
61+
62+
SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = SpringLambdaContainerHandler.getAwsProxyHandler(EchoSpringAppConfig.class);
63+
AwsProxyResponse output = handler.proxy(request, lambdaContext);
64+
assertEquals(200, output.getStatusCode());
65+
66+
MapResponseModel response = objectMapper.readValue(output.getBody(), MapResponseModel.class);
67+
assertEquals(3, response.getValues().size());
68+
assertEquals("override-profile", response.getValues().get("profileTest"));
69+
assertEquals("not-overridden", response.getValues().get("noOverride"));
70+
assertEquals("override-profile-from-bean", response.getValues().get("beanInjectedValue"));
71+
}
72+
}

0 commit comments

Comments
 (0)