Skip to content

Commit b982d29

Browse files
authored
Merge pull request #13 from mattcorey/simplified-profile-support
Simplified profile support and closing issue #12
2 parents 6fd1475 + 76e12f2 commit b982d29

File tree

12 files changed

+177
-3
lines changed

12 files changed

+177
-3
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 using the `SpringLambdaContainerHandler.activateSpringProfiles(String...)` method - common drivers of this might be the AWS Lambda stage that you're deployed under, or stage variables. 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: 12 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 List<String> springProfiles;
5051

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

88+
public List<String> getSpringProfiles() {
89+
return Collections.unmodifiableList(springProfiles);
90+
}
91+
92+
public void setSpringProfiles(List<String> springProfiles) {
93+
this.springProfiles = new ArrayList<>(springProfiles);
94+
}
95+
8796
@Override
8897
public void onStartup(ServletContext servletContext) throws ServletException {
98+
if (springProfiles != null) {
99+
applicationContext.getEnvironment().setActiveProfiles(springProfiles.toArray(new String[0]));
100+
}
89101
applicationContext.setServletContext(servletContext);
90102

91103
dispatcherConfig = new DefaultDispatcherConfig(servletContext);

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
2626

2727
import javax.servlet.ServletContext;
28+
import java.util.Arrays;
2829
import java.util.concurrent.CountDownLatch;
2930

3031
/**
@@ -104,6 +105,14 @@ protected AwsHttpServletResponse getContainerResponse(CountDownLatch latch) {
104105
return new AwsHttpServletResponse(latch);
105106
}
106107

108+
public void activateSpringProfiles(String... profiles) throws ContainerInitializationException {
109+
if (initializer == null) {
110+
throw new ContainerInitializationException(LambdaSpringApplicationInitializer.ERROR_NO_CONTEXT, null);
111+
}
112+
113+
initializer.setSpringProfiles(Arrays.asList(profiles));
114+
}
115+
107116
@Override
108117
protected void handleRequest(AwsProxyHttpServletRequest containerRequest, AwsHttpServletResponse containerResponse, Context lambdaContext) throws Exception {
109118
if (initializer == null) {

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,11 @@
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+
@Configuration
8+
@Profile("override")
9+
@PropertySource("classpath:/application-override.properties")
10+
public class ProfileOverrideConfig {
11+
}
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,31 @@
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+
}
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+
.build();
60+
61+
SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = SpringLambdaContainerHandler.getAwsProxyHandler(EchoSpringAppConfig.class);
62+
handler.activateSpringProfiles("override");
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)