Merge pull request #714 from dheeraj-mummareddy/master
#473 serveless implementation using aws compute engine and serverless fram…
							
								
								
									
										6
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						@@ -48,6 +48,11 @@
 | 
			
		||||
        <mongo-java-driver.version>3.3.0</mongo-java-driver.version>
 | 
			
		||||
        <slf4j.version>1.7.21</slf4j.version>
 | 
			
		||||
        <logback.version>1.1.7</logback.version>
 | 
			
		||||
        <aws-lambda-core.version>1.1.0</aws-lambda-core.version>
 | 
			
		||||
        <aws-java-sdk-dynamodb.version>1.11.289</aws-java-sdk-dynamodb.version>
 | 
			
		||||
        <aws-lambda-log4j.version>1.0.0</aws-lambda-log4j.version>
 | 
			
		||||
        <aws-lambda-java-events.version>2.0.1</aws-lambda-java-events.version>
 | 
			
		||||
        <jackson.version>2.8.5</jackson.version>
 | 
			
		||||
    </properties>
 | 
			
		||||
    <modules>
 | 
			
		||||
        <module>abstract-factory</module>
 | 
			
		||||
@@ -154,6 +159,7 @@
 | 
			
		||||
        <module>eip-aggregator</module>
 | 
			
		||||
        <module>retry</module>
 | 
			
		||||
		<module>trampoline</module>
 | 
			
		||||
        <module>serverless</module>
 | 
			
		||||
    </modules>
 | 
			
		||||
 | 
			
		||||
    <repositories>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										199
									
								
								serverless/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,199 @@
 | 
			
		||||
---
 | 
			
		||||
layout: pattern
 | 
			
		||||
title: serverless
 | 
			
		||||
folder: serverless
 | 
			
		||||
permalink: /patterns/serverless/
 | 
			
		||||
categories: Architectural
 | 
			
		||||
tags:
 | 
			
		||||
 - Java
 | 
			
		||||
 - Difficulty-Intermediate
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## Serverless
 | 
			
		||||
 | 
			
		||||
Serverless eliminates the need to plan for infrastructure and let's you focus on your 
 | 
			
		||||
application. 
 | 
			
		||||
 | 
			
		||||
Following are optimization katas you should be aware of while building a serverless 
 | 
			
		||||
applications
 | 
			
		||||
 | 
			
		||||
* The Lean function
 | 
			
		||||
    * Concise logic - Use functions to transform, not transport (utilize some of the 
 | 
			
		||||
    integration available from the provider to transport), and make sure you read only
 | 
			
		||||
     what you need
 | 
			
		||||
    * Efficient/single purpose code - avoid conditional/routing logic and break down 
 | 
			
		||||
    into individual functions, avoid "fat"/monolithic functions and control the 
 | 
			
		||||
    dependencies in the function deployment package to reduce the load time for your 
 | 
			
		||||
    function
 | 
			
		||||
    * ephemeral environment - Utilize container start for expensive initializations
 | 
			
		||||
* Eventful Invocations
 | 
			
		||||
    * Succinct payloads - Scrutinize the event as much as possible, and watch for 
 | 
			
		||||
    payload constraints (async - 128K)
 | 
			
		||||
    * resilient routing - Understand retry policies and leverage dead letter queues 
 | 
			
		||||
    (SQS or SNS for replays) and remember retries count as invocations
 | 
			
		||||
    * concurrent execution - lambda thinks of it's scale in terms of concurrency and 
 | 
			
		||||
    its not request based/duration based. Lambda will spin up the number of instances 
 | 
			
		||||
    based on the request. 
 | 
			
		||||
* Coordinated calls
 | 
			
		||||
    * Decoupled via APIs - best practice to setup your application is to have API's as
 | 
			
		||||
     contracts that ensures separation of concerns
 | 
			
		||||
    * scale-matched downstream - make sure when Lambda is calling downstream 
 | 
			
		||||
    components, you are matching scale configuration to it (by specifying max 
 | 
			
		||||
    concurrency based on downstream services)
 | 
			
		||||
    * secured - Always ask a question, do I need a VPC?
 | 
			
		||||
* Serviceful operations
 | 
			
		||||
    * Automated - use automated tools to manage and maintain the stack 
 | 
			
		||||
    * monitored applications - use monitoring services to get holistic view of your 
 | 
			
		||||
    serverless applications
 | 
			
		||||
 | 
			
		||||
## Intent
 | 
			
		||||
 | 
			
		||||
Whether to reduce your infrastructure costs, shrink the time you spend on ops tasks, 
 | 
			
		||||
simplify your deployment processes, reach infinite scalability, serverless cuts time 
 | 
			
		||||
to market in half.
 | 
			
		||||
 
 | 
			
		||||
## Explanation
 | 
			
		||||
 | 
			
		||||
Serverless computing is a cloud computing execution model in which the cloud provider 
 | 
			
		||||
dynamically manages the allocation of machine resources. Pricing is based on the 
 | 
			
		||||
actual amount of resources consumed by an application, rather than on pre-purchased 
 | 
			
		||||
units of capacity. 
 | 
			
		||||
 | 
			
		||||
## Serverless framework
 | 
			
		||||
 | 
			
		||||
[Serverless](https://serverless.com/) is a toolkit for deploying and operating serverless architectures. 
 | 
			
		||||
 | 
			
		||||
## (Function as a Service or "FaaS")
 | 
			
		||||
 | 
			
		||||
The term ‘Serverless’ is confusing since with such applications there are both server 
 | 
			
		||||
hardware and server processes running somewhere, but the difference to normal 
 | 
			
		||||
approaches is that the organization building and supporting a ‘Serverless’ application
 | 
			
		||||
 is not looking after the hardware or the processes - they are outsourcing this to a vendor.
 | 
			
		||||
 | 
			
		||||
Some of the Serverless Cloud Providers are 
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||

 | 
			
		||||

 | 
			
		||||

 | 
			
		||||

 | 
			
		||||

 | 
			
		||||

 | 
			
		||||
...
 | 
			
		||||
 | 
			
		||||
Anything that triggers an Lambda Function to execute is regarded by the Framework as 
 | 
			
		||||
an Event. Most of the Serverless Cloud Providers support following Events
 | 
			
		||||
- Http
 | 
			
		||||
- PubSub Events
 | 
			
		||||
- scheduled
 | 
			
		||||
 | 
			
		||||
AWS supports processing event generated from AWS Services (S3/Cloudwatch/etc) and 
 | 
			
		||||
using aws as a compute engine is our first choice.
 | 
			
		||||
 | 
			
		||||
## (Backend as a Service or "BaaS")
 | 
			
		||||
This example creates a backend for ‘persons’ collection which uses DynamoDB NoSQL 
 | 
			
		||||
database service also provided by Amazon. 
 | 
			
		||||
 | 
			
		||||
## AWS lambda function implementation
 | 
			
		||||
 | 
			
		||||
[AWS Lambda SDK](https://aws.amazon.com/sdk-for-java/) provides pre-defined interface 
 | 
			
		||||
`com.amazonaws.services.lambda.runtime
 | 
			
		||||
.RequestHandler` to implement our lambda function. 
 | 
			
		||||
 | 
			
		||||
```java
 | 
			
		||||
public class LambdaInfoApiHandler implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {
 | 
			
		||||
 | 
			
		||||
  private static final Logger LOG = Logger.getLogger(LambdaInfoApiHandler.class);
 | 
			
		||||
  private static final Integer SUCCESS_STATUS_CODE = 200;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {
 | 
			
		||||
    
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
handleRequest method is where the function code is implemented. Context provides 
 | 
			
		||||
useful information about Lambda execution environment. AWS Lambda function needs a 
 | 
			
		||||
deployment package. This package is either a .zip or .jar file that contains all the 
 | 
			
		||||
dependencies of the function.
 | 
			
		||||
 | 
			
		||||
`serverless.yml` contains configuration to manage deployments for your functions.
 | 
			
		||||
 | 
			
		||||
## Run example in local
 | 
			
		||||
 | 
			
		||||
# Pre-requisites
 | 
			
		||||
* Node.js v6.5.0 or later.
 | 
			
		||||
* Serverless CLI v1.9.0 or later. You can run npm install -g serverless to install it.
 | 
			
		||||
* An AWS account. If you don't already have one, you can sign up for a free trial that includes 1 million free Lambda requests per month.
 | 
			
		||||
* [Set-up](https://serverless.com/framework/docs/providers/aws/guide/credentials/) your Provider Credentials. Watch the video on setting up credentials
 | 
			
		||||
 | 
			
		||||
# build and deploy
 | 
			
		||||
 | 
			
		||||
* `cd serverless`
 | 
			
		||||
* `mvn clean package`
 | 
			
		||||
* `serverless deploy --stage=dev --verbose`
 | 
			
		||||
 | 
			
		||||
Based on the configuration in `serverless.yml` serverless framework creates following 
 | 
			
		||||
resources
 | 
			
		||||
* CloudFormation stack for S3 (ServerlessDeploymentBucket)
 | 
			
		||||
* IAM Role (IamRoleLambdaExecution)
 | 
			
		||||
* CloudWatch (log groups)
 | 
			
		||||
* API Gateway (ApiGatewayRestApi) 
 | 
			
		||||
* Lambda function
 | 
			
		||||
* DynamoDB collection
 | 
			
		||||
 | 
			
		||||
The command will print out Stack Outputs which looks something like this
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
endpoints:
 | 
			
		||||
  GET - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/info
 | 
			
		||||
  POST - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person
 | 
			
		||||
  GET - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person/{id}
 | 
			
		||||
  
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
CurrentTimeLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:xxxxxxxxxxx:function:lambda-info-http-endpoint-dev-currentTime:4
 | 
			
		||||
ServiceEndpoint: https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev
 | 
			
		||||
ServerlessDeploymentBucketName: lambda-info-http-endpoin-serverlessdeploymentbuck-2u8uz2i7cap2
 | 
			
		||||
```
 | 
			
		||||
access the endpoint to invoke the function.
 | 
			
		||||
 | 
			
		||||
Use the following cURL commands to test the endpoints
 | 
			
		||||
 | 
			
		||||
```cURL
 | 
			
		||||
curl -X GET \
 | 
			
		||||
  https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/info \
 | 
			
		||||
  -H 'cache-control: no-cache'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```cURL
 | 
			
		||||
curl -X POST \
 | 
			
		||||
  https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person \
 | 
			
		||||
  -H 'cache-control: no-cache' \
 | 
			
		||||
  -H 'content-type: application/json' \
 | 
			
		||||
  -d '{
 | 
			
		||||
	"firstName": "Thor",
 | 
			
		||||
	"lastName": "Odinson",
 | 
			
		||||
	"address": {
 | 
			
		||||
		"addressLineOne": "1 Odin ln",
 | 
			
		||||
		"addressLineTwo": "100",
 | 
			
		||||
		"city": "Asgard",
 | 
			
		||||
		"state": "country of the Gods",
 | 
			
		||||
		"zipCode": "00001"
 | 
			
		||||
	}
 | 
			
		||||
}'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```cURL
 | 
			
		||||
curl -X GET \
 | 
			
		||||
  https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person/{id} \
 | 
			
		||||
  -H 'cache-control: no-cache'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Credits
 | 
			
		||||
 | 
			
		||||
* [serverless docs](https://serverless.com/framework/docs/)
 | 
			
		||||
* [Serverless Architectures](https://martinfowler.com/articles/serverless.html)
 | 
			
		||||
* [Serverless Black Belt](https://youtu.be/oQFORsso2go)
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								serverless/etc/aws-black.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 9.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								serverless/etc/azure-black.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								serverless/etc/gcf-black.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								serverless/etc/kubeless-logos-black.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 8.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								serverless/etc/openwhisk-black.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								serverless/etc/spotinst-logos-black-small.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 5.3 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								serverless/etc/webtask-small-grayscale.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 8.2 KiB  | 
							
								
								
									
										133
									
								
								serverless/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,133 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
    The MIT License
 | 
			
		||||
    Copyright (c) 2014-2017 Ilkka Seppälä
 | 
			
		||||
    Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
    of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
    in the Software without restriction, including without limitation the rights
 | 
			
		||||
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
    copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
    furnished to do so, subject to the following conditions:
 | 
			
		||||
    The above copyright notice and this permission notice shall be included in
 | 
			
		||||
    all copies or substantial portions of the Software.
 | 
			
		||||
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
    THE SOFTWARE.
 | 
			
		||||
-->
 | 
			
		||||
<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>
 | 
			
		||||
    <artifactId>serverless</artifactId>
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>com.iluwatar</groupId>
 | 
			
		||||
        <artifactId>java-design-patterns</artifactId>
 | 
			
		||||
        <version>1.20.0-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.amazonaws</groupId>
 | 
			
		||||
            <artifactId>aws-lambda-java-core</artifactId>
 | 
			
		||||
            <version>${aws-lambda-core.version}</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.amazonaws</groupId>
 | 
			
		||||
            <artifactId>aws-java-sdk-dynamodb</artifactId>
 | 
			
		||||
            <version>${aws-java-sdk-dynamodb.version}</version>
 | 
			
		||||
            <exclusions>
 | 
			
		||||
                <exclusion>
 | 
			
		||||
                    <groupId>com.amazonaws</groupId>
 | 
			
		||||
                    <artifactId>aws-java-sdk-s3</artifactId>
 | 
			
		||||
                </exclusion>
 | 
			
		||||
                <exclusion>
 | 
			
		||||
                    <groupId>com.amazonaws</groupId>
 | 
			
		||||
                    <artifactId>aws-java-sdk-kms</artifactId>
 | 
			
		||||
                </exclusion>
 | 
			
		||||
            </exclusions>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.amazonaws</groupId>
 | 
			
		||||
            <artifactId>aws-lambda-java-events</artifactId>
 | 
			
		||||
            <version>${aws-lambda-java-events.version}</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.amazonaws</groupId>
 | 
			
		||||
            <artifactId>aws-lambda-java-log4j</artifactId>
 | 
			
		||||
            <version>${aws-lambda-log4j.version}</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.fasterxml.jackson.core</groupId>
 | 
			
		||||
            <artifactId>jackson-core</artifactId>
 | 
			
		||||
            <version>${jackson.version}</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.fasterxml.jackson.core</groupId>
 | 
			
		||||
            <artifactId>jackson-databind</artifactId>
 | 
			
		||||
            <version>${jackson.version}</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.fasterxml.jackson.core</groupId>
 | 
			
		||||
            <artifactId>jackson-annotations</artifactId>
 | 
			
		||||
            <version>${jackson.version}</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.junit.jupiter</groupId>
 | 
			
		||||
            <artifactId>junit-jupiter-api</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.junit.jupiter</groupId>
 | 
			
		||||
            <artifactId>junit-jupiter-engine</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.mockito</groupId>
 | 
			
		||||
            <artifactId>mockito-core</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>junit</groupId>
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
        <plugins>
 | 
			
		||||
            <!--
 | 
			
		||||
              Using the Apache Maven Shade plugin to package the jar
 | 
			
		||||
 | 
			
		||||
              "This plugin provides the capability to package the artifact
 | 
			
		||||
              in an uber-jar, including its dependencies and to shade - i.e. rename -
 | 
			
		||||
              the packages of some of the dependencies."
 | 
			
		||||
 | 
			
		||||
              Link: https://maven.apache.org/plugins/maven-shade-plugin/
 | 
			
		||||
            -->
 | 
			
		||||
            <plugin>
 | 
			
		||||
                <groupId>org.apache.maven.plugins</groupId>
 | 
			
		||||
                <artifactId>maven-shade-plugin</artifactId>
 | 
			
		||||
                <version>2.3</version>
 | 
			
		||||
                <configuration>
 | 
			
		||||
                    <createDependencyReducedPom>false</createDependencyReducedPom>
 | 
			
		||||
                </configuration>
 | 
			
		||||
                <executions>
 | 
			
		||||
                    <execution>
 | 
			
		||||
                        <phase>package</phase>
 | 
			
		||||
                        <goals>
 | 
			
		||||
                            <goal>shade</goal>
 | 
			
		||||
                        </goals>
 | 
			
		||||
                        <configuration>
 | 
			
		||||
                            <finalName>${project.artifactId}</finalName>
 | 
			
		||||
                        </configuration>
 | 
			
		||||
                    </execution>
 | 
			
		||||
                </executions>
 | 
			
		||||
            </plugin>
 | 
			
		||||
        </plugins>
 | 
			
		||||
    </build>
 | 
			
		||||
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										102
									
								
								serverless/serverless.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,102 @@
 | 
			
		||||
#
 | 
			
		||||
# The MIT License
 | 
			
		||||
# Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
#
 | 
			
		||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
# of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
# in the Software without restriction, including without limitation the rights
 | 
			
		||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
# copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
# furnished to do so, subject to the following conditions:
 | 
			
		||||
#
 | 
			
		||||
# The above copyright notice and this permission notice shall be included in
 | 
			
		||||
# all copies or substantial portions of the Software.
 | 
			
		||||
#
 | 
			
		||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
# THE SOFTWARE.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
service: serverless-services
 | 
			
		||||
 | 
			
		||||
frameworkVersion: ">=1.2.0 <2.0.0"
 | 
			
		||||
 | 
			
		||||
provider:
 | 
			
		||||
  name: aws
 | 
			
		||||
  runtime: java8
 | 
			
		||||
  usagePlan:
 | 
			
		||||
    quota:
 | 
			
		||||
      limit: 500
 | 
			
		||||
      offset: 2
 | 
			
		||||
      period: MONTH
 | 
			
		||||
    throttle:
 | 
			
		||||
      burstLimit: 20
 | 
			
		||||
      rateLimit: 10
 | 
			
		||||
 | 
			
		||||
package:
 | 
			
		||||
  artifact: target/serverless.jar
 | 
			
		||||
 | 
			
		||||
functions:
 | 
			
		||||
  lambdaInfoApi:
 | 
			
		||||
    handler: com.iluwatar.serverless.faas.api.LambdaInfoApiHandler
 | 
			
		||||
    events:
 | 
			
		||||
      - http:
 | 
			
		||||
          path: info
 | 
			
		||||
          method: get
 | 
			
		||||
 | 
			
		||||
  savePerson:
 | 
			
		||||
    handler: com.iluwatar.serverless.baas.api.SavePersonApiHandler
 | 
			
		||||
    events:
 | 
			
		||||
      - http:
 | 
			
		||||
          path: api/person
 | 
			
		||||
          method: post
 | 
			
		||||
          cors: true
 | 
			
		||||
          integration: lambda-proxy
 | 
			
		||||
 | 
			
		||||
  getPerson:
 | 
			
		||||
    handler: com.iluwatar.serverless.baas.api.FindPersonApiHandler
 | 
			
		||||
    events:
 | 
			
		||||
      - http:
 | 
			
		||||
          path: api/person/{id}
 | 
			
		||||
          method: get
 | 
			
		||||
          cors: true
 | 
			
		||||
          integration: lambda-proxy
 | 
			
		||||
 | 
			
		||||
resources:
 | 
			
		||||
  Resources:
 | 
			
		||||
    DynamoDbTable:
 | 
			
		||||
      Type: AWS::DynamoDB::Table
 | 
			
		||||
      Properties:
 | 
			
		||||
        TableName: persons
 | 
			
		||||
        AttributeDefinitions:
 | 
			
		||||
          - AttributeName: id
 | 
			
		||||
            AttributeType: S
 | 
			
		||||
        KeySchema:
 | 
			
		||||
          - AttributeName: id
 | 
			
		||||
            KeyType: HASH
 | 
			
		||||
        ProvisionedThroughput:
 | 
			
		||||
          ReadCapacityUnits: 1
 | 
			
		||||
          WriteCapacityUnits: 1
 | 
			
		||||
    DynamoDBIamPolicy:
 | 
			
		||||
      Type: AWS::IAM::Policy
 | 
			
		||||
      DependsOn: DynamoDbTable
 | 
			
		||||
      Properties:
 | 
			
		||||
        PolicyName: lambda-dynamodb
 | 
			
		||||
        PolicyDocument:
 | 
			
		||||
          Version: '2012-10-17'
 | 
			
		||||
          Statement:
 | 
			
		||||
            - Effect: Allow
 | 
			
		||||
              Action:
 | 
			
		||||
                - dynamodb:GetItem
 | 
			
		||||
                - dynamodb:PutItem
 | 
			
		||||
                - dynamodb:UpdateItem
 | 
			
		||||
                - dynamodb:DeleteItem
 | 
			
		||||
                - dynamodb:Query
 | 
			
		||||
                - dynamodb:Scan
 | 
			
		||||
              Resource: arn:aws:dynamodb:*:*:table/persons
 | 
			
		||||
        Roles:
 | 
			
		||||
          - Ref: IamRoleLambdaExecution
 | 
			
		||||
@@ -0,0 +1,101 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.baas.api;
 | 
			
		||||
 | 
			
		||||
import com.amazonaws.regions.Regions;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
 | 
			
		||||
import com.fasterxml.jackson.core.JsonProcessingException;
 | 
			
		||||
import com.fasterxml.jackson.databind.ObjectMapper;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * abstract dynamodb handler
 | 
			
		||||
 * @param <T> - serializable collection
 | 
			
		||||
 */
 | 
			
		||||
public abstract class AbstractDynamoDbHandler<T extends Serializable> {
 | 
			
		||||
  private DynamoDBMapper dynamoDbMapper;
 | 
			
		||||
 | 
			
		||||
  private ObjectMapper objectMapper;
 | 
			
		||||
 | 
			
		||||
  public AbstractDynamoDbHandler() {
 | 
			
		||||
    this.initAmazonDynamoDb();
 | 
			
		||||
    this.objectMapper = new ObjectMapper();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void initAmazonDynamoDb() {
 | 
			
		||||
    AmazonDynamoDB amazonDynamoDb = AmazonDynamoDBClientBuilder
 | 
			
		||||
        .standard()
 | 
			
		||||
        .withRegion(Regions.US_EAST_1)
 | 
			
		||||
        .build();
 | 
			
		||||
 | 
			
		||||
    this.dynamoDbMapper = new DynamoDBMapper(amazonDynamoDb);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected DynamoDBMapper getDynamoDbMapper() {
 | 
			
		||||
    return this.dynamoDbMapper;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected ObjectMapper getObjectMapper() {
 | 
			
		||||
    return objectMapper;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setDynamoDbMapper(DynamoDBMapper dynamoDbMapper) {
 | 
			
		||||
    this.dynamoDbMapper = dynamoDbMapper;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  protected Map<String, String> headers() {
 | 
			
		||||
    Map<String, String> headers = new HashMap<>();
 | 
			
		||||
    headers.put("Content-Type", "application/json");
 | 
			
		||||
 | 
			
		||||
    return headers;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * API Gateway response
 | 
			
		||||
   *
 | 
			
		||||
   * @param statusCode - status code
 | 
			
		||||
   * @param body - Object body
 | 
			
		||||
   * @return - api gateway proxy response
 | 
			
		||||
   */
 | 
			
		||||
  protected APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent(Integer statusCode, T body) {
 | 
			
		||||
    APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent =
 | 
			
		||||
        new APIGatewayProxyResponseEvent().withHeaders(headers());
 | 
			
		||||
    try {
 | 
			
		||||
      apiGatewayProxyResponseEvent
 | 
			
		||||
          .withStatusCode(statusCode)
 | 
			
		||||
          .withBody(getObjectMapper()
 | 
			
		||||
              .writeValueAsString(body));
 | 
			
		||||
 | 
			
		||||
    } catch (JsonProcessingException jsonProcessingException) {
 | 
			
		||||
      throw new RuntimeException(jsonProcessingException);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return apiGatewayProxyResponseEvent;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,51 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.baas.api;
 | 
			
		||||
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.Context;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.RequestHandler;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
 | 
			
		||||
import com.iluwatar.serverless.baas.model.Person;
 | 
			
		||||
import org.apache.log4j.Logger;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * find person from persons collection
 | 
			
		||||
 * Created by dheeraj.mummar on 3/5/18.
 | 
			
		||||
 */
 | 
			
		||||
public class FindPersonApiHandler extends AbstractDynamoDbHandler
 | 
			
		||||
    implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
 | 
			
		||||
 | 
			
		||||
  private static final Logger LOG = Logger.getLogger(FindPersonApiHandler.class);
 | 
			
		||||
  private static final Integer SUCCESS_STATUS_CODE = 200;
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent,
 | 
			
		||||
                                                    Context context) {
 | 
			
		||||
    LOG.info(apiGatewayProxyRequestEvent.getPathParameters());
 | 
			
		||||
    Person person = this.getDynamoDbMapper().load(Person.class, apiGatewayProxyRequestEvent
 | 
			
		||||
        .getPathParameters().get("id"));
 | 
			
		||||
 | 
			
		||||
    return apiGatewayProxyResponseEvent(SUCCESS_STATUS_CODE, person);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.baas.api;
 | 
			
		||||
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.Context;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.RequestHandler;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
 | 
			
		||||
import com.iluwatar.serverless.baas.model.Person;
 | 
			
		||||
import org.apache.log4j.Logger;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * save person into persons collection
 | 
			
		||||
 * Created by dheeraj.mummar on 3/4/18.
 | 
			
		||||
 */
 | 
			
		||||
public class SavePersonApiHandler extends AbstractDynamoDbHandler
 | 
			
		||||
    implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
 | 
			
		||||
 | 
			
		||||
  private static final Logger LOG = Logger.getLogger(SavePersonApiHandler.class);
 | 
			
		||||
  private static final Integer CREATED_STATUS_CODE = 201;
 | 
			
		||||
  private static final Integer BAD_REQUEST_STATUS_CODE = 400;
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent
 | 
			
		||||
                                                apiGatewayProxyRequestEvent, Context context) {
 | 
			
		||||
    APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent;
 | 
			
		||||
    Person person;
 | 
			
		||||
    try {
 | 
			
		||||
      person = getObjectMapper().readValue(apiGatewayProxyRequestEvent.getBody(), Person.class);
 | 
			
		||||
      getDynamoDbMapper().save(person);
 | 
			
		||||
      apiGatewayProxyResponseEvent = apiGatewayProxyResponseEvent(CREATED_STATUS_CODE, person);
 | 
			
		||||
    } catch (IOException ioException) {
 | 
			
		||||
      LOG.error("unable to parse body", ioException);
 | 
			
		||||
      apiGatewayProxyResponseEvent = apiGatewayProxyResponseEvent(BAD_REQUEST_STATUS_CODE, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return apiGatewayProxyResponseEvent;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,141 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.baas.model;
 | 
			
		||||
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDocument;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Address class
 | 
			
		||||
 * Created by dheeraj.mummarareddy on 3/4/18.
 | 
			
		||||
 */
 | 
			
		||||
@DynamoDBDocument
 | 
			
		||||
public class Address implements Serializable {
 | 
			
		||||
 | 
			
		||||
  private static final long serialVersionUID = 6760844284799736970L;
 | 
			
		||||
 | 
			
		||||
  private String addressLineOne;
 | 
			
		||||
  private String addressLineTwo;
 | 
			
		||||
  private String city;
 | 
			
		||||
  private String state;
 | 
			
		||||
  private String zipCode;
 | 
			
		||||
 | 
			
		||||
  @DynamoDBAttribute(attributeName = "addressLineOne")
 | 
			
		||||
  public String getAddressLineOne() {
 | 
			
		||||
    return addressLineOne;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setAddressLineOne(String addressLineOne) {
 | 
			
		||||
    this.addressLineOne = addressLineOne;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @DynamoDBAttribute(attributeName = "addressLineTwo")
 | 
			
		||||
  public String getAddressLineTwo() {
 | 
			
		||||
    return addressLineTwo;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setAddressLineTwo(String addressLineTwo) {
 | 
			
		||||
    this.addressLineTwo = addressLineTwo;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @DynamoDBAttribute(attributeName = "city")
 | 
			
		||||
  public String getCity() {
 | 
			
		||||
    return city;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setCity(String city) {
 | 
			
		||||
    this.city = city;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @DynamoDBAttribute(attributeName = "state")
 | 
			
		||||
  public String getState() {
 | 
			
		||||
    return state;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setState(String state) {
 | 
			
		||||
    this.state = state;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @DynamoDBAttribute(attributeName = "zipCode")
 | 
			
		||||
  public String getZipCode() {
 | 
			
		||||
    return zipCode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setZipCode(String zipCode) {
 | 
			
		||||
    this.zipCode = zipCode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public boolean equals(Object o) {
 | 
			
		||||
    if (this == o) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (o == null || getClass() != o.getClass()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Address address = (Address) o;
 | 
			
		||||
 | 
			
		||||
    if (addressLineOne != null ? !addressLineOne.equals(address.addressLineOne) :
 | 
			
		||||
        address.addressLineOne != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (addressLineTwo != null ? !addressLineTwo.equals(address.addressLineTwo) :
 | 
			
		||||
        address.addressLineTwo != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (city != null ? !city.equals(address.city) : address.city != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (state != null ? !state.equals(address.state) : address.state != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return zipCode != null ? zipCode.equals(address.zipCode) : address.zipCode == null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public int hashCode() {
 | 
			
		||||
    int result = addressLineOne != null ? addressLineOne.hashCode() : 0;
 | 
			
		||||
    result = 31 * result + (addressLineTwo != null ? addressLineTwo.hashCode() : 0);
 | 
			
		||||
    result = 31 * result + (city != null ? city.hashCode() : 0);
 | 
			
		||||
    result = 31 * result + (state != null ? state.hashCode() : 0);
 | 
			
		||||
    result = 31 * result + (zipCode != null ? zipCode.hashCode() : 0);
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public String toString() {
 | 
			
		||||
    return "Address{"
 | 
			
		||||
        + "addressLineOne='" + addressLineOne + '\''
 | 
			
		||||
        + ", addressLineTwo='" + addressLineTwo + '\''
 | 
			
		||||
        + ", city='" + city + '\''
 | 
			
		||||
        + ", state='" + state + '\''
 | 
			
		||||
        + ", zipCode='" + zipCode + '\''
 | 
			
		||||
        + '}';
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,124 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.baas.model;
 | 
			
		||||
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Person class
 | 
			
		||||
 * Created by dheeraj.mummarareddy on 3/4/18.
 | 
			
		||||
 */
 | 
			
		||||
@DynamoDBTable(tableName = "persons")
 | 
			
		||||
public class Person implements Serializable {
 | 
			
		||||
 | 
			
		||||
  private static final long serialVersionUID = -3413087924608627075L;
 | 
			
		||||
 | 
			
		||||
  private String id;
 | 
			
		||||
  private String firstName;
 | 
			
		||||
  private String lastName;
 | 
			
		||||
  private Address address;
 | 
			
		||||
 | 
			
		||||
  @JsonProperty(access = JsonProperty.Access.READ_ONLY)
 | 
			
		||||
  @DynamoDBHashKey(attributeName = "id")
 | 
			
		||||
  @DynamoDBAutoGeneratedKey
 | 
			
		||||
  public String getId() {
 | 
			
		||||
    return id;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setId(String id) {
 | 
			
		||||
    this.id = id;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @DynamoDBAttribute(attributeName = "firstName")
 | 
			
		||||
  public String getFirstName() {
 | 
			
		||||
    return firstName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setFirstName(String firstName) {
 | 
			
		||||
    this.firstName = firstName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @DynamoDBAttribute(attributeName = "lastName")
 | 
			
		||||
  public String getLastName() {
 | 
			
		||||
    return lastName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setLastName(String lastName) {
 | 
			
		||||
    this.lastName = lastName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @DynamoDBAttribute(attributeName = "address")
 | 
			
		||||
  public Address getAddress() {
 | 
			
		||||
    return address;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setAddress(Address address) {
 | 
			
		||||
    this.address = address;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public boolean equals(Object o) {
 | 
			
		||||
    if (this == o) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (o == null || getClass() != o.getClass()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Person person = (Person) o;
 | 
			
		||||
 | 
			
		||||
    if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return address != null ? address.equals(person.address) : person.address == null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public int hashCode() {
 | 
			
		||||
    int result = firstName != null ? firstName.hashCode() : 0;
 | 
			
		||||
    result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
 | 
			
		||||
    result = 31 * result + (address != null ? address.hashCode() : 0);
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public String toString() {
 | 
			
		||||
    return "Person{"
 | 
			
		||||
        + "id='" + id + '\''
 | 
			
		||||
        + ", firstName='" + firstName + '\''
 | 
			
		||||
        + ", lastName='" + lastName + '\''
 | 
			
		||||
        + ", address=" + address
 | 
			
		||||
        + '}';
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,166 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.faas;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.core.JsonProcessingException;
 | 
			
		||||
import com.fasterxml.jackson.databind.ObjectMapper;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Api gateway response
 | 
			
		||||
 *
 | 
			
		||||
 * @param <T> serializable object
 | 
			
		||||
 */
 | 
			
		||||
public class ApiGatewayResponse<T extends Serializable> implements Serializable {
 | 
			
		||||
 | 
			
		||||
  private static final long serialVersionUID = 1181159426782844892L;
 | 
			
		||||
 | 
			
		||||
  private final Integer statusCode;
 | 
			
		||||
  private final String body;
 | 
			
		||||
  private final Map<String, String> headers;
 | 
			
		||||
  private final Boolean isBase64Encoded;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * api gateway response
 | 
			
		||||
   *
 | 
			
		||||
   * @param statusCode - http status code
 | 
			
		||||
   * @param body - response body
 | 
			
		||||
   * @param headers - response headers
 | 
			
		||||
   * @param isBase64Encoded - base64Encoded flag
 | 
			
		||||
   */
 | 
			
		||||
  public ApiGatewayResponse(Integer statusCode, String body, Map<String, String> headers,
 | 
			
		||||
                            Boolean isBase64Encoded) {
 | 
			
		||||
    this.statusCode = statusCode;
 | 
			
		||||
    this.body = body;
 | 
			
		||||
    this.headers = headers;
 | 
			
		||||
    this.isBase64Encoded = isBase64Encoded;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * http status code
 | 
			
		||||
   *
 | 
			
		||||
   * @return statusCode - http status code
 | 
			
		||||
   */
 | 
			
		||||
  public Integer getStatusCode() {
 | 
			
		||||
    return statusCode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * response body
 | 
			
		||||
   *
 | 
			
		||||
   * @return string body
 | 
			
		||||
   */
 | 
			
		||||
  public String getBody() {
 | 
			
		||||
    return body;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * response headers
 | 
			
		||||
   *
 | 
			
		||||
   * @return response headers
 | 
			
		||||
   */
 | 
			
		||||
  public Map<String, String> getHeaders() {
 | 
			
		||||
    return headers;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * base64Encoded flag, API Gateway expects the property to be called "isBase64Encoded"
 | 
			
		||||
   *
 | 
			
		||||
   * @return base64Encoded flag
 | 
			
		||||
   */
 | 
			
		||||
  public Boolean isBase64Encoded() {
 | 
			
		||||
    return isBase64Encoded;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * ApiGatewayResponse Builder class
 | 
			
		||||
   * @param <T> Serializable object
 | 
			
		||||
   */
 | 
			
		||||
  public static class ApiGatewayResponseBuilder<T extends Serializable> {
 | 
			
		||||
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
 | 
			
		||||
    private Integer statusCode;
 | 
			
		||||
    private T body;
 | 
			
		||||
    private Map<String, String> headers;
 | 
			
		||||
    private Boolean isBase64Encoded;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * http status code
 | 
			
		||||
     * @param statusCode - http status code
 | 
			
		||||
     * @return ApiGatewayResponseBuilder
 | 
			
		||||
     */
 | 
			
		||||
    public ApiGatewayResponseBuilder statusCode(Integer statusCode) {
 | 
			
		||||
      this.statusCode = statusCode;
 | 
			
		||||
      return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Serializable body
 | 
			
		||||
     * @param body - Serializable object
 | 
			
		||||
     * @return ApiGatewayResponseBuilder
 | 
			
		||||
     */
 | 
			
		||||
    public ApiGatewayResponseBuilder body(T body) {
 | 
			
		||||
      this.body = body;
 | 
			
		||||
      return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * response headers
 | 
			
		||||
     * @param headers - response headers
 | 
			
		||||
     * @return ApiGatewayResponseBuilder
 | 
			
		||||
     */
 | 
			
		||||
    public ApiGatewayResponseBuilder headers(Map<String, String> headers) {
 | 
			
		||||
      this.headers = headers;
 | 
			
		||||
      return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * base64Encoded glag
 | 
			
		||||
     * @param isBase64Encoded - base64Encoded flag
 | 
			
		||||
     * @return ApiGatewayResponseBuilder
 | 
			
		||||
     */
 | 
			
		||||
    public ApiGatewayResponseBuilder base64Encoded(Boolean isBase64Encoded) {
 | 
			
		||||
      this.isBase64Encoded = isBase64Encoded;
 | 
			
		||||
      return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * build ApiGatewayResponse
 | 
			
		||||
     *
 | 
			
		||||
     * @return ApiGatewayResponse
 | 
			
		||||
     */
 | 
			
		||||
    public ApiGatewayResponse build() {
 | 
			
		||||
      String strBody = null;
 | 
			
		||||
      if (this.body != null) {
 | 
			
		||||
        try {
 | 
			
		||||
          strBody = OBJECT_MAPPER.writeValueAsString(body);
 | 
			
		||||
        } catch (JsonProcessingException e) {
 | 
			
		||||
          throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return new ApiGatewayResponse(this.statusCode, strBody, this.headers, this.isBase64Encoded);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,140 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.faas;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Lambda context information
 | 
			
		||||
 */
 | 
			
		||||
public class LambdaInfo implements Serializable {
 | 
			
		||||
 | 
			
		||||
  private static final long serialVersionUID = 3936130599040848923L;
 | 
			
		||||
 | 
			
		||||
  private String awsRequestId;
 | 
			
		||||
  private String logGroupName;
 | 
			
		||||
  private String logStreamName;
 | 
			
		||||
  private String functionName;
 | 
			
		||||
  private String functionVersion;
 | 
			
		||||
  private Integer memoryLimitInMb;
 | 
			
		||||
 | 
			
		||||
  public String getAwsRequestId() {
 | 
			
		||||
    return awsRequestId;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setAwsRequestId(String awsRequestId) {
 | 
			
		||||
    this.awsRequestId = awsRequestId;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String getLogGroupName() {
 | 
			
		||||
    return logGroupName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setLogGroupName(String logGroupName) {
 | 
			
		||||
    this.logGroupName = logGroupName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String getLogStreamName() {
 | 
			
		||||
    return logStreamName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setLogStreamName(String logStreamName) {
 | 
			
		||||
    this.logStreamName = logStreamName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String getFunctionName() {
 | 
			
		||||
    return functionName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setFunctionName(String functionName) {
 | 
			
		||||
    this.functionName = functionName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public String getFunctionVersion() {
 | 
			
		||||
    return functionVersion;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setFunctionVersion(String functionVersion) {
 | 
			
		||||
    this.functionVersion = functionVersion;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public Integer getMemoryLimitInMb() {
 | 
			
		||||
    return memoryLimitInMb;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public void setMemoryLimitInMb(Integer memoryLimitInMb) {
 | 
			
		||||
    this.memoryLimitInMb = memoryLimitInMb;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public String toString() {
 | 
			
		||||
    return "LambdaInfo{"
 | 
			
		||||
        + "awsRequestId='" + awsRequestId + '\''
 | 
			
		||||
        + ", logGroupName='" + logGroupName + '\''
 | 
			
		||||
        + ", logStreamName='" + logStreamName + '\''
 | 
			
		||||
        + ", functionName='" + functionName + '\''
 | 
			
		||||
        + ", functionVersion='" + functionVersion + '\''
 | 
			
		||||
        + ", memoryLimitInMb=" + memoryLimitInMb
 | 
			
		||||
        + '}';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public boolean equals(Object o) {
 | 
			
		||||
    if (this == o) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (o == null || getClass() != o.getClass()) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LambdaInfo that = (LambdaInfo) o;
 | 
			
		||||
 | 
			
		||||
    if (awsRequestId != null ? !awsRequestId.equals(that.awsRequestId) : that.awsRequestId != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (logGroupName != null ? !logGroupName.equals(that.logGroupName) : that.logGroupName != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (logStreamName != null ? !logStreamName.equals(that.logStreamName) : that.logStreamName != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (functionName != null ? !functionName.equals(that.functionName) : that.functionName != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    if (functionVersion != null ? !functionVersion.equals(that.functionVersion) : that.functionVersion != null) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return memoryLimitInMb != null ? memoryLimitInMb.equals(that.memoryLimitInMb) : that.memoryLimitInMb == null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public int hashCode() {
 | 
			
		||||
    int result = awsRequestId != null ? awsRequestId.hashCode() : 0;
 | 
			
		||||
    result = 31 * result + (logGroupName != null ? logGroupName.hashCode() : 0);
 | 
			
		||||
    result = 31 * result + (logStreamName != null ? logStreamName.hashCode() : 0);
 | 
			
		||||
    result = 31 * result + (functionName != null ? functionName.hashCode() : 0);
 | 
			
		||||
    result = 31 * result + (functionVersion != null ? functionVersion.hashCode() : 0);
 | 
			
		||||
    result = 31 * result + (memoryLimitInMb != null ? memoryLimitInMb.hashCode() : 0);
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.faas.api;
 | 
			
		||||
 | 
			
		||||
import com.iluwatar.serverless.faas.ApiGatewayResponse;
 | 
			
		||||
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.Context;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.RequestHandler;
 | 
			
		||||
import com.iluwatar.serverless.faas.LambdaInfo;
 | 
			
		||||
import org.apache.log4j.BasicConfigurator;
 | 
			
		||||
import org.apache.log4j.Logger;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * LambdaInfoApiHandler - simple api to get lambda context
 | 
			
		||||
 * Created by dheeraj.mummar on 2/5/18.
 | 
			
		||||
 */
 | 
			
		||||
public class LambdaInfoApiHandler implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {
 | 
			
		||||
 | 
			
		||||
  private static final Logger LOG = Logger.getLogger(LambdaInfoApiHandler.class);
 | 
			
		||||
  private static final Integer SUCCESS_STATUS_CODE = 200;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {
 | 
			
		||||
    BasicConfigurator.configure();
 | 
			
		||||
    LOG.info("received: " + input);
 | 
			
		||||
 | 
			
		||||
    return new ApiGatewayResponse
 | 
			
		||||
            .ApiGatewayResponseBuilder<LambdaInfo>()
 | 
			
		||||
            .headers(headers())
 | 
			
		||||
            .statusCode(SUCCESS_STATUS_CODE)
 | 
			
		||||
            .body(lambdaInfo(context))
 | 
			
		||||
            .build();
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * lambdaInfo
 | 
			
		||||
   * @param context - Lambda context
 | 
			
		||||
   * @return LambdaInfo
 | 
			
		||||
   */
 | 
			
		||||
  private LambdaInfo lambdaInfo(Context context) {
 | 
			
		||||
    LambdaInfo lambdaInfo = new LambdaInfo();
 | 
			
		||||
    lambdaInfo.setAwsRequestId(context.getAwsRequestId());
 | 
			
		||||
    lambdaInfo.setFunctionName(context.getFunctionName());
 | 
			
		||||
    lambdaInfo.setFunctionVersion(context.getFunctionVersion());
 | 
			
		||||
    lambdaInfo.setLogGroupName(context.getLogGroupName());
 | 
			
		||||
    lambdaInfo.setLogStreamName(context.getLogStreamName());
 | 
			
		||||
    lambdaInfo.setMemoryLimitInMb(context.getMemoryLimitInMB());
 | 
			
		||||
 | 
			
		||||
    return lambdaInfo;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private Map<String, String> headers() {
 | 
			
		||||
    Map<String, String> headers = new HashMap<>();
 | 
			
		||||
    headers.put("Content-Type", "application/json");
 | 
			
		||||
 | 
			
		||||
    return headers;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								serverless/src/main/resources/log4j.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,29 @@
 | 
			
		||||
#
 | 
			
		||||
# The MIT License
 | 
			
		||||
# Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
#
 | 
			
		||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
# of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
# in the Software without restriction, including without limitation the rights
 | 
			
		||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
# copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
# furnished to do so, subject to the following conditions:
 | 
			
		||||
#
 | 
			
		||||
# The above copyright notice and this permission notice shall be included in
 | 
			
		||||
# all copies or substantial portions of the Software.
 | 
			
		||||
#
 | 
			
		||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
# THE SOFTWARE.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
log = .
 | 
			
		||||
log4j.rootLogger = DEBUG, LAMBDA
 | 
			
		||||
 | 
			
		||||
log4j.appender.LAMBDA=com.amazonaws.services.lambda.runtime.log4j.LambdaAppender
 | 
			
		||||
log4j.appender.LAMBDA.layout=org.apache.log4j.PatternLayout
 | 
			
		||||
log4j.appender.LAMBDA.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} <%X{AWSRequestId}> %-5p %c:%L - %m%n
 | 
			
		||||
@@ -0,0 +1,72 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.baas.api;
 | 
			
		||||
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.Context;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
 | 
			
		||||
import com.iluwatar.serverless.baas.api.FindPersonApiHandler;
 | 
			
		||||
import com.iluwatar.serverless.baas.api.SavePersonApiHandler;
 | 
			
		||||
import com.iluwatar.serverless.baas.model.Person;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.runners.MockitoJUnitRunner;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.times;
 | 
			
		||||
import static org.mockito.Mockito.verify;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Unit tests for FindPersonApiHandler
 | 
			
		||||
 * Created by dheeraj.mummar on 3/5/18.
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(MockitoJUnitRunner.class)
 | 
			
		||||
public class FindPersonApiHandlerTest {
 | 
			
		||||
 | 
			
		||||
  private FindPersonApiHandler findPersonApiHandler;
 | 
			
		||||
 | 
			
		||||
  @Mock
 | 
			
		||||
  private DynamoDBMapper dynamoDbMapper;
 | 
			
		||||
 | 
			
		||||
  @Before
 | 
			
		||||
  public void setUp() {
 | 
			
		||||
    this.findPersonApiHandler = new FindPersonApiHandler();
 | 
			
		||||
    this.findPersonApiHandler.setDynamoDbMapper(dynamoDbMapper);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void handleRequest() {
 | 
			
		||||
    findPersonApiHandler.handleRequest(apiGatewayProxyRequestEvent(), mock(Context.class));
 | 
			
		||||
    verify(dynamoDbMapper, times(1)).load(Person.class, "37e7a1fe-3544-473d-b764-18128f02d72d");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent() {
 | 
			
		||||
    return new APIGatewayProxyRequestEvent()
 | 
			
		||||
        .withPathParamters(Collections
 | 
			
		||||
            .singletonMap("id", "37e7a1fe-3544-473d-b764-18128f02d72d"));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,101 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.baas.api;
 | 
			
		||||
 | 
			
		||||
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.Context;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
 | 
			
		||||
import com.fasterxml.jackson.core.JsonProcessingException;
 | 
			
		||||
import com.fasterxml.jackson.databind.ObjectMapper;
 | 
			
		||||
import com.iluwatar.serverless.baas.api.SavePersonApiHandler;
 | 
			
		||||
import com.iluwatar.serverless.baas.model.Address;
 | 
			
		||||
import com.iluwatar.serverless.baas.model.Person;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.runners.MockitoJUnitRunner;
 | 
			
		||||
 | 
			
		||||
import static org.mockito.Mockito.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Unit tests for SavePersonApiHandler
 | 
			
		||||
 * Created by dheeraj.mummar on 3/4/18.
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(MockitoJUnitRunner.class)
 | 
			
		||||
public class SavePersonApiHandlerTest {
 | 
			
		||||
 | 
			
		||||
  private SavePersonApiHandler savePersonApiHandler;
 | 
			
		||||
 | 
			
		||||
  @Mock
 | 
			
		||||
  private DynamoDBMapper dynamoDbMapper;
 | 
			
		||||
 | 
			
		||||
  private ObjectMapper objectMapper = new ObjectMapper();
 | 
			
		||||
 | 
			
		||||
  @Before
 | 
			
		||||
  public void setUp() {
 | 
			
		||||
    this.savePersonApiHandler = new SavePersonApiHandler();
 | 
			
		||||
    this.savePersonApiHandler.setDynamoDbMapper(dynamoDbMapper);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void handleRequestSavePersonSuccessful() throws JsonProcessingException {
 | 
			
		||||
    Person person = newPerson();
 | 
			
		||||
    APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent =
 | 
			
		||||
        this.savePersonApiHandler
 | 
			
		||||
            .handleRequest(apiGatewayProxyRequestEvent(objectMapper.writeValueAsString(person)), mock(Context.class));
 | 
			
		||||
    verify(dynamoDbMapper, times(1)).save(person);
 | 
			
		||||
    Assert.assertNotNull(apiGatewayProxyResponseEvent);
 | 
			
		||||
    Assert.assertEquals(new Integer(201), apiGatewayProxyResponseEvent.getStatusCode());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void handleRequestSavePersonException() {
 | 
			
		||||
    APIGatewayProxyResponseEvent apiGatewayProxyResponseEvent =
 | 
			
		||||
        this.savePersonApiHandler
 | 
			
		||||
            .handleRequest(apiGatewayProxyRequestEvent("invalid sample request"), mock(Context.class));
 | 
			
		||||
    Assert.assertNotNull(apiGatewayProxyResponseEvent);
 | 
			
		||||
    Assert.assertEquals(new Integer(400), apiGatewayProxyResponseEvent.getStatusCode());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent(String body) {
 | 
			
		||||
    APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent = new APIGatewayProxyRequestEvent();
 | 
			
		||||
    return apiGatewayProxyRequestEvent.withBody(body);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private Person newPerson() {
 | 
			
		||||
    Person person = new Person();
 | 
			
		||||
    person.setFirstName("Thor");
 | 
			
		||||
    person.setLastName("Odinson");
 | 
			
		||||
    Address address = new Address();
 | 
			
		||||
    address.setAddressLineOne("1 Odin ln");
 | 
			
		||||
    address.setCity("Asgard");
 | 
			
		||||
    address.setState("country of the Gods");
 | 
			
		||||
    address.setZipCode("00001");
 | 
			
		||||
    person.setAddress(address);
 | 
			
		||||
 | 
			
		||||
    return person;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,49 @@
 | 
			
		||||
/**
 | 
			
		||||
 * The MIT License
 | 
			
		||||
 * Copyright (c) 2014 Ilkka Seppälä
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 * <p>
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
package com.iluwatar.serverless.faas.api;
 | 
			
		||||
 | 
			
		||||
import com.amazonaws.services.lambda.runtime.Context;
 | 
			
		||||
import org.junit.jupiter.api.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.runners.MockitoJUnitRunner;
 | 
			
		||||
 | 
			
		||||
import static org.hamcrest.MatcherAssert.assertThat;
 | 
			
		||||
import static org.hamcrest.core.IsNull.notNullValue;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.when;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Unit tests for LambdaInfoApiHandler
 | 
			
		||||
 */
 | 
			
		||||
@RunWith(MockitoJUnitRunner.class)
 | 
			
		||||
public class LambdaInfoApiHandlerTest {
 | 
			
		||||
 | 
			
		||||
  @Test
 | 
			
		||||
  public void handleRequestWithMockContext() {
 | 
			
		||||
    LambdaInfoApiHandler lambdaInfoApiHandler = new LambdaInfoApiHandler();
 | 
			
		||||
    Context context = mock(Context.class);
 | 
			
		||||
    when(context.getAwsRequestId()).thenReturn("mock aws request id");
 | 
			
		||||
 | 
			
		||||
    assertThat(lambdaInfoApiHandler.handleRequest(null, context), notNullValue());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||