From 1279742774fa5bf8484e38c2bcb8c1951f153c45 Mon Sep 17 00:00:00 2001
From: Mark Sailes <45629314+msailes@users.noreply.github.com>
Date: Tue, 11 Jun 2024 15:18:15 +0100
Subject: [PATCH 001/103] Adds the V2 version of the pre token generation
event. (#465)
---
...nitoUserPoolPreTokenGenerationEventV2.java | 134 ++++++++++++++++++
.../lambda/runtime/tests/EventLoader.java | 4 +
.../lambda/runtime/tests/EventLoaderTest.java | 15 +-
...er_pool_pre_token_generation_event_v2.json | 33 +++++
4 files changed, 185 insertions(+), 1 deletion(-)
create mode 100644 aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CognitoUserPoolPreTokenGenerationEventV2.java
create mode 100644 aws-lambda-java-tests/src/test/resources/cognito_user_pool_pre_token_generation_event_v2.json
diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CognitoUserPoolPreTokenGenerationEventV2.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CognitoUserPoolPreTokenGenerationEventV2.java
new file mode 100644
index 000000000..c72505703
--- /dev/null
+++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CognitoUserPoolPreTokenGenerationEventV2.java
@@ -0,0 +1,134 @@
+/* Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. */
+
+package com.amazonaws.services.lambda.runtime.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+import java.util.Map;
+
+/**
+ * Represent the class for the Cognito User Pool Pre Token Generation Lambda Trigger V2
+ *
+ * See Pre Token Generation Lambda Trigger
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@ToString(callSuper = true)
+public class CognitoUserPoolPreTokenGenerationEventV2 extends CognitoUserPoolEvent {
+ /**
+ * The request from the Amazon Cognito service.
+ */
+ private Request request;
+
+ /**
+ * The response from your Lambda trigger.
+ */
+ private Response response;
+
+ @Builder(setterPrefix = "with")
+ public CognitoUserPoolPreTokenGenerationEventV2(
+ String version,
+ String triggerSource,
+ String region,
+ String userPoolId,
+ String userName,
+ CallerContext callerContext,
+ Request request,
+ Response response) {
+ super(version, triggerSource, region, userPoolId, userName, callerContext);
+ this.request = request;
+ this.response = response;
+ }
+
+ @Data
+ @EqualsAndHashCode(callSuper = true)
+ @NoArgsConstructor
+ @ToString(callSuper = true)
+ public static class Request extends CognitoUserPoolEvent.Request {
+
+ private String[] scopes;
+ private GroupConfiguration groupConfiguration;
+ private Map clientMetadata;
+
+ @Builder(setterPrefix = "with")
+ public Request(Map userAttributes, String[] scopes, GroupConfiguration groupConfiguration, Map clientMetadata) {
+ super(userAttributes);
+ this.scopes = scopes;
+ this.groupConfiguration = groupConfiguration;
+ this.clientMetadata = clientMetadata;
+ }
+ }
+
+ @Data
+ @AllArgsConstructor
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ public static class GroupConfiguration {
+ /**
+ * A list of the group names that are associated with the user that the identity token is issued for.
+ */
+ private String[] groupsToOverride;
+ /**
+ * A list of the current IAM roles associated with these groups.
+ */
+ private String[] iamRolesToOverride;
+ /**
+ * Indicates the preferred IAM role.
+ */
+ private String preferredRole;
+ }
+
+ @Data
+ @AllArgsConstructor
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ public static class Response {
+ private ClaimsAndScopeOverrideDetails claimsAndScopeOverrideDetails;
+ }
+
+ @Data
+ @AllArgsConstructor
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ public static class ClaimsAndScopeOverrideDetails {
+ private IdTokenGeneration idTokenGeneration;
+ private AccessTokenGeneration accessTokenGeneration;
+ private GroupOverrideDetails groupOverrideDetails;
+ }
+
+ @Data
+ @AllArgsConstructor
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ public static class IdTokenGeneration {
+ private Map claimsToAddOrOverride;
+ private String[] claimsToSuppress;
+ }
+
+ @Data
+ @AllArgsConstructor
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ public static class AccessTokenGeneration {
+ private Map claimsToAddOrOverride;
+ private String[] claimsToSuppress;
+ private String[] scopesToAdd;
+ private String[] scopesToSuppress;
+ }
+
+ @Data
+ @AllArgsConstructor
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ public static class GroupOverrideDetails {
+ private Map groupsToOverride;
+ private Map iamRolesToOverride;
+ private String preferredRole;
+ }
+}
\ No newline at end of file
diff --git a/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java b/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
index 7228fb90d..aa600749c 100644
--- a/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
+++ b/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
@@ -113,6 +113,10 @@ public static RabbitMQEvent loadRabbitMQEvent(String filename) {
return loadEvent(filename, RabbitMQEvent.class);
}
+ public static CognitoUserPoolPreTokenGenerationEventV2 loadCognitoUserPoolPreTokenGenerationEventV2(String filename) {
+ return loadEvent(filename, CognitoUserPoolPreTokenGenerationEventV2.class);
+ }
+
public static T loadEvent(String filename, Class targetClass) {
if (!filename.endsWith("json")) {
diff --git a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java
index 3177b9ccc..1c9d17e16 100644
--- a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java
+++ b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java
@@ -14,7 +14,6 @@
import static java.time.Instant.ofEpochSecond;
import static org.assertj.core.api.Assertions.*;
-import static org.assertj.core.api.Assertions.from;
import com.amazonaws.services.lambda.runtime.events.*;
@@ -363,4 +362,18 @@ public void testLoadRabbitMQEvent() {
assertThat(header1.get("bytes")).contains(118, 97, 108, 117, 101, 49);
assertThat((Integer) headers.get("numberInHeader")).isEqualTo(10);
}
+
+ @Test
+ public void testLoadCognitoUserPoolPreTokenGenerationEventV2() {
+ CognitoUserPoolPreTokenGenerationEventV2 event = EventLoader.loadCognitoUserPoolPreTokenGenerationEventV2("cognito_user_pool_pre_token_generation_event_v2.json");
+ assertThat(event).isNotNull();
+ assertThat(event)
+ .returns("2", from(CognitoUserPoolPreTokenGenerationEventV2::getVersion))
+ .returns("us-east-1", from(CognitoUserPoolPreTokenGenerationEventV2::getRegion))
+ .returns("TokenGeneration_Authentication", from(CognitoUserPoolPreTokenGenerationEventV2::getTriggerSource));
+
+ CognitoUserPoolPreTokenGenerationEventV2.Request request = event.getRequest();
+ String[] requestScopes = request.getScopes();
+ assertThat("aws.cognito.signin.user.admin").isEqualTo(requestScopes[0]);
+ }
}
diff --git a/aws-lambda-java-tests/src/test/resources/cognito_user_pool_pre_token_generation_event_v2.json b/aws-lambda-java-tests/src/test/resources/cognito_user_pool_pre_token_generation_event_v2.json
new file mode 100644
index 000000000..43f8e0f7d
--- /dev/null
+++ b/aws-lambda-java-tests/src/test/resources/cognito_user_pool_pre_token_generation_event_v2.json
@@ -0,0 +1,33 @@
+{
+ "version": "2",
+ "triggerSource": "TokenGeneration_Authentication",
+ "region": "us-east-1",
+ "userPoolId": "us-east-1_EXAMPLE",
+ "userName": "JaneDoe",
+ "callerContext": {
+ "awsSdkVersion": "aws-sdk-unknown-unknown",
+ "clientId": "1example23456789"
+ },
+ "request": {
+ "userAttributes": {
+ "sub": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
+ "cognito:user_status": "CONFIRMED",
+ "email_verified": "true",
+ "phone_number_verified": "true",
+ "phone_number": "+12065551212",
+ "family_name": "Zoe",
+ "email": "Jane.Doe@example.com"
+ },
+ "groupConfiguration": {
+ "groupsToOverride": ["group-1", "group-2", "group-3"],
+ "iamRolesToOverride": ["arn:aws:iam::123456789012:role/sns_caller1", "arn:aws:iam::123456789012:role/sns_caller2", "arn:aws:iam::123456789012:role/sns_caller3"],
+ "preferredRole": ["arn:aws:iam::123456789012:role/sns_caller"]
+ },
+ "scopes": [
+ "aws.cognito.signin.user.admin", "openid", "email", "phone"
+ ]
+ },
+ "response": {
+ "claimsAndScopeOverrideDetails": []
+ }
+}
\ No newline at end of file
From 5c53c44e69dbd6a5bb61afda52f3f5ee2cad5af3 Mon Sep 17 00:00:00 2001
From: Andrea Culot <95755271+andclt@users.noreply.github.com>
Date: Tue, 11 Jun 2024 16:00:22 +0100
Subject: [PATCH 002/103] Stage aws-lambda-java-events 3.11.6 (#483)
---
README.md | 2 +-
aws-lambda-java-events/README.md | 2 +-
aws-lambda-java-events/RELEASE.CHANGELOG.md | 4 ++++
aws-lambda-java-events/pom.xml | 2 +-
aws-lambda-java-tests/pom.xml | 2 +-
samples/kinesis-firehose-event-handler/pom.xml | 2 +-
6 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index b2145ce16..445e35f97 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,7 @@ public class SqsHandler implements RequestHandler {
com.amazonaws
aws-lambda-java-events
- 3.11.5
+ 3.11.6
```
diff --git a/aws-lambda-java-events/README.md b/aws-lambda-java-events/README.md
index 6519bcebd..8c60b3a23 100644
--- a/aws-lambda-java-events/README.md
+++ b/aws-lambda-java-events/README.md
@@ -69,7 +69,7 @@
com.amazonaws
aws-lambda-java-events
- 3.11.5
+ 3.11.6
...
diff --git a/aws-lambda-java-events/RELEASE.CHANGELOG.md b/aws-lambda-java-events/RELEASE.CHANGELOG.md
index bc814dd0e..a19bd260a 100644
--- a/aws-lambda-java-events/RELEASE.CHANGELOG.md
+++ b/aws-lambda-java-events/RELEASE.CHANGELOG.md
@@ -1,3 +1,7 @@
+### June 11, 2024
+`3.11.6`:
+- Add the V2 version of the pre token generation event([#465](https://github.com/aws/aws-lambda-java-libs/pull/465))
+
### April 12, 2024
`3.11.5`:
- Add requestHeaders field for Appsync lambda authorizer event([#473](https://github.com/aws/aws-lambda-java-libs/pull/473))
diff --git a/aws-lambda-java-events/pom.xml b/aws-lambda-java-events/pom.xml
index 4167a3d51..2c7442c06 100644
--- a/aws-lambda-java-events/pom.xml
+++ b/aws-lambda-java-events/pom.xml
@@ -5,7 +5,7 @@
com.amazonaws
aws-lambda-java-events
- 3.11.5
+ 3.11.6
jar
AWS Lambda Java Events Library
diff --git a/aws-lambda-java-tests/pom.xml b/aws-lambda-java-tests/pom.xml
index 23be8e597..b77032b73 100644
--- a/aws-lambda-java-tests/pom.xml
+++ b/aws-lambda-java-tests/pom.xml
@@ -45,7 +45,7 @@
com.amazonaws
aws-lambda-java-events
- 3.11.5
+ 3.11.6
org.junit.jupiter
diff --git a/samples/kinesis-firehose-event-handler/pom.xml b/samples/kinesis-firehose-event-handler/pom.xml
index 669c0979b..1dc96d3d5 100644
--- a/samples/kinesis-firehose-event-handler/pom.xml
+++ b/samples/kinesis-firehose-event-handler/pom.xml
@@ -46,7 +46,7 @@
com.amazonaws
aws-lambda-java-events
- 3.11.5
+ 3.11.6
From 9a5450a070e03765135f3bca9636a425b3c4540e Mon Sep 17 00:00:00 2001
From: Maxime David
Date: Fri, 28 Jun 2024 18:31:15 +0100
Subject: [PATCH 003/103] release 2.5.1 (#487)
---
.github/dependabot.yml | 7 +
.github/workflows/aws-lambda-java-core.yml | 9 +-
...aws-lambda-java-events-sdk-transformer.yml | 7 +-
.github/workflows/aws-lambda-java-events.yml | 7 +-
.github/workflows/aws-lambda-java-log4j2.yml | 7 +-
.../aws-lambda-java-serialization.yml | 7 +-
.github/workflows/aws-lambda-java-tests.yml | 7 +-
.github/workflows/repo-sync.yml | 4 +
...runtime-interface-client_merge_to_main.yml | 9 +-
.../workflows/runtime-interface-client_pr.yml | 15 ++-
.github/workflows/samples.yml | 3 +-
.gitignore | 5 +-
README.md | 2 +-
.../Makefile | 19 ++-
.../README.md | 4 +-
.../RELEASE.CHANGELOG.md | 5 +
.../pom.xml | 40 +++++-
.../ric-dev-environment/publish_snapshot.sh | 6 +-
.../services/lambda/crac/ContextImpl.java | 43 +++---
.../services/lambda/crac/DNSManager.java | 10 ++
.../lambda/runtime/api/client/UserFault.java | 21 ++-
.../api/client/runtimeapi/JniHelper.java | 64 +++++++++
.../api/client/runtimeapi/NativeClient.java | 62 +--------
.../src/main/jni/Dockerfile.glibc | 9 +-
.../src/main/jni/Dockerfile.musl | 9 +-
.../src/main/jni/build-jni-lib.sh | 13 +-
...zonaws_services_lambda_crac_DNSManager.cpp | 27 ++++
...mazonaws_services_lambda_crac_DNSManager.h | 19 +++
...ime_api_client_runtimeapi_NativeClient.cpp | 22 +---
...ntime_api_client_runtimeapi_NativeClient.h | 4 +
.../src/main/jni/macro.h | 14 ++
.../services/lambda/crac/ContextImplTest.java | 21 ++-
.../lambda/crac/DNSCacheManagerTest.java | 124 ++++++++++++++++++
.../runtime/api/client/UserFaultTest.java | 40 ++++++
.../codebuild/buildspec.os.alpine.yml | 2 +-
.../codebuild/buildspec.os.amazoncorretto.yml | 2 +-
.../codebuild/buildspec.os.amazonlinux.1.yml | 2 +-
.../codebuild/buildspec.os.amazonlinux.2.yml | 2 +-
.../test/integration/test-handler/pom.xml | 2 +-
39 files changed, 525 insertions(+), 150 deletions(-)
create mode 100644 .github/dependabot.yml
create mode 100644 aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/crac/DNSManager.java
create mode 100644 aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/JniHelper.java
create mode 100644 aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.cpp
create mode 100644 aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.h
create mode 100644 aws-lambda-java-runtime-interface-client/src/main/jni/macro.h
create mode 100644 aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/DNSCacheManagerTest.java
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..3722537ae
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,7 @@
+version: 2
+updates:
+
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
\ No newline at end of file
diff --git a/.github/workflows/aws-lambda-java-core.yml b/.github/workflows/aws-lambda-java-core.yml
index 0b553bbc3..39ff12914 100644
--- a/.github/workflows/aws-lambda-java-core.yml
+++ b/.github/workflows/aws-lambda-java-core.yml
@@ -7,11 +7,12 @@ on:
push:
branches: [ main ]
paths:
- - 'aws-lambda-java-core/**'
+ - 'aws-lambda-java-core/**'
pull_request:
branches: [ '*' ]
paths:
- - 'aws-lambda-java-core/**'
+ - 'aws-lambda-java-core/**'
+ - '.github/workflows/aws-lambda-java-core.yml'
jobs:
build:
@@ -21,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up JDK 1.8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: corretto
@@ -38,3 +39,5 @@ jobs:
- name: Run 'pr' target
working-directory: ./aws-lambda-java-runtime-interface-client
run: make pr
+ env:
+ IS_JAVA_8: true
diff --git a/.github/workflows/aws-lambda-java-events-sdk-transformer.yml b/.github/workflows/aws-lambda-java-events-sdk-transformer.yml
index 679639d34..05a870add 100644
--- a/.github/workflows/aws-lambda-java-events-sdk-transformer.yml
+++ b/.github/workflows/aws-lambda-java-events-sdk-transformer.yml
@@ -7,11 +7,12 @@ on:
push:
branches: [ main ]
paths:
- - 'aws-lambda-java-events-sdk-transformer/**'
+ - 'aws-lambda-java-events-sdk-transformer/**'
pull_request:
branches: [ '*' ]
paths:
- - 'aws-lambda-java-events-sdk-transformer/**'
+ - 'aws-lambda-java-events-sdk-transformer/**'
+ - '.github/workflows/aws-lambda-java-events-sdk-transformer.yml'
jobs:
build:
@@ -21,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up JDK 1.8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: corretto
diff --git a/.github/workflows/aws-lambda-java-events.yml b/.github/workflows/aws-lambda-java-events.yml
index bdd01eb7f..634d803ea 100644
--- a/.github/workflows/aws-lambda-java-events.yml
+++ b/.github/workflows/aws-lambda-java-events.yml
@@ -7,11 +7,12 @@ on:
push:
branches: [ main ]
paths:
- - 'aws-lambda-java-events/**'
+ - 'aws-lambda-java-events/**'
pull_request:
branches: [ '*' ]
paths:
- - 'aws-lambda-java-events/**'
+ - 'aws-lambda-java-events/**'
+ - '.github/workflows/aws-lambda-java-events.yml'
jobs:
build:
@@ -21,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up JDK 1.8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: corretto
diff --git a/.github/workflows/aws-lambda-java-log4j2.yml b/.github/workflows/aws-lambda-java-log4j2.yml
index 427c7536b..ab86f200f 100644
--- a/.github/workflows/aws-lambda-java-log4j2.yml
+++ b/.github/workflows/aws-lambda-java-log4j2.yml
@@ -7,11 +7,12 @@ on:
push:
branches: [ main ]
paths:
- - 'aws-lambda-java-log4j2/**'
+ - 'aws-lambda-java-log4j2/**'
pull_request:
branches: [ '*' ]
paths:
- - 'aws-lambda-java-log4j2/**'
+ - 'aws-lambda-java-log4j2/**'
+ - '.github/workflows/aws-lambda-java-log4j2.yml'
jobs:
build:
@@ -21,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up JDK 1.8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: corretto
diff --git a/.github/workflows/aws-lambda-java-serialization.yml b/.github/workflows/aws-lambda-java-serialization.yml
index 9d71cbabf..baa6052fc 100644
--- a/.github/workflows/aws-lambda-java-serialization.yml
+++ b/.github/workflows/aws-lambda-java-serialization.yml
@@ -7,11 +7,12 @@ on:
push:
branches: [ main ]
paths:
- - 'aws-lambda-java-serialization/**'
+ - 'aws-lambda-java-serialization/**'
pull_request:
branches: [ '*' ]
paths:
- - 'aws-lambda-java-serialization/**'
+ - 'aws-lambda-java-serialization/**'
+ - '.github/workflows/aws-lambda-java-serialization.yml'
jobs:
build:
@@ -21,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up JDK 1.8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: corretto
diff --git a/.github/workflows/aws-lambda-java-tests.yml b/.github/workflows/aws-lambda-java-tests.yml
index fc587e8e4..bf17ed2a6 100644
--- a/.github/workflows/aws-lambda-java-tests.yml
+++ b/.github/workflows/aws-lambda-java-tests.yml
@@ -7,11 +7,12 @@ on:
push:
branches: [ main ]
paths:
- - 'aws-lambda-java-tests/**'
+ - 'aws-lambda-java-tests/**'
pull_request:
branches: [ '*' ]
paths:
- - 'aws-lambda-java-tests/**'
+ - 'aws-lambda-java-tests/**'
+ - '.github/workflows/aws-lambda-java-tests.yml'
jobs:
build:
@@ -21,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up JDK 1.8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: corretto
diff --git a/.github/workflows/repo-sync.yml b/.github/workflows/repo-sync.yml
index 91054f9ef..c667bcebd 100644
--- a/.github/workflows/repo-sync.yml
+++ b/.github/workflows/repo-sync.yml
@@ -3,6 +3,10 @@ name: Repo Sync
on:
schedule:
- cron: "0 8 * * 1-5" # At 08:00 on every day-of-week from Monday through Friday
+ pull_request:
+ branches: [ '*' ]
+ paths:
+ - '.github/workflows/repo-sync.yml'
workflow_dispatch:
jobs:
diff --git a/.github/workflows/runtime-interface-client_merge_to_main.yml b/.github/workflows/runtime-interface-client_merge_to_main.yml
index 1783f1cde..27b22fd78 100644
--- a/.github/workflows/runtime-interface-client_merge_to_main.yml
+++ b/.github/workflows/runtime-interface-client_merge_to_main.yml
@@ -15,6 +15,7 @@ on:
branches: [ main ]
paths:
- 'aws-lambda-java-runtime-interface-client/**'
+ workflow_dispatch:
jobs:
@@ -29,13 +30,13 @@ jobs:
- uses: actions/checkout@v3
- name: Set up JDK 1.8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: corretto
- name: Set up QEMU
- uses: docker/setup-qemu-action@v2
+ uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
@@ -48,9 +49,11 @@ jobs:
- name: Test Runtime Interface Client xplatform build - Run 'build' target
working-directory: ./aws-lambda-java-runtime-interface-client
run: make build
+ env:
+ IS_JAVA_8: true
- name: Issue AWS credentials
- uses: aws-actions/configure-aws-credentials@v1
+ uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ secrets.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_ROLE }}
diff --git a/.github/workflows/runtime-interface-client_pr.yml b/.github/workflows/runtime-interface-client_pr.yml
index 7a7f602e9..b935f4f7d 100644
--- a/.github/workflows/runtime-interface-client_pr.yml
+++ b/.github/workflows/runtime-interface-client_pr.yml
@@ -7,7 +7,8 @@ on:
pull_request:
branches: [ '*' ]
paths:
- - 'aws-lambda-java-runtime-interface-client/**'
+ - 'aws-lambda-java-runtime-interface-client/**'
+ - '.github/workflows/runtime-interface-client_pr.yml'
jobs:
@@ -17,7 +18,7 @@ jobs:
- uses: actions/checkout@v3
- name: Set up JDK 1.8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: corretto
@@ -25,6 +26,8 @@ jobs:
- name: Runtime Interface Client smoke tests - Run 'pr' target
working-directory: ./aws-lambda-java-runtime-interface-client
run: make pr
+ env:
+ IS_JAVA_8: true
build:
runs-on: ubuntu-latest
@@ -32,13 +35,13 @@ jobs:
- uses: actions/checkout@v3
- name: Set up JDK 1.8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: corretto
- name: Set up QEMU
- uses: docker/setup-qemu-action@v2
+ uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
@@ -51,9 +54,11 @@ jobs:
- name: Test Runtime Interface Client xplatform build - Run 'build' target
working-directory: ./aws-lambda-java-runtime-interface-client
run: make build
+ env:
+ IS_JAVA_8: true
- name: Save the built jar
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: aws-lambda-java-runtime-interface-client
path: ./aws-lambda-java-runtime-interface-client/target/aws-lambda-java-runtime-interface-client-*.jar
diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml
index 2171ae785..cd6655494 100644
--- a/.github/workflows/samples.yml
+++ b/.github/workflows/samples.yml
@@ -12,6 +12,7 @@ on:
branches: [ '*' ]
paths:
- 'samples/kinesis-firehose-event-handler/**'
+ - '.github/workflows/samples.yml'
jobs:
build:
@@ -21,7 +22,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up JDK 1.8
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 8
distribution: corretto
diff --git a/.gitignore b/.gitignore
index 2f2f0af47..371bed6b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,4 +24,7 @@ dependency-reduced-pom.xml
.project
# OSX
-.DS_Store
\ No newline at end of file
+.DS_Store
+
+# snapshot process
+aws-lambda-java-runtime-interface-client/pom.xml.versionsBackup
diff --git a/README.md b/README.md
index 445e35f97..94f842fb3 100644
--- a/README.md
+++ b/README.md
@@ -140,7 +140,7 @@ The purpose of this package is to allow developers to deploy their applications
com.amazonaws
aws-lambda-java-runtime-interface-client
- 2.5.0
+ 2.5.1
```
diff --git a/aws-lambda-java-runtime-interface-client/Makefile b/aws-lambda-java-runtime-interface-client/Makefile
index e57daf3a8..b3a204213 100644
--- a/aws-lambda-java-runtime-interface-client/Makefile
+++ b/aws-lambda-java-runtime-interface-client/Makefile
@@ -4,6 +4,13 @@ ARCHITECTURE := $(shell arch)
ARCHITECTURE_ALIAS := $($(shell echo "$(ARCHITECTURE)_ALIAS"))
ARCHITECTURE_ALIAS := $(or $(ARCHITECTURE_ALIAS),amd64) # on any other archs defaulting to amd64
+# Java 8 does not support passing some args (such add --add-opens) so we need to clear them
+ifeq ($(IS_JAVA_8),true)
+ EXTRA_LOAD_ARG := -DargLineForReflectionTestOnly=""
+else
+ EXTRA_LOAD_ARG :=
+endif
+
# This optional module exports MAVEN_REPO_URL, MAVEN_REPO_USERNAME and MAVEN_REPO_PASSWORD environment variables
# making it possible to publish resulting artifacts to a codeartifact maven repository
-include ric-dev-environment/codeartifact-repo.mk
@@ -15,7 +22,7 @@ target:
.PHONY: test
test:
- mvn test
+ mvn test $(EXTRA_LOAD_ARG)
.PHONY: setup-codebuild-agent
setup-codebuild-agent:
@@ -44,11 +51,11 @@ pr: test test-smoke
.PHONY: build
build:
- mvn clean install
- mvn install -P linux-x86_64
- mvn install -P linux_musl-x86_64
- mvn install -P linux-aarch64
- mvn install -P linux_musl-aarch64
+ mvn clean install $(EXTRA_LOAD_ARG)
+ mvn install -P linux-x86_64 $(EXTRA_LOAD_ARG)
+ mvn install -P linux_musl-x86_64 $(EXTRA_LOAD_ARG)
+ mvn install -P linux-aarch64 $(EXTRA_LOAD_ARG)
+ mvn install -P linux_musl-aarch64 $(EXTRA_LOAD_ARG)
.PHONY: publish
publish:
diff --git a/aws-lambda-java-runtime-interface-client/README.md b/aws-lambda-java-runtime-interface-client/README.md
index 13f8658f8..ae299c77e 100644
--- a/aws-lambda-java-runtime-interface-client/README.md
+++ b/aws-lambda-java-runtime-interface-client/README.md
@@ -70,7 +70,7 @@ pom.xml
com.amazonaws
aws-lambda-java-runtime-interface-client
- 2.5.0
+ 2.5.1
@@ -160,7 +160,7 @@ platform-specific JAR by setting the ``.
com.amazonaws
aws-lambda-java-runtime-interface-client
- 2.5.0
+ 2.5.1
linux-x86_64
```
diff --git a/aws-lambda-java-runtime-interface-client/RELEASE.CHANGELOG.md b/aws-lambda-java-runtime-interface-client/RELEASE.CHANGELOG.md
index 1fefd0e23..bb5794c20 100644
--- a/aws-lambda-java-runtime-interface-client/RELEASE.CHANGELOG.md
+++ b/aws-lambda-java-runtime-interface-client/RELEASE.CHANGELOG.md
@@ -1,3 +1,8 @@
+### June 28, 2024
+`2.5.1`
+- Runtime API client improvements: fix a DNS cache issue
+- Runtime API client improvements: fix circular exception references causing stackOverflow
+
### March 20, 2024
`2.5.0`
- Runtime API client improvements ([#471](https://github.com/aws/aws-lambda-java-libs/pull/471))
diff --git a/aws-lambda-java-runtime-interface-client/pom.xml b/aws-lambda-java-runtime-interface-client/pom.xml
index 29d20c8d8..a4f022a48 100644
--- a/aws-lambda-java-runtime-interface-client/pom.xml
+++ b/aws-lambda-java-runtime-interface-client/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.amazonaws
aws-lambda-java-runtime-interface-client
- 2.5.0
+ 2.5.1
jar
AWS Lambda Java Runtime Interface Client
@@ -35,6 +35,8 @@
UTF-8
UTF-8
0.8.8
+ 2.4
+ 3.1.1
5.9.2
+ --add-opens java.base/java.net=ALL-UNNAMED
@@ -90,9 +97,22 @@
+
+ maven-install-plugin
+ org.apache.maven.plugins
+ ${maven-install-plugin.version}
+
+
+ maven-deploy-plugin
+ org.apache.maven.plugins
+ ${maven-deploy-plugin.version}
+
maven-surefire-plugin
3.0.0-M9
+
+ ${argLineForReflectionTestOnly}
+
org.junit.jupiter
@@ -110,6 +130,24 @@
maven-antrun-plugin
1.7
+
+ build-jni-lib-for-tests
+ generate-test-sources
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
build-jni-lib
prepare-package
diff --git a/aws-lambda-java-runtime-interface-client/ric-dev-environment/publish_snapshot.sh b/aws-lambda-java-runtime-interface-client/ric-dev-environment/publish_snapshot.sh
index cf5969e1f..9d2f9837f 100755
--- a/aws-lambda-java-runtime-interface-client/ric-dev-environment/publish_snapshot.sh
+++ b/aws-lambda-java-runtime-interface-client/ric-dev-environment/publish_snapshot.sh
@@ -18,6 +18,10 @@ else
echo "Already -SNAPSHOT version"
fi
+# get the updated project version
+snapshotProjectVersion=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)
+echo "Updated project version is ${snapshotProjectVersion}"
+
CLASSIFIERS_ARRAY=("linux-x86_64" "linux_musl-x86_64" "linux-aarch_64" "linux_musl-aarch_64")
for str in "${CLASSIFIERS_ARRAY[@]}"; do
@@ -36,7 +40,7 @@ mvn -B -X -P ci-repo \
-DgroupId=com.amazonaws \
-DartifactId=aws-lambda-java-runtime-interface-client \
-Dpackaging=jar \
- -Dversion=$projectVersion \
+ -Dversion=$snapshotProjectVersion \
-Dfile=./target/aws-lambda-java-runtime-interface-client-$projectVersion.jar \
-Dfiles=$FILES \
-Dclassifiers=$CLASSIFIERS \
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/crac/ContextImpl.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/crac/ContextImpl.java
index ac4bc6480..87fb0ff2f 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/crac/ContextImpl.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/crac/ContextImpl.java
@@ -23,25 +23,9 @@ public class ContextImpl extends Context {
@Override
public synchronized void beforeCheckpoint(Context extends Resource> context) throws CheckpointException {
-
- List exceptionsThrown = new ArrayList<>();
- for (Resource resource : getCheckpointQueueReverseOrderOfRegistration()) {
- try {
- resource.beforeCheckpoint(this);
- } catch (CheckpointException e) {
- Collections.addAll(exceptionsThrown, e.getSuppressed());
- } catch (Exception e) {
- exceptionsThrown.add(e);
- }
- }
-
- if (!exceptionsThrown.isEmpty()) {
- CheckpointException checkpointException = new CheckpointException();
- for (Throwable t : exceptionsThrown) {
- checkpointException.addSuppressed(t);
- }
- throw checkpointException;
- }
+ executeBeforeCheckpointHooks();
+ DNSManager.clearCache();
+ System.gc();
}
@Override
@@ -87,4 +71,25 @@ private List getCheckpointQueueForwardOrderOfRegistration() {
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
+
+ private void executeBeforeCheckpointHooks() throws CheckpointException {
+ List exceptionsThrown = new ArrayList<>();
+ for (Resource resource : getCheckpointQueueReverseOrderOfRegistration()) {
+ try {
+ resource.beforeCheckpoint(this);
+ } catch (CheckpointException e) {
+ Collections.addAll(exceptionsThrown, e.getSuppressed());
+ } catch (Exception e) {
+ exceptionsThrown.add(e);
+ }
+ }
+
+ if (!exceptionsThrown.isEmpty()) {
+ CheckpointException checkpointException = new CheckpointException();
+ for (Throwable t : exceptionsThrown) {
+ checkpointException.addSuppressed(t);
+ }
+ throw checkpointException;
+ }
+ }
}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/crac/DNSManager.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/crac/DNSManager.java
new file mode 100644
index 000000000..4c1a6cd59
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/crac/DNSManager.java
@@ -0,0 +1,10 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package com.amazonaws.services.lambda.crac;
+
+class DNSManager {
+ static native void clearCache();
+}
\ No newline at end of file
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/UserFault.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/UserFault.java
index bc95af572..fc8eb005a 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/UserFault.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/UserFault.java
@@ -4,6 +4,8 @@
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.HashSet;
+import java.util.Set;
public final class UserFault extends RuntimeException {
private static final long serialVersionUID = -479308856905162038L;
@@ -65,6 +67,16 @@ public static String trace(Throwable t) {
* the same object for convenience.
*/
public static T filterStackTrace(T t) {
+ return filterStackTrace(t, new HashSet<>(), new HashSet<>());
+ }
+
+ private static T filterStackTrace(T t, Set visited, Set visitedSuppressed) {
+ if (visited.contains(t)) {
+ return t;
+ }
+
+ visited.add(t);
+
StackTraceElement[] trace = t.getStackTrace();
for (int i = 0; i < trace.length; i++) {
if (trace[i].getClassName().startsWith(packagePrefix)) {
@@ -78,12 +90,15 @@ public static T filterStackTrace(T t) {
Throwable cause = t.getCause();
if (cause != null) {
- filterStackTrace(cause);
+ filterStackTrace(cause, visited, visitedSuppressed);
}
Throwable[] suppressedExceptions = t.getSuppressed();
- for (Throwable suppressed : suppressedExceptions) {
- filterStackTrace(suppressed);
+ for(Throwable suppressed: suppressedExceptions) {
+ if (!visitedSuppressed.contains(suppressed)) {
+ visitedSuppressed.add(suppressed);
+ filterStackTrace(suppressed, visited, visitedSuppressed);
+ }
}
return t;
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/JniHelper.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/JniHelper.java
new file mode 100644
index 000000000..82586d272
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/JniHelper.java
@@ -0,0 +1,64 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+package com.amazonaws.services.lambda.runtime.api.client.runtimeapi;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JniHelper {
+
+ private static final String NATIVE_LIB_PATH = "/tmp/.libaws-lambda-jni.so";
+ private static final String NATIVE_CLIENT_JNI_PROPERTY = "com.amazonaws.services.lambda.runtime.api.client.runtimeapi.NativeClient.JNI";
+
+ /**
+ * Unpacks JNI library from the JAR to a temporary location and tries to load it using System.load()
+ * Implementation based on AWS CRT
+ * (ref. ...)
+ *
+ * @param libsToTry - array of native libraries to try
+ */
+ public static void load() {
+ String jniLib = System.getProperty(NATIVE_CLIENT_JNI_PROPERTY);
+ if (jniLib != null) {
+ System.load(jniLib);
+ } else {
+ String[] libsToTry = new String[]{
+ "libaws-lambda-jni.linux-x86_64.so",
+ "libaws-lambda-jni.linux-aarch_64.so",
+ "libaws-lambda-jni.linux_musl-x86_64.so",
+ "libaws-lambda-jni.linux_musl-aarch_64.so"
+ };
+ unpackAndLoad(libsToTry, NativeClient.class);
+ }
+ }
+
+ private static void unpackAndLoad(String[] libsToTry, Class clazz) {
+ List errorMessages = new ArrayList<>();
+ for (String libToTry : libsToTry) {
+ try (InputStream inputStream = clazz.getResourceAsStream(
+ Paths.get("/jni", libToTry).toString())) {
+ if (inputStream == null) {
+ throw new FileNotFoundException("Specified file not in the JAR: " + libToTry);
+ }
+ Files.copy(inputStream, Paths.get(NATIVE_LIB_PATH), StandardCopyOption.REPLACE_EXISTING);
+ System.load(NATIVE_LIB_PATH);
+ return;
+ } catch (UnsatisfiedLinkError | Exception e) {
+ errorMessages.add(e.getMessage());
+ }
+ }
+
+ for (int i = 0; i < libsToTry.length; ++i) {
+ System.err.println("Failed to load the native runtime interface client library " + libsToTry[i] +
+ ". Exception: " + errorMessages.get(i));
+ }
+ System.exit(-1);
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java
index a311ff00d..10e6bafd4 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java
@@ -5,14 +5,7 @@
package com.amazonaws.services.lambda.runtime.api.client.runtimeapi;
import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.InvocationRequest;
-
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.util.ArrayList;
-import java.util.List;
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.JniHelper;
import static com.amazonaws.services.lambda.runtime.api.client.runtimeapi.LambdaRuntimeApiClientImpl.USER_AGENT;
@@ -21,60 +14,11 @@
* interactions with the Runtime API.
*/
class NativeClient {
- private static final String NATIVE_LIB_PATH = "/tmp/.libaws-lambda-jni.so";
- public static final String NATIVE_CLIENT_JNI_PROPERTY = "com.amazonaws.services.lambda.runtime.api.client.runtimeapi.NativeClient.JNI";
static void init() {
- loadJNILib();
+ JniHelper.load();
initializeClient(USER_AGENT.getBytes());
}
-
- private static void loadJNILib() {
- String jniLib = System.getProperty(NATIVE_CLIENT_JNI_PROPERTY);
- if (jniLib != null) {
- System.load(jniLib);
- } else {
- String[] libsToTry = new String[]{
- "libaws-lambda-jni.linux-x86_64.so",
- "libaws-lambda-jni.linux-aarch_64.so",
- "libaws-lambda-jni.linux_musl-x86_64.so",
- "libaws-lambda-jni.linux_musl-aarch_64.so"
- };
- unpackAndLoadNativeLibrary(libsToTry);
- }
- }
-
-
- /**
- * Unpacks JNI library from the JAR to a temporary location and tries to load it using System.load()
- * Implementation based on AWS CRT
- * (ref. ...)
- *
- * @param libsToTry - array of native libraries to try
- */
- static void unpackAndLoadNativeLibrary(String[] libsToTry) {
-
- List errorMessages = new ArrayList<>();
- for (String libToTry : libsToTry) {
- try (InputStream inputStream = NativeClient.class.getResourceAsStream(
- Paths.get("/jni", libToTry).toString())) {
- if (inputStream == null) {
- throw new FileNotFoundException("Specified file not in the JAR: " + libToTry);
- }
- Files.copy(inputStream, Paths.get(NATIVE_LIB_PATH), StandardCopyOption.REPLACE_EXISTING);
- System.load(NATIVE_LIB_PATH);
- return;
- } catch (UnsatisfiedLinkError | Exception e) {
- errorMessages.add(e.getMessage());
- }
- }
-
- for (int i = 0; i < libsToTry.length; ++i) {
- System.err.println("Failed to load the native runtime interface client library " + libsToTry[i] +
- ". Exception: " + errorMessages.get(i));
- }
- System.exit(-1);
- }
-
+
static native void initializeClient(byte[] userAgent);
static native InvocationRequest next();
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.glibc b/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.glibc
index dd4fdb22e..1cfcfbb1d 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.glibc
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.glibc
@@ -53,9 +53,16 @@ RUN /usr/bin/c++ -c \
-I${JAVA_HOME}/include/linux \
-I ./deps/artifacts/include \
com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp -o com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o && \
+ /usr/bin/c++ -c \
+ -std=gnu++11 \
+ -fPIC \
+ -I${JAVA_HOME}/include \
+ -I${JAVA_HOME}/include/linux \
+ -I ./deps/artifacts/include \
+ com_amazonaws_services_lambda_crac_DNSManager.cpp -o com_amazonaws_services_lambda_crac_DNSManager.o && \
/usr/bin/c++ -shared \
-std=gnu++11 \
- -o aws-lambda-runtime-interface-client.so com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o \
+ -o aws-lambda-runtime-interface-client.so com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o com_amazonaws_services_lambda_crac_DNSManager.o \
-L ./deps/artifacts/lib64/ \
-L ./deps/artifacts/lib/ \
-laws-lambda-runtime \
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.musl b/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.musl
index e15f6adc5..64725c140 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.musl
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/Dockerfile.musl
@@ -54,9 +54,16 @@ RUN /usr/bin/c++ -c \
-I${JAVA_HOME}/include/linux \
-I ./deps/artifacts/include \
com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp -o com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o && \
+ /usr/bin/c++ -c \
+ -std=gnu++11 \
+ -fPIC \
+ -I${JAVA_HOME}/include \
+ -I${JAVA_HOME}/include/linux \
+ -I ./deps/artifacts/include \
+ com_amazonaws_services_lambda_crac_DNSManager.cpp -o com_amazonaws_services_lambda_crac_DNSManager.o && \
/usr/bin/c++ -shared \
-std=gnu++11 \
- -o aws-lambda-runtime-interface-client.so com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o \
+ -o aws-lambda-runtime-interface-client.so com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.o com_amazonaws_services_lambda_crac_DNSManager.o \
-L ./deps/artifacts/lib/ \
-laws-lambda-runtime \
-lcurl \
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/build-jni-lib.sh b/aws-lambda-java-runtime-interface-client/src/main/jni/build-jni-lib.sh
index 3b505e74d..b7dbb5a80 100755
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/build-jni-lib.sh
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/build-jni-lib.sh
@@ -51,10 +51,21 @@ function build_for_libc_arch() {
echo "multi-arch not requested, assuming this is a workaround to goofyness when docker buildx is enabled on Linux CI environments."
echo "enabling docker buildx often updates the docker api version, so assuming that docker cli is also too old to use --output type=tar, so doing alternative build-tag-run approach"
image_name="lambda-java-jni-lib-${libc_impl}-${arch}"
+
+ # GitHub actions is using dockerx build under the hood. We need to pass --load option to be able to run the image
+ # This args is NOT part of the classic docker build command, so we need to check against a GitHub Action env var not to make local build crash.
+ if [[ "${GITHUB_RUN_ID:+isset}" == "isset" ]]; then
+ EXTRA_LOAD_ARG="--load"
+ else
+ EXTRA_LOAD_ARG=""
+ fi
+
docker build --platform="${docker_platform}" \
-t "${image_name}" \
-f "${SRC_DIR}/Dockerfile.${libc_impl}" \
- --build-arg CURL_VERSION=${CURL_VERSION} "${SRC_DIR}"
+ --build-arg CURL_VERSION=${CURL_VERSION} "${SRC_DIR}" ${EXTRA_LOAD_ARG}
+
+ echo "Docker image has been successfully built"
docker run --rm --entrypoint /bin/cat "${image_name}" \
/src/aws-lambda-runtime-interface-client.so > "${artifact}"
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.cpp b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.cpp
new file mode 100644
index 000000000..ccf5481b9
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.cpp
@@ -0,0 +1,27 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+#include
+#include "macro.h"
+#include "com_amazonaws_services_lambda_crac_DNSManager.h"
+
+JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_crac_DNSManager_clearCache
+ (JNIEnv *env, jclass thisClass) {
+ jclass iNetAddressClass;
+ jclass concurrentMap;
+ jfieldID cacheFieldID;
+ jobject cacheObj;
+ jmethodID clearMethodID;
+ CHECK_EXCEPTION(env, iNetAddressClass = env->FindClass("java/net/InetAddress"));
+ CHECK_EXCEPTION(env, concurrentMap = env->FindClass("java/util/concurrent/ConcurrentMap"));
+ CHECK_EXCEPTION(env, cacheFieldID = env->GetStaticFieldID(iNetAddressClass, "cache", "Ljava/util/concurrent/ConcurrentMap;"));
+ CHECK_EXCEPTION(env, cacheObj = (jobject) env->GetStaticObjectField(iNetAddressClass, cacheFieldID));
+ CHECK_EXCEPTION(env, clearMethodID = env->GetMethodID(concurrentMap, "clear", "()V"));
+ CHECK_EXCEPTION(env, env->CallVoidMethod(cacheObj, clearMethodID));
+ return;
+
+ ERROR:
+ // we need to fail silently here
+ env->ExceptionClear();
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.h b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.h
new file mode 100644
index 000000000..f26639ba9
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_crac_DNSManager.h
@@ -0,0 +1,19 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+#include
+
+#ifndef _Included_com_amazonaws_services_lambda_crac_DNSManager
+#define _Included_com_amazonaws_services_lambda_crac_DNSManager
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_crac_DNSManager_clearCache
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp
index 02cfeb7e2..db71b8194 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp
@@ -1,27 +1,13 @@
/*
- * Copyright 2019-present Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- * http://aws.amazon.com/apache2.0
- *
- * or in the "license" file accompanying this file. This file is distributed
- * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
#include
+#include "macro.h"
#include "com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h"
#include "aws/lambda-runtime/runtime.h"
#include "aws/lambda-runtime/version.h"
-#define CHECK_EXCEPTION(env, expr) \
- expr; \
- if ((env)->ExceptionOccurred()) \
- goto ERROR;
-
static aws::lambda_runtime::runtime * CLIENT = nullptr;
static jint JNI_VERSION = JNI_VERSION_1_8;
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h
index 28a6f444a..27c636117 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h
@@ -1,3 +1,7 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
#include
#ifndef _Included_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/macro.h b/aws-lambda-java-runtime-interface-client/src/main/jni/macro.h
new file mode 100644
index 000000000..df5759afe
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/macro.h
@@ -0,0 +1,14 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+#ifndef _Included_macros
+#define _Included_macros
+
+#define CHECK_EXCEPTION(env, expr) \
+ expr; \
+ if ((env)->ExceptionOccurred()) \
+ goto ERROR;
+
+#endif
diff --git a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/ContextImplTest.java b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/ContextImplTest.java
index b81660730..bad72ea20 100644
--- a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/ContextImplTest.java
+++ b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/ContextImplTest.java
@@ -1,22 +1,35 @@
/*
- * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- */
-
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
package com.amazonaws.services.lambda.crac;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
import org.mockito.ArgumentMatchers;
import org.mockito.InOrder;
import org.mockito.Mockito;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.doThrow;
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.JniHelper;
+
+@DisabledOnOs(OS.MAC)
public class ContextImplTest {
private Resource throwsWithSuppressedException, noop, noop2, throwsException, throwCustomException;
+ @BeforeAll
+ public static void jniLoad() {
+ JniHelper.load();
+ }
+
@BeforeEach
public void setup() throws Exception {
diff --git a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/DNSCacheManagerTest.java b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/DNSCacheManagerTest.java
new file mode 100644
index 000000000..5eb6f749f
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/crac/DNSCacheManagerTest.java
@@ -0,0 +1,124 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package com.amazonaws.services.lambda.crac;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.JniHelper;
+
+import java.util.Map;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.lang.reflect.Field;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+@DisabledOnOs(OS.MAC)
+public class DNSCacheManagerTest {
+
+ static String CACHE_FIELD_NAME = "cache";
+
+ // this should have no effect, as the DNS cache is cleared explicitly in these tests
+ static {
+ java.security.Security.setProperty("networkaddress.cache.ttl" , "10000");
+ java.security.Security.setProperty("networkaddress.cache.negative.ttl" , "10000");
+ }
+
+ @BeforeAll
+ public static void jniLoad() {
+ JniHelper.load();
+ }
+
+ @BeforeEach
+ public void setup() {
+ Core.resetGlobalContext();
+ DNSManager.clearCache();
+ }
+
+ static class StatefulResource implements Resource {
+
+ int state = 0;
+
+ @Override
+ public void afterRestore(Context extends Resource> context) {
+ state += 1;
+ }
+
+ @Override
+ public void beforeCheckpoint(Context extends Resource> context) {
+ state += 2;
+ }
+
+ int getValue() {
+ return state;
+ }
+ }
+
+ @Test
+ public void positiveDnsCacheShouldBeEmpty() throws CheckpointException, RestoreException, UnknownHostException, ReflectiveOperationException {
+ int baselineDNSEntryCount = getDNSEntryCount();
+
+ StatefulResource resource = new StatefulResource();
+ Core.getGlobalContext().register(resource);
+
+ String[] hosts = {"www.stackoverflow.com", "www.amazon.com", "www.yahoo.com"};
+ for(String singleHost : hosts) {
+ InetAddress address = InetAddress.getByName(singleHost);
+ }
+ // n hosts -> n DNS entries
+ assertEquals(hosts.length, getDNSEntryCount() - baselineDNSEntryCount);
+
+ // this should call the native static method clearDNSCache
+ Core.getGlobalContext().beforeCheckpoint(null);
+
+ // cache should be cleared
+ assertEquals(0, getDNSEntryCount());
+ }
+
+ @Test
+ public void negativeDnsCacheShouldBeEmpty() throws CheckpointException, RestoreException, UnknownHostException, ReflectiveOperationException {
+ int baselineDNSEntryCount = getDNSEntryCount();
+
+ StatefulResource resource = new StatefulResource();
+ Core.getGlobalContext().register(resource);
+
+ String invalidHost = "not.a.valid.host";
+ try {
+ InetAddress address = InetAddress.getByName(invalidHost);
+ fail();
+ } catch(UnknownHostException uhe) {
+ // this is actually fine
+ }
+
+ // 1 host -> 1 DNS entry
+ assertEquals(1, getDNSEntryCount() - baselineDNSEntryCount);
+
+ // this should the native static method clearDNSCache
+ Core.getGlobalContext().beforeCheckpoint(null);
+
+ // cache should be cleared
+ assertEquals(0, getDNSEntryCount());
+ }
+
+ // helper functions to access the cache via reflection (see maven-surefire-plugin command args)
+ protected static Map, ?> getDNSCache() throws ReflectiveOperationException {
+ Class klass = InetAddress.class;
+ Field acf = klass.getDeclaredField(CACHE_FIELD_NAME);
+ acf.setAccessible(true);
+ Object addressCache = acf.get(null);
+ return (Map, ?>) acf.get(addressCache);
+ }
+
+ protected static int getDNSEntryCount() throws ReflectiveOperationException {
+ Map, ?> cache = getDNSCache();
+ return cache.size();
+ }
+}
diff --git a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/UserFaultTest.java b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/UserFaultTest.java
index 9e88024b0..5a57e6e03 100644
--- a/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/UserFaultTest.java
+++ b/aws-lambda-java-runtime-interface-client/src/test/java/com/amazonaws/services/lambda/runtime/api/client/UserFaultTest.java
@@ -84,4 +84,44 @@ public void testSuppressedExceptionsAreIncluded() {
assertTrue(reportableUserFault.contains("Suppressed: java.lang.RuntimeException: error 2"), "Suppressed error 2 missing in reported UserFault");
}
}
+
+ @Test
+ public void testCircularExceptionReference() {
+ RuntimeException e1 = new RuntimeException();
+ RuntimeException e2 = new RuntimeException(e1);
+ e1.initCause(e2);
+
+ try {
+ throw e2;
+ } catch (Exception e) {
+ String stackTrace = UserFault.trace(e);
+ String expectedStackTrace = "java.lang.RuntimeException: java.lang.RuntimeException\n" +
+ "Caused by: java.lang.RuntimeException\n" +
+ "Caused by: [CIRCULAR REFERENCE: java.lang.RuntimeException: java.lang.RuntimeException]\n";
+
+ assertEquals(expectedStackTrace, stackTrace);
+ }
+ }
+
+ @Test
+ public void testCircularSuppressedExceptionReference() {
+ RuntimeException e1 = new RuntimeException("Primary Exception");
+ RuntimeException e2 = new RuntimeException(e1);
+ RuntimeException e3 = new RuntimeException("Exception with suppressed");
+
+ e1.addSuppressed(e2);
+ e3.addSuppressed(e2);
+
+ try {
+ throw e3;
+ } catch (Exception e) {
+ String stackTrace = UserFault.trace(e);
+ String expectedStackTrace = "java.lang.RuntimeException: Exception with suppressed\n" +
+ "\tSuppressed: java.lang.RuntimeException: java.lang.RuntimeException: Primary Exception\n" +
+ "\tCaused by: java.lang.RuntimeException: Primary Exception\n" +
+ "\t\tSuppressed: [CIRCULAR REFERENCE: java.lang.RuntimeException: java.lang.RuntimeException: Primary Exception]\n";
+
+ assertEquals(expectedStackTrace, stackTrace);
+ }
+ }
}
diff --git a/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.alpine.yml b/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.alpine.yml
index 4f8caf39d..cdc27a655 100644
--- a/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.alpine.yml
+++ b/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.alpine.yml
@@ -44,7 +44,7 @@ phases:
- (cd aws-lambda-java-events && mvn install)
# Install serialization (dependency of RIC)
- (cd aws-lambda-java-serialization && mvn install)
- - (cd aws-lambda-java-runtime-interface-client && mvn install)
+ - (cd aws-lambda-java-runtime-interface-client && mvn install -DargLineForReflectionTestOnly="")
- (cd aws-lambda-java-runtime-interface-client/test/integration/test-handler && mvn install)
- export IMAGE_TAG="java-${OS_DISTRIBUTION}-${DISTRO_VERSION}:${RUNTIME_VERSION}"
- echo "Extracting and including Runtime Interface Emulator"
diff --git a/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazoncorretto.yml b/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazoncorretto.yml
index fd45aabb8..67dd7617d 100644
--- a/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazoncorretto.yml
+++ b/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazoncorretto.yml
@@ -43,7 +43,7 @@ phases:
- (cd aws-lambda-java-events && mvn install)
# Install serialization (dependency of RIC)
- (cd aws-lambda-java-serialization && mvn install)
- - (cd aws-lambda-java-runtime-interface-client && mvn install)
+ - (cd aws-lambda-java-runtime-interface-client && mvn install -DargLineForReflectionTestOnly="")
- (cd aws-lambda-java-runtime-interface-client/test/integration/test-handler && mvn install)
- export IMAGE_TAG="java-${OS_DISTRIBUTION}-${DISTRO_VERSION}:${RUNTIME_VERSION}"
- echo "Extracting and including Runtime Interface Emulator"
diff --git a/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazonlinux.1.yml b/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazonlinux.1.yml
index 197e97249..04c486a88 100644
--- a/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazonlinux.1.yml
+++ b/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazonlinux.1.yml
@@ -38,7 +38,7 @@ phases:
- (cd aws-lambda-java-events && mvn install)
# Install serialization (dependency of RIC)
- (cd aws-lambda-java-serialization && mvn install)
- - (cd aws-lambda-java-runtime-interface-client && mvn install -DmultiArch=false)
+ - (cd aws-lambda-java-runtime-interface-client && mvn install -DmultiArch=false -DargLineForReflectionTestOnly="")
- (cd aws-lambda-java-runtime-interface-client/test/integration/test-handler && mvn install)
- export IMAGE_TAG="java-${OS_DISTRIBUTION}-${DISTRO_VERSION}:${RUNTIME_VERSION}"
- echo "Extracting and including Runtime Interface Emulator"
diff --git a/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazonlinux.2.yml b/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazonlinux.2.yml
index 75b816e8b..8222bb41a 100644
--- a/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazonlinux.2.yml
+++ b/aws-lambda-java-runtime-interface-client/test/integration/codebuild/buildspec.os.amazonlinux.2.yml
@@ -42,7 +42,7 @@ phases:
- (cd aws-lambda-java-events && mvn install)
# Install serialization (dependency of RIC)
- (cd aws-lambda-java-serialization && mvn install)
- - (cd aws-lambda-java-runtime-interface-client && mvn install)
+ - (cd aws-lambda-java-runtime-interface-client && mvn install -DargLineForReflectionTestOnly="")
- (cd aws-lambda-java-runtime-interface-client/test/integration/test-handler && mvn install)
- export IMAGE_TAG="java-${OS_DISTRIBUTION}-${DISTRO_VERSION}:${RUNTIME_VERSION}"
- echo "Extracting and including Runtime Interface Emulator"
diff --git a/aws-lambda-java-runtime-interface-client/test/integration/test-handler/pom.xml b/aws-lambda-java-runtime-interface-client/test/integration/test-handler/pom.xml
index dd69c8e03..40c79fe98 100644
--- a/aws-lambda-java-runtime-interface-client/test/integration/test-handler/pom.xml
+++ b/aws-lambda-java-runtime-interface-client/test/integration/test-handler/pom.xml
@@ -15,7 +15,7 @@
com.amazonaws
aws-lambda-java-runtime-interface-client
- 2.5.0
+ 2.5.1
From c0b4f60a8aaa70a8a79c7590202ab24225c6a79d Mon Sep 17 00:00:00 2001
From: Shashank <48707265+ShashankAWS@users.noreply.github.com>
Date: Wed, 10 Jul 2024 19:04:13 +0530
Subject: [PATCH 004/103] Added event class MskFirehoseEvent.java for Firehose
Lambda transformation when MSK is the source (#490)
* Create MskFirehoseEvent.java
* Create MSKFirehoseResponse.java
---
aws-lambda-java-events/README.md | 2 +
.../runtime/events/MSKFirehoseEvent.java | 51 ++++++++++++++++
.../runtime/events/MSKFirehoseResponse.java | 61 +++++++++++++++++++
.../lambda/runtime/tests/EventLoader.java | 4 ++
.../lambda/runtime/tests/EventLoaderTest.java | 13 ++++
.../test/resources/msk_firehose_event.json | 18 ++++++
.../java/example/MSKFirehoseEventHandler.java | 39 ++++++++++++
.../example/MSKFirehoseEventHandlerTest.java | 32 ++++++++++
.../src/test/resources/event.json | 18 ++++++
9 files changed, 238 insertions(+)
create mode 100644 aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/MSKFirehoseEvent.java
create mode 100644 aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/MSKFirehoseResponse.java
create mode 100644 aws-lambda-java-tests/src/test/resources/msk_firehose_event.json
create mode 100644 samples/msk-firehose-event-handler/src/main/java/example/MSKFirehoseEventHandler.java
create mode 100644 samples/msk-firehose-event-handler/src/test/java/example/MSKFirehoseEventHandlerTest.java
create mode 100644 samples/msk-firehose-event-handler/src/test/resources/event.json
diff --git a/aws-lambda-java-events/README.md b/aws-lambda-java-events/README.md
index 8c60b3a23..aaa2a38fe 100644
--- a/aws-lambda-java-events/README.md
+++ b/aws-lambda-java-events/README.md
@@ -44,6 +44,8 @@
* `KinesisFirehoseEvent`
* `LambdaDestinationEvent`
* `LexEvent`
+* `MSKFirehoseEvent`
+* `MSKFirehoseResponse`
* `RabbitMQEvent`
* `S3BatchEvent`
* `S3BatchResponse`
diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/MSKFirehoseEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/MSKFirehoseEvent.java
new file mode 100644
index 000000000..1af40ce43
--- /dev/null
+++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/MSKFirehoseEvent.java
@@ -0,0 +1,51 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package com.amazonaws.services.lambda.runtime.events;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder(setterPrefix = "with")
+@NoArgsConstructor
+@AllArgsConstructor
+
+public class MSKFirehoseEvent {
+
+ private String invocationId;
+
+ private String deliveryStreamArn;
+
+ private String sourceMSKArn;
+
+ private String region;
+
+ private List records;
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class Record {
+
+ private ByteBuffer kafkaRecordValue;
+
+ private String recordId;
+
+ private Long approximateArrivalEpoch;
+
+ private Long approximateArrivalTimestamp;
+
+ private Map mskRecordMetadata;
+
+ }
+}
diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/MSKFirehoseResponse.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/MSKFirehoseResponse.java
new file mode 100644
index 000000000..18b5aa13f
--- /dev/null
+++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/MSKFirehoseResponse.java
@@ -0,0 +1,61 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package com.amazonaws.services.lambda.runtime.events;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * Response model for Amazon Data Firehose Lambda transformation with MSK as a source.
+ * [+] Amazon Data Firehose Data Transformation - Data Transformation and Status Model - ...
+ * OK : Indicates that processing of this item succeeded.
+ * ProcessingFailed : Indicate that the processing of this item failed.
+ * Dropped : Indicates that this item should be silently dropped
+ */
+
+@Data
+@Builder(setterPrefix = "with")
+@NoArgsConstructor
+@AllArgsConstructor
+
+public class MSKFirehoseResponse {
+
+ public enum Result {
+
+ /**
+ * Indicates that processing of this item succeeded.
+ */
+ Ok,
+
+ /**
+ * Indicate that the processing of this item failed
+ */
+ ProcessingFailed,
+
+ /**
+ * Indicates that this item should be silently dropped
+ */
+ Dropped
+ }
+ public List records;
+
+ @Data
+ @NoArgsConstructor
+ @Builder(setterPrefix = "with")
+ @AllArgsConstructor
+
+ public static class Record {
+ public String recordId;
+ public Result result;
+ public ByteBuffer kafkaRecordValue;
+
+ }
+}
diff --git a/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java b/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
index aa600749c..601d2f3fb 100644
--- a/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
+++ b/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
@@ -89,6 +89,10 @@ public static LexEvent loadLexEvent(String filename) {
return loadEvent(filename, LexEvent.class);
}
+ public static MSKFirehoseEvent loadMSKFirehoseEvent(String filename) {
+ return loadEvent(filename, MSKFirehoseEvent.class);
+ }
+
public static S3Event loadS3Event(String filename) {
return loadEvent(filename, S3Event.class);
}
diff --git a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java
index 1c9d17e16..12dc436c7 100644
--- a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java
+++ b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java
@@ -118,6 +118,19 @@ public void testLoadKinesisFirehoseEvent() {
assertThat(event.getRecords().get(0).getData().array()).asString().isEqualTo("Hello, this is a test 123.");
}
+ @Test
+ public void testLoadMSKFirehoseEvent() {
+ MSKFirehoseEvent event = EventLoader.loadMSKFirehoseEvent("msk_firehose_event.json");
+
+ assertThat(event).isNotNull();
+ assertThat(event.getSourceMSKArn()).isEqualTo("arn:aws:kafka:EXAMPLE");
+ assertThat(event.getDeliveryStreamArn()).isEqualTo("arn:aws:firehose:EXAMPLE");
+ assertThat(event.getRecords()).hasSize(1);
+ assertThat(event.getRecords().get(0).getKafkaRecordValue().array()).asString().isEqualTo("{\"Name\":\"Hello World\"}");
+ assertThat(event.getRecords().get(0).getApproximateArrivalTimestamp()).asString().isEqualTo("1716369573887");
+ assertThat(event.getRecords().get(0).getMskRecordMetadata()).asString().isEqualTo("{offset=0, partitionId=1, approximateArrivalTimestamp=1716369573887}");
+ }
+
@Test
public void testLoadS3Event() {
S3Event event = EventLoader.loadS3Event("s3_event.json");
diff --git a/aws-lambda-java-tests/src/test/resources/msk_firehose_event.json b/aws-lambda-java-tests/src/test/resources/msk_firehose_event.json
new file mode 100644
index 000000000..6b839912d
--- /dev/null
+++ b/aws-lambda-java-tests/src/test/resources/msk_firehose_event.json
@@ -0,0 +1,18 @@
+{
+ "invocationId": "12345621-4787-0000-a418-36e56Example",
+ "sourceMSKArn": "arn:aws:kafka:EXAMPLE",
+ "deliveryStreamArn": "arn:aws:firehose:EXAMPLE",
+ "region": "us-east-1",
+ "records": [
+ {
+ "recordId": "00000000000000000000000000000000000000000000000000000000000000",
+ "approximateArrivalTimestamp": 1716369573887,
+ "mskRecordMetadata": {
+ "offset": "0",
+ "partitionId": "1",
+ "approximateArrivalTimestamp": 1716369573887
+ },
+ "kafkaRecordValue": "eyJOYW1lIjoiSGVsbG8gV29ybGQifQ=="
+ }
+ ]
+}
diff --git a/samples/msk-firehose-event-handler/src/main/java/example/MSKFirehoseEventHandler.java b/samples/msk-firehose-event-handler/src/main/java/example/MSKFirehoseEventHandler.java
new file mode 100644
index 000000000..f5e513496
--- /dev/null
+++ b/samples/msk-firehose-event-handler/src/main/java/example/MSKFirehoseEventHandler.java
@@ -0,0 +1,39 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package example;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.amazonaws.services.lambda.runtime.events.MSKFirehoseResponse;
+import com.amazonaws.services.lambda.runtime.events.MSKFirehoseEvent;
+import org.json.JSONObject;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A sample MSKFirehoseEvent handler
+ * For more information see the developer guide - ...
+ */
+public class MSKFirehoseEventHandler implements RequestHandler {
+
+ @Override
+ public MSKFirehoseResponse handleRequest(MSKFirehoseEvent MSKFirehoseEvent, Context context) {
+ List records = new ArrayList<>();
+
+ for (MSKFirehoseEvent.Record record : MSKFirehoseEvent.getRecords()) {
+ String recordData = new String(record.getKafkaRecordValue().array());
+ // Your business logic
+ JSONObject jsonObject = new JSONObject(recordData);
+ records.add(new MSKFirehoseResponse.Record(record.getRecordId(), MSKFirehoseResponse.Result.Ok, encode(jsonObject.toString())));
+ }
+ return new MSKFirehoseResponse(records);
+ }
+ private ByteBuffer encode(String content) {
+ return ByteBuffer.wrap(content.getBytes());
+ }
+}
diff --git a/samples/msk-firehose-event-handler/src/test/java/example/MSKFirehoseEventHandlerTest.java b/samples/msk-firehose-event-handler/src/test/java/example/MSKFirehoseEventHandlerTest.java
new file mode 100644
index 000000000..77223e516
--- /dev/null
+++ b/samples/msk-firehose-event-handler/src/test/java/example/MSKFirehoseEventHandlerTest.java
@@ -0,0 +1,32 @@
+/*
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: Apache-2.0
+*/
+
+package example;
+
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.tests.annotations.Event;
+import com.amazonaws.services.lambda.runtime.events.MSKFirehoseEvent;
+import com.amazonaws.services.lambda.runtime.events.MSKFirehoseResponse;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.params.ParameterizedTest;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+public class MSKFirehoseEventHandlerTest {
+
+ private Context context; // intentionally null as it's not used in the test
+
+ @ParameterizedTest
+ @Event(value = "event.json", type = MSKFirehoseEvent.class)
+ public void testEventHandler(MSKFirehoseEvent event) {
+ MSKFirehoseEventHandler Sample = new MSKFirehoseEventHandler();
+ MSKFirehoseResponse response = Sample.handleRequest(event, context);
+
+ String expectedString = "{\"Name\":\"Hello World\"}";
+ MSKFirehoseResponse.Record firstRecord = response.getRecords().get(0);
+ Assertions.assertEquals(expectedString, UTF_8.decode(firstRecord.getKafkaRecordValue()).toString());
+ Assertions.assertEquals(MSKFirehoseResponse.Result.Ok, firstRecord.getResult());
+ }
+}
diff --git a/samples/msk-firehose-event-handler/src/test/resources/event.json b/samples/msk-firehose-event-handler/src/test/resources/event.json
new file mode 100644
index 000000000..91c4b4203
--- /dev/null
+++ b/samples/msk-firehose-event-handler/src/test/resources/event.json
@@ -0,0 +1,18 @@
+{
+ "invocationId": "12345621-4787-0000-a418-36e56Example",
+ "sourceMSKArn": "",
+ "deliveryStreamArn": "",
+ "region": "us-east-1",
+ "records": [
+ {
+ "recordId": "00000000000000000000000000000000000000000000000000000000000000",
+ "approximateArrivalTimestamp": 1716369573887,
+ "mskRecordMetadata": {
+ "offset": "0",
+ "partitionId": "1",
+ "approximateArrivalTimestamp": 1716369573887
+ },
+ "kafkaRecordValue": "eyJOYW1lIjoiSGVsbG8gV29ybGQifQ=="
+ }
+ ]
+}
From aa9686fcbbf8fe032fc628c73050da16e9055732 Mon Sep 17 00:00:00 2001
From: Mark Sailes
Date: Thu, 11 Jul 2024 11:56:44 +0100
Subject: [PATCH 005/103] CloudWatch alarm events
---
aws-lambda-java-events/README.md | 2 +
aws-lambda-java-events/pom.xml | 2 +
.../events/CloudWatchCompositeAlarmEvent.java | 70 +++++++++
.../events/CloudWatchMetricAlarmEvent.java | 99 +++++++++++++
.../lambda/runtime/tests/EventLoader.java | 8 +
.../lambda/runtime/tests/EventLoaderTest.java | 138 +++++++++++++++++-
.../resources/cloudwatch_composite_alarm.json | 30 ++++
.../resources/cloudwatch_metric_alarm.json | 42 ++++++
8 files changed, 389 insertions(+), 2 deletions(-)
create mode 100644 aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CloudWatchCompositeAlarmEvent.java
create mode 100644 aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CloudWatchMetricAlarmEvent.java
create mode 100644 aws-lambda-java-tests/src/test/resources/cloudwatch_composite_alarm.json
create mode 100644 aws-lambda-java-tests/src/test/resources/cloudwatch_metric_alarm.json
diff --git a/aws-lambda-java-events/README.md b/aws-lambda-java-events/README.md
index aaa2a38fe..92bea0ea6 100644
--- a/aws-lambda-java-events/README.md
+++ b/aws-lambda-java-events/README.md
@@ -16,7 +16,9 @@
* `AppSyncLambdaAuthorizerResponse`
* `CloudFormationCustomResourceEvent`
* `CloudFrontEvent`
+* `CloudWatchCompositeAlarmEvent`
* `CloudWatchLogsEvent`
+* `CloudWatchMetricAlarmEvent`
* `CodeCommitEvent`
* `CognitoEvent`
* `CognitoUserPoolCreateAuthChallengeEvent`
diff --git a/aws-lambda-java-events/pom.xml b/aws-lambda-java-events/pom.xml
index 2c7442c06..4abea0f87 100644
--- a/aws-lambda-java-events/pom.xml
+++ b/aws-lambda-java-events/pom.xml
@@ -35,6 +35,8 @@
1.8
1.8
1.18.22
+ UTF-8
+ UTF-8
diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CloudWatchCompositeAlarmEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CloudWatchCompositeAlarmEvent.java
new file mode 100644
index 000000000..d4090b55b
--- /dev/null
+++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CloudWatchCompositeAlarmEvent.java
@@ -0,0 +1,70 @@
+package com.amazonaws.services.lambda.runtime.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * Represents an CloudWatch Composite Alarm event. This event occurs when a composite alarm is triggered.
+ *
+ * @see Using Amazon CloudWatch alarms
+ */
+@Data
+@Builder(setterPrefix = "with")
+@NoArgsConstructor
+@AllArgsConstructor
+public class CloudWatchCompositeAlarmEvent {
+ private String source;
+ private String alarmArn;
+ private String accountId;
+ private String time;
+ private String region;
+ private AlarmData alarmData;
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class AlarmData {
+ private String alarmName;
+ private State state;
+ private PreviousState previousState;
+ private Configuration configuration;
+ }
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class State {
+ private String value;
+ private String reason;
+ private String reasonData;
+ private String timestamp;
+ }
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class PreviousState {
+ private String value;
+ private String reason;
+ private String reasonData;
+ private String timestamp;
+ private String actionsSuppressedBy;
+ private String actionsSuppressedReason;
+ }
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class Configuration {
+ private String alarmRule;
+ private String actionsSuppressor;
+ private Integer actionsSuppressorWaitPeriod;
+ private Integer actionsSuppressorExtensionPeriod;
+ }
+}
diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CloudWatchMetricAlarmEvent.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CloudWatchMetricAlarmEvent.java
new file mode 100644
index 000000000..2b5f503c3
--- /dev/null
+++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/CloudWatchMetricAlarmEvent.java
@@ -0,0 +1,99 @@
+package com.amazonaws.services.lambda.runtime.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents an CloudWatch Metric Alarm event. This event occurs when a metric alarm is triggered.
+ *
+ * @see Using Amazon CloudWatch alarms
+ */
+@Data
+@Builder(setterPrefix = "with")
+@NoArgsConstructor
+@AllArgsConstructor
+public class CloudWatchMetricAlarmEvent {
+ private String source;
+ private String alarmArn;
+ private String accountId;
+ private String time;
+ private String region;
+ private AlarmData alarmData;
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class AlarmData {
+ private String alarmName;
+ private State state;
+ private PreviousState previousState;
+ private Configuration configuration;
+ }
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class State {
+ private String value;
+ private String reason;
+ private String timestamp;
+ }
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class PreviousState {
+ private String value;
+ private String reason;
+ private String reasonData;
+ private String timestamp;
+ }
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class Configuration {
+ private String description;
+ private List metrics;
+ }
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class Metric {
+ private String id;
+ private MetricStat metricStat;
+ private Boolean returnData;
+ }
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class MetricStat {
+ private MetricDetail metric;
+ private Integer period;
+ private String stat;
+ private String unit;
+ }
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class MetricDetail {
+ private String namespace;
+ private String name;
+ private Map dimensions;
+ }
+}
diff --git a/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java b/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
index 601d2f3fb..778122673 100644
--- a/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
+++ b/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
@@ -45,10 +45,18 @@ public static CloudFrontEvent loadCloudFrontEvent(String filename) {
return loadEvent(filename, CloudFrontEvent.class);
}
+ public static CloudWatchCompositeAlarmEvent loadCloudWatchCompositeAlarmEvent(String filename) {
+ return loadEvent(filename, CloudWatchCompositeAlarmEvent.class);
+ }
+
public static CloudWatchLogsEvent loadCloudWatchLogsEvent(String filename) {
return loadEvent(filename, CloudWatchLogsEvent.class);
}
+ public static CloudWatchMetricAlarmEvent loadCloudWatchMetricAlarmEvent(String filename) {
+ return loadEvent(filename, CloudWatchMetricAlarmEvent.class);
+ }
+
public static CodeCommitEvent loadCodeCommitEvent(String filename) {
return loadEvent(filename, CodeCommitEvent.class);
}
diff --git a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java
index 12dc436c7..4aa920f8c 100644
--- a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java
+++ b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/EventLoaderTest.java
@@ -1,6 +1,38 @@
/* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. */
package com.amazonaws.services.lambda.runtime.tests;
+import com.amazonaws.services.lambda.runtime.events.APIGatewayCustomAuthorizerEvent;
+import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.APIGatewayV2CustomAuthorizerEvent;
+import com.amazonaws.services.lambda.runtime.events.APIGatewayV2HTTPEvent;
+import com.amazonaws.services.lambda.runtime.events.ActiveMQEvent;
+import com.amazonaws.services.lambda.runtime.events.ApplicationLoadBalancerRequestEvent;
+import com.amazonaws.services.lambda.runtime.events.CloudFormationCustomResourceEvent;
+import com.amazonaws.services.lambda.runtime.events.CloudFrontEvent;
+import com.amazonaws.services.lambda.runtime.events.CloudWatchCompositeAlarmEvent;
+import com.amazonaws.services.lambda.runtime.events.CloudWatchCompositeAlarmEvent.AlarmData;
+import com.amazonaws.services.lambda.runtime.events.CloudWatchCompositeAlarmEvent.Configuration;
+import com.amazonaws.services.lambda.runtime.events.CloudWatchCompositeAlarmEvent.PreviousState;
+import com.amazonaws.services.lambda.runtime.events.CloudWatchCompositeAlarmEvent.State;
+import com.amazonaws.services.lambda.runtime.events.CloudWatchLogsEvent;
+import com.amazonaws.services.lambda.runtime.events.CloudWatchMetricAlarmEvent;
+import com.amazonaws.services.lambda.runtime.events.CodeCommitEvent;
+import com.amazonaws.services.lambda.runtime.events.CognitoUserPoolPreTokenGenerationEventV2;
+import com.amazonaws.services.lambda.runtime.events.ConfigEvent;
+import com.amazonaws.services.lambda.runtime.events.ConnectEvent;
+import com.amazonaws.services.lambda.runtime.events.DynamodbEvent;
+import com.amazonaws.services.lambda.runtime.events.KafkaEvent;
+import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
+import com.amazonaws.services.lambda.runtime.events.KinesisFirehoseEvent;
+import com.amazonaws.services.lambda.runtime.events.LambdaDestinationEvent;
+import com.amazonaws.services.lambda.runtime.events.LexEvent;
+import com.amazonaws.services.lambda.runtime.events.MSKFirehoseEvent;
+import com.amazonaws.services.lambda.runtime.events.RabbitMQEvent;
+import com.amazonaws.services.lambda.runtime.events.S3Event;
+import com.amazonaws.services.lambda.runtime.events.SNSEvent;
+import com.amazonaws.services.lambda.runtime.events.SQSEvent;
+import com.amazonaws.services.lambda.runtime.events.ScheduledEvent;
+import com.amazonaws.services.lambda.runtime.events.SecretsManagerRotationEvent;
import com.amazonaws.services.lambda.runtime.events.models.dynamodb.AttributeValue;
import com.amazonaws.services.lambda.runtime.events.models.dynamodb.Record;
import com.amazonaws.services.lambda.runtime.events.models.dynamodb.StreamRecord;
@@ -15,8 +47,6 @@
import static java.time.Instant.ofEpochSecond;
import static org.assertj.core.api.Assertions.*;
-import com.amazonaws.services.lambda.runtime.events.*;
-
public class EventLoaderTest {
@Test
@@ -389,4 +419,108 @@ public void testLoadCognitoUserPoolPreTokenGenerationEventV2() {
String[] requestScopes = request.getScopes();
assertThat("aws.cognito.signin.user.admin").isEqualTo(requestScopes[0]);
}
+
+ @Test
+ public void testCloudWatchCompositeAlarmEvent() {
+ CloudWatchCompositeAlarmEvent event = EventLoader.loadCloudWatchCompositeAlarmEvent("cloudwatch_composite_alarm.json");
+ assertThat(event).isNotNull();
+ assertThat(event)
+ .returns("aws.cloudwatch", from(CloudWatchCompositeAlarmEvent::getSource))
+ .returns("arn:aws:cloudwatch:us-east-1:111122223333:alarm:SuppressionDemo.Main", from(CloudWatchCompositeAlarmEvent::getAlarmArn))
+ .returns("111122223333", from(CloudWatchCompositeAlarmEvent::getAccountId))
+ .returns("2023-08-04T12:56:46.138+0000", from(CloudWatchCompositeAlarmEvent::getTime))
+ .returns("us-east-1", from(CloudWatchCompositeAlarmEvent::getRegion));
+
+ AlarmData alarmData = event.getAlarmData();
+ assertThat(alarmData).isNotNull();
+ assertThat(alarmData)
+ .returns("CompositeDemo.Main", from(AlarmData::getAlarmName));
+
+ State state = alarmData.getState();
+ assertThat(state).isNotNull();
+ assertThat(state)
+ .returns("ALARM", from(State::getValue))
+ .returns("arn:aws:cloudwatch:us-east-1:111122223333:alarm:CompositeDemo.FirstChild transitioned to ALARM at Friday 04 August, 2023 12:54:46 UTC", from(State::getReason))
+ .returns("{\"triggeringAlarms\":[{\"arn\":\"arn:aws:cloudwatch:us-east-1:111122223333:alarm:CompositeDemo.FirstChild\",\"state\":{\"value\":\"ALARM\",\"timestamp\":\"2023-08-04T12:54:46.138+0000\"}}]}", from(State::getReasonData))
+ .returns("2023-08-04T12:56:46.138+0000", from(State::getTimestamp));
+
+ PreviousState previousState = alarmData.getPreviousState();
+ assertThat(previousState).isNotNull();
+ assertThat(previousState)
+ .returns("ALARM", from(PreviousState::getValue))
+ .returns("arn:aws:cloudwatch:us-east-1:111122223333:alarm:CompositeDemo.FirstChild transitioned to ALARM at Friday 04 August, 2023 12:54:46 UTC", from(PreviousState::getReason))
+ .returns("{\"triggeringAlarms\":[{\"arn\":\"arn:aws:cloudwatch:us-east-1:111122223333:alarm:CompositeDemo.FirstChild\",\"state\":{\"value\":\"ALARM\",\"timestamp\":\"2023-08-04T12:54:46.138+0000\"}}]}", from(PreviousState::getReasonData))
+ .returns("2023-08-04T12:54:46.138+0000", from(PreviousState::getTimestamp))
+ .returns("WaitPeriod", from(PreviousState::getActionsSuppressedBy))
+ .returns("Actions suppressed by WaitPeriod", from(PreviousState::getActionsSuppressedReason));
+
+ Configuration configuration = alarmData.getConfiguration();
+ assertThat(configuration).isNotNull();
+ assertThat(configuration)
+ .returns("ALARM(CompositeDemo.FirstChild) OR ALARM(CompositeDemo.SecondChild)", from(Configuration::getAlarmRule))
+ .returns("CompositeDemo.ActionsSuppressor", from(Configuration::getActionsSuppressor))
+ .returns(120, from(Configuration::getActionsSuppressorWaitPeriod))
+ .returns(180, from(Configuration::getActionsSuppressorExtensionPeriod));
+ }
+
+ @Test
+ public void testCloudWatchMetricAlarmEvent() {
+ CloudWatchMetricAlarmEvent event = EventLoader.loadCloudWatchMetricAlarmEvent("cloudwatch_metric_alarm.json");
+ assertThat(event).isNotNull();
+ assertThat(event)
+ .returns("aws.cloudwatch", from(CloudWatchMetricAlarmEvent::getSource))
+ .returns("arn:aws:cloudwatch:us-east-1:444455556666:alarm:lambda-demo-metric-alarm", from(CloudWatchMetricAlarmEvent::getAlarmArn))
+ .returns("444455556666", from(CloudWatchMetricAlarmEvent::getAccountId))
+ .returns("2023-08-04T12:36:15.490+0000", from(CloudWatchMetricAlarmEvent::getTime))
+ .returns("us-east-1", from(CloudWatchMetricAlarmEvent::getRegion));
+
+ CloudWatchMetricAlarmEvent.AlarmData alarmData = event.getAlarmData();
+ assertThat(alarmData).isNotNull();
+ assertThat(alarmData)
+ .returns("lambda-demo-metric-alarm", from(CloudWatchMetricAlarmEvent.AlarmData::getAlarmName));
+
+ CloudWatchMetricAlarmEvent.State state = alarmData.getState();
+ assertThat(state).isNotNull();
+ assertThat(state)
+ .returns("ALARM", from(CloudWatchMetricAlarmEvent.State::getValue))
+ .returns("test", from(CloudWatchMetricAlarmEvent.State::getReason))
+ .returns("2023-08-04T12:36:15.490+0000", from(CloudWatchMetricAlarmEvent.State::getTimestamp));
+
+ CloudWatchMetricAlarmEvent.PreviousState previousState = alarmData.getPreviousState();
+ assertThat(previousState).isNotNull();
+ assertThat(previousState)
+ .returns("INSUFFICIENT_DATA", from(CloudWatchMetricAlarmEvent.PreviousState::getValue))
+ .returns("Insufficient Data: 5 datapoints were unknown.", from(CloudWatchMetricAlarmEvent.PreviousState::getReason))
+ .returns("{\"version\":\"1.0\",\"queryDate\":\"2023-08-04T12:31:29.591+0000\",\"statistic\":\"Average\",\"period\":60,\"recentDatapoints\":[],\"threshold\":5.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2023-08-04T12:30:00.000+0000\"},{\"timestamp\":\"2023-08-04T12:29:00.000+0000\"},{\"timestamp\":\"2023-08-04T12:28:00.000+0000\"},{\"timestamp\":\"2023-08-04T12:27:00.000+0000\"},{\"timestamp\":\"2023-08-04T12:26:00.000+0000\"}]}", from(CloudWatchMetricAlarmEvent.PreviousState::getReasonData))
+ .returns("2023-08-04T12:31:29.595+0000", from(CloudWatchMetricAlarmEvent.PreviousState::getTimestamp));
+
+ CloudWatchMetricAlarmEvent.Configuration configuration = alarmData.getConfiguration();
+ assertThat(configuration).isNotNull();
+ assertThat(configuration)
+ .returns("Metric Alarm to test Lambda actions", from(CloudWatchMetricAlarmEvent.Configuration::getDescription));
+
+ List metrics = configuration.getMetrics();
+ assertThat(metrics).hasSize(1);
+ CloudWatchMetricAlarmEvent.Metric metric = metrics.get(0);
+ assertThat(metric)
+ .returns("1234e046-06f0-a3da-9534-EXAMPLEe4c", from(CloudWatchMetricAlarmEvent.Metric::getId));
+
+ CloudWatchMetricAlarmEvent.MetricStat metricStat = metric.getMetricStat();
+ assertThat(metricStat).isNotNull();
+ assertThat(metricStat)
+ .returns(60, from(CloudWatchMetricAlarmEvent.MetricStat::getPeriod))
+ .returns("Average", from(CloudWatchMetricAlarmEvent.MetricStat::getStat))
+ .returns("Percent", from(CloudWatchMetricAlarmEvent.MetricStat::getUnit));
+
+ CloudWatchMetricAlarmEvent.MetricDetail metricDetail = metricStat.getMetric();
+ assertThat(metricDetail).isNotNull();
+ assertThat(metricDetail)
+ .returns("AWS/Logs", from(CloudWatchMetricAlarmEvent.MetricDetail::getNamespace))
+ .returns("CallCount", from(CloudWatchMetricAlarmEvent.MetricDetail::getName));
+
+ Map dimensions = metricDetail.getDimensions();
+ assertThat(dimensions).isNotEmpty().hasSize(1);
+ assertThat(dimensions)
+ .contains(entry("InstanceId", "i-12345678"));
+ }
}
diff --git a/aws-lambda-java-tests/src/test/resources/cloudwatch_composite_alarm.json b/aws-lambda-java-tests/src/test/resources/cloudwatch_composite_alarm.json
new file mode 100644
index 000000000..353d470ae
--- /dev/null
+++ b/aws-lambda-java-tests/src/test/resources/cloudwatch_composite_alarm.json
@@ -0,0 +1,30 @@
+{
+ "source": "aws.cloudwatch",
+ "alarmArn": "arn:aws:cloudwatch:us-east-1:111122223333:alarm:SuppressionDemo.Main",
+ "accountId": "111122223333",
+ "time": "2023-08-04T12:56:46.138+0000",
+ "region": "us-east-1",
+ "alarmData": {
+ "alarmName": "CompositeDemo.Main",
+ "state": {
+ "value": "ALARM",
+ "reason": "arn:aws:cloudwatch:us-east-1:111122223333:alarm:CompositeDemo.FirstChild transitioned to ALARM at Friday 04 August, 2023 12:54:46 UTC",
+ "reasonData": "{\"triggeringAlarms\":[{\"arn\":\"arn:aws:cloudwatch:us-east-1:111122223333:alarm:CompositeDemo.FirstChild\",\"state\":{\"value\":\"ALARM\",\"timestamp\":\"2023-08-04T12:54:46.138+0000\"}}]}",
+ "timestamp": "2023-08-04T12:56:46.138+0000"
+ },
+ "previousState": {
+ "value": "ALARM",
+ "reason": "arn:aws:cloudwatch:us-east-1:111122223333:alarm:CompositeDemo.FirstChild transitioned to ALARM at Friday 04 August, 2023 12:54:46 UTC",
+ "reasonData": "{\"triggeringAlarms\":[{\"arn\":\"arn:aws:cloudwatch:us-east-1:111122223333:alarm:CompositeDemo.FirstChild\",\"state\":{\"value\":\"ALARM\",\"timestamp\":\"2023-08-04T12:54:46.138+0000\"}}]}",
+ "timestamp": "2023-08-04T12:54:46.138+0000",
+ "actionsSuppressedBy": "WaitPeriod",
+ "actionsSuppressedReason": "Actions suppressed by WaitPeriod"
+ },
+ "configuration": {
+ "alarmRule": "ALARM(CompositeDemo.FirstChild) OR ALARM(CompositeDemo.SecondChild)",
+ "actionsSuppressor": "CompositeDemo.ActionsSuppressor",
+ "actionsSuppressorWaitPeriod": 120,
+ "actionsSuppressorExtensionPeriod": 180
+ }
+ }
+}
\ No newline at end of file
diff --git a/aws-lambda-java-tests/src/test/resources/cloudwatch_metric_alarm.json b/aws-lambda-java-tests/src/test/resources/cloudwatch_metric_alarm.json
new file mode 100644
index 000000000..61b4187b5
--- /dev/null
+++ b/aws-lambda-java-tests/src/test/resources/cloudwatch_metric_alarm.json
@@ -0,0 +1,42 @@
+{
+ "source": "aws.cloudwatch",
+ "alarmArn": "arn:aws:cloudwatch:us-east-1:444455556666:alarm:lambda-demo-metric-alarm",
+ "accountId": "444455556666",
+ "time": "2023-08-04T12:36:15.490+0000",
+ "region": "us-east-1",
+ "alarmData": {
+ "alarmName": "lambda-demo-metric-alarm",
+ "state": {
+ "value": "ALARM",
+ "reason": "test",
+ "timestamp": "2023-08-04T12:36:15.490+0000"
+ },
+ "previousState": {
+ "value": "INSUFFICIENT_DATA",
+ "reason": "Insufficient Data: 5 datapoints were unknown.",
+ "reasonData": "{\"version\":\"1.0\",\"queryDate\":\"2023-08-04T12:31:29.591+0000\",\"statistic\":\"Average\",\"period\":60,\"recentDatapoints\":[],\"threshold\":5.0,\"evaluatedDatapoints\":[{\"timestamp\":\"2023-08-04T12:30:00.000+0000\"},{\"timestamp\":\"2023-08-04T12:29:00.000+0000\"},{\"timestamp\":\"2023-08-04T12:28:00.000+0000\"},{\"timestamp\":\"2023-08-04T12:27:00.000+0000\"},{\"timestamp\":\"2023-08-04T12:26:00.000+0000\"}]}",
+ "timestamp": "2023-08-04T12:31:29.595+0000"
+ },
+ "configuration": {
+ "description": "Metric Alarm to test Lambda actions",
+ "metrics": [
+ {
+ "id": "1234e046-06f0-a3da-9534-EXAMPLEe4c",
+ "metricStat": {
+ "metric": {
+ "namespace": "AWS/Logs",
+ "name": "CallCount",
+ "dimensions": {
+ "InstanceId": "i-12345678"
+ }
+ },
+ "period": 60,
+ "stat": "Average",
+ "unit": "Percent"
+ },
+ "returnData": true
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
From 791486fd912420bbf01bf4bbf1418baa6ffced04 Mon Sep 17 00:00:00 2001
From: Maxime David
Date: Thu, 11 Jul 2024 15:30:45 +0100
Subject: [PATCH 006/103] bump: aws-lambda-java-events from 3.11.6 to 3.12.0
---
README.md | 2 +-
aws-lambda-java-events/README.md | 2 +-
aws-lambda-java-events/RELEASE.CHANGELOG.md | 4 ++++
aws-lambda-java-events/pom.xml | 2 +-
aws-lambda-java-tests/pom.xml | 2 +-
samples/kinesis-firehose-event-handler/pom.xml | 2 +-
6 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 94f842fb3..cc560dcb7 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,7 @@ public class SqsHandler implements RequestHandler {
com.amazonaws
aws-lambda-java-events
- 3.11.6
+ 3.12.0
```
diff --git a/aws-lambda-java-events/README.md b/aws-lambda-java-events/README.md
index 92bea0ea6..53377ecc4 100644
--- a/aws-lambda-java-events/README.md
+++ b/aws-lambda-java-events/README.md
@@ -73,7 +73,7 @@
com.amazonaws
aws-lambda-java-events
- 3.11.6
+ 3.12.0
...
diff --git a/aws-lambda-java-events/RELEASE.CHANGELOG.md b/aws-lambda-java-events/RELEASE.CHANGELOG.md
index a19bd260a..12e1e0bb1 100644
--- a/aws-lambda-java-events/RELEASE.CHANGELOG.md
+++ b/aws-lambda-java-events/RELEASE.CHANGELOG.md
@@ -1,3 +1,7 @@
+### July 11, 2024
+`3.12.0`:
+- Added the object representations of the CloudWatch alarms([#493](https://github.com/aws/aws-lambda-java-libs/pull/493))
+
### June 11, 2024
`3.11.6`:
- Add the V2 version of the pre token generation event([#465](https://github.com/aws/aws-lambda-java-libs/pull/465))
diff --git a/aws-lambda-java-events/pom.xml b/aws-lambda-java-events/pom.xml
index 4abea0f87..909b3997c 100644
--- a/aws-lambda-java-events/pom.xml
+++ b/aws-lambda-java-events/pom.xml
@@ -5,7 +5,7 @@
com.amazonaws
aws-lambda-java-events
- 3.11.6
+ 3.12.0
jar
AWS Lambda Java Events Library
diff --git a/aws-lambda-java-tests/pom.xml b/aws-lambda-java-tests/pom.xml
index b77032b73..2ecbd7a9d 100644
--- a/aws-lambda-java-tests/pom.xml
+++ b/aws-lambda-java-tests/pom.xml
@@ -45,7 +45,7 @@
com.amazonaws
aws-lambda-java-events
- 3.11.6
+ 3.12.0
org.junit.jupiter
diff --git a/samples/kinesis-firehose-event-handler/pom.xml b/samples/kinesis-firehose-event-handler/pom.xml
index 1dc96d3d5..145337f53 100644
--- a/samples/kinesis-firehose-event-handler/pom.xml
+++ b/samples/kinesis-firehose-event-handler/pom.xml
@@ -46,7 +46,7 @@
com.amazonaws
aws-lambda-java-events
- 3.11.6
+ 3.12.0
From 2ef83fe98fec3cb82b0bd529d6483ea2eecc71b1 Mon Sep 17 00:00:00 2001
From: Maxime David
Date: Thu, 11 Jul 2024 15:37:05 +0100
Subject: [PATCH 007/103] bump: aws-lambda-java-events from 3.11.6 to 3.12.0
---
aws-lambda-java-events/RELEASE.CHANGELOG.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/aws-lambda-java-events/RELEASE.CHANGELOG.md b/aws-lambda-java-events/RELEASE.CHANGELOG.md
index 12e1e0bb1..bbb9505e8 100644
--- a/aws-lambda-java-events/RELEASE.CHANGELOG.md
+++ b/aws-lambda-java-events/RELEASE.CHANGELOG.md
@@ -1,6 +1,7 @@
### July 11, 2024
`3.12.0`:
- Added the object representations of the CloudWatch alarms([#493](https://github.com/aws/aws-lambda-java-libs/pull/493))
+- Added event class MskFirehoseEvent.java for Firehose Lambda transformation when MSK is the source([#490](https://github.com/aws/aws-lambda-java-libs/pull/490))
### June 11, 2024
`3.11.6`:
From a626ed390ce6ce619bb2a025b8d869f5063354be Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 19 Jul 2024 10:21:45 +0100
Subject: [PATCH 008/103] Bump docker/setup-buildx-action from 2 to 3 (#488)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3)
---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/runtime-interface-client_merge_to_main.yml | 2 +-
.github/workflows/runtime-interface-client_pr.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/runtime-interface-client_merge_to_main.yml b/.github/workflows/runtime-interface-client_merge_to_main.yml
index 27b22fd78..27c7dfec8 100644
--- a/.github/workflows/runtime-interface-client_merge_to_main.yml
+++ b/.github/workflows/runtime-interface-client_merge_to_main.yml
@@ -39,7 +39,7 @@ jobs:
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
+ uses: docker/setup-buildx-action@v3
with:
install: true
diff --git a/.github/workflows/runtime-interface-client_pr.yml b/.github/workflows/runtime-interface-client_pr.yml
index b935f4f7d..0d4aa9b21 100644
--- a/.github/workflows/runtime-interface-client_pr.yml
+++ b/.github/workflows/runtime-interface-client_pr.yml
@@ -44,7 +44,7 @@ jobs:
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
+ uses: docker/setup-buildx-action@v3
with:
install: true
From 70467ba5af66d4e32c3eb92f9f1988b15552b48a Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Fri, 19 Jul 2024 11:13:39 +0100
Subject: [PATCH 009/103] Bump actions/checkout from 3 to 4 (#489)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)
---
updated-dependencies:
- dependency-name: actions/checkout
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/aws-lambda-java-core.yml | 2 +-
.github/workflows/aws-lambda-java-events-sdk-transformer.yml | 2 +-
.github/workflows/aws-lambda-java-events.yml | 2 +-
.github/workflows/aws-lambda-java-log4j2.yml | 2 +-
.github/workflows/aws-lambda-java-serialization.yml | 2 +-
.github/workflows/aws-lambda-java-tests.yml | 2 +-
.github/workflows/repo-sync.yml | 2 +-
.github/workflows/runtime-interface-client_merge_to_main.yml | 2 +-
.github/workflows/runtime-interface-client_pr.yml | 4 ++--
.github/workflows/samples.yml | 2 +-
10 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/.github/workflows/aws-lambda-java-core.yml b/.github/workflows/aws-lambda-java-core.yml
index 39ff12914..267d901c9 100644
--- a/.github/workflows/aws-lambda-java-core.yml
+++ b/.github/workflows/aws-lambda-java-core.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 1.8
uses: actions/setup-java@v4
with:
diff --git a/.github/workflows/aws-lambda-java-events-sdk-transformer.yml b/.github/workflows/aws-lambda-java-events-sdk-transformer.yml
index 05a870add..66f6b2bfe 100644
--- a/.github/workflows/aws-lambda-java-events-sdk-transformer.yml
+++ b/.github/workflows/aws-lambda-java-events-sdk-transformer.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 1.8
uses: actions/setup-java@v4
with:
diff --git a/.github/workflows/aws-lambda-java-events.yml b/.github/workflows/aws-lambda-java-events.yml
index 634d803ea..04ab53a50 100644
--- a/.github/workflows/aws-lambda-java-events.yml
+++ b/.github/workflows/aws-lambda-java-events.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 1.8
uses: actions/setup-java@v4
with:
diff --git a/.github/workflows/aws-lambda-java-log4j2.yml b/.github/workflows/aws-lambda-java-log4j2.yml
index ab86f200f..7ae54cbe1 100644
--- a/.github/workflows/aws-lambda-java-log4j2.yml
+++ b/.github/workflows/aws-lambda-java-log4j2.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 1.8
uses: actions/setup-java@v4
with:
diff --git a/.github/workflows/aws-lambda-java-serialization.yml b/.github/workflows/aws-lambda-java-serialization.yml
index baa6052fc..c24c48d72 100644
--- a/.github/workflows/aws-lambda-java-serialization.yml
+++ b/.github/workflows/aws-lambda-java-serialization.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 1.8
uses: actions/setup-java@v4
with:
diff --git a/.github/workflows/aws-lambda-java-tests.yml b/.github/workflows/aws-lambda-java-tests.yml
index bf17ed2a6..a28bca886 100644
--- a/.github/workflows/aws-lambda-java-tests.yml
+++ b/.github/workflows/aws-lambda-java-tests.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 1.8
uses: actions/setup-java@v4
with:
diff --git a/.github/workflows/repo-sync.yml b/.github/workflows/repo-sync.yml
index c667bcebd..25f05029a 100644
--- a/.github/workflows/repo-sync.yml
+++ b/.github/workflows/repo-sync.yml
@@ -16,7 +16,7 @@ jobs:
env:
IS_CONFIGURED: ${{ secrets.SOURCE_REPO != '' }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
if: ${{ env.IS_CONFIGURED == 'true' }}
- uses: repo-sync/github-sync@v2
name: Sync repo to branch
diff --git a/.github/workflows/runtime-interface-client_merge_to_main.yml b/.github/workflows/runtime-interface-client_merge_to_main.yml
index 27c7dfec8..8dd3b8179 100644
--- a/.github/workflows/runtime-interface-client_merge_to_main.yml
+++ b/.github/workflows/runtime-interface-client_merge_to_main.yml
@@ -27,7 +27,7 @@ jobs:
contents: read
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 1.8
uses: actions/setup-java@v4
diff --git a/.github/workflows/runtime-interface-client_pr.yml b/.github/workflows/runtime-interface-client_pr.yml
index 0d4aa9b21..6cf510889 100644
--- a/.github/workflows/runtime-interface-client_pr.yml
+++ b/.github/workflows/runtime-interface-client_pr.yml
@@ -15,7 +15,7 @@ jobs:
smoke-test:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 1.8
uses: actions/setup-java@v4
@@ -32,7 +32,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 1.8
uses: actions/setup-java@v4
diff --git a/.github/workflows/samples.yml b/.github/workflows/samples.yml
index cd6655494..cdf923eae 100644
--- a/.github/workflows/samples.yml
+++ b/.github/workflows/samples.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 1.8
uses: actions/setup-java@v4
with:
From c5e2ee3f0346a97a894119f4b296c1b666fb623e Mon Sep 17 00:00:00 2001
From: Maxime David
Date: Mon, 29 Jul 2024 11:47:35 +0100
Subject: [PATCH 010/103] fix: make initializeClient a pure function (#498)
* fix: make initializeClient a pure function
* fix: make initializeClient a pure function
---
.../api/client/runtimeapi/LambdaRuntimeApiClientImpl.java | 2 +-
.../lambda/runtime/api/client/runtimeapi/NativeClient.java | 6 +++---
...es_lambda_runtime_api_client_runtimeapi_NativeClient.cpp | 4 ++--
...ices_lambda_runtime_api_client_runtimeapi_NativeClient.h | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImpl.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImpl.java
index 83ac0b39a..a62e0a692 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImpl.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeApiClientImpl.java
@@ -38,7 +38,7 @@ public LambdaRuntimeApiClientImpl(String hostnameAndPort) {
Objects.requireNonNull(hostnameAndPort, "hostnameAndPort cannot be null");
this.baseUrl = "http://" + hostnameAndPort;
this.invocationEndpoint = this.baseUrl + "/2018-06-01/runtime/invocation/";
- NativeClient.init();
+ NativeClient.init(hostnameAndPort);
}
@Override
diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java
index 10e6bafd4..3929e1147 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java
+++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java
@@ -14,12 +14,12 @@
* interactions with the Runtime API.
*/
class NativeClient {
- static void init() {
+ static void init(String awsLambdaRuntimeApi) {
JniHelper.load();
- initializeClient(USER_AGENT.getBytes());
+ initializeClient(USER_AGENT.getBytes(), awsLambdaRuntimeApi.getBytes());
}
- static native void initializeClient(byte[] userAgent);
+ static native void initializeClient(byte[] userAgent, byte[] awsLambdaRuntimeApi);
static native InvocationRequest next();
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp
index db71b8194..7fe47aa4d 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp
@@ -69,9 +69,9 @@ static std::string toNativeString(JNIEnv *env, jbyteArray jArray) {
return nativeString;
}
-JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_initializeClient(JNIEnv *env, jobject thisObject, jbyteArray userAgent) {
+JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_initializeClient(JNIEnv *env, jobject thisObject, jbyteArray userAgent, jbyteArray awsLambdaRuntimeApi) {
std::string user_agent = toNativeString(env, userAgent);
- std::string endpoint(getenv("AWS_LAMBDA_RUNTIME_API"));
+ std::string endpoint = toNativeString(env, awsLambdaRuntimeApi);
CLIENT = new aws::lambda_runtime::runtime(endpoint, user_agent);
}
diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h
index 27c636117..7219109b0 100644
--- a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h
+++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h
@@ -11,7 +11,7 @@ extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_initializeClient
- (JNIEnv *, jobject, jbyteArray);
+ (JNIEnv *, jobject, jbyteArray, jbyteArray);
JNIEXPORT jobject JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_next
(JNIEnv *, jobject);
From a36e04148ac2cac04d1f16feec3c6ae67254c34d Mon Sep 17 00:00:00 2001
From: Maxime David
Date: Mon, 29 Jul 2024 12:04:59 +0100
Subject: [PATCH 011/103] misc: add Maven badges to README (#499)
---
README.md | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/README.md b/README.md
index cc560dcb7..4aabef59c 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,8 @@ For information on how to optimize your functions watch the re:Invent talk [Opti
## Core Java Lambda interfaces - aws-lambda-java-core
+[](https://central.sonatype.com/artifact/com.amazonaws/aws-lambda-java-core)
+
This package defines the Lambda [Context](http://docs.aws.amazon.com/lambda/latest/dg/java-context-object.html) object
as well as [interfaces](http://docs.aws.amazon.com/lambda/latest/dg/java-handler-using-predefined-interfaces.html) that Lambda accepts.
@@ -47,6 +49,8 @@ public class HandlerStream implements RequestStreamHandler {
## Java objects of Lambda event sources - aws-lambda-java-events
+[](https://central.sonatype.com/artifact/com.amazonaws/aws-lambda-java-events)
+
This package defines [event sources](http://docs.aws.amazon.com/lambda/latest/dg/intro-invocation-modes.html) that Lambda natively accepts.
See the [documentation](aws-lambda-java-events/README.md) for a list of currently supported event sources.
Using this library you can have Java objects which represent event sources.
@@ -77,6 +81,8 @@ public class SqsHandler implements RequestHandler {
## Java Lambda JUnit Support - aws-lambda-java-tests
+[](https://central.sonatype.com/artifact/com.amazonaws/aws-lambda-java-tests)
+
This package provides utils to ease Lambda Java testing. It uses the same Lambda serialisation logic and `aws-lambda-java-events` to inject events in your JUnit tests.
- [Release Notes](aws-lambda-java-tests/RELEASE.CHANGELOG.md)
@@ -100,6 +106,8 @@ public void testInjectSQSEvent(SQSEvent event) {
## aws-lambda-java-events-sdk-transformer
+[](https://central.sonatype.com/artifact/com.amazonaws/aws-lambda-java-events-sdk-transformer)
+
This package provides helper classes/methods to use alongside `aws-lambda-java-events` in order to transform
Lambda input event model objects into SDK-compatible output model objects.
See the [documentation](aws-lambda-java-events-sdk-transformer/README.md) for more information.
@@ -116,6 +124,8 @@ See the [documentation](aws-lambda-java-events-sdk-transformer/README.md) for mo
## Java Lambda Log4J2 support - aws-lambda-java-log4j2
+[](https://central.sonatype.com/artifact/com.amazonaws/aws-lambda-java-log4j2)
+
This package defines the Lambda adapter to use with Log4J version 2.
See the [README](aws-lambda-java-log4j2/README.md) or the [official documentation](http://docs.aws.amazon.com/lambda/latest/dg/java-logging.html#java-wt-logging-using-log4j) for information on how to use the adapter.
@@ -130,6 +140,7 @@ See the [README](aws-lambda-java-log4j2/README.md) or the [official documentatio
```
## Java implementation of the Runtime Interface Client API - aws-lambda-java-runtime-interface-client
+[](https://central.sonatype.com/artifact/com.amazonaws/aws-lambda-java-runtime-interface-client)
This package defines the Lambda Java Runtime Interface Client package, a Lambda Runtime component that starts the runtime and interacts with the Runtime API - i.e., it calls the API for invocation events, starts the function code, calls the API to return the response.
The purpose of this package is to allow developers to deploy their applications in Lambda under the form of Container Images. See the [README](aws-lambda-java-runtime-interface-client/README.md) for information on how to use the library.
@@ -146,6 +157,8 @@ The purpose of this package is to allow developers to deploy their applications
## Java Lambda provided serialization support - aws-lambda-java-serialization
+[](https://central.sonatype.com/artifact/com.amazonaws/aws-lambda-java-serialization)
+
This package defines the Lambda serialization logic using in the `aws-lambda-java-runtime-client` library. It has no current standalone usage.
- [Release Notes](aws-lambda-java-serialization/RELEASE.CHANGELOG.md)
From aa399f58791eaf0273c3780a7b5f477806a55731 Mon Sep 17 00:00:00 2001
From: Martin Merfort <395822+mmerfort@users.noreply.github.com>
Date: Mon, 29 Jul 2024 13:13:57 +0200
Subject: [PATCH 012/103] Add S3BatchEventV2 (#496)
* Add S3BatchEventV2 class
* Add test for S3BatchEventV2
---------
Co-authored-by: Martin Merfort
Co-authored-by: Alexander Smirnov <75367056+smirnoal@users.noreply.github.com>
---
.../lambda/runtime/events/S3BatchEventV2.java | 50 +++++++++++++++++++
.../runtime/events/S3BatchResponse.java | 8 ++-
.../lambda/runtime/tests/EventLoader.java | 4 ++
.../runtime/tests/S3BatchEventV2Test.java | 20 ++++++++
.../src/test/resources/s3_batch_event_v2.json | 21 ++++++++
5 files changed, 102 insertions(+), 1 deletion(-)
create mode 100644 aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/S3BatchEventV2.java
create mode 100644 aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/S3BatchEventV2Test.java
create mode 100644 aws-lambda-java-tests/src/test/resources/s3_batch_event_v2.json
diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/S3BatchEventV2.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/S3BatchEventV2.java
new file mode 100644
index 000000000..92b8722d7
--- /dev/null
+++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/S3BatchEventV2.java
@@ -0,0 +1,50 @@
+package com.amazonaws.services.lambda.runtime.events;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Event to represent the payload which is sent to Lambda by S3 Batch to perform a custom
+ * action when using invocation schema version 2.0.
+ *
+ * https://docs.aws.amazon.com/AmazonS3/latest/dev/batch-ops-invoke-lambda.html
+ */
+
+@Data
+@Builder(setterPrefix = "with")
+@NoArgsConstructor
+@AllArgsConstructor
+public class S3BatchEventV2 {
+
+ private String invocationSchemaVersion;
+ private String invocationId;
+ private Job job;
+ private List tasks;
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class Job {
+
+ private String id;
+ private Map userArguments;
+ }
+
+ @Data
+ @Builder(setterPrefix = "with")
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class Task {
+
+ private String taskId;
+ private String s3Key;
+ private String s3VersionId;
+ private String s3BucketName;
+ }
+}
diff --git a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/S3BatchResponse.java b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/S3BatchResponse.java
index 4fdd12732..d584a31dd 100644
--- a/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/S3BatchResponse.java
+++ b/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/S3BatchResponse.java
@@ -62,4 +62,10 @@ public static S3BatchResponseBuilder fromS3BatchEvent(S3BatchEvent s3BatchEvent)
.withInvocationId(s3BatchEvent.getInvocationId())
.withInvocationSchemaVersion(s3BatchEvent.getInvocationSchemaVersion());
}
-}
\ No newline at end of file
+
+ public static S3BatchResponseBuilder fromS3BatchEvent(S3BatchEventV2 s3BatchEvent) {
+ return S3BatchResponse.builder()
+ .withInvocationId(s3BatchEvent.getInvocationId())
+ .withInvocationSchemaVersion(s3BatchEvent.getInvocationSchemaVersion());
+ }
+}
diff --git a/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java b/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
index 778122673..0c5d66206 100644
--- a/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
+++ b/aws-lambda-java-tests/src/main/java/com/amazonaws/services/lambda/runtime/tests/EventLoader.java
@@ -105,6 +105,10 @@ public static S3Event loadS3Event(String filename) {
return loadEvent(filename, S3Event.class);
}
+ public static S3BatchEventV2 loadS3BatchEventV2(String filename) {
+ return loadEvent(filename, S3BatchEventV2.class);
+ }
+
public static SecretsManagerRotationEvent loadSecretsManagerRotationEvent(String filename) {
return loadEvent(filename, SecretsManagerRotationEvent.class);
}
diff --git a/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/S3BatchEventV2Test.java b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/S3BatchEventV2Test.java
new file mode 100644
index 000000000..2c9913dc4
--- /dev/null
+++ b/aws-lambda-java-tests/src/test/java/com/amazonaws/services/lambda/runtime/tests/S3BatchEventV2Test.java
@@ -0,0 +1,20 @@
+package com.amazonaws.services.lambda.runtime.tests;
+
+import com.amazonaws.services.lambda.runtime.events.S3BatchEventV2;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.*;
+
+public class S3BatchEventV2Test {
+
+ @Test
+ public void testS3BatchEventV2() {
+ S3BatchEventV2 event = EventLoader.loadS3BatchEventV2("s3_batch_event_v2.json");
+ assertThat(event).isNotNull();
+ assertThat(event.getInvocationId()).isEqualTo("Jr3s8KZqYWRmaiBhc2RmdW9hZHNmZGpmaGFzbGtkaGZzatx7Ruy");
+ assertThat(event.getJob()).isNotNull();
+ assertThat(event.getJob().getUserArguments().get("MyDestinationBucket")).isEqualTo("destination-directory-bucket-name");
+ assertThat(event.getTasks()).hasSize(1);
+ assertThat(event.getTasks().get(0).getS3Key()).isEqualTo("s3objectkey");
+ }
+}
diff --git a/aws-lambda-java-tests/src/test/resources/s3_batch_event_v2.json b/aws-lambda-java-tests/src/test/resources/s3_batch_event_v2.json
new file mode 100644
index 000000000..4cdbacaaa
--- /dev/null
+++ b/aws-lambda-java-tests/src/test/resources/s3_batch_event_v2.json
@@ -0,0 +1,21 @@
+{
+ "invocationSchemaVersion": "2.0",
+ "invocationId": "Jr3s8KZqYWRmaiBhc2RmdW9hZHNmZGpmaGFzbGtkaGZzatx7Ruy",
+ "job": {
+ "id": "ry77cd60-61f6-4a2b-8a21-d07600c874gf",
+ "userArguments": {
+ "MyDestinationBucket": "destination-directory-bucket-name",
+ "MyDestinationBucketRegion": "us-east-1",
+ "MyDestinationPrefix": "copied/",
+ "MyDestinationObjectKeySuffix": "_new_suffix"
+ }
+ },
+ "tasks": [
+ {
+ "taskId": "y5R3a2lkZ29lc2hlurcS",
+ "s3Key": "s3objectkey",
+ "s3VersionId": null,
+ "s3Bucket": "source-directory-bucket-name"
+ }
+ ]
+}
From bf708eef3bcbfd746e3adb7473cf35a67f3cecf5 Mon Sep 17 00:00:00 2001
From: Maxime David
Date: Mon, 29 Jul 2024 14:08:41 +0100
Subject: [PATCH 013/103] bump: aws-lambda-java-events from 3.12.0 to 3.13.0
(#500)
* bump: aws-lambda-java-events from 3.12.0 to 3.13.0
---
README.md | 2 +-
aws-lambda-java-events/README.md | 2 +-
aws-lambda-java-events/RELEASE.CHANGELOG.md | 4 ++++
aws-lambda-java-events/pom.xml | 2 +-
aws-lambda-java-tests/pom.xml | 2 +-
samples/kinesis-firehose-event-handler/pom.xml | 2 +-
6 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 4aabef59c..de00e92ca 100644
--- a/README.md
+++ b/README.md
@@ -75,7 +75,7 @@ public class SqsHandler implements RequestHandler {
com.amazonaws
aws-lambda-java-events
- 3.12.0
+ 3.13.0
```
diff --git a/aws-lambda-java-events/README.md b/aws-lambda-java-events/README.md
index 53377ecc4..a37847848 100644
--- a/aws-lambda-java-events/README.md
+++ b/aws-lambda-java-events/README.md
@@ -73,7 +73,7 @@
com.amazonaws
aws-lambda-java-events
- 3.12.0
+ 3.13.0
...
diff --git a/aws-lambda-java-events/RELEASE.CHANGELOG.md b/aws-lambda-java-events/RELEASE.CHANGELOG.md
index bbb9505e8..ff2160e6e 100644
--- a/aws-lambda-java-events/RELEASE.CHANGELOG.md
+++ b/aws-lambda-java-events/RELEASE.CHANGELOG.md
@@ -1,3 +1,7 @@
+### July 29, 2024
+`3.13.0`:
+- Add S3BatchEventV2 ([#496](https://github.com/aws/aws-lambda-java-libs/pull/496))
+
### July 11, 2024
`3.12.0`:
- Added the object representations of the CloudWatch alarms([#493](https://github.com/aws/aws-lambda-java-libs/pull/493))
diff --git a/aws-lambda-java-events/pom.xml b/aws-lambda-java-events/pom.xml
index 909b3997c..e13d5bb27 100644
--- a/aws-lambda-java-events/pom.xml
+++ b/aws-lambda-java-events/pom.xml
@@ -5,7 +5,7 @@
com.amazonaws
aws-lambda-java-events
- 3.12.0
+ 3.13.0
jar
AWS Lambda Java Events Library
diff --git a/aws-lambda-java-tests/pom.xml b/aws-lambda-java-tests/pom.xml
index 2ecbd7a9d..233a0f0fc 100644
--- a/aws-lambda-java-tests/pom.xml
+++ b/aws-lambda-java-tests/pom.xml
@@ -45,7 +45,7 @@
com.amazonaws
aws-lambda-java-events
- 3.12.0
+ 3.13.0
org.junit.jupiter
diff --git a/samples/kinesis-firehose-event-handler/pom.xml b/samples/kinesis-firehose-event-handler/pom.xml
index 145337f53..dcea81c5b 100644
--- a/samples/kinesis-firehose-event-handler/pom.xml
+++ b/samples/kinesis-firehose-event-handler/pom.xml
@@ -46,7 +46,7 @@
com.amazonaws
aws-lambda-java-events
- 3.12.0
+ 3.13.0
From ff5d9e0c58c97be9e9451a5669ecc9049fe51743 Mon Sep 17 00:00:00 2001
From: Maxime David
Date: Tue, 30 Jul 2024 13:43:00 +0100
Subject: [PATCH 014/103] misc: add linter (#497)
* misc: add linter
* misc: add linter
---
.../build-tools/checkstyle.xml | 115 ++
.../pom.xml | 21 +
.../lambda/crac/CheckpointException.java | 6 +-
.../services/lambda/crac/Context.java | 5 +-
.../services/lambda/crac/ContextImpl.java | 25 +-
.../amazonaws/services/lambda/crac/Core.java | 9 +-
.../services/lambda/crac/DNSManager.java | 2 +-
.../services/lambda/crac/Resource.java | 5 +-
.../lambda/crac/RestoreException.java | 6 +-
.../lambda/runtime/api/client/AWSLambda.java | 8 +-
.../runtime/api/client/ClasspathLoader.java | 5 +-
.../api/client/CustomerClassLoader.java | 8 +-
.../api/client/EventHandlerLoader.java | 1286 +++++++++--------
.../runtime/api/client/HandlerInfo.java | 15 +-
.../runtime/api/client/LambdaEnvironment.java | 15 +-
.../api/client/LambdaRequestHandler.java | 22 +-
.../api/client/PojoSerializerLoader.java | 8 +-
.../ReservedRuntimeEnvironmentVariables.java | 18 +-
...TooManyServiceProvidersFoundException.java | 7 +-
.../lambda/runtime/api/client/UserFault.java | 10 +-
.../api/client/api/LambdaClientContext.java | 6 +-
.../client/api/LambdaClientContextClient.java | 5 +-
.../api/client/api/LambdaCognitoIdentity.java | 5 +-
.../runtime/api/client/api/LambdaContext.java | 5 +-
.../client/logging/AbstractLambdaLogger.java | 12 +-
.../runtime/api/client/logging/FrameType.java | 21 +-
.../logging/FramedTelemetryLogSink.java | 12 +-
.../api/client/logging/JsonLogFormatter.java | 16 +-
.../client/logging/LambdaContextLogger.java | 12 +-
.../api/client/logging/LogFiltering.java | 5 +-
.../api/client/logging/LogFormatter.java | 7 +-
.../runtime/api/client/logging/LogSink.java | 10 +-
.../api/client/logging/StdOutLogSink.java | 10 +-
.../client/logging/StructuredLogMessage.java | 5 +-
.../api/client/logging/TextLogFormatter.java | 26 +-
.../api/client/runtimeapi/DtoSerializers.java | 21 +-
.../api/client/runtimeapi/JniHelper.java | 14 +-
.../runtimeapi/LambdaRuntimeApiClient.java | 1 -
.../LambdaRuntimeApiClientImpl.java | 18 +-
.../api/client/runtimeapi/NativeClient.java | 2 -
.../converters/LambdaErrorConverter.java | 4 +-
.../converters/XRayErrorCauseConverter.java | 13 +-
.../runtime/api/client/util/EnvReader.java | 5 +-
.../api/client/util/LambdaOutputStream.java | 7 +-
.../runtime/api/client/util/UnsafeUtil.java | 8 +-
.../services/lambda/crac/ContextImplTest.java | 1 +
46 files changed, 1031 insertions(+), 816 deletions(-)
create mode 100644 aws-lambda-java-runtime-interface-client/build-tools/checkstyle.xml
diff --git a/aws-lambda-java-runtime-interface-client/build-tools/checkstyle.xml b/aws-lambda-java-runtime-interface-client/build-tools/checkstyle.xml
new file mode 100644
index 000000000..263834dc4
--- /dev/null
+++ b/aws-lambda-java-runtime-interface-client/build-tools/checkstyle.xml
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aws-lambda-java-runtime-interface-client/pom.xml b/aws-lambda-java-runtime-interface-client/pom.xml
index a4f022a48..24e73a8de 100644
--- a/aws-lambda-java-runtime-interface-client/pom.xml
+++ b/aws-lambda-java-runtime-interface-client/pom.xml
@@ -38,6 +38,7 @@
2.4
3.1.1
5.9.2
+ 3.4.0
+ Icon-Architecture/64/Arch_AWS-Lambda_64
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aws-lambda-java-profiler/docs/example-cold-start-flame-graph-small.png b/aws-lambda-java-profiler/docs/example-cold-start-flame-graph-small.png
new file mode 100644
index 0000000000000000000000000000000000000000..81ae8cba3923ad19695e673fb5096108c133580c
GIT binary patch
literal 543704
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