Skip to content

Commit 386b7bc

Browse files
authored
GAM Serverless Implementation (#92)
* #Fix: Log4Java broken after refactoring - LogManager delay initialization * WebAppStartup base directory * Issue 74643 If the first object that was called after the webapp was started was GXOAuthAccessToken a nullpointer excpetion was throwed when the logger was initialized * In the last commit there was an error in the place that logger was created. * Improved Log Initial configuration * Revert Issue 74643 * Fix android build LogManager. * #Fix: Logger initialization fixes. REST, WS Native. * GX Serverless support * POM version update * Renamed artifactId * Renamed project folder to a more descriptive one: from gxawslambda to gxawsserverless. * Remove unnecesary plugin POM.xml * Serverless support for GXupload binary. * GeneXus Object id must be saved in Cache API. * Improved support for Upload in External Storage - Fix Upload Control not working with External Storage - Web Session not supported in Lambda (we should improve this) - Support for Uploads in Lambda * - Added some Tests - Remove PublicTemp y PrivateTemp folders from git. * GAM Serverless Implementation * Remove unused unit test
1 parent e2a8a19 commit 386b7bc

File tree

5 files changed

+172
-91
lines changed

5 files changed

+172
-91
lines changed
Lines changed: 122 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
package com.genexus.cloud.serverless.aws;
22

3+
import javax.servlet.ServletConfig;
4+
import javax.servlet.ServletContext;
35
import javax.ws.rs.core.Application;
46

7+
import com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletResponse;
8+
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest;
9+
import com.amazonaws.serverless.proxy.internal.servlet.AwsServletContext;
510
import com.genexus.specific.java.LogManager;
11+
import com.genexus.webpanels.GXObjectUploadServices;
12+
import com.genexus.webpanels.GXWebObjectStub;
613
import org.glassfish.jersey.server.ResourceConfig;
714

815
import com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler;
@@ -13,50 +20,122 @@
1320
import com.genexus.ApplicationContext;
1421
import com.genexus.diagnostics.core.ILogger;
1522
import com.genexus.util.IniFile;
23+
import com.genexus.webpanels.*;
24+
25+
import java.util.Enumeration;
26+
import java.util.concurrent.CountDownLatch;
27+
28+
import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletResponseWriter;
1629

1730
public class LambdaHandler implements RequestHandler<AwsProxyRequest, AwsProxyResponse> {
1831

19-
private static ILogger logger = null;
20-
public static JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = null;
21-
private static ResourceConfig jerseyApplication = null;
22-
private static final String BASE_REST_PATH = "/rest/";
23-
24-
public LambdaHandler() throws Exception {
25-
if (LambdaHandler.jerseyApplication == null) {
26-
logger = com.genexus.specific.java.LogManager.initialize(".", LambdaHandler.class);
27-
LambdaHandler.jerseyApplication = ResourceConfig.forApplication(initialize());
28-
if (jerseyApplication.getClasses().size() == 0) {
29-
String errMsg = "No endpoints found for this application";
30-
logger.error(errMsg);
31-
throw new Exception(errMsg);
32-
}
33-
jerseyApplication.register(GxObjectRestService.class);
34-
LambdaHandler.handler = JerseyLambdaContainerHandler.getAwsProxyHandler(LambdaHandler.jerseyApplication);
35-
}
36-
}
37-
38-
public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
39-
String path = awsProxyRequest.getPath().replace(BASE_REST_PATH, "/");
40-
awsProxyRequest.setPath(path);
41-
return this.handler.proxy(awsProxyRequest, context);
42-
}
43-
44-
private static Application initialize() throws Exception {
45-
LogManager.initialize(".");
46-
IniFile config = com.genexus.ConfigFileFinder.getConfigFile(null, "client.cfg", null);
47-
String className = config.getProperty("Client", "PACKAGE", null);
48-
Class<?> cls;
49-
try {
50-
cls = Class.forName(className + ".GXApplication");
51-
Application app = (Application) cls.newInstance();
52-
ApplicationContext appContext = ApplicationContext.getInstance();
53-
appContext.setServletEngine(true);
54-
appContext.setServletEngineDefaultPath("");
55-
com.genexus.Application.init(cls);
56-
return app;
57-
} catch (Exception e) {
58-
logger.error("Failed to initialize App", e);
59-
throw e;
60-
}
61-
}
32+
private static ILogger logger = null;
33+
public static JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = null;
34+
private static ResourceConfig jerseyApplication = null;
35+
private static final String BASE_REST_PATH = "/rest/";
36+
37+
public LambdaHandler() throws Exception {
38+
if (LambdaHandler.jerseyApplication == null) {
39+
LambdaHandler.jerseyApplication = ResourceConfig.forApplication(initialize());
40+
if (jerseyApplication.getClasses().size() == 0) {
41+
String errMsg = "No endpoints found for this application";
42+
logger.error(errMsg);
43+
throw new Exception(errMsg);
44+
}
45+
LambdaHandler.handler = JerseyLambdaContainerHandler.getAwsProxyHandler(LambdaHandler.jerseyApplication);
46+
}
47+
}
48+
49+
public AwsProxyResponse handleRequest(AwsProxyRequest awsProxyRequest, Context context) {
50+
String path = awsProxyRequest.getPath();
51+
if (!path.contains(BASE_REST_PATH)) {
52+
return handleServletRequest(awsProxyRequest, context);
53+
} else {
54+
awsProxyRequest.setPath(path.replace(BASE_REST_PATH, "/"));
55+
return this.handler.proxy(awsProxyRequest, context);
56+
}
57+
}
58+
59+
private AwsProxyResponse handleServletRequest(AwsProxyRequest awsProxyRequest, Context context) {
60+
try {
61+
GXWebObjectStub servlet = resolveServlet(awsProxyRequest);
62+
if (servlet != null) {
63+
CountDownLatch latch = new CountDownLatch(0);
64+
ServletContext servletContext = new AwsServletContext(null);//AwsServletContext.getInstance(lambdaContext, null);
65+
AwsProxyHttpServletRequest servletRequest = new AwsProxyHttpServletRequest(awsProxyRequest, context, null);
66+
servlet.init(new ServletConfig() {
67+
@Override
68+
public String getServletName() {
69+
return "";
70+
}
71+
72+
@Override
73+
public ServletContext getServletContext() {
74+
return servletContext;
75+
}
76+
77+
@Override
78+
public String getInitParameter(String s) {
79+
return "";
80+
}
81+
82+
@Override
83+
public Enumeration<String> getInitParameterNames() {
84+
return null;
85+
}
86+
});
87+
AwsHttpServletResponse response = new AwsHttpServletResponse(servletRequest, latch);
88+
servletRequest.setServletContext(servletContext);
89+
servlet.service(servletRequest, response);
90+
return new AwsProxyHttpServletResponseWriter().writeResponse(response, context);
91+
} else {
92+
return new AwsProxyResponse(404);
93+
}
94+
} catch (Exception e) {
95+
logger.error("Error processing servlet request", e);
96+
}
97+
return new AwsProxyResponse(500);
98+
}
99+
100+
private GXWebObjectStub resolveServlet(AwsProxyRequest awsProxyRequest) {
101+
//TODO: Use web.xml catalog to obtain Handler Class Name to instantiate.
102+
GXWebObjectStub handler = null;
103+
String path = awsProxyRequest.getPath();
104+
switch (path) {
105+
case "/gxobject":
106+
handler = new GXObjectUploadServices();
107+
break;
108+
case "/oauth/access_token":
109+
handler = new GXOAuthAccessToken();
110+
break;
111+
case "/oauth/logout":
112+
handler = new GXOAuthLogout();
113+
break;
114+
case "/oauth/userinfo":
115+
handler = new GXOAuthUserInfo();
116+
break;
117+
default:
118+
logger.error("Could not handle Servlet Path: " + path);
119+
}
120+
return handler;
121+
}
122+
123+
private static Application initialize() throws Exception {
124+
logger = LogManager.initialize(".", LambdaHandler.class);
125+
IniFile config = com.genexus.ConfigFileFinder.getConfigFile(null, "client.cfg", null);
126+
String className = config.getProperty("Client", "PACKAGE", null);
127+
Class<?> cls;
128+
try {
129+
cls = Class.forName(className + ".GXApplication");
130+
Application app = (Application) cls.newInstance();
131+
ApplicationContext appContext = ApplicationContext.getInstance();
132+
appContext.setServletEngine(true);
133+
appContext.setServletEngineDefaultPath("");
134+
com.genexus.Application.init(cls);
135+
return app;
136+
} catch (Exception e) {
137+
logger.error("Failed to initialize App", e);
138+
throw e;
139+
}
140+
}
62141
}

gxawsserverless/src/test/java/com/genexus/serverless/proxy/test/jersey/JerseyAwsProxyTest.java

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@
2020
import java.io.File;
2121
import java.io.FileInputStream;
2222
import java.io.IOException;
23-
import java.util.UUID;
2423

25-
import com.genexus.cloud.serverless.aws.GxObjectRestService;
24+
import com.genexus.webpanels.GXObjectUploadServices;
2625
import org.glassfish.jersey.server.ResourceConfig;
2726
import org.junit.Test;
2827

2928
import com.amazonaws.serverless.proxy.internal.testutils.AwsProxyRequestBuilder;
3029
import com.amazonaws.serverless.proxy.internal.testutils.MockLambdaContext;
30+
import com.amazonaws.serverless.proxy.internal.servlet.*;
3131
import com.amazonaws.serverless.proxy.jersey.JerseyLambdaContainerHandler;
3232
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
3333
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
@@ -39,6 +39,13 @@
3939
import com.genexus.cloud.serverless.aws.LambdaHandler;
4040
import org.junit.*;
4141

42+
43+
import javax.servlet.http.HttpServlet;
44+
import javax.servlet.http.HttpServletResponse;
45+
import java.util.Enumeration;
46+
import java.util.concurrent.CountDownLatch;
47+
import javax.servlet.*;
48+
4249
/**
4350
* Unit test class for the Jersey AWS_PROXY default implementation
4451
*/
@@ -47,12 +54,13 @@ public class JerseyAwsProxyTest {
4754
private static final String CUSTOM_HEADER_VALUE = "my-custom-value";
4855

4956
private ResourceConfig app;
57+
private LambdaHandler l;
5058

5159
@Before
5260
public void setUpStreams() {
5361
try {
5462
System.setProperty("LAMBDA_TASK_ROOT", ".");
55-
LambdaHandler l = new LambdaHandler();
63+
l = new LambdaHandler();
5664
handler = LambdaHandler.handler;
5765
} catch (Exception e) {
5866
e.printStackTrace();
@@ -220,7 +228,7 @@ public void testGXDataProviderWithParams() {
220228

221229
@Test
222230
public void gxUploadServicesTest() {
223-
File file = new File("pom.xml");
231+
File file = new File("pom.xml");
224232
try {
225233
FileInputStream stream = new FileInputStream(file);
226234

@@ -229,13 +237,28 @@ public void gxUploadServicesTest() {
229237
.header("Content-Type", "text/xml")
230238
.build();
231239

232-
AwsProxyResponse output = handler.proxy(request, lambdaContext);
240+
AwsProxyResponse output = l.handleRequest(request, lambdaContext);
233241
assertEquals(201, output.getStatusCode());
234-
assert( output.getBody().contains("gxupload"));
235-
}
236-
catch (Exception e) {
242+
assert (output.getBody().contains("gxupload"));
243+
} catch (Exception e) {
237244
fail(e.getMessage());
238245
}
239246
}
240247

248+
@Test
249+
@Ignore
250+
public void gxTestOAuthAccessToken() {
251+
252+
AwsProxyRequest request = new AwsProxyRequestBuilder("/oauth/access_token", "POST")
253+
.body("client_id=b0be5400435f42e588480fa06330f5ff&grant_type=password&username=ggallotti&password=gonzalo&scope=FullControl")
254+
.header("Content-Type", "application/x-www-form-urlencoded")
255+
//.header("Content-Length", "116")
256+
.build();
257+
258+
AwsProxyResponse output = l.handleRequest(request, lambdaContext);
259+
System.out.println(output);
260+
//assertEquals(200, output.getStatusCode());
261+
262+
}
263+
241264
}

java/src/main/java/com/genexus/Application.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ public static ExternalProvider getExternalProvider()
157157
}
158158
catch (Exception e)
159159
{
160+
logger.error("Unrecognized External Provider class : " + providerService.getName() + " / " + providerService.getClassName(), e);
160161
throw new InternalError("Unrecognized External Provider class : " + providerService.getName() + " / " + providerService.getClassName());
161162
}
162163
}

java/src/main/java/com/genexus/webpanels/HttpContextWeb.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ public Hashtable getPostData() {
346346
if (FileUpload.isMultipartContent(request))
347347
postData = parseMultipartPostData(getPostedparts());
348348
else
349-
postData = parsePostData(request, request.getContentLength(), request.getInputStream());
349+
postData = parsePostData(request, request.getInputStream());
350350
}
351351
Object value = postData.get("GXState");
352352
if (value != null) {
@@ -1129,10 +1129,10 @@ static private Hashtable parseMultipartPostData(FileItemCollection fileItemColle
11291129
return com.genexus.webpanels.HttpUtils.parseMultipartPostData(fileItemCollection);
11301130
}
11311131

1132-
static public Hashtable parsePostData(HttpServletRequest request, int len, ServletInputStream in) {
1132+
static public Hashtable parsePostData(HttpServletRequest request, ServletInputStream in) {
11331133
try {
11341134
// Nuestra versión del parsePostData utiliza UTF-8
1135-
return com.genexus.webpanels.HttpUtils.parsePostData(len, in);
1135+
return com.genexus.webpanels.HttpUtils.parsePostData(in);
11361136
} catch (IllegalArgumentException e) {
11371137
return com.genexus.webpanels.HttpUtils.parsePostData(request);
11381138
}
@@ -1161,12 +1161,11 @@ public String getDefaultPath() {
11611161
return ((java.io.File) servletContext.getAttribute(servletContext.TEMPDIR)).getAbsolutePath();
11621162
}
11631163

1164-
if (path == null) // AWS LAMBDA SERVERLESS
1164+
if (path == null) { // AWS LAMBDA SERVERLESS
11651165
path = System.getenv("LAMBDA_TASK_ROOT");
1166-
1167-
if (path == null) // AWS LAMBDA SERVERLESS
1168-
path = System.getProperty("LAMBDA_TASK_ROOT");
1169-
1166+
if (path == null)
1167+
path = System.getProperty("LAMBDA_TASK_ROOT");
1168+
}
11701169

11711170
if (path.endsWith(File.separator)) {
11721171
path = path.substring(0, path.length() - 1);

java/src/main/java/com/genexus/webpanels/HttpUtils.java

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
package com.genexus.webpanels;
2+
import org.apache.commons.io.IOUtils;
3+
24
import java.io.IOException;
35
import java.io.UnsupportedEncodingException;
46
import java.util.Enumeration;
@@ -103,43 +105,20 @@ public static Hashtable parsePostData(HttpServletRequest request)
103105
return ht;
104106
}
105107

106-
public static Hashtable parsePostData(int len, ServletInputStream in)
108+
public static Hashtable parsePostData(ServletInputStream in)
107109
{
108-
if(len <= 0)
109-
return new Hashtable();
110-
if(in == null)
111-
throw new IllegalArgumentException();
112-
byte postedBytes[] = new byte[len];
113-
try
114-
{
115-
int offset = 0;
116-
do
117-
{
118-
int inputLen = in.read(postedBytes, offset, len - offset);
119-
if(inputLen <= 0)
110+
if(in == null)
111+
throw new IllegalArgumentException();
112+
try
120113
{
121-
throw new IllegalArgumentException ("err.io.short_read : length " + len + " read : " + offset + " Content: \n" + new String(postedBytes));
114+
return parseQueryString(IOUtils.toString(in, "8859_1"));
115+
}
116+
catch(IOException e)
117+
{
118+
throw new IllegalArgumentException(e.getMessage());
122119
}
123-
offset += inputLen;
124-
} while(len - offset > 0);
125-
}
126-
catch(IOException e)
127-
{
128-
throw new IllegalArgumentException(e.getMessage());
129-
}
130-
try
131-
{
132-
String postedBody = new String(postedBytes, 0, len, "8859_1");
133-
return parseQueryString(postedBody);
134-
}
135-
catch(UnsupportedEncodingException e)
136-
{
137-
throw new IllegalArgumentException(e.getMessage());
138-
}
139120
}
140121

141-
private static String encoding = "UTF8";
142-
143122
private static String parseName(String s, StringBuffer sb)
144123
{
145124
sb.setLength(0);

0 commit comments

Comments
 (0)