Skip to content

Commit 3878044

Browse files
committed
-rename titles
1 parent b8e03c9 commit 3878044

File tree

20 files changed

+165
-66
lines changed

20 files changed

+165
-66
lines changed

README.md

+12-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
| __Works on__ | LocalStack v2 |
1212

1313

14+
### UPDATE
15+
16+
The Terraform configuration file now randomly generates names for the bucket, in order to avoid conflicts
17+
at a global scale on AWS. This name shall be written out to a properties file, which the app will pick up
18+
and use for the S3 client. Furthermore, the name is also passed as an environment variable to the Lambda function by Terraform,
19+
so there's no need to worry about managing it.
20+
21+
1422
## Introduction
1523

1624
This application was created for demonstration purposes to highlight the ease of switching from
@@ -137,7 +145,7 @@ $ export AWS_SECRET_ACCESS_KEY=[your_aws_secret_access_key_id]
137145

138146
Make sure you have Terraform [installed](https://developer.hashicorp.com/terraform/downloads)
139147

140-
Under setup/terraform run:
148+
Under `terraform` run:
141149

142150
```
143151
$ terraform init
@@ -210,12 +218,12 @@ to get rid of any files that keep track of the resources' state. Then:
210218

211219
```
212220
$ tflocal init
213-
$ tflocal plan -var 'env=dev'
221+
$ tflocal plan
214222
$ tflocal apply
215223
```
216224

217-
What we're doing here is just passing an environmental variable to let the Lambda
218-
know this is the `dev` environment.
225+
We run the exact same commands for the exact same file. We no longer need to pass any environment
226+
variables, since the bucket name is generated and passed by Terraform.
219227

220228
### Starting the backend
221229

package-lock.json

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

setup/terraform/vars.tf

-11
This file was deleted.

shipment-picture-lambda-validator/pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@
5555
<artifactId>thumbnailator</artifactId>
5656
<version>0.4.19</version>
5757
</dependency>
58+
<dependency>
59+
<groupId>org.projectlombok</groupId>
60+
<artifactId>lombok</artifactId>
61+
<version>1.18.22</version>
62+
<scope>compile</scope>
63+
</dependency>
5864
</dependencies>
5965

6066
<dependencyManagement>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package dev.ancaghenade.shipmentpicturelambdavalidator;
2+
3+
import lombok.Getter;
4+
import software.amazon.awssdk.regions.Region;
5+
6+
@Getter
7+
public enum Location {
8+
9+
10+
REGION(Region.US_EAST_1);
11+
12+
private final Region region;
13+
Location(Region region) {
14+
this.region = region;
15+
}
16+
}

shipment-picture-lambda-validator/src/main/java/dev/ancaghenade/shipmentpicturelambdavalidator/S3ClientHelper.java

+5-7
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,20 @@
22

33
import java.io.IOException;
44
import java.net.URI;
5-
import software.amazon.awssdk.regions.Region;
5+
import java.util.Objects;
66
import software.amazon.awssdk.services.s3.S3Client;
77

88
public class S3ClientHelper {
99

10-
private static final String ENVIRONMENT = System.getenv("ENVIRONMENT");
11-
private static PropertiesProvider properties = new PropertiesProvider();
10+
private static final String LOCALSTACK_HOSTNAME = System.getenv("LOCALSTACK_HOSTNAME");
1211

1312
public static S3Client getS3Client() throws IOException {
1413

1514
var clientBuilder = S3Client.builder();
16-
if (properties.getProperty("environment.dev").equals(ENVIRONMENT)) {
17-
15+
if (Objects.nonNull(LOCALSTACK_HOSTNAME)) {
1816
return clientBuilder
19-
.region(Region.of(properties.getProperty("aws.region")))
20-
.endpointOverride(URI.create(properties.getProperty("s3.endpoint")))
17+
.region(Location.REGION.getRegion())
18+
.endpointOverride(URI.create(String.format("http://%s:4566", LOCALSTACK_HOSTNAME)))
2119
.forcePathStyle(true)
2220
.build();
2321
} else {

shipment-picture-lambda-validator/src/main/java/dev/ancaghenade/shipmentpicturelambdavalidator/SNSClientHelper.java

+10-11
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,29 @@
11
package dev.ancaghenade.shipmentpicturelambdavalidator;
22

3-
import java.io.IOException;
43
import java.net.URI;
5-
import software.amazon.awssdk.regions.Region;
4+
import java.util.Objects;
65
import software.amazon.awssdk.services.sns.SnsClient;
76

87
public class SNSClientHelper {
98

10-
private static final String ENVIRONMENT = System.getenv("ENVIRONMENT");
11-
private static PropertiesProvider properties = new PropertiesProvider();
12-
9+
private static final String LOCALSTACK_HOSTNAME = System.getenv("LOCALSTACK_HOSTNAME");
1310
private static String snsTopicArn;
1411

15-
public static SnsClient getSnsClient() throws IOException {
12+
public static SnsClient getSnsClient() {
1613

1714
var clientBuilder = SnsClient.builder();
1815

19-
if (properties.getProperty("environment.dev").equals(ENVIRONMENT)) {
20-
snsTopicArn = properties.getProperty("sns.arn.dev");
16+
if (Objects.nonNull(LOCALSTACK_HOSTNAME)) {
17+
snsTopicArn = String.format("arn:aws:sns:%s:000000000000:update_shipment_picture_topic",
18+
Location.REGION.getRegion());
2119

2220
return clientBuilder
23-
.region(Region.of(properties.getProperty("aws.region")))
24-
.endpointOverride(URI.create(properties.getProperty("sns.endpoint")))
21+
.region(Location.REGION.getRegion())
22+
.endpointOverride(URI.create(String.format("http://%s:4566", LOCALSTACK_HOSTNAME)))
2523
.build();
2624
} else {
27-
snsTopicArn = properties.getProperty("sns.arn.prod");
25+
snsTopicArn = String.format("arn:aws:sns:%s:%s:update_shipment_picture_topic",
26+
Location.REGION.getRegion(), "932043840972");
2827
return clientBuilder.build();
2928
}
3029
}

shipment-picture-lambda-validator/src/main/java/dev/ancaghenade/shipmentpicturelambdavalidator/ServiceHandler.java

+13-10
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,19 @@
1414
import java.util.Objects;
1515
import javax.imageio.ImageIO;
1616
import org.apache.http.entity.ContentType;
17+
import software.amazon.awssdk.core.ResponseInputStream;
1718
import software.amazon.awssdk.core.sync.RequestBody;
1819
import software.amazon.awssdk.services.s3.S3Client;
1920
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
21+
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
2022
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
2123
import software.amazon.awssdk.services.sns.SnsClient;
2224
import software.amazon.awssdk.services.sns.model.PublishRequest;
2325

2426

2527
public class ServiceHandler implements RequestStreamHandler {
2628

27-
private static final String BUCKET_NAME = "shipment-picture-bucket";
28-
29+
private static final String BUCKET_NAME = System.getenv("BUCKET");
2930
public ServiceHandler() {
3031
}
3132

@@ -50,9 +51,15 @@ public void handleRequest(InputStream inputStream, OutputStream outputStream,
5051
.key(objectKey)
5152
.build();
5253

53-
var s3ObjectResponse = s3Client.getObject(
54-
getObjectRequest);
55-
54+
ResponseInputStream<GetObjectResponse> s3ObjectResponse;
55+
try {
56+
s3ObjectResponse = s3Client.getObject(
57+
getObjectRequest);
58+
} catch (Exception e) {
59+
e.printStackTrace();
60+
context.getLogger().log(e.getMessage());
61+
return;
62+
}
5663
context.getLogger().log("Object fetched");
5764

5865
// Check if the image was already processed
@@ -150,11 +157,7 @@ private S3Client acquireS3Client() {
150157
}
151158

152159
private SnsClient acquireSnsClient() {
153-
try {
154-
return SNSClientHelper.getSnsClient();
155-
} catch (IOException e) {
156-
throw new RuntimeException(e);
157-
}
160+
return SNSClientHelper.getSnsClient();
158161
}
159162
}
160163

shipment-picture-lambda-validator/src/main/resources/lambda_update_script.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
awslocal lambda update-function-code --function-name shipment-picture-lambda-validator \
55
--zip-file fileb://target/shipment-picture-lambda-validator.jar \
6-
--region eu-central-1
6+
--region us-east-1
77

88
aws lambda update-function-code --function-name shipment-picture-lambda-validator \
99
--zip-file fileb://target/shipment-picture-lambda-validator.jar \
10-
--region eu-central-1
10+
--region us-east-1
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,25 @@
11
package dev.ancaghenade.shipmentlistdemo.buckets;
22

3-
import lombok.Getter;
3+
import org.springframework.beans.factory.annotation.Value;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.context.annotation.PropertySource;
6+
import org.springframework.stereotype.Component;
47

5-
@Getter
6-
public enum BucketName {
8+
@Component
9+
@Configuration
10+
@PropertySource(value = "classpath:buckets.properties")
11+
public class BucketName {
712

8-
SHIPMENT_PICTURE("shipment-picture-bucket");
13+
@Value("${shipment-picture-bucket}")
14+
private String shipmentPictureBucket;
15+
@Value("${shipment-picture-bucket-validator}")
16+
private String shipmentPictureValidatorBucket;
917

10-
private final String bucketName;
18+
public String getShipmentPictureBucket() {
19+
return shipmentPictureBucket;
20+
}
1121

12-
BucketName(String bucketName) {
13-
this.bucketName = bucketName;
22+
public String getShipmentPictureValidatorBucket() {
23+
return shipmentPictureValidatorBucket;
1424
}
1525
}

src/main/java/dev/ancaghenade/shipmentlistdemo/repository/DynamoDBService.java

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public Optional<Shipment> getShipment(String shipmentId) {
3939

4040
public String delete(String shipmentId) {
4141
shipmentTable.deleteItem(Key.builder().partitionValue(shipmentId).build());
42+
4243
return "Shipment has been deleted";
4344
}
4445

src/main/java/dev/ancaghenade/shipmentlistdemo/repository/S3StorageService.java

+43-3
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,43 @@
33
import dev.ancaghenade.shipmentlistdemo.buckets.BucketName;
44
import dev.ancaghenade.shipmentlistdemo.util.FileUtil;
55
import java.io.IOException;
6+
import java.util.ArrayList;
7+
import java.util.List;
68
import org.slf4j.Logger;
79
import org.slf4j.LoggerFactory;
810
import org.springframework.beans.factory.annotation.Autowired;
911
import org.springframework.stereotype.Service;
1012
import org.springframework.web.multipart.MultipartFile;
13+
import software.amazon.awssdk.core.exception.SdkException;
1114
import software.amazon.awssdk.core.sync.RequestBody;
1215
import software.amazon.awssdk.services.s3.S3Client;
16+
import software.amazon.awssdk.services.s3.model.DeleteObjectsRequest;
17+
import software.amazon.awssdk.services.s3.model.DeleteObjectsResponse;
1318
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
1419
import software.amazon.awssdk.services.s3.model.NoSuchKeyException;
20+
import software.amazon.awssdk.services.s3.model.ObjectIdentifier;
1521
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
22+
import software.amazon.awssdk.services.s3.model.S3Error;
23+
import software.amazon.awssdk.services.s3.model.S3Object;
1624

1725
@Service
1826
public class S3StorageService {
1927

2028
private final S3Client s3;
2129
private static final Logger LOGGER = LoggerFactory.getLogger(S3StorageService.class);
2230

31+
private final BucketName bucketName;
2332
@Autowired
24-
public S3StorageService(S3Client s3) {
33+
public S3StorageService(S3Client s3, BucketName bucketName) {
2534
this.s3 = s3;
35+
this.bucketName = bucketName;
2636
}
2737

2838
public void save(String path, String fileName,
2939
MultipartFile multipartFile)
3040
throws IOException {
3141
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
32-
.bucket(BucketName.SHIPMENT_PICTURE.getBucketName())
42+
.bucket(bucketName.getShipmentPictureBucket())
3343
.key(path + "/" + fileName)
3444
.contentType(multipartFile.getContentType())
3545
.contentLength(multipartFile.getSize())
@@ -42,7 +52,7 @@ public void save(String path, String fileName,
4252

4353
public byte[] download(String key) throws IOException {
4454
GetObjectRequest getObjectRequest = GetObjectRequest.builder()
45-
.bucket(BucketName.SHIPMENT_PICTURE.getBucketName())
55+
.bucket(bucketName.getShipmentPictureBucket())
4656
.key(key)
4757
.build();
4858
byte[] object = new byte[0];
@@ -54,4 +64,34 @@ public byte[] download(String key) throws IOException {
5464
return object;
5565
}
5666

67+
public void delete(String folderPrefix) {
68+
List<ObjectIdentifier> keysToDelete = new ArrayList<>();
69+
s3.listObjectsV2Paginator(
70+
builder -> builder.bucket(bucketName.getShipmentPictureBucket())
71+
.prefix(folderPrefix + "/"))
72+
.contents().stream()
73+
.map(S3Object::key)
74+
.forEach(key -> keysToDelete.add(ObjectIdentifier.builder().key(key).build()));
75+
76+
DeleteObjectsRequest deleteRequest = DeleteObjectsRequest.builder()
77+
.bucket(bucketName.getShipmentPictureBucket())
78+
.delete(builder -> builder.objects(keysToDelete).build())
79+
.build();
80+
81+
try {
82+
DeleteObjectsResponse response = s3.deleteObjects(deleteRequest);
83+
List<S3Error> errors = response.errors();
84+
if (!errors.isEmpty()) {
85+
LOGGER.error("Errors occurred while deleting objects:");
86+
errors.forEach(error -> System.out.println("Object: " + error.key() +
87+
", Error Code: " + error.code() +
88+
", Error Message: " + error.message()));
89+
} else {
90+
LOGGER.info("Objects deleted successfully.");
91+
}
92+
} catch (SdkException e) {
93+
LOGGER.error("Error occurred during object deletion: " + e.getMessage());
94+
}
95+
}
96+
5797
}

src/main/java/dev/ancaghenade/shipmentlistdemo/service/ShipmentService.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public List<Shipment> getAllShipments() {
3434
}
3535

3636
public String deleteShipment(String shipmentId) {
37+
s3StorageService.delete(shipmentId);
3738
return dynamoDBService.delete(shipmentId);
3839
}
3940

@@ -59,12 +60,12 @@ public void uploadShipmentImage(String shipmentId, MultipartFile file) {
5960
} catch (IOException e) {
6061
throw new IllegalStateException(e);
6162
}
62-
shipment.setImageLink(fileName);
63+
shipment.setImageLink(format("%s/%s", path, fileName));
6364
dynamoDBService.upsert(shipment);
6465
}
6566

6667

67-
public byte[] downloadShipmentImage(String shipmentId) {
68+
public byte[] downloadShipmentImage(String shipmentId) throws IllegalStateException {
6869
Shipment shipment = dynamoDBService.getShipment(shipmentId).stream()
6970
.findFirst()
7071
.orElseThrow(

src/main/resources/application-dev.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ aws:
88
endpoint: http://localhost.localstack.cloud:4566/
99
sqs:
1010
endpoint: http://localhost:4566/000000000000
11-
region: eu-central-1
11+
region: us-east-1

src/main/resources/application-prod.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ aws:
88
endpoint: https://s3.eu-central-1.amazonaws.com
99
sqs:
1010
endpoint: https://sqs.eu-central-1.amazonaws.com
11-
region: eu-central-1
11+
region: us-east-1

src/main/resources/buckets.properties

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
shipment-picture-bucket=shipment-picture-bucket-concise-malamute
2+
shipment-picture-bucket-validator=shipment-picture-lambda-validator-bucket-concise-malamute
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)