diff --git a/aws-lambda/lambda/pom.xml b/aws-lambda/lambda/pom.xml
new file mode 100644
index 0000000000..2d903aabc5
--- /dev/null
+++ b/aws-lambda/lambda/pom.xml
@@ -0,0 +1,100 @@
+
+
+ 4.0.0
+ aws-lambda-examples
+ 0.1.0-SNAPSHOT
+ aws-lambda-examples
+ jar
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+ ../../
+
+
+
+
+ com.amazonaws
+ aws-java-sdk-dynamodb
+ ${aws-java-sdk.version}
+
+
+ com.amazonaws
+ aws-java-sdk-core
+ ${aws-java-sdk.version}
+
+
+ com.amazonaws
+ aws-lambda-java-core
+ ${aws-lambda-java-core.version}
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+ com.amazonaws
+ aws-lambda-java-events
+ ${aws-lambda-java-events.version}
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+ com.google.code.gson
+ gson
+ ${gson.version}
+
+
+ commons-io
+ commons-io
+ ${commons-io.version}
+
+
+ com.googlecode.json-simple
+ json-simple
+ ${json-simple.version}
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ ${maven-shade-plugin.version}
+
+ false
+
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
+
+ 1.1.1
+ 2.5
+ 1.3.0
+ 1.2.0
+ 2.8.2
+ 1.11.241
+ 3.0.0
+
+
+
diff --git a/aws-lambda/sam-templates/template-implicit.yaml b/aws-lambda/lambda/sam-templates/template-implicit.yaml
similarity index 100%
rename from aws-lambda/sam-templates/template-implicit.yaml
rename to aws-lambda/lambda/sam-templates/template-implicit.yaml
diff --git a/aws-lambda/sam-templates/template-inline-swagger.yaml b/aws-lambda/lambda/sam-templates/template-inline-swagger.yaml
similarity index 100%
rename from aws-lambda/sam-templates/template-inline-swagger.yaml
rename to aws-lambda/lambda/sam-templates/template-inline-swagger.yaml
diff --git a/aws-lambda/src/main/java/com/baeldung/lambda/LambdaMethodHandler.java b/aws-lambda/lambda/src/main/java/com/baeldung/lambda/LambdaMethodHandler.java
similarity index 100%
rename from aws-lambda/src/main/java/com/baeldung/lambda/LambdaMethodHandler.java
rename to aws-lambda/lambda/src/main/java/com/baeldung/lambda/LambdaMethodHandler.java
diff --git a/aws-lambda/src/main/java/com/baeldung/lambda/LambdaRequestHandler.java b/aws-lambda/lambda/src/main/java/com/baeldung/lambda/LambdaRequestHandler.java
similarity index 100%
rename from aws-lambda/src/main/java/com/baeldung/lambda/LambdaRequestHandler.java
rename to aws-lambda/lambda/src/main/java/com/baeldung/lambda/LambdaRequestHandler.java
diff --git a/aws-lambda/src/main/java/com/baeldung/lambda/LambdaRequestStreamHandler.java b/aws-lambda/lambda/src/main/java/com/baeldung/lambda/LambdaRequestStreamHandler.java
similarity index 100%
rename from aws-lambda/src/main/java/com/baeldung/lambda/LambdaRequestStreamHandler.java
rename to aws-lambda/lambda/src/main/java/com/baeldung/lambda/LambdaRequestStreamHandler.java
diff --git a/aws-lambda/src/main/java/com/baeldung/lambda/apigateway/APIDemoHandler.java b/aws-lambda/lambda/src/main/java/com/baeldung/lambda/apigateway/APIDemoHandler.java
similarity index 100%
rename from aws-lambda/src/main/java/com/baeldung/lambda/apigateway/APIDemoHandler.java
rename to aws-lambda/lambda/src/main/java/com/baeldung/lambda/apigateway/APIDemoHandler.java
diff --git a/aws-lambda/src/main/java/com/baeldung/lambda/apigateway/model/Person.java b/aws-lambda/lambda/src/main/java/com/baeldung/lambda/apigateway/model/Person.java
similarity index 100%
rename from aws-lambda/src/main/java/com/baeldung/lambda/apigateway/model/Person.java
rename to aws-lambda/lambda/src/main/java/com/baeldung/lambda/apigateway/model/Person.java
diff --git a/aws-lambda/src/main/java/com/baeldung/lambda/dynamodb/SavePersonHandler.java b/aws-lambda/lambda/src/main/java/com/baeldung/lambda/dynamodb/SavePersonHandler.java
similarity index 100%
rename from aws-lambda/src/main/java/com/baeldung/lambda/dynamodb/SavePersonHandler.java
rename to aws-lambda/lambda/src/main/java/com/baeldung/lambda/dynamodb/SavePersonHandler.java
diff --git a/aws-lambda/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonRequest.java b/aws-lambda/lambda/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonRequest.java
similarity index 100%
rename from aws-lambda/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonRequest.java
rename to aws-lambda/lambda/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonRequest.java
diff --git a/aws-lambda/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonResponse.java b/aws-lambda/lambda/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonResponse.java
similarity index 100%
rename from aws-lambda/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonResponse.java
rename to aws-lambda/lambda/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonResponse.java
diff --git a/aws-lambda/src/main/resources/logback.xml b/aws-lambda/lambda/src/main/resources/logback.xml
similarity index 100%
rename from aws-lambda/src/main/resources/logback.xml
rename to aws-lambda/lambda/src/main/resources/logback.xml
diff --git a/aws-lambda/pom.xml b/aws-lambda/pom.xml
index e1d2c7df27..116fc801aa 100644
--- a/aws-lambda/pom.xml
+++ b/aws-lambda/pom.xml
@@ -5,95 +5,19 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
aws-lambda
- 0.1.0-SNAPSHOT
aws-lambda
- jar
+ pom
com.baeldung
parent-modules
1.0.0-SNAPSHOT
+ ../
-
-
- com.amazonaws
- aws-java-sdk-dynamodb
- ${aws-java-sdk.version}
-
-
- com.amazonaws
- aws-java-sdk-core
- ${aws-java-sdk.version}
-
-
- com.amazonaws
- aws-lambda-java-core
- ${aws-lambda-java-core.version}
-
-
- commons-logging
- commons-logging
-
-
-
-
- com.amazonaws
- aws-lambda-java-events
- ${aws-lambda-java-events.version}
-
-
- commons-logging
- commons-logging
-
-
-
-
- com.google.code.gson
- gson
- ${gson.version}
-
-
- commons-io
- commons-io
- ${commons-io.version}
-
-
- com.googlecode.json-simple
- json-simple
- ${json-simple.version}
-
-
+
+ lambda
+ shipping-tracker/ShippingFunction
+
-
-
-
- org.apache.maven.plugins
- maven-shade-plugin
- ${maven-shade-plugin.version}
-
- false
-
-
-
- package
-
- shade
-
-
-
-
-
-
-
-
- 1.1.1
- 2.5
- 1.3.0
- 1.2.0
- 2.8.2
- 1.11.241
- 3.0.0
-
-
-
\ No newline at end of file
+
diff --git a/aws-lambda/shipping-tracker/.gitignore b/aws-lambda/shipping-tracker/.gitignore
new file mode 100644
index 0000000000..9984c2e554
--- /dev/null
+++ b/aws-lambda/shipping-tracker/.gitignore
@@ -0,0 +1 @@
+.aws-sam/
diff --git a/aws-lambda/shipping-tracker/ShippingFunction/pom.xml b/aws-lambda/shipping-tracker/ShippingFunction/pom.xml
new file mode 100644
index 0000000000..ac39c9ea54
--- /dev/null
+++ b/aws-lambda/shipping-tracker/ShippingFunction/pom.xml
@@ -0,0 +1,73 @@
+
+ 4.0.0
+ com.baeldung
+ ShippingFunction
+ 1.0
+ jar
+ Shipping Tracker Lambda Function
+
+ 1.8
+ 1.8
+ 5.4.21.Final
+
+
+
+
+ com.amazonaws
+ aws-lambda-java-core
+ 1.2.0
+
+
+ com.amazonaws
+ aws-lambda-java-events
+ 3.1.0
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.11.2
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ org.hibernate
+ hibernate-core
+ ${hibernate.version}
+
+
+ org.hibernate
+ hibernate-hikaricp
+ ${hibernate.version}
+
+
+ org.postgresql
+ postgresql
+ 42.2.16
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.1.1
+
+
+
+
+ package
+
+ shade
+
+
+
+
+
+
+
diff --git a/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/App.java b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/App.java
new file mode 100644
index 0000000000..719725598c
--- /dev/null
+++ b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/App.java
@@ -0,0 +1,108 @@
+package com.baeldung.lambda.shipping;
+
+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.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.hibernate.SessionFactory;
+import org.hibernate.boot.MetadataSources;
+import org.hibernate.boot.registry.StandardServiceRegistry;
+import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hibernate.cfg.AvailableSettings.*;
+import static org.hibernate.cfg.AvailableSettings.PASS;
+
+/**
+ * Handler for requests to Lambda function.
+ */
+public class App implements RequestHandler {
+private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+ public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
+ try (SessionFactory sessionFactory = createSessionFactory()) {
+ ShippingService service = new ShippingService(sessionFactory, new ShippingDao());
+ return routeRequest(input, service);
+ }
+ }
+
+ private APIGatewayProxyResponseEvent routeRequest(APIGatewayProxyRequestEvent input, ShippingService service) {
+ Map headers = new HashMap<>();
+ headers.put("Content-Type", "application/json");
+ headers.put("X-Custom-Header", "application/json");
+
+ Object result = "OK";
+
+ switch (input.getResource()) {
+ case "/consignment":
+ result = service.createConsignment(
+ fromJson(input.getBody(), Consignment.class));
+ break;
+ case "/consignment/{id}":
+ result = service.view(input.getPathParameters().get("id"));
+ break;
+ case "/consignment/{id}/item":
+ service.addItem(input.getPathParameters().get("id"),
+ fromJson(input.getBody(), Item.class));
+ break;
+ case "/consignment/{id}/checkin":
+ service.checkIn(input.getPathParameters().get("id"),
+ fromJson(input.getBody(), Checkin.class));
+ break;
+ }
+
+ return new APIGatewayProxyResponseEvent()
+ .withHeaders(headers)
+ .withStatusCode(200)
+ .withBody(toJson(result));
+ }
+
+ private static String toJson(T object) {
+ try {
+ return OBJECT_MAPPER.writeValueAsString(object);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static T fromJson(String json, Class type) {
+ try {
+ return OBJECT_MAPPER.readValue(json, type);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static SessionFactory createSessionFactory() {
+ Map settings = new HashMap<>();
+ settings.put(URL, System.getenv("DB_URL"));
+ settings.put(DIALECT, "org.hibernate.dialect.PostgreSQLDialect");
+ settings.put(DEFAULT_SCHEMA, "shipping");
+ settings.put(DRIVER, "org.postgresql.Driver");
+ settings.put(USER, System.getenv("DB_USER"));
+ settings.put(PASS, System.getenv("DB_PASSWORD"));
+ settings.put("hibernate.hikari.connectionTimeout", "20000");
+ settings.put("hibernate.hikari.minimumIdle", "1");
+ settings.put("hibernate.hikari.maximumPoolSize", "2");
+ settings.put("hibernate.hikari.idleTimeout", "30000");
+
+// commented out as we only need them on first use
+// settings.put(HBM2DDL_AUTO, "create-only");
+// settings.put(HBM2DDL_DATABASE_ACTION, "create");
+
+ StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
+ .applySettings(settings)
+ .build();
+
+ return new MetadataSources(registry)
+ .addAnnotatedClass(Consignment.class)
+ .addAnnotatedClass(Item.class)
+ .addAnnotatedClass(Checkin.class)
+ .buildMetadata()
+ .buildSessionFactory();
+ }
+}
diff --git a/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/Checkin.java b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/Checkin.java
new file mode 100644
index 0000000000..93e6404749
--- /dev/null
+++ b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/Checkin.java
@@ -0,0 +1,28 @@
+package com.baeldung.lambda.shipping;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class Checkin {
+ private String timeStamp;
+ private String location;
+
+ @Column(name = "timestamp")
+ public String getTimeStamp() {
+ return timeStamp;
+ }
+
+ public void setTimeStamp(String timeStamp) {
+ this.timeStamp = timeStamp;
+ }
+
+ @Column(name = "location")
+ public String getLocation() {
+ return location;
+ }
+
+ public void setLocation(String location) {
+ this.location = location;
+ }
+}
diff --git a/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/Consignment.java b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/Consignment.java
new file mode 100644
index 0000000000..1a2371b37f
--- /dev/null
+++ b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/Consignment.java
@@ -0,0 +1,77 @@
+package com.baeldung.lambda.shipping;
+
+import javax.persistence.*;
+import java.util.ArrayList;
+import java.util.List;
+
+import static javax.persistence.FetchType.EAGER;
+
+@Entity(name = "consignment")
+@Table(name = "consignment")
+public class Consignment {
+ private String id;
+ private String source;
+ private String destination;
+ private boolean isDelivered;
+ private List- items = new ArrayList<>();
+ private List checkins = new ArrayList<>();
+
+ @Id
+ @Column(name = "consignment_id")
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @Column(name = "source")
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ @Column(name = "destination")
+ public String getDestination() {
+ return destination;
+ }
+
+ public void setDestination(String destination) {
+ this.destination = destination;
+ }
+
+ @Column(name = "delivered", columnDefinition = "boolean")
+ public boolean isDelivered() {
+ return isDelivered;
+ }
+
+ public void setDelivered(boolean delivered) {
+ isDelivered = delivered;
+ }
+
+ @ElementCollection(fetch = EAGER)
+ @CollectionTable(name = "consignment_item", joinColumns = @JoinColumn(name = "consignment_id"))
+ @OrderColumn(name = "item_index")
+ public List
- getItems() {
+ return items;
+ }
+
+ public void setItems(List
- items) {
+ this.items = items;
+ }
+
+ @ElementCollection(fetch = EAGER)
+ @CollectionTable(name = "consignment_checkin", joinColumns = @JoinColumn(name = "consignment_id"))
+ @OrderColumn(name = "checkin_index")
+ public List getCheckins() {
+ return checkins;
+ }
+
+ public void setCheckins(List checkins) {
+ this.checkins = checkins;
+ }
+}
diff --git a/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/Item.java b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/Item.java
new file mode 100644
index 0000000000..de6194e180
--- /dev/null
+++ b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/Item.java
@@ -0,0 +1,38 @@
+package com.baeldung.lambda.shipping;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+
+@Embeddable
+public class Item {
+ private String location;
+ private String description;
+ private String timeStamp;
+
+ @Column(name = "location")
+ public String getLocation() {
+ return location;
+ }
+
+ public void setLocation(String location) {
+ this.location = location;
+ }
+
+ @Column(name = "description")
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ @Column(name = "timestamp")
+ public String getTimeStamp() {
+ return timeStamp;
+ }
+
+ public void setTimeStamp(String timeStamp) {
+ this.timeStamp = timeStamp;
+ }
+}
diff --git a/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/ShippingDao.java b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/ShippingDao.java
new file mode 100644
index 0000000000..369dc33935
--- /dev/null
+++ b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/ShippingDao.java
@@ -0,0 +1,25 @@
+package com.baeldung.lambda.shipping;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+
+import java.util.Optional;
+
+public class ShippingDao {
+ /**
+ * Save a consignment to the database
+ * @param consignment the consignment to save
+ */
+ public void save(Session session, Consignment consignment) {
+ Transaction transaction = session.beginTransaction();
+ session.save(consignment);
+ transaction.commit();
+ }
+
+ /**
+ * Find a consignment in the database by id
+ */
+ public Optional find(Session session, String id) {
+ return Optional.ofNullable(session.get(Consignment.class, id));
+ }
+}
diff --git a/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/ShippingService.java b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/ShippingService.java
new file mode 100644
index 0000000000..4c951068ea
--- /dev/null
+++ b/aws-lambda/shipping-tracker/ShippingFunction/src/main/java/com/baeldung/lambda/shipping/ShippingService.java
@@ -0,0 +1,62 @@
+package com.baeldung.lambda.shipping;
+
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+
+import java.util.Comparator;
+import java.util.UUID;
+
+public class ShippingService {
+ private SessionFactory sessionFactory;
+ private ShippingDao shippingDao;
+
+ public ShippingService(SessionFactory sessionFactory, ShippingDao shippingDao) {
+ this.sessionFactory = sessionFactory;
+ this.shippingDao = shippingDao;
+ }
+
+ public String createConsignment(Consignment consignment) {
+ try (Session session = sessionFactory.openSession()) {
+ consignment.setDelivered(false);
+ consignment.setId(UUID.randomUUID().toString());
+ shippingDao.save(session, consignment);
+ return consignment.getId();
+ }
+ }
+
+ public void addItem(String consignmentId, Item item) {
+ try (Session session = sessionFactory.openSession()) {
+ shippingDao.find(session, consignmentId)
+ .ifPresent(consignment -> addItem(session, consignment, item));
+ }
+ }
+
+ private void addItem(Session session, Consignment consignment, Item item) {
+ consignment.getItems()
+ .add(item);
+ shippingDao.save(session, consignment);
+ }
+
+ public void checkIn(String consignmentId, Checkin checkin) {
+ try (Session session = sessionFactory.openSession()) {
+ shippingDao.find(session, consignmentId)
+ .ifPresent(consignment -> checkIn(session, consignment, checkin));
+ }
+ }
+
+ private void checkIn(Session session, Consignment consignment, Checkin checkin) {
+ consignment.getCheckins().add(checkin);
+ consignment.getCheckins().sort(Comparator.comparing(Checkin::getTimeStamp));
+ if (checkin.getLocation().equals(consignment.getDestination())) {
+ consignment.setDelivered(true);
+ }
+ shippingDao.save(session, consignment);
+ }
+
+ public Consignment view(String consignmentId) {
+ try (Session session = sessionFactory.openSession()) {
+ return shippingDao.find(session, consignmentId)
+ .orElseGet(Consignment::new);
+ }
+ }
+}
diff --git a/aws-lambda/shipping-tracker/template.yaml b/aws-lambda/shipping-tracker/template.yaml
new file mode 100644
index 0000000000..ec75c51ba1
--- /dev/null
+++ b/aws-lambda/shipping-tracker/template.yaml
@@ -0,0 +1,47 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Transform: AWS::Serverless-2016-10-31
+Description: >
+ shipping-tracker
+
+ Sample SAM Template for shipping-tracker
+
+# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
+Globals:
+ Function:
+ Timeout: 20
+
+Resources:
+ ShippingFunction:
+ Type: AWS::Serverless::Function
+ Properties:
+ CodeUri: ShippingFunction
+ Handler: com.baeldung.lambda.shipping.App::handleRequest
+ Runtime: java8
+ MemorySize: 512
+ Environment:
+ Variables:
+ DB_URL: jdbc:postgresql://postgres/postgres
+ DB_USER: postgres
+ DB_PASSWORD: password
+ Events:
+ CreateConsignment:
+ Type: Api
+ Properties:
+ Path: /consignment
+ Method: post
+ AddItem:
+ Type: Api
+ Properties:
+ Path: /consignment/{id}/item
+ Method: post
+ CheckIn:
+ Type: Api
+ Properties:
+ Path: /consignment/{id}/checkin
+ Method: post
+ ViewConsignment:
+ Type: Api
+ Properties:
+ Path: /consignment/{id}
+ Method: get
+