Skip to content

Commit 9f9f139

Browse files
committed
Cleanup for README preparing for 0.9 release. Documentation is now in the wiki
1 parent f634f6e commit 9f9f139

File tree

1 file changed

+14
-198
lines changed

1 file changed

+14
-198
lines changed

README.md

Lines changed: 14 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -1,205 +1,20 @@
11
# Serverless Java container [![Build Status](https://travis-ci.org/awslabs/aws-serverless-java-container.svg?branch=master)](https://travis-ci.org/awslabs/aws-serverless-java-container) [![Help](http://img.shields.io/badge/help-gitter-E91E63.svg?style=flat-square)](https://gitter.im/awslabs/aws-serverless-java-container)
2-
The `aws-serverless-java-container` is collection of interfaces and their implementations that let you run Java application written with frameworks such as [Jersey](https://jersey.java.net/) or [Spark](http://sparkjava.com/) in [AWS Lambda](https://aws.amazon.com/lambda/).
2+
The `aws-serverless-java-container` makes it easy to run Java applications written wih frameworks such as [Spring](https://spring.io/), [Spring Boot](https://projects.spring.io/spring-boot/), [Jersey](https://jersey.java.net/), or [Spark](http://sparkjava.com/) in [AWS Lambda](https://aws.amazon.com/lambda/).
33

4-
The library contains a core artifact called `aws-serverless-java-container-core` that defines the interfaces and base classes required as well as default implementation of the Java servlet `HttpServletRequest` and `HttpServletResponse`.
5-
The library also includes two initial implementations of the interfaces to support Jersey apps (`aws-serverless-java-container-jersey`) and Spark (`aws-serverless-java-container-spark`).
4+
Serverless Java Container natively supports API Gateway's proxy integration models for requests and responses, you can create and inject custom models for methods that use custom mappings.
65

7-
To include the library in your Maven project, add the desired implementation to your `pom.xml` file, for example:
6+
Follow the quick started guides in [our wiki](wiki) to integrate Serverless Java Container with your project:
7+
* [Spring quick start](wiki/Quick-start---Spring)
8+
* [Spring Boot quick start](wiki/Quick-start---Spring-Boot)
9+
* [Jersey quick start](wiki/Quick-start---Jersey)
10+
* [Spark quick start](wiki/Quick-start---Spark)
811

9-
```
10-
<dependency>
11-
<groupId>com.amazonaws.serverless</groupId>
12-
<artifactId>aws-serverless-java-container-jersey</artifactId>
13-
<version>0.8</version>
14-
</dependency>
15-
```
16-
17-
## Integrating with Lambda
18-
The simplest way to run your application serverlessly is to configure [API Gateway](https://aws.amazon.com/api-gateway/) to use the
19-
[`AWS_PROXY`](http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-set-up-simple-proxy.html#api-gateway-set-up-lambda-proxy-integration-on-proxy-resource) integration type and
20-
configure your desired `LambdaContainerHandler` implementation to use `AwsProxyRequest`/`AwsProxyResponse` readers and writers. Both Spark and Jersey implementations provide static helper methods that
21-
pre-configure this for you.
22-
23-
When using a Cognito User Pool authorizer, use the Lambda `RequestStreamHandler` instead of the POJO-based `RequestHandler` handler. An example of this is included at the bottom of this file. The POJO handler does not support Jackson annotations required for the `CognitoAuthorizerClaims` class.
24-
25-
### Jersey support
26-
The library expects to receive a valid [JAX-RS](https://jax-rs-spec.java.net) application object. For the Jersey implementation this is the `ResourceConfig` object.
27-
28-
```java
29-
public class LambdaHandler implements RequestHandler<AwsProxyRequest, AwsProxyResponse> {
30-
private ResourceConfig jerseyApplication = new ResourceConfig().packages("my.jersey.app.package");
31-
private JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler
32-
= JerseyLambdaContainerHandler.getAwsProxyHandler(jerseyApplication);
33-
34-
public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
35-
return handler.proxy(awsProxyRequest, context);
36-
}
37-
}
38-
```
39-
40-
### Spring support
41-
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.
42-
43-
```java
44-
@Configuration
45-
@ComponentScan("com.amazonaws.serverless.proxy.spring.echoapp")
46-
public class EchoSpringAppConfig {
47-
}
48-
```
49-
50-
Once you have declared a configuration class, you can initialize the library with the class name:
51-
```java
52-
public class LambdaHandler implements RequestHandler<AwsProxyRequest, AwsProxyResponse> {
53-
SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler =
54-
SpringLambdaContainerHandler.getAwsProxyHandler(EchoSpringAppConfig.class);
55-
56-
public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
57-
return handler.proxy(awsProxyRequest, context);
58-
}
59-
}
60-
```
61-
62-
#### Spring Profiles
63-
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.
64-
65-
#### Spring Boot
66-
You can also use this framework to start Spring Boot applications inside Lambda. The framework does not recognize classes annotated with `@SpringBootApplication` automatically. However, you can wrap the Spring Boot application class in a regular `ConfigurableWebApplicationContext` object. In your handler class, instead of initializing the `SpringLambdaContainerHandler` with the Spring Boot application class, initialize another context and set the Spring Boot app as a parent:
67-
68-
```java
69-
SpringApplication springBootApplication = new SpringApplication(SpringBootApplication.class);
70-
springBootApplication.setWebEnvironment(false);
71-
springBootApplication.setBannerMode(Banner.Mode.OFF);
72-
73-
// create a new empty context and set the spring boot application as a parent of it
74-
ConfigurableWebApplicationContext wrappingContext = new AnnotationConfigWebApplicationContext();
75-
wrappingContext.setParent(springBootApplication.run());
76-
77-
// now we can initialize the framework with the wrapping context
78-
SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler =
79-
SpringLambdaContainerHandler.getAwsProxyHandler(wrappingContext);
80-
```
81-
82-
When using Spring Boot, make sure to configure the shade plugin in your pom file to exclude the embedded container and all unnecessary libraries to reduce the size of your built jar.
83-
84-
### Spark support
85-
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.
86-
87-
```java
88-
public class LambdaHandler implements RequestHandler<AwsProxyRequest, AwsProxyResponse> {
89-
private SparkLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler =
90-
SparkLambdaContainerHandler.getAwsProxyHandler();
91-
private boolean initialized = false;
92-
93-
public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
94-
if (!initialized) {
95-
defineRoutes();
96-
// it's important to call the awaitInitialization method not to run into race
97-
// conditions as routes are loaded asynchronously
98-
Spark.awaitInitialization();
99-
initialized = true;
100-
}
101-
return handler.proxy(awsProxyRequest, context);
102-
}
103-
104-
private void defineRoutes() {
105-
get("/hello", (req, res) -> "Hello World");
106-
}
107-
}
108-
```
109-
110-
If you configure an [`initExceptionHandler` method](http://sparkjava.com/documentation#stopping-the-server), make sure that you call `System.exit` at the end of the method. This framework keeps a `CountDownLatch` on the request
111-
and unless you forcefully exit from the thread, the Lambda function will hang waiting for a latch that is never released.
112-
113-
```java
114-
initExceptionHandler((e) -> {
115-
LOG.error("ignite failed", e);
116-
System.exit(100);
117-
});
118-
```
119-
120-
# Security context
121-
The `aws-serverless-java-container-core` contains a default implementation of the `SecurityContextWriter` that supports API Gateway's proxy integration. The generated security context uses the API Gateway `$context` object to establish the request security context. The context looks for the following values in order and returns the first matched type:
122-
123-
1. Cognito My User Pools
124-
2. Custom authorizers
125-
3. IAM auth.
126-
127-
The String values for these are exposed as static variables in the `AwsProxySecurityContext` object.
128-
129-
1. `AUTH_SCHEME_COGNITO_POOL`
130-
2. `AUTH_SCHEME_CUSTOM`
131-
3. `AUTH_SCHEME_IAM`
132-
133-
# Supporting other event types
134-
The `RequestReader` and `ResponseWriter` interfaces in the core package can be used to support event types and generate different responses. For example, ff you have configured mapping templates in
135-
API Gateway to create a custom event body or response you can create your own implementation of the `RequestReader` and `ResponseWriter` to handle these.
136-
137-
The `LambdaContainerHandler` also requires a `SecurityContextWriter` and an `ExceptionHandler`. You can also create custom implementations of these interfaces.
138-
139-
The `RequestReader`, `ResponseWriter`, `SecurityContextWriter`, and `ExceptionHandler` objects are passed to the constructor of the `LambdaContainerHandler` implementation:
140-
141-
```java
142-
JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler =
143-
new JerseyLambdaContainerHandler<>(new MyCustomRequestReader(),
144-
new MyCustomResponseWriter(),
145-
new MyCustomSecurityContextWriter(),
146-
new MyCustomExceptionHandler(),
147-
jaxRsApplication);
148-
```
149-
150-
# Jersey Servlet injection
151-
The `aws-serverless-java-container-jersey` includes Jersey factory classes to produce `HttpServletRequest` and `ServletContext` objects for your methods. First, you will need to register the factory with your Jersey application.
152-
153-
```java
154-
ResourceConfig app = new ResourceConfig()
155-
.packages("com.amazonaws.serverless.proxy.test.jersey")
156-
.register(new AbstractBinder() {
157-
@Override
158-
protected void configure() {
159-
bindFactory(AwsProxyServletRequestFactory.class)
160-
.to(HttpServletRequest.class)
161-
.in(RequestScoped.class);
162-
bindFactory(AwsProxyServletContextFactory.class)
163-
.to(ServletContext.class)
164-
.in(RequestScoped.class);
165-
}
166-
});
167-
```
168-
169-
Once the factory is registered, you can receive `HttpServletRequest` and `ServletContext` objects in your methods using the `@Context` annotation.
170-
171-
```java
172-
@Path("/my-servlet") @GET
173-
public String echoServletHeaders(@Context HttpServletRequest context) {
174-
Enumeration<String> headerNames = context.getHeaderNames();
175-
while (headerNames.hasMoreElements()) {
176-
String headerName = headerNames.nextElement();
177-
}
178-
return "servlet";
179-
}
180-
```
181-
182-
## Servlet Filters
183-
You can register [`Filter`](https://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html) implementations by implementing a `StartupsHandler` as defined in the `AwsLambdaServletContainerHandler` class. The `onStartup` methods receives a reference to the current `ServletContext`.
184-
185-
```java
186-
handler.onStartup(c -> {
187-
FilterRegistration.Dynamic registration = c.addFilter("CustomHeaderFilter", CustomHeaderFilter.class);
188-
// update the registration to map to a path
189-
registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
190-
// servlet name mappings are disabled and will throw an exception
191-
});
192-
```
193-
194-
# Using the Lambda Stream handler
195-
By default, Lambda does not use Jackson annotations when marshalling and unmarhsalling JSON. This can cause issues when receiving requests that include the claims object from a Cognito User Pool authorizer. To support these type of requests, use Lambda's `RequestStreamHandler` interface instead of the POJO-based `RequestHandler`. This allows you to use a custom version of Jackson with support for annotations.
196-
197-
This library uses Jackson annotations in the `com.amazonaws.serverless.proxy.model.CognitoAuthorizerClaims` object. The example below shows how to do this with a `SpringLambdaContainerHandler`, you can use the same methodology with all of the other implementations.
12+
Below is the most basic AWS Lambda handler example that launches a Spring application. You can also take a look at the [samples](tree/master/samples) in this repository, our main wiki page includes a [step-by-step guide](wiki#deploying-the-sample-applications) on how to deploy the various sample applications using Maven and [SAM](https://github.com/awslabs/serverless-application-model).
19813

19914
```java
20015
public class StreamLambdaHandler implements RequestStreamHandler {
20116
private SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
202-
private static ObjectMapper mapper = new ObjectMapper();
17+
private Logger log = LoggerFactory.getLogger(StreamLambdaHandler.class);
20318

20419
@Override
20520
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
@@ -208,18 +23,19 @@ public class StreamLambdaHandler implements RequestStreamHandler {
20823
try {
20924
handler = SpringLambdaContainerHandler.getAwsProxyHandler(PetStoreSpringAppConfig.class);
21025
} catch (ContainerInitializationException e) {
211-
e.printStackTrace();
26+
log.error("Cannot initialize Spring container", e);
21227
outputStream.close();
28+
throw new RuntimeException(e);
21329
}
21430
}
21531

216-
AwsProxyRequest request = mapper.readValue(inputStream, AwsProxyRequest.class);
32+
AwsProxyRequest request = LambdaContainerHandler.getObjectMapper().readValue(inputStream, AwsProxyRequest.class);
21733

21834
AwsProxyResponse resp = handler.proxy(request, context);
21935

220-
mapper.writeValue(outputStream, resp);
36+
LambdaContainerHandler.getObjectMapper().writeValue(outputStream, resp);
22137
// just in case it wasn't closed by the mapper
22238
outputStream.close();
22339
}
22440
}
225-
```
41+
```

0 commit comments

Comments
 (0)