-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
shorturl-s3-lambda: first full implementation
- Loading branch information
1 parent
9b7e281
commit 157e76f
Showing
16 changed files
with
389 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
...l-api/src/main/java/org/eclipse/epsilon/labs/playground/fn/shorturl/ShortURLResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package org.eclipse.epsilon.labs.playground.fn.shorturl; | ||
|
||
import io.micronaut.serde.annotation.Serdeable; | ||
|
||
@Serdeable | ||
public class ShortURLResponse extends ShortURLRequest { | ||
private String error; | ||
|
||
public String getError() { | ||
return error; | ||
} | ||
|
||
public void setError(String error) { | ||
this.error = error; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
plugins { | ||
id 'io.micronaut.application' | ||
id 'com.gradleup.shadow' | ||
id 'io.micronaut.openapi' | ||
id 'backend.java-conventions' | ||
} | ||
|
||
dependencies { | ||
implementation(project(':shorturl-api')) | ||
|
||
annotationProcessor(mn.micronaut.serde.processor) | ||
annotationProcessor(mn.micronaut.validation.processor) | ||
implementation("com.amazonaws:aws-lambda-java-events") | ||
implementation(mn.micronaut.http.client.jdk) | ||
implementation(mn.micronaut.aws.lambda.events.serde) | ||
implementation(mn.micronaut.aws.sdk.v2) | ||
implementation(mn.micronaut.function.aws) | ||
implementation(mn.micronaut.function.aws.custom.runtime) | ||
implementation(mn.micronaut.object.storage.aws) | ||
implementation(mn.micronaut.serde.jackson) | ||
implementation(mn.micronaut.validation) | ||
implementation("jakarta.validation:jakarta.validation-api") | ||
runtimeOnly("ch.qos.logback:logback-classic") | ||
|
||
testImplementation(mn.micronaut.object.storage.local) | ||
} | ||
|
||
application { | ||
mainClass = "org.eclipse.epsilon.labs.playground.FunctionLambdaRuntime" | ||
} | ||
|
||
micronaut { | ||
runtime("lambda_provided") | ||
testRuntime("junit5") | ||
processing { | ||
incremental(true) | ||
annotations("org.eclipse.epsilon.labs.playground.*") | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
...rl-s3-lambda/src/main/java/org/eclipse/epsilon/labs/playground/FunctionLambdaRuntime.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.eclipse.epsilon.labs.playground; | ||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; | ||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; | ||
import io.micronaut.function.aws.runtime.AbstractMicronautLambdaRuntime; | ||
import java.net.MalformedURLException; | ||
import com.amazonaws.services.lambda.runtime.RequestHandler; | ||
import io.micronaut.core.annotation.Nullable; | ||
public class FunctionLambdaRuntime extends AbstractMicronautLambdaRuntime<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent, APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> | ||
{ | ||
public static void main(String[] args) { | ||
try { | ||
new FunctionLambdaRuntime().run(args); | ||
} catch (MalformedURLException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
|
||
@Override | ||
@Nullable | ||
protected RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> createRequestHandler(String... args) { | ||
return new FunctionRequestHandler(); | ||
} | ||
} |
138 changes: 138 additions & 0 deletions
138
...l-s3-lambda/src/main/java/org/eclipse/epsilon/labs/playground/FunctionRequestHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package org.eclipse.epsilon.labs.playground; | ||
|
||
import io.micronaut.core.annotation.NonNull; | ||
import io.micronaut.function.aws.MicronautRequestHandler; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
import io.micronaut.http.HttpHeaders; | ||
import io.micronaut.http.MediaType; | ||
import io.micronaut.json.JsonMapper; | ||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; | ||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; | ||
import io.micronaut.objectstorage.ObjectStorageEntry; | ||
import io.micronaut.objectstorage.ObjectStorageOperations; | ||
import io.micronaut.objectstorage.request.UploadRequest; | ||
import io.micronaut.objectstorage.response.UploadResponse; | ||
import jakarta.inject.Inject; | ||
import jakarta.validation.ConstraintViolation; | ||
import jakarta.validation.Validator; | ||
import org.eclipse.epsilon.labs.playground.fn.shorturl.ShortURLRequest; | ||
import org.eclipse.epsilon.labs.playground.fn.shorturl.ShortURLResponse; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.util.Collections; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
import java.util.UUID; | ||
import java.util.stream.Collectors; | ||
|
||
public class FunctionRequestHandler extends MicronautRequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> { | ||
private static final Logger LOGGER = LoggerFactory.getLogger(FunctionRequestHandler.class); | ||
|
||
@Inject | ||
JsonMapper objectMapper; | ||
|
||
@Inject | ||
Validator validator; | ||
|
||
@Inject | ||
ObjectStorageOperations<?, ?, ?> objectStorage; | ||
|
||
@Override | ||
public APIGatewayProxyResponseEvent execute(APIGatewayProxyRequestEvent input) { | ||
APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); | ||
if (!"POST".equals(input.getHttpMethod())) { | ||
setResponseText(response, "Invalid HTTP method. Valid HTTP methods are: [POST]"); | ||
response.setStatusCode(400); | ||
return response; | ||
} | ||
|
||
try { | ||
var request = objectMapper.readValue(input.getBody(), ShortURLRequest.class); | ||
Set<ConstraintViolation<ShortURLRequest>> violations = validator.validate(request); | ||
if (!violations.isEmpty()) { | ||
processInvalidRequest(violations, response); | ||
} else { | ||
processValidRequest(request, response); | ||
} | ||
} catch (IOException e) { | ||
LOGGER.error(e.getMessage(), e); | ||
response.setStatusCode(500); | ||
} | ||
return response; | ||
} | ||
|
||
private void processInvalidRequest(Set<ConstraintViolation<ShortURLRequest>> violations, APIGatewayProxyResponseEvent response) throws IOException { | ||
var responseBody = new ShortURLResponse(); | ||
responseBody.setError("Invalid request: " + String.join(",", | ||
violations.stream().map(e -> e.getPropertyPath() + " " + e.getMessage() | ||
).collect(Collectors.toList()))); | ||
response.setStatusCode(400); | ||
setResponseJSON(response, responseBody); | ||
} | ||
|
||
protected static void setResponseText(APIGatewayProxyResponseEvent response, String body) { | ||
response.setBody(body); | ||
response.setHeaders(Collections.singletonMap( | ||
HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN)); | ||
} | ||
|
||
protected void setResponseJSON(APIGatewayProxyResponseEvent response, ShortURLResponse responseBody) throws IOException { | ||
response.setBody(objectMapper.writeValueAsString(responseBody)); | ||
response.setHeaders(Collections.singletonMap( | ||
HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)); | ||
} | ||
|
||
protected void processValidRequest(ShortURLRequest request, APIGatewayProxyResponseEvent response) throws IOException { | ||
var responseMsg = new ShortURLResponse(); | ||
if (request.getShortened() != null) { | ||
processDownloadRequest(request, response, responseMsg); | ||
} else if (request.getContent() != null) { | ||
processUploadRequest(request, response, responseMsg); | ||
} else { | ||
setResponseText(response, "Exactly one of shortened or content must be specified"); | ||
response.setStatusCode(400); | ||
} | ||
} | ||
|
||
protected void processUploadRequest(ShortURLRequest request, APIGatewayProxyResponseEvent response, ShortURLResponse responseMsg) throws IOException { | ||
String key = getShortened(request.getContent()); | ||
UploadRequest uploadRequest = UploadRequest.fromBytes( | ||
request.getContent().getBytes(StandardCharsets.UTF_8), key); | ||
|
||
@NonNull UploadResponse<?> uploadResponse = objectStorage.upload(uploadRequest); | ||
responseMsg.setShortened(uploadResponse.getKey()); | ||
setResponseJSON(response, responseMsg); | ||
response.setStatusCode(200); | ||
} | ||
|
||
protected void processDownloadRequest(ShortURLRequest request, APIGatewayProxyResponseEvent response, ShortURLResponse responseMsg) throws IOException { | ||
Optional<ObjectStorageEntry<?>> content = objectStorage.retrieve(request.getShortened()); | ||
if (content.isPresent()) { | ||
try ( | ||
InputStream is = content.get().getInputStream(); | ||
ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||
) { | ||
byte[] buffer = new byte[1024]; | ||
for (int length; (length = is.read(buffer)) != -1; ) { | ||
baos.write(buffer, 0, length); | ||
} | ||
responseMsg.setContent(baos.toString(StandardCharsets.UTF_8)); | ||
setResponseJSON(response, responseMsg); | ||
response.setStatusCode(200); | ||
} | ||
} else { | ||
response.setStatusCode(404); | ||
} | ||
} | ||
|
||
protected String getShortened(String content) { | ||
return UUID.nameUUIDFromBytes(content.getBytes()).toString().substring(0, 8); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
#Thu Dec 05 11:57:54 UTC 2024 | ||
micronaut.application.name=shorturl-s3-lambda |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<configuration> | ||
|
||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | ||
<!-- encoders are assigned the type | ||
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> | ||
<encoder> | ||
<pattern>%cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n</pattern> | ||
</encoder> | ||
</appender> | ||
|
||
<root level="info"> | ||
<appender-ref ref="STDOUT" /> | ||
</root> | ||
</configuration> |
Oops, something went wrong.