Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cumulative fixpack (README, CORS, logging) #55

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ target
.project
.classpath
.settings
/bin/
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Lambada framework is a REST framework that implements [JAX-RS](https://jax-rs-sp
* Support for the most common JAX-RS annotations.
* XML based configuration for Lambda function including VPC, custom execution role
* Support for multiple stages and regions.
* Support for CORS and Custom Response Headers (using native JAX RS Response.header())

Lambada consists of a runtime module, a local simulator and finally a maven plugin to configure and deploy the whole project to API Gateway.

Expand Down Expand Up @@ -77,7 +78,7 @@ The configuration values should be present under maven plugin's configuration.
<plugins>
<plugin>
<groupId>org.lambadaframework</groupId>
<artifactId>maven-plugin</artifactId>
<artifactId>lambada-maven-plugin</artifactId>
<version>0.0.6</version>
<configuration>
...
Expand Down
2 changes: 1 addition & 1 deletion jax-rs-extractor/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>org.lambadaframework</groupId>
<artifactId>lambada</artifactId>
<version>0.0.6</version>
<version>0.0.6-cors</version>
</parent>
<artifactId>jax-rs-extractor</artifactId>
<packaging>jar</packaging>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ private List<Class<? extends Object>> getClassesInPackage(String packageName, Cl
final String classSeperator = ".";


final String jarPath = clazz.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
final URL location = clazz.getProtectionDomain().getCodeSource().getLocation();
final String jarPath = new File(location.toURI()).getAbsolutePath();

if (jarPath.endsWith(".jar")) {
/**
Expand All @@ -115,7 +116,7 @@ private List<Class<? extends Object>> getClassesInPackage(String packageName, Cl
return getClassesInJarFile(jarPath);
}

final String packagePath = jarPath + packageName.replace(classSeperator, File.separator);
final String packagePath = jarPath + File.separator + packageName.replace(classSeperator, File.separator);

Files.walkFileTree(Paths.get(packagePath), new SimpleFileVisitor<Path>() {
@Override
Expand All @@ -125,7 +126,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
String fileName = file.toString();

if (fileName.endsWith(classExtension)) {
String className = fileName.replace(jarPath, blank).replace(File.separator, classSeperator);
String className = fileName.replace(jarPath + File.separator, blank).replace(File.separator, classSeperator);
className = className.substring(0, className.length() - classExtension.length());

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import java.io.File;
import java.io.FilenameFilter;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.junit.Test;
Expand Down Expand Up @@ -43,8 +45,24 @@ public void testScanPackage() throws Exception {
}
assertEquals(6, totalMethod);

Collections.sort(resourceList, new PathComparator());

assertEquals("/resource1", resourceList.get(0).getPath());
assertEquals("/resource1", resourceList.get(1).getPath());
assertEquals("/resource1/{id}", resourceList.get(2).getPath());
assertEquals("/resource1/{id}/users", resourceList.get(3).getPath());
}

private class PathComparator implements Comparator<Resource> {

@Override
public int compare(Resource o1, Resource o2) {
return o1.getPath().compareTo(o2.getPath());
}

@Override
public boolean equals(Object obj) {
return false;
}
}
}
6 changes: 1 addition & 5 deletions lambada-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@
<parent>
<groupId>org.lambadaframework</groupId>
<artifactId>lambada</artifactId>
<version>0.0.6</version>
<version>0.0.6-cors</version>
</parent>

<artifactId>lambada-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>

<properties>
<aws-sdk.version>1.11.9</aws-sdk.version>
</properties>

<name>Lambada Deploying Plugin</name>

<dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
package org.lambadaframework.aws;

import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.ws.rs.HeaderParam;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

import org.lambadaframework.deployer.Deployment;
import org.lambadaframework.jaxrs.JAXRSParser;
import org.lambadaframework.jaxrs.model.Resource;
import org.lambadaframework.jaxrs.model.ResourceMethod;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonWebServiceRequest;
import com.amazonaws.ClientConfiguration;
Expand All @@ -10,25 +26,11 @@
import com.amazonaws.services.apigateway.AmazonApiGateway;
import com.amazonaws.services.apigateway.AmazonApiGatewayClient;
import com.amazonaws.services.apigateway.model.*;
import org.lambadaframework.deployer.Deployment;
import org.lambadaframework.jaxrs.model.Resource;
import org.lambadaframework.jaxrs.model.ResourceMethod;
import org.lambadaframework.jaxrs.JAXRSParser;

import javax.ws.rs.HeaderParam;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;


public class ApiGateway extends AWSTools {


protected static final int API_LIMIT = 500;
protected static final int API_LIMIT = 500;

protected static final String PACKAGE_VARIABLE = "<PACKAGE>";

Expand Down Expand Up @@ -66,8 +68,12 @@ public class ApiGateway extends AWSTools {
" #end\n" +
"}";


protected final String OUTPUT_TEMPLATE = "$input.json('$.entity')";
protected final String OUTPUT_JSON =
"$input.json('$.entity')\n" +
"#set($map = $util.parseJson($input.json('$.headers')))\n" +
"#foreach ($mapEntry in $map.entrySet())\n" +
"#set($context.responseOverride.header[\"${mapEntry.key}\"] = \"${mapEntry.value}\")\n" +
"#end\n";

protected final String AUTHORIZATION_TYPE = "NONE";
protected final String INVOCATION_METHOD = "POST";
Expand Down Expand Up @@ -491,7 +497,7 @@ protected void deployMethods(Resource jerseyResource, com.amazonaws.services.api
.withResourceId(apiGatewayResource.getId())
.withHttpMethod(httpMethod)
.withSelectionPattern(selectionPattern)
.withResponseTemplates(getResponseTemplate())
.withResponseTemplates(getResponseTemplate(method))
.withStatusCode(String.valueOf(responseCode))
);

Expand All @@ -500,13 +506,33 @@ protected void deployMethods(Resource jerseyResource, com.amazonaws.services.api
});
}

private static final List<MediaType> BINARY_TYPES = Arrays.asList(
new MediaType[] {
MediaType.APPLICATION_OCTET_STREAM_TYPE,
new MediaType("image", "jpeg"),
new MediaType("image", "png")
});

private Map<String, String> getResponseTemplate() {
private Map<String, String> getResponseTemplate(ResourceMethod method) {

Map<String, String> responseTemplate = new LinkedHashMap<>();

responseTemplate.put(MediaType.APPLICATION_JSON, OUTPUT_TEMPLATE);


if(method.getProducedTypes().size() > 0 && BINARY_TYPES.contains(method.getProducedTypes().get(0))) {
if(method.getProducedTypes().size() != 1) {
throw new IllegalArgumentException("Ambiguous Produces(MediaType) annotations.");
}
MediaType primaryType = method.getProducedTypes().get(0);
if(!method.getInvocable().getRawResponseType().isAssignableFrom(byte[].class)) {
throw new IllegalArgumentException(primaryType + " requires a byte[] return.");
}
responseTemplate.put(MediaType.APPLICATION_JSON,
String.format(
"$util.base64Decode($input.json('$.entity'))\n" +
"#set($context.responseOverride.header['Content-Type'] = '%s')\n", primaryType.toString()));
}
else {
responseTemplate.put(MediaType.APPLICATION_JSON, OUTPUT_JSON);
}
return responseTemplate;
}

Expand All @@ -515,6 +541,7 @@ protected Map<String, String> getInputTemplate(ResourceMethod jerseyMethod) {
String packageName = jerseyMethod.getInvocable().getHandler().getHandlerClass().getPackage().getName();
Map<String, String> requestTemplates = new LinkedHashMap<>();
requestTemplates.put(MediaType.APPLICATION_JSON, INPUT_TEMPLATE.replace(PACKAGE_VARIABLE, packageName));
requestTemplates.put(MediaType.TEXT_PLAIN, INPUT_TEMPLATE.replace(PACKAGE_VARIABLE, packageName));
return requestTemplates;
}

Expand Down
2 changes: 1 addition & 1 deletion logger/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>lambada</artifactId>
<groupId>org.lambadaframework</groupId>
<version>0.0.6</version>
<version>0.0.6-cors</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<name>Log support</name>
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.lambadaframework</groupId>
<artifactId>lambada</artifactId>
<version>0.0.6</version>
<version>0.0.6-cors</version>
<packaging>pom</packaging>

<name>${project.groupId}:${project.artifactId}</name>
Expand Down Expand Up @@ -36,7 +36,7 @@

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<aws-sdk.version>1.11.13</aws-sdk.version>
<aws-sdk.version>1.11.524</aws-sdk.version>
<junit.version>4.12</junit.version>
<logback.version>1.1.7</logback.version>
<mockito.version>1.10.19</mockito.version>
Expand Down
2 changes: 1 addition & 1 deletion runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<parent>
<groupId>org.lambadaframework</groupId>
<artifactId>lambada</artifactId>
<version>0.0.6</version>
<version>0.0.6-cors</version>
</parent>
<artifactId>runtime</artifactId>
<packaging>jar</packaging>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import org.lambadaframework.jaxrs.model.ResourceMethod;
import org.lambadaframework.runtime.errorhandling.ErrorHandler;
import org.lambadaframework.runtime.models.Request;
import org.lambadaframework.runtime.models.Response;
import org.lambadaframework.runtime.router.Router;
Expand Down Expand Up @@ -61,7 +60,8 @@ public Response handleRequest(Request request, Context context) {
logger.debug("Returning result.");
return Response.buildFromJAXRSResponse(ResourceMethodInvoker.invoke(matchedResourceMethod, request, context));
} catch (Exception ex) {
return ErrorHandler.getErrorResponse(ex);
logger.fatal(request.toString(), ex);
return new Response(502, "Internal Error: Uncaught exception logged by framework.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ResourceMethodInvoker {
Expand Down Expand Up @@ -69,6 +70,8 @@ public static Object invoke(ResourceMethod resourceMethod,
Invocable invocable = resourceMethod.getInvocable();

Method method = invocable.getHandlingMethod();
logger.debug("Method is " + method.toString());

Class<?> clazz = invocable.getHandler().getHandlerClass();

Object instance = clazz.newInstance();
Expand Down Expand Up @@ -101,7 +104,7 @@ public static Object invoke(ResourceMethod resourceMethod,
/**
* Query parameter
*/
if (parameter.isAnnotationPresent(QueryParam.class)) {
else if (parameter.isAnnotationPresent(QueryParam.class)) {
QueryParam annotation = parameter.getAnnotation(QueryParam.class);
varargs.add(toObject(
request.getQueryParams().get(annotation.value()), parameterClass
Expand All @@ -112,15 +115,20 @@ public static Object invoke(ResourceMethod resourceMethod,
/**
* Query parameter
*/
if (parameter.isAnnotationPresent(HeaderParam.class)) {
else if (parameter.isAnnotationPresent(HeaderParam.class)) {
HeaderParam annotation = parameter.getAnnotation(HeaderParam.class);
varargs.add(toObject(
request.getRequestHeaders().get(annotation.value()), parameterClass
)
);
}

if (consumesAnnotation != null && consumesSpecificType(consumesAnnotation, MediaType.APPLICATION_JSON)) {
/**
* text/plain is treated the same as application/json, in order to avoid pre-flight CORS OPTION request
*
*/
else if (consumesAnnotation != null && consumesSpecificType(consumesAnnotation,
Arrays.asList(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN))) {
if (parameterClass == String.class) {
//Pass raw request body
varargs.add(request.getRequestBody());
Expand All @@ -140,19 +148,28 @@ public static Object invoke(ResourceMethod resourceMethod,
/**
* Lambda Context can be automatically injected
*/
if (parameter.getType() == Context.class) {
else if (parameter.getType() == Context.class) {
varargs.add(lambdaContext);
}

/**
* last resort
*/
else {
throw new IllegalArgumentException("Can't handle parameter type [" + parameter.getType() + "]");
}
}


logger.debug("Varargs = " + varargs);

return method.invoke(instance, varargs.toArray());
}

private static boolean consumesSpecificType(Consumes annotation, String type) {
private static boolean consumesSpecificType(Consumes annotation, List<String> types) {

String[] consumingTypes = annotation.value();
for (String consumingType : consumingTypes) {
if (type.equals(consumingType)) {
if (types.contains(consumingType)) {
return true;
}
}
Expand Down
Loading