|
3 | 3 | import com.amazonaws.services.lambda.runtime.Context;
|
4 | 4 | import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
|
5 | 5 | import com.jayway.jsonpath.JsonPath;
|
6 |
| -import java.awt.image.BufferedImage; |
7 |
| -import java.io.ByteArrayOutputStream; |
8 |
| -import java.io.File; |
9 |
| -import java.io.IOException; |
10 |
| -import java.io.InputStream; |
11 |
| -import java.io.OutputStream; |
12 |
| -import java.util.Collections; |
13 |
| -import java.util.List; |
14 |
| -import java.util.Objects; |
15 |
| -import javax.imageio.ImageIO; |
16 | 6 | import org.apache.http.entity.ContentType;
|
17 | 7 | import software.amazon.awssdk.core.ResponseInputStream;
|
18 | 8 | import software.amazon.awssdk.core.sync.RequestBody;
|
|
23 | 13 | import software.amazon.awssdk.services.sns.SnsClient;
|
24 | 14 | import software.amazon.awssdk.services.sns.model.PublishRequest;
|
25 | 15 |
|
| 16 | +import javax.imageio.ImageIO; |
| 17 | +import java.awt.image.BufferedImage; |
| 18 | +import java.io.ByteArrayOutputStream; |
| 19 | +import java.io.File; |
| 20 | +import java.io.IOException; |
| 21 | +import java.io.InputStream; |
| 22 | +import java.io.OutputStream; |
| 23 | +import java.util.Collections; |
| 24 | +import java.util.List; |
| 25 | +import java.util.Objects; |
26 | 26 |
|
27 | 27 | public class ServiceHandler implements RequestStreamHandler {
|
28 | 28 |
|
29 | 29 | private static final String BUCKET_NAME = System.getenv("BUCKET");
|
30 |
| - public ServiceHandler() { |
31 |
| - } |
32 | 30 |
|
33 | 31 | @Override
|
34 |
| - public void handleRequest(InputStream inputStream, OutputStream outputStream, |
35 |
| - Context context) throws IOException { |
36 |
| - var isValid = true; |
37 |
| - |
38 |
| - var s3Client = acquireS3Client(); |
39 |
| - var snsClient = acquireSnsClient(); |
40 |
| - var objectKey = getObjectKey(inputStream, context); |
| 32 | + public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException { |
| 33 | + S3Client s3Client = acquireS3Client(); |
| 34 | + SnsClient snsClient = acquireSnsClient(); |
| 35 | + String objectKey = getObjectKey(inputStream, context); |
41 | 36 |
|
42 |
| - if (Objects.isNull(objectKey)) { |
| 37 | + if (objectKey == null) { |
43 | 38 | context.getLogger().log("Object key is null");
|
44 | 39 | return;
|
45 | 40 | }
|
46 | 41 |
|
47 | 42 | context.getLogger().log("Object key: " + objectKey);
|
| 43 | + processObject(s3Client, snsClient, objectKey, context); |
| 44 | + } |
48 | 45 |
|
49 |
| - var getObjectRequest = GetObjectRequest.builder() |
50 |
| - .bucket(BUCKET_NAME) |
51 |
| - .key(objectKey) |
52 |
| - .build(); |
53 |
| - |
54 |
| - ResponseInputStream<GetObjectResponse> s3ObjectResponse; |
| 46 | + private void processObject(S3Client s3Client, SnsClient snsClient, String objectKey, Context context) { |
55 | 47 | try {
|
56 |
| - s3ObjectResponse = s3Client.getObject( |
57 |
| - getObjectRequest); |
| 48 | + GetObjectRequest getObjectRequest = GetObjectRequest.builder() |
| 49 | + .bucket(BUCKET_NAME) |
| 50 | + .key(objectKey) |
| 51 | + .build(); |
| 52 | + |
| 53 | + ResponseInputStream<GetObjectResponse> s3ObjectResponse = s3Client.getObject(getObjectRequest); |
| 54 | + context.getLogger().log("Object fetched."); |
| 55 | + |
| 56 | + if (isObjectAlreadyProcessed(s3ObjectResponse)) { |
| 57 | + context.getLogger().log("Object already present."); |
| 58 | + return; |
| 59 | + } |
| 60 | + |
| 61 | + boolean isValid = validateObject(s3ObjectResponse, context); |
| 62 | + byte[] objectData = s3ObjectResponse.readAllBytes(); |
| 63 | + String newObjectKey = objectKey; |
| 64 | + if (!isValid) { |
| 65 | + newObjectKey = handleInvalidObject(s3Client, objectKey, context); |
| 66 | + } else { |
| 67 | + handleValidObject(s3Client, objectKey, s3ObjectResponse, objectData, context); |
| 68 | + } |
| 69 | + |
| 70 | + publishToSns(snsClient, newObjectKey, context); |
| 71 | + |
58 | 72 | } catch (Exception e) {
|
59 |
| - e.printStackTrace(); |
60 | 73 | context.getLogger().log(e.getMessage());
|
61 |
| - return; |
| 74 | + } finally { |
| 75 | + closeClients(s3Client, snsClient); |
62 | 76 | }
|
63 |
| - context.getLogger().log("Object fetched"); |
| 77 | + } |
64 | 78 |
|
65 |
| - // Check if the image was already processed |
66 |
| - if (s3ObjectResponse.response().metadata().entrySet().stream().anyMatch( |
67 |
| - entry -> entry.getKey().equals("skip-processing") && entry.getValue().equals("true"))) { |
68 |
| - context.getLogger().log("Object already present."); |
69 |
| - return; |
70 |
| - } |
| 79 | + private boolean isObjectAlreadyProcessed(ResponseInputStream<GetObjectResponse> s3ObjectResponse) { |
| 80 | + return s3ObjectResponse.response().metadata().entrySet().stream() |
| 81 | + .anyMatch(entry -> entry.getKey().equals("skip-processing") && entry.getValue().equals("true")); |
| 82 | + } |
71 | 83 |
|
72 |
| - // Check the file extension to determine the image format |
73 |
| - if (!List.of(ContentType.IMAGE_JPEG.getMimeType(), |
| 84 | + private boolean validateObject(ResponseInputStream<GetObjectResponse> s3ObjectResponse, Context context) { |
| 85 | + String contentType = s3ObjectResponse.response().contentType(); |
| 86 | + boolean isValid = List.of( |
| 87 | + ContentType.IMAGE_JPEG.getMimeType(), |
74 | 88 | ContentType.IMAGE_PNG.getMimeType(),
|
75 |
| - ContentType.IMAGE_BMP.getMimeType()) |
76 |
| - .contains(s3ObjectResponse.response().contentType())) { |
77 |
| - isValid = false; |
78 |
| - context.getLogger().log("Object invalid due to wrong format."); |
| 89 | + ContentType.IMAGE_BMP.getMimeType() |
| 90 | + ).contains(contentType); |
79 | 91 |
|
| 92 | + if (!isValid) { |
| 93 | + context.getLogger().log("Object invalid due to wrong format."); |
80 | 94 | }
|
81 | 95 |
|
82 |
| - // Get the object data as a byte array |
83 |
| - var objectData = s3Client.getObject(getObjectRequest).readAllBytes(); |
| 96 | + return isValid; |
| 97 | + } |
84 | 98 |
|
85 |
| - if (!isValid) { |
86 |
| - try { |
87 |
| - File imageFile = new File("placeholder.jpg"); |
88 |
| - BufferedImage image = ImageIO.read(imageFile); |
| 99 | + private String handleInvalidObject(S3Client s3Client, String objectKey, Context context) { |
| 100 | + try { |
| 101 | + File imageFile = new File("placeholder.jpg"); |
| 102 | + BufferedImage image = ImageIO.read(imageFile); |
89 | 103 |
|
90 |
| - ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| 104 | + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { |
91 | 105 | ImageIO.write(image, "jpg", baos);
|
92 | 106 | byte[] imageBytes = baos.toByteArray();
|
93 | 107 |
|
94 |
| - objectKey = TextParser.replaceSufix(objectKey, "placeholder.jpg"); |
| 108 | + objectKey = TextParser.replaceSuffix(objectKey, "placeholder.jpg"); |
| 109 | + context.getLogger().log("NEW IMAGE LINK: " + objectKey); |
| 110 | + |
| 111 | + PutObjectRequest putObjectRequest = PutObjectRequest.builder() |
| 112 | + .bucket(BUCKET_NAME) |
| 113 | + .key(objectKey) |
| 114 | + .metadata(Collections.singletonMap("skip-processing", "true")) |
| 115 | + .build(); |
| 116 | + |
| 117 | + s3Client.putObject(putObjectRequest, RequestBody.fromBytes(imageBytes)); |
| 118 | + } |
| 119 | + } catch (IOException e) { |
| 120 | + context.getLogger().log("Error handling invalid object: " + e.getMessage()); |
| 121 | + } |
| 122 | + |
| 123 | + return objectKey; |
| 124 | + } |
95 | 125 |
|
96 |
| - System.out.println("NEW IMAGE LINK: " + objectKey); |
| 126 | + private void handleValidObject(S3Client s3Client, String objectKey, ResponseInputStream<GetObjectResponse> s3ObjectResponse, byte[] objectData, Context context) throws IOException { |
| 127 | + String extension = s3ObjectResponse.response().contentType(); |
97 | 128 |
|
98 |
| - var putObjectRequest = PutObjectRequest.builder() |
| 129 | + PutObjectRequest putObjectRequest = PutObjectRequest.builder() |
99 | 130 | .bucket(BUCKET_NAME)
|
100 | 131 | .key(objectKey)
|
101 | 132 | .metadata(Collections.singletonMap("skip-processing", "true"))
|
102 | 133 | .build();
|
103 | 134 |
|
104 |
| - s3Client.putObject(putObjectRequest, RequestBody.fromBytes(imageBytes)); |
105 |
| - |
106 |
| - baos.close(); |
107 |
| - } catch (IOException e) { |
108 |
| - e.printStackTrace(); |
109 |
| - } |
110 |
| - |
111 |
| - } else { |
112 |
| - var extension = s3ObjectResponse.response().contentType(); |
| 135 | + s3Client.putObject(putObjectRequest, RequestBody.fromBytes(Watermark.watermarkImage(objectData, extension.substring(extension.lastIndexOf("/") + 1)))); |
| 136 | + context.getLogger().log("Watermark has been added."); |
| 137 | + } |
113 | 138 |
|
114 |
| - var putObjectRequest = PutObjectRequest.builder() |
115 |
| - .bucket(BUCKET_NAME) |
116 |
| - .key(objectKey) |
117 |
| - .metadata(Collections.singletonMap("skip-processing", "true")) |
118 |
| - .build(); |
| 139 | + private void publishToSns(SnsClient snsClient, String objectKey, Context context) { |
| 140 | + PublishRequest request = PublishRequest.builder() |
| 141 | + .message(objectKey) |
| 142 | + .topicArn(SNSClientHelper.topicARN()) |
| 143 | + .build(); |
119 | 144 |
|
120 |
| - s3Client.putObject(putObjectRequest, RequestBody.fromBytes( |
121 |
| - Watermark.watermarkImage(objectData, |
122 |
| - extension.substring(extension.lastIndexOf("/") + 1)))); |
123 |
| - context.getLogger().log("Watermark has been added."); |
124 |
| - } |
125 |
| - var request = PublishRequest |
126 |
| - .builder() |
127 |
| - .message(objectKey) |
128 |
| - .topicArn(SNSClientHelper.topicARN()) |
129 |
| - .build(); |
130 | 145 | snsClient.publish(request);
|
131 | 146 | context.getLogger().log("Published to topic: " + request.topicArn());
|
| 147 | + } |
132 | 148 |
|
133 |
| - // Close clients |
| 149 | + private void closeClients(S3Client s3Client, SnsClient snsClient) { |
134 | 150 | s3Client.close();
|
135 | 151 | snsClient.close();
|
136 |
| - |
137 | 152 | }
|
138 | 153 |
|
139 | 154 | private String getObjectKey(InputStream inputStream, Context context) {
|
140 | 155 | try {
|
141 | 156 | List<String> keys = JsonPath.read(inputStream, "$.Records[*].s3.object.key");
|
142 |
| - if (keys.iterator().hasNext()) { |
143 |
| - return keys.iterator().next(); |
144 |
| - } |
| 157 | + return keys.isEmpty() ? null : keys.get(0); |
145 | 158 | } catch (IOException ioe) {
|
146 |
| - context.getLogger().log("caught IOException reading input stream: " + ioe.getMessage()); |
| 159 | + context.getLogger().log("Caught IOException reading input stream: " + ioe.getMessage()); |
| 160 | + return null; |
147 | 161 | }
|
148 |
| - return null; |
149 | 162 | }
|
150 | 163 |
|
151 | 164 | private S3Client acquireS3Client() {
|
152 | 165 | try {
|
153 | 166 | return S3ClientHelper.getS3Client();
|
154 | 167 | } catch (IOException e) {
|
155 |
| - throw new RuntimeException(e); |
| 168 | + throw new RuntimeException("Failed to acquire S3 client", e); |
156 | 169 | }
|
157 | 170 | }
|
158 | 171 |
|
159 | 172 | private SnsClient acquireSnsClient() {
|
160 | 173 | return SNSClientHelper.getSnsClient();
|
161 | 174 | }
|
162 | 175 | }
|
163 |
| - |
|
0 commit comments