Skip to content

Commit

Permalink
Add sample and documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
olegz committed Jun 30, 2023
1 parent d5c865b commit 123a1b4
Show file tree
Hide file tree
Showing 14 changed files with 727 additions and 5 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
*.jar
*.war
*.ear
*.project
*.classpath
*.settings

# Idea project files
.idea/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,27 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.function.serverless.web.FunctionClassUtils;
import org.springframework.cloud.function.serverless.web.ProxyHttpServletRequest;
import org.springframework.cloud.function.serverless.web.ProxyMvc;
import org.springframework.core.KotlinDetector;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import com.amazonaws.serverless.proxy.AwsHttpApiV2SecurityContextWriter;
import com.amazonaws.serverless.proxy.AwsProxySecurityContextWriter;
Expand Down Expand Up @@ -48,6 +62,8 @@
*/
public class SpringDelegatingLambdaContainerHandler implements RequestStreamHandler {

private static Log logger = LogFactory.getLog(SpringDelegatingLambdaContainerHandler.class);

private final Class<?>[] startupClasses;

private final ProxyMvc mvc;
Expand All @@ -56,6 +72,10 @@ public class SpringDelegatingLambdaContainerHandler implements RequestStreamHand

private final AwsProxyHttpServletResponseWriter responseWriter;

public SpringDelegatingLambdaContainerHandler() {
this(new Class[] {FunctionClassUtils.getStartClass()});
}

public SpringDelegatingLambdaContainerHandler(Class<?>... startupClasses) {
this.startupClasses = startupClasses;
this.mvc = ProxyMvc.INSTANCE(this.startupClasses);
Expand Down Expand Up @@ -84,15 +104,17 @@ public void handleRequest(InputStream input, OutputStream output, Context lambda
}
}


@SuppressWarnings({ "unchecked", "rawtypes" })
private HttpServletRequest generateRequest(Map request, Context lambdaContext, SecurityContextWriter securityWriter) {
AwsProxyRequest v1Request = this.mapper.convertValue(request, AwsProxyRequest.class);

ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(this.mvc.getApplicationContext().getServletContext(),
v1Request.getHttpMethod(), v1Request.getPath());
httpRequest.setContentType("application/json");
httpRequest.setContent(v1Request.getBody().getBytes(StandardCharsets.UTF_8));

if (StringUtils.hasText(v1Request.getBody())) {
httpRequest.setContentType("application/json");
httpRequest.setContent(v1Request.getBody().getBytes(StandardCharsets.UTF_8));
}
httpRequest.setAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY, v1Request.getRequestContext());
httpRequest.setAttribute(RequestReader.API_GATEWAY_STAGE_VARS_PROPERTY, v1Request.getStageVariables());
httpRequest.setAttribute(RequestReader.API_GATEWAY_EVENT_PROPERTY, v1Request);
Expand All @@ -107,8 +129,11 @@ public HttpServletRequest generateRequest2(Map request, Context lambdaContext, S
HttpApiV2ProxyRequest v2Request = this.mapper.convertValue(request, HttpApiV2ProxyRequest.class);
ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(this.mvc.getApplicationContext().getServletContext(),
v2Request.getRequestContext().getHttp().getMethod(), v2Request.getRequestContext().getHttp().getPath());
httpRequest.setContentType("application/json");
httpRequest.setContent(v2Request.getBody().getBytes(StandardCharsets.UTF_8));

if (StringUtils.hasText(v2Request.getBody())) {
httpRequest.setContentType("application/json");
httpRequest.setContent(v2Request.getBody().getBytes(StandardCharsets.UTF_8));
}
httpRequest.setAttribute(RequestReader.HTTP_API_CONTEXT_PROPERTY, v2Request.getRequestContext());
httpRequest.setAttribute(RequestReader.HTTP_API_STAGE_VARS_PROPERTY, v2Request.getStageVariables());
httpRequest.setAttribute(RequestReader.HTTP_API_EVENT_PROPERTY, v2Request);
Expand Down
39 changes: 39 additions & 0 deletions samples/springboot3/alt-pet-store/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Serverless Spring Boot 3 example
A basic pet store written with the [Spring Boot 3 framework](https://projects.spring.io/spring-boot/). Unlike older examples, this example is relying on the new
`SpringDelegatingLambdaContainerHandler`, which you simply need to identify as a _handler_ of the Lambda function. The main configuration class identified as `MAIN_CLASS`
environment variable or `Start-Class` or `Main-Class` entry in Manifest file. See provided `template.yml` file for reference.


The application can be deployed in an AWS account using the [Serverless Application Model](https://github.com/awslabs/serverless-application-model). The `template.yml` file in the root folder contains the application definition.

## Pre-requisites
* [AWS CLI](https://aws.amazon.com/cli/)
* [SAM CLI](https://github.com/awslabs/aws-sam-cli)
* [Gradle](https://gradle.org/) or [Maven](https://maven.apache.org/)

## Deployment
In a shell, navigate to the sample's folder and use the SAM CLI to build a deployable package
```
$ sam build
```

This command compiles the application and prepares a deployment package in the `.aws-sam` sub-directory.

To deploy the application in your AWS account, you can use the SAM CLI's guided deployment process and follow the instructions on the screen

```
$ sam deploy --guided
```

Once the deployment is completed, the SAM CLI will print out the stack's outputs, including the new application URL. You can use `curl` or a web browser to make a call to the URL

```
...
---------------------------------------------------------------------------------------------------------
OutputKey-Description OutputValue
---------------------------------------------------------------------------------------------------------
PetStoreApi - URL for application https://xxxxxxxxxx.execute-api.us-west-2.amazonaws.com/pets
---------------------------------------------------------------------------------------------------------
$ curl https://xxxxxxxxxx.execute-api.us-west-2.amazonaws.com/pets
```
29 changes: 29 additions & 0 deletions samples/springboot3/alt-pet-store/builds.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
apply plugin: 'java'

repositories {
mavenLocal()
mavenCentral()
maven {url "https://repo.spring.io/milestone"}
maven {url "https://repo.spring.io/snapshot"}
}

dependencies {
implementation (
implementation('org.springframework.boot:spring-boot-starter-web:3.1.1') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
},
'com.amazonaws.serverless:aws-serverless-java-container-springboot3:[2.0-SNAPSHOT,)',
)
}

task buildZip(type: Zip) {
from compileJava
from processResources
into('lib') {
from(configurations.compileClasspath) {
exclude 'tomcat-embed-*'
}
}
}

build.dependsOn buildZip
154 changes: 154 additions & 0 deletions samples/springboot3/alt-pet-store/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.amazonaws.serverless.sample</groupId>
<artifactId>petstore-springboot3-example</artifactId>
<version>2.0-SNAPSHOT</version>
<name>Spring Boot example for the aws-serverless-java-container library</name>
<description>Simple pet store written with the Spring framework and Spring Boot</description>
<url>https://aws.amazon.com/lambda/</url>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.1</version>
</parent>

<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>

<properties>
<java.version>17</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>com.amazonaws.serverless</groupId>
<artifactId>aws-serverless-java-container-springboot3</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
</dependencies>

<profiles>
<profile>
<id>shaded-jar</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<exclude>org.apache.tomcat.embed:*</exclude>
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>assembly-zip</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<build>
<plugins>
<!-- don't build a jar, we'll use the classes dir -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>default-jar</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<!-- select and copy only runtime dependencies to a temporary lib folder -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>zip-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<descriptors>
<descriptor>src${file.separator}assembly${file.separator}bin.xml</descriptor>
</descriptors>
<attach>false</attach>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>


</project>
27 changes: 27 additions & 0 deletions samples/springboot3/alt-pet-store/src/assembly/bin.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>lambda-package</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<!-- copy runtime dependencies with some exclusions -->
<fileSet>
<directory>${project.build.directory}${file.separator}lib</directory>
<outputDirectory>lib</outputDirectory>
<excludes>
<exclude>tomcat-embed*</exclude>
</excludes>
</fileSet>
<!-- copy all classes -->
<fileSet>
<directory>${project.build.directory}${file.separator}classes</directory>
<includes>
<include>**</include>
</includes>
<outputDirectory>${file.separator}</outputDirectory>
</fileSet>
</fileSets>
</assembly>
Loading

0 comments on commit 123a1b4

Please sign in to comment.