Skip to content

Commit

Permalink
Merge pull request #1042 from evanchooly/lambda
Browse files Browse the repository at this point in the history
Basic support for AWS Lambdas
  • Loading branch information
stuartwdouglas committed Feb 28, 2019
2 parents 32ea8a4 + f56ee9a commit 1870138
Show file tree
Hide file tree
Showing 16 changed files with 480 additions and 1 deletion.
17 changes: 17 additions & 0 deletions build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
<debezium.version>0.8.3.Final</debezium.version>
<zookeeper.version>3.4.10</zookeeper.version>
<scala.version>2.12.2</scala.version>
<aws-lambda-java.version>1.1.0</aws-lambda-java.version>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -569,6 +570,16 @@
<artifactId>quarkus-infinispan-client-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-lambda-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-lambda-runtime</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
Expand Down Expand Up @@ -1434,6 +1445,12 @@
<version>${reactive-streams.version}</version>
</dependency>

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>${aws-lambda-java.version}</version>
</dependency>

</dependencies>
</dependencyManagement>

Expand Down
62 changes: 62 additions & 0 deletions extensions/lambda/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-lambda</artifactId>
<version>1.0.0.Alpha1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>quarkus-lambda-deployment</artifactId>
<name>Quarkus - Lambda - Deployment</name>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-lambda-runtime</artifactId>
</dependency>

<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-undertow-deployment</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.quarkus.lambda.deployment;

import org.jboss.builder.item.MultiBuildItem;

public final class LambdaBuildItem extends MultiBuildItem {

private final String className;
private final String path;

public LambdaBuildItem(String className, String path) {
this.className = className;
this.path = path;
}

public String getClassName() {
return className;
}

public String getPath() {
return path;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.quarkus.lambda.deployment;

import java.util.ArrayList;
import java.util.List;

import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.MethodInfo;

import com.amazonaws.services.lambda.runtime.RequestHandler;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.BeanContainerBuildItem;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.ExecutionTime;
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.substrate.ReflectiveHierarchyBuildItem;
import io.quarkus.deployment.recording.RecorderContext;
import io.quarkus.lambda.runtime.LambdaServlet;
import io.quarkus.lambda.runtime.LambdaTemplate;
import io.quarkus.undertow.ServletBuildItem;

public final class LambdaProcessor {
private static final DotName REQUEST_HANDLER = DotName.createSimple(RequestHandler.class.getName());

@BuildStep
List<LambdaBuildItem> discover(CombinedIndexBuildItem combinedIndexBuildItem,
BuildProducer<ReflectiveHierarchyBuildItem> reflectiveClasses) {
List<LambdaBuildItem> ret = new ArrayList<>();

for (ClassInfo info : combinedIndexBuildItem.getIndex().getAllKnownImplementors(REQUEST_HANDLER)) {
final DotName name = info.name();

final String lambda = name.toString();
final String mapping = name.local();
ret.add(new LambdaBuildItem(lambda, mapping));

ClassInfo current = info;
boolean done = false;
while (current != null && !done) {
for (MethodInfo method : current.methods()) {
if (method.name().equals("handleRequest")
&& method.parameters().size() == 2
&& !method.parameters().get(0).name().equals(DotName.createSimple(Object.class.getName()))) {
reflectiveClasses.produce(new ReflectiveHierarchyBuildItem(method.parameters().get(0)));
done = true;
break;
}
}
current = combinedIndexBuildItem.getIndex().getClassByName(current.superName());
}
}
return ret;
}

@BuildStep
List<AdditionalBeanBuildItem> beans(List<LambdaBuildItem> lambdas) {
List<AdditionalBeanBuildItem> ret = new ArrayList<>();
for (LambdaBuildItem i : lambdas) {
ret.add(new AdditionalBeanBuildItem(false, i.getClassName()));
}
return ret;
}

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
public void servlets(List<LambdaBuildItem> lambdas,
BuildProducer<ServletBuildItem> servletProducer,
BeanContainerBuildItem beanContainerBuildItem,
LambdaTemplate template,
RecorderContext context) {

for (LambdaBuildItem info : lambdas) {
servletProducer.produce(ServletBuildItem.builder(info.getClassName(), LambdaServlet.class.getName())
.setLoadOnStartup(1)
.setInstanceFactory(template.lambdaServletInstanceFactory(
(Class<? extends RequestHandler>) context.classProxy(info.getClassName()),
beanContainerBuildItem.getValue()))
.addMapping("/" + info.getPath())
.build());
}
}
}
23 changes: 23 additions & 0 deletions extensions/lambda/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<artifactId>quarkus-build-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>1.0.0.Alpha1-SNAPSHOT</version>
<relativePath>../../build-parent/pom.xml</relativePath>
</parent>

<artifactId>quarkus-lambda</artifactId>
<name>Quarkus - Lambda</name>
<packaging>pom</packaging>

<modules>
<module>runtime</module>
<module>deployment</module>
</modules>

</project>
55 changes: 55 additions & 0 deletions extensions/lambda/runtime/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-lambda</artifactId>
<version>1.0.0.Alpha1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>quarkus-lambda-runtime</artifactId>
<name>Quarkus - Lambda - Runtime</name>

<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core-runtime</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-undertow-runtime</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.quarkus.lambda.runtime;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.quarkus.arc.runtime.BeanContainer;

public class LambdaServlet extends HttpServlet {
private static final String ALLOWED_METHODS = "POST, OPTIONS";
private final BeanContainer.Instance<? extends RequestHandler> handler;
private final ObjectMapper mapper = new ObjectMapper();
private final Class<?> targetType;

public LambdaServlet(final BeanContainer.Instance<? extends RequestHandler> instance, Class<?> targetType) {
this.handler = instance;
this.targetType = targetType;
}

@Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) {
addCorsResponseHeaders(resp);
resp.addHeader("Allow", ALLOWED_METHODS);
}

@Override
@SuppressWarnings("unchecked")
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
addCorsResponseHeaders(resp);
String body = req.getReader().lines().collect(Collectors.joining(System.lineSeparator()));

final Object value = mapper.readValue(body, targetType);

resp.getOutputStream().print(mapper.writeValueAsString(handler.get().handleRequest(value, null)));
}

@Override
public void destroy() {
handler.close();
}

private static void addCorsResponseHeaders(HttpServletResponse response) {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Methods", ALLOWED_METHODS);
response.addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
response.addHeader("Access-Control-Max-Age", "86400");
}
}
Loading

0 comments on commit 1870138

Please sign in to comment.