Skip to content
Merged
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 gxawsserverless/GXApplicationClasses.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
com.gx.serverless.test.test_services_rest
com.gx.serverless.test.receivenumber_services_rest
com.gx.serverless.test.sessionset_services_rest
com.genexus.serverless.proxy.test.jersey.EchoJerseyResource
2 changes: 1 addition & 1 deletion gxawsserverless/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<dependency>
<groupId>com.amazonaws.serverless</groupId>
<artifactId>aws-serverless-java-container-jersey</artifactId>
<version>1.6</version>
<version>1.8.2</version>
</dependency>

<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,45 @@
package com.genexus.cloud.serverless.aws;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.ws.rs.core.Application;

import com.amazonaws.serverless.proxy.RequestReader;
import com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletResponse;
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest;
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletResponseWriter;
import com.amazonaws.serverless.proxy.internal.servlet.AwsServletContext;
import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap;
import com.genexus.cloud.serverless.aws.handler.AwsGxServletResponse;
import com.genexus.specific.java.Connect;
import com.genexus.specific.java.LogManager;
import com.genexus.webpanels.GXWebObjectStub;
import org.glassfish.jersey.server.ResourceConfig;

import com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.model.MultiValuedTreeMap;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.genexus.ApplicationContext;
import com.genexus.cloud.serverless.aws.handler.AwsGxServletResponse;
import com.genexus.cloud.serverless.aws.handler.LambdaApplicationHelper;
import com.genexus.diagnostics.core.ILogger;
import com.genexus.util.IniFile;
import com.genexus.webpanels.*;
import com.genexus.specific.java.LogManager;
import com.genexus.webpanels.GXOAuthAccessToken;
import com.genexus.webpanels.GXOAuthLogout;
import com.genexus.webpanels.GXOAuthUserInfo;
import com.genexus.webpanels.GXWebObjectStub;
import org.glassfish.jersey.server.ResourceConfig;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletResponseWriter;

public class LambdaHandler implements RequestHandler<AwsProxyRequest, AwsProxyResponse> {
private static ILogger logger = null;
public static JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = null;
private static ResourceConfig jerseyApplication = null;
private static final String BASE_REST_PATH = "/rest/";
private static final String GX_APPLICATION_CLASS = "GXApplication";

public LambdaHandler() throws Exception {
if (LambdaHandler.jerseyApplication == null) {
JerseyLambdaContainerHandler.getContainerConfig().setDefaultContentCharset("UTF-8");
LambdaHandler.jerseyApplication = ResourceConfig.forApplication(initialize());
logger = LogManager.initialize(".", LambdaHandler.class);
LambdaHandler.jerseyApplication = ResourceConfig.forApplication(LambdaApplicationHelper.initialize());
if (jerseyApplication.getClasses().size() == 0) {
String errMsg = "No endpoints found for this application";
logger.error(errMsg);
throw new Exception(errMsg);
logger.error("No HTTP endpoints found for this application");
}
LambdaHandler.handler = JerseyLambdaContainerHandler.getAwsProxyHandler(LambdaHandler.jerseyApplication);
}
Expand All @@ -61,7 +55,7 @@ public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context c
dumpRequest(awsProxyRequest);

logger.debug("Before handle Request");

awsProxyRequest.setPath(path.replace(BASE_REST_PATH, "/"));
AwsProxyResponse response = this.handler.proxy(awsProxyRequest, context);

Expand All @@ -70,7 +64,7 @@ public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context c
awsProxyRequest.setPath(path);
logger.debug("Trying servlet request: " + path);
AwsGxServletResponse servletResponse = handleServletRequest(awsProxyRequest, context);
if (servletResponse.wasHandled()){
if (servletResponse.wasHandled()) {
response = servletResponse.getAwsProxyResponse();
}
}
Expand Down Expand Up @@ -166,27 +160,8 @@ private GXWebObjectStub resolveServlet(AwsProxyRequest awsProxyRequest) {
return handler;
}

private static Application initialize() throws Exception {
logger = LogManager.initialize(".", LambdaHandler.class);
Connect.init();
IniFile config = com.genexus.ConfigFileFinder.getConfigFile(null, "client.cfg", null);
String className = config.getProperty("Client", "PACKAGE", null);
Class<?> cls;
try {
cls = Class.forName(className.isEmpty() ? GX_APPLICATION_CLASS: String.format("%s.%s", className, GX_APPLICATION_CLASS));
Application app = (Application) cls.getDeclaredConstructor().newInstance();
ApplicationContext appContext = ApplicationContext.getInstance();
appContext.setServletEngine(true);
appContext.setServletEngineDefaultPath("");
com.genexus.Application.init(cls);
return app;
} catch (Exception e) {
logger.error("Failed to initialize App", e);
throw e;
}
}

private void dumpRequest(AwsProxyRequest awsProxyRequest){
private void dumpRequest(AwsProxyRequest awsProxyRequest) {
String lineSeparator = System.lineSeparator();
String reqData = String.format("Path: %s", awsProxyRequest.getPath()) + lineSeparator;
reqData += String.format("Method: %s", awsProxyRequest.getHttpMethod()) + lineSeparator;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.genexus.cloud.serverless.aws.handler;

import com.genexus.ApplicationContext;
import com.genexus.specific.java.Connect;
import com.genexus.util.IniFile;

import javax.ws.rs.core.Application;

public class LambdaApplicationHelper {
private static final String GX_APPLICATION_CLASS = "GXApplication";
private static final String GX_APPLICATION_CONFIG = "client.cfg";

public static Application initialize() throws Exception {
Connect.init();
IniFile config = com.genexus.ConfigFileFinder.getConfigFile(null, GX_APPLICATION_CONFIG, null);
String className = config.getProperty("Client", "PACKAGE", null);
Class<?> cls = Class.forName(className.isEmpty() ? GX_APPLICATION_CLASS : String.format("%s.%s", className, GX_APPLICATION_CLASS));
Application app = (Application) cls.getDeclaredConstructor().newInstance();
ApplicationContext appContext = ApplicationContext.getInstance();
appContext.setServletEngine(true);
appContext.setServletEngineDefaultPath("");
com.genexus.Application.init(cls);
return app;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.genexus.cloud.serverless.aws.handler;

import com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.genexus.cloud.serverless.aws.LambdaHandler;
import com.genexus.cloud.serverless.aws.handler.internal.GxJerseyLambdaContainerHandlerFactory;
import com.genexus.diagnostics.core.ILogger;
import com.genexus.specific.java.LogManager;
import org.glassfish.jersey.server.ResourceConfig;

import java.util.Map;

public class LambdaHttpApiHandler implements RequestHandler<HttpApiV2ProxyRequest, AwsProxyResponse> {
private static final String BASE_REST_PATH = "/rest/";
public static JerseyLambdaContainerHandler<HttpApiV2ProxyRequest, AwsProxyResponse> handler = null;
private static ILogger logger = null;
private static ResourceConfig jerseyApplication = null;

public LambdaHttpApiHandler() throws Exception {
if (LambdaHttpApiHandler.jerseyApplication == null) {
JerseyLambdaContainerHandler.getContainerConfig().setDefaultContentCharset("UTF-8");
logger = LogManager.initialize(".", LambdaHandler.class);
LambdaHttpApiHandler.jerseyApplication = ResourceConfig.forApplication(LambdaApplicationHelper.initialize());

if (jerseyApplication.getClasses().size() == 0) {
logger.error("No HTTP endpoints found for this application");
}

handler = GxJerseyLambdaContainerHandlerFactory.getHttpApiV2ProxyHandler(LambdaHttpApiHandler.jerseyApplication);
}
}

@Override
public AwsProxyResponse handleRequest(HttpApiV2ProxyRequest awsProxyRequest, Context context) {
if (logger.isDebugEnabled()) {
dumpRequest(awsProxyRequest);
}

String path = awsProxyRequest.getRawPath();
prepareRequest(awsProxyRequest);

logger.debug("Before handle Request");

awsProxyRequest.setRawPath(path.replace(BASE_REST_PATH, "/"));
AwsProxyResponse response = handler.proxy(awsProxyRequest, context);

int statusCode = response.getStatusCode();
logger.debug("After handle Request - Status Code: " + statusCode);

if (statusCode >= 404 && statusCode <= 599) {
logger.warn(String.format("Request could not be handled (%d): %s", response.getStatusCode(), path));
}
return response;
}

private void prepareRequest(HttpApiV2ProxyRequest awsProxyRequest) {
Map<String, String> headers = awsProxyRequest.getHeaders();

if (headers == null) {
return;
}

// In Jersey lambda context, the Referer Header has a special meaning. So we copy it to another Header.
String referer = headers.get("Referer");
if (referer != null && !referer.isEmpty()) {
headers.put("GX-Referer", referer);
}
}

private void dumpRequest(HttpApiV2ProxyRequest awsProxyRequest) {
String lineSeparator = System.lineSeparator();
String reqData = String.format("Path: %s", awsProxyRequest.getRawPath()) + lineSeparator;
reqData += String.format("Method: %s", awsProxyRequest.getRequestContext().getHttp().getMethod()) + lineSeparator;
reqData += String.format("QueryString: %s", awsProxyRequest.getRawQueryString()) + lineSeparator;
reqData += String.format("Body: %sn", awsProxyRequest.getBody()) + lineSeparator;
logger.debug(reqData);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.genexus.cloud.serverless.aws.handler.internal;

import com.amazonaws.serverless.exceptions.InvalidRequestEventException;
import com.amazonaws.serverless.proxy.RequestReader;
import com.amazonaws.serverless.proxy.internal.servlet.AwsHttpApiV2ProxyHttpServletRequest;
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
import com.amazonaws.serverless.proxy.model.ContainerConfig;
import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
import com.amazonaws.services.lambda.runtime.Context;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.SecurityContext;

public class GxAwsHttpApiV2HttpServletRequestReader extends RequestReader<HttpApiV2ProxyRequest, HttpServletRequest> {
static final String INVALID_REQUEST_ERROR = "The incoming event is not a valid HTTP API v2 proxy request";

@Override
public HttpServletRequest readRequest(HttpApiV2ProxyRequest request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config) throws InvalidRequestEventException {
if (request.getRequestContext() == null || request.getRequestContext().getHttp().getMethod() == null || request.getRequestContext().getHttp().getMethod().equals("")) {
throw new InvalidRequestEventException(INVALID_REQUEST_ERROR);
}

// clean out the request path based on the container config
request.setRawPath(stripBasePath(request.getRawPath(), config));

AwsHttpApiV2ProxyHttpServletRequest servletRequest = new AwsHttpApiV2ProxyHttpServletRequest(request, lambdaContext, securityContext, config);

AwsProxyRequestContext rContext = new AwsProxyRequestContext();
rContext.setRequestId(request.getRequestContext().getRequestId());
servletRequest.setAttribute(API_GATEWAY_CONTEXT_PROPERTY, rContext);
servletRequest.setAttribute(HTTP_API_CONTEXT_PROPERTY, request.getRequestContext());
servletRequest.setAttribute(HTTP_API_STAGE_VARS_PROPERTY, request.getStageVariables());
servletRequest.setAttribute(HTTP_API_EVENT_PROPERTY, request);
servletRequest.setAttribute(LAMBDA_CONTEXT_PROPERTY, lambdaContext);
servletRequest.setAttribute(JAX_SECURITY_CONTEXT_PROPERTY, securityContext);

return servletRequest;
}

@Override
protected Class<? extends HttpApiV2ProxyRequest> getRequestClass() {
return HttpApiV2ProxyRequest.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.genexus.cloud.serverless.aws.handler.internal;

import com.amazonaws.serverless.proxy.*;
import com.amazonaws.serverless.proxy.internal.servlet.*;
import com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;

import javax.ws.rs.core.Application;

public class GxJerseyLambdaContainerHandlerFactory {
public static JerseyLambdaContainerHandler<HttpApiV2ProxyRequest, AwsProxyResponse> getHttpApiV2ProxyHandler(Application jaxRsApplication) {
JerseyLambdaContainerHandler<HttpApiV2ProxyRequest, AwsProxyResponse> newHandler = new JerseyLambdaContainerHandler<>(
HttpApiV2ProxyRequest.class,
AwsProxyResponse.class,
new GxAwsHttpApiV2HttpServletRequestReader(),
new AwsProxyHttpServletResponseWriter(true),
new AwsHttpApiV2SecurityContextWriter(),
new AwsProxyExceptionHandler(),
jaxRsApplication);
newHandler.initialize();
return newHandler;
}
}
Loading