Skip to content

Commit 8e4f9f8

Browse files
committed
initial version of large message handling
1 parent b191d72 commit 8e4f9f8

File tree

14 files changed

+788
-7
lines changed

14 files changed

+788
-7
lines changed

pom.xml

+8-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>software.amazon.lambda</groupId>
88
<artifactId>powertools-parent</artifactId>
9-
<version>1.16.1</version>
9+
<version>1.17.0-SNAPSHOT</version>
1010
<packaging>pom</packaging>
1111

1212
<name>Powertools for AWS Lambda (Java) library Parent</name>
@@ -38,6 +38,7 @@
3838
<module>powertools-test-suite</module>
3939
<module>powertools-cloudformation</module>
4040
<module>powertools-idempotency</module>
41+
<module>powertools-large-messages</module>
4142
<module>powertools-e2e-tests</module>
4243
<module>examples</module>
4344
</modules>
@@ -246,6 +247,12 @@
246247
<version>${junit-jupiter.version}</version>
247248
<scope>test</scope>
248249
</dependency>
250+
<dependency>
251+
<groupId>org.junit-pioneer</groupId>
252+
<artifactId>junit-pioneer</artifactId>
253+
<version>1.9.1</version>
254+
<scope>test</scope>
255+
</dependency>
249256
<dependency>
250257
<groupId>org.apache.commons</groupId>
251258
<artifactId>commons-lang3</artifactId>

powertools-idempotency/pom.xml

-6
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@
9191
<dependency>
9292
<groupId>org.junit-pioneer</groupId>
9393
<artifactId>junit-pioneer</artifactId>
94-
<version>1.9.1</version>
9594
<scope>test</scope>
9695
</dependency>
9796
<dependency>
@@ -119,11 +118,6 @@
119118
<artifactId>aws-lambda-java-events</artifactId>
120119
<scope>test</scope>
121120
</dependency>
122-
<dependency>
123-
<groupId>com.amazonaws</groupId>
124-
<artifactId>aws-lambda-java-tests</artifactId>
125-
<scope>test</scope>
126-
</dependency>
127121
<dependency>
128122
<groupId>com.amazonaws</groupId>
129123
<artifactId>DynamoDBLocal</artifactId>

powertools-large-messages/pom.xml

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>software.amazon.lambda</groupId>
9+
<artifactId>powertools-parent</artifactId>
10+
<version>1.17.0-SNAPSHOT</version>
11+
</parent>
12+
13+
<artifactId>powertools-large-messages</artifactId>
14+
<packaging>jar</packaging>
15+
16+
<name>Powertools for AWS Lambda (Java) library Large messages</name>
17+
18+
<issueManagement>
19+
<system>GitHub Issues</system>
20+
<url>https://github.com/aws-powertools/powertools-lambda-java/issues</url>
21+
</issueManagement>
22+
<scm>
23+
<url>https://github.com/aws-powertools/powertools-lambda-java.git</url>
24+
</scm>
25+
<developers>
26+
<developer>
27+
<name>Powertools for AWS Lambda team</name>
28+
<organization>Amazon Web Services</organization>
29+
<organizationUrl>https://aws.amazon.com/</organizationUrl>
30+
</developer>
31+
</developers>
32+
33+
<distributionManagement>
34+
<snapshotRepository>
35+
<id>ossrh</id>
36+
<url>https://aws.oss.sonatype.org/content/repositories/snapshots</url>
37+
</snapshotRepository>
38+
</distributionManagement>
39+
40+
<dependencies>
41+
<dependency>
42+
<groupId>software.amazon.lambda</groupId>
43+
<artifactId>powertools-core</artifactId>
44+
</dependency>
45+
<dependency>
46+
<groupId>org.aspectj</groupId>
47+
<artifactId>aspectjrt</artifactId>
48+
</dependency>
49+
<dependency>
50+
<groupId>com.amazonaws</groupId>
51+
<artifactId>aws-lambda-java-events</artifactId>
52+
</dependency>
53+
<dependency>
54+
<groupId>software.amazon.payloadoffloading</groupId>
55+
<artifactId>payloadoffloading-common</artifactId>
56+
</dependency>
57+
<dependency>
58+
<groupId>software.amazon.awssdk</groupId>
59+
<artifactId>s3</artifactId>
60+
<exclusions>
61+
<exclusion>
62+
<groupId>software.amazon.awssdk</groupId>
63+
<artifactId>netty-nio-client</artifactId>
64+
</exclusion>
65+
<exclusion>
66+
<groupId>software.amazon.awssdk</groupId>
67+
<artifactId>apache-client</artifactId>
68+
</exclusion>
69+
</exclusions>
70+
</dependency>
71+
<dependency>
72+
<groupId>software.amazon.awssdk</groupId>
73+
<artifactId>url-connection-client</artifactId>
74+
<version>${aws.sdk.version}</version>
75+
</dependency>
76+
77+
<!-- Test dependencies -->
78+
<dependency>
79+
<groupId>org.junit.jupiter</groupId>
80+
<artifactId>junit-jupiter-api</artifactId>
81+
<scope>test</scope>
82+
</dependency>
83+
<dependency>
84+
<groupId>org.junit.jupiter</groupId>
85+
<artifactId>junit-jupiter-engine</artifactId>
86+
<scope>test</scope>
87+
</dependency>
88+
<dependency>
89+
<groupId>org.junit-pioneer</groupId>
90+
<artifactId>junit-pioneer</artifactId>
91+
<scope>test</scope>
92+
</dependency>
93+
<dependency>
94+
<groupId>org.mockito</groupId>
95+
<artifactId>mockito-core</artifactId>
96+
<scope>test</scope>
97+
</dependency>
98+
<dependency>
99+
<groupId>org.mockito</groupId>
100+
<artifactId>mockito-inline</artifactId>
101+
<scope>test</scope>
102+
</dependency>
103+
<dependency>
104+
<groupId>org.apache.commons</groupId>
105+
<artifactId>commons-lang3</artifactId>
106+
<scope>test</scope>
107+
</dependency>
108+
<dependency>
109+
<groupId>org.assertj</groupId>
110+
<artifactId>assertj-core</artifactId>
111+
<scope>test</scope>
112+
</dependency>
113+
</dependencies>
114+
115+
<build>
116+
<plugins>
117+
<plugin>
118+
<artifactId>maven-surefire-plugin</artifactId>
119+
<version>3.1.2</version>
120+
<configuration>
121+
<environmentVariables>
122+
<AWS_REGION>eu-central-1</AWS_REGION>
123+
</environmentVariables>
124+
</configuration>
125+
</plugin>
126+
</plugins>
127+
</build>
128+
129+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package software.amazon.lambda.powertools.largemessages;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@Target(ElementType.METHOD)
10+
public @interface LargeMessage {
11+
12+
boolean deleteS3Objects() default true;
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package software.amazon.lambda.powertools.largemessages;
2+
3+
import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
4+
import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
5+
import software.amazon.awssdk.regions.Region;
6+
import software.amazon.awssdk.services.s3.S3Client;
7+
import software.amazon.awssdk.services.s3.S3ClientBuilder;
8+
9+
import static software.amazon.lambda.powertools.core.internal.LambdaConstants.AWS_LAMBDA_INITIALIZATION_TYPE;
10+
import static software.amazon.lambda.powertools.core.internal.LambdaConstants.AWS_REGION_ENV;
11+
import static software.amazon.lambda.powertools.core.internal.LambdaConstants.ON_DEMAND;
12+
13+
/**
14+
* Singleton instance for Large Message Config.
15+
* <br/>
16+
* Optional: Use it in your Lambda constructor to pass a custom {@link S3Client} to the {@link software.amazon.lambda.powertools.largemessages.internal.LargeMessageProcessor}
17+
* <br/>
18+
* If you don't use this, a default S3Client will be created.
19+
* <pre>
20+
* public MyLambdaHandler() {
21+
* LargeMessageConfig.builder().withS3Client(S3Client.create()).build();
22+
* }
23+
* </pre>
24+
*/
25+
public class LargeMessageConfig {
26+
27+
private static final LargeMessageConfig INSTANCE = new LargeMessageConfig();
28+
private S3Client s3Client;
29+
30+
private LargeMessageConfig() {}
31+
32+
public static LargeMessageConfig get() {
33+
return INSTANCE;
34+
}
35+
36+
public static LargeMessageConfig init() {
37+
return INSTANCE;
38+
}
39+
40+
public void withS3Client(S3Client s3Client) {
41+
if (this.s3Client == null) {
42+
this.s3Client = s3Client;
43+
}
44+
}
45+
46+
// For tests purpose
47+
void setS3Client(S3Client s3Client) {
48+
this.s3Client = s3Client;
49+
}
50+
51+
// Getter needs to initialize if not done with setter
52+
public S3Client getS3Client() {
53+
if (this.s3Client == null) {
54+
S3ClientBuilder s3ClientBuilder = S3Client.builder()
55+
.httpClient(UrlConnectionHttpClient.builder().build())
56+
.region(Region.of(System.getenv(AWS_REGION_ENV)));
57+
58+
// AWS_LAMBDA_INITIALIZATION_TYPE has two values on-demand and snap-start
59+
// when using snap-start mode, the env var creds provider isn't used and causes a fatal error if set
60+
// fall back to the default provider chain if the mode is anything other than on-demand.
61+
String initializationType = System.getenv().get(AWS_LAMBDA_INITIALIZATION_TYPE);
62+
if (initializationType != null && initializationType.equals(ON_DEMAND)) {
63+
s3ClientBuilder.credentialsProvider(EnvironmentVariableCredentialsProvider.create());
64+
}
65+
this.s3Client = s3ClientBuilder.build();
66+
}
67+
return this.s3Client;
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package software.amazon.lambda.powertools.largemessages;
2+
3+
public class LargeMessageProcessingException extends RuntimeException {
4+
public LargeMessageProcessingException(String message, Throwable cause) {
5+
super(message, cause);
6+
}
7+
8+
public LargeMessageProcessingException(String message) {
9+
super(message);
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package software.amazon.lambda.powertools.largemessages.internal;
2+
3+
import org.aspectj.lang.ProceedingJoinPoint;
4+
import org.aspectj.lang.annotation.Around;
5+
import org.aspectj.lang.annotation.Aspect;
6+
import org.aspectj.lang.annotation.Pointcut;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
import software.amazon.lambda.powertools.largemessages.LargeMessage;
10+
11+
import java.util.Optional;
12+
13+
import static java.lang.String.format;
14+
15+
16+
@Aspect
17+
public class LargeMessageAspect {
18+
19+
private static final Logger LOG = LoggerFactory.getLogger(LargeMessageAspect.class);
20+
21+
@SuppressWarnings({"EmptyMethod"})
22+
@Pointcut("@annotation(largeMessage)")
23+
public void callAt(LargeMessage largeMessage) {
24+
}
25+
26+
@Around(value = "callAt(largeMessage) && execution(@LargeMessage * *.*(..))", argNames = "pjp,largeMessage")
27+
public Object around(ProceedingJoinPoint pjp,
28+
LargeMessage largeMessage) throws Throwable {
29+
Object[] proceedArgs = pjp.getArgs();
30+
31+
// we need a message to process
32+
if (proceedArgs.length == 0) {
33+
LOG.warn("@LargeMessage annotation is placed on a method without any message to process, proceeding");
34+
return pjp.proceed(proceedArgs);
35+
}
36+
37+
Object message = proceedArgs[0];
38+
Optional<LargeMessageProcessor<?>> largeMessageProcessor = LargeMessageProcessorFactory.get(message);
39+
40+
if (!largeMessageProcessor.isPresent()) {
41+
LOG.warn(format("@LargeMessage annotation is placed on a method with unsupported message type [%s], proceeding", message.getClass()));
42+
return pjp.proceed(proceedArgs);
43+
}
44+
45+
return largeMessageProcessor.get().process(pjp, largeMessage.deleteS3Objects());
46+
}
47+
48+
}

0 commit comments

Comments
 (0)