diff --git a/examples/complete/events/test-infoset-request.http b/examples/complete/events/test-infoset-request.http index d8ebc79..bb7f9ac 100644 --- a/examples/complete/events/test-infoset-request.http +++ b/examples/complete/events/test-infoset-request.http @@ -1,5 +1,5 @@ ### Send POST request with json body -POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/execute/ +POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/annie Content-Type: application/fastinfoset Accept: application/json @@ -17,14 +17,14 @@ client.test("Response text Matches.", function() { %} ### Same with GATE XML Response -POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/execute/ +POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/annie/ Content-Type: application/fastinfoset Accept: application/gate+xml < hello-world.finf ### Same with GATE XML Response -POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/execute/ +POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/annie/ Content-Type: application/fastinfoset Accept: application/fastinfoset diff --git a/examples/complete/events/test-response-types.http b/examples/complete/events/test-response-types.http index 39fd07a..072e165 100644 --- a/examples/complete/events/test-response-types.http +++ b/examples/complete/events/test-response-types.http @@ -1,12 +1,12 @@ ### Send POST request with json body -POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/execute/ +POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/annie?annotations=:Token Content-Type: text/plain Accept: application/json Hello World! ### Send POST request with json body -POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/execute/ +POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/annie/ Content-Type: text/json Accept: application/json @@ -15,7 +15,7 @@ Accept: application/json } ### Send POST request for gate+xml -POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/execute/ +POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/annie/ Content-Type: text/json Accept: application/gate+xml @@ -24,7 +24,7 @@ Accept: application/gate+xml } ### Send POST request for gate+xml -POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/execute/ +POST https://mh4gdixkm7.execute-api.us-east-1.amazonaws.com/Prod/annie/ Content-Type: text/json Accept: application/fastinfoset diff --git a/examples/complete/template.yaml b/examples/complete/template.yaml index bea327c..eb19d52 100644 --- a/examples/complete/template.yaml +++ b/examples/complete/template.yaml @@ -24,15 +24,23 @@ Resources: Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object Variables: GATE_APP_NAME: application + GATE_APP_COST_PER_REQUEST: 1 + GATE_APP_DAILY_QUOTA: 10000 + GATE_APP_DEFAULT_ANNOTATIONS: :Address, :Date, :Location, :Organization, :Person + GATE_APP_ADDITIONAL_ANNOTATIONS: :Money, :Percent, :Token, :SpaceToken, :Sentence Policies: - AWSXrayWriteOnlyAccess - Events: - ApiGatewayGateApp: + Execute: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: - Path: /execute + Path: /annie Method: post + GetMetadata: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /annie/metadata + Method: get Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function @@ -40,7 +48,7 @@ Outputs: # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api LambdaGateAppApi: Description: "API Gateway endpoint URL for Prod stage for Gate Application" - Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/execute/" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/annie/" LambdaGateApp: Description: "Gate Application ARN" Value: !GetAtt LambdaGateApp.Arn diff --git a/src/main/java/co/zeroae/gate/App.java b/src/main/java/co/zeroae/gate/App.java index d33540c..ab08ec1 100644 --- a/src/main/java/co/zeroae/gate/App.java +++ b/src/main/java/co/zeroae/gate/App.java @@ -9,6 +9,8 @@ import com.amazonaws.util.Base64; import com.amazonaws.xray.AWSXRay; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import gate.*; import gate.corpora.DocumentImpl; import gate.util.GateException; @@ -50,6 +52,8 @@ public class App implements RequestHandler exporters = AWSXRay.createSegment( "Gate Exporters", Utils::loadExporters ); @@ -60,8 +64,32 @@ public class App implements RequestHandler()); + response.getHeaders().put("Content-Type", "application/json"); + try { + metadata.name = input.getPath().split("/")[1]; + response.withBody(new ObjectMapper().writeValueAsString(metadata)).withStatusCode(200); + } catch (JsonProcessingException e) { + // This is really bad... let it go through + throw new RuntimeException(e); + } + return response; + } + + public APIGatewayProxyResponseEvent handleExecute(APIGatewayProxyRequestEvent input, final Context context) { + final APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent() + .withHeaders(new HashMap<>()); final Map queryStringParams = Optional.ofNullable(input.getQueryStringParameters()).orElse(new HashMap<>()); final Map> mQueryStringParams = Optional.ofNullable(input.getMultiValueQueryStringParameters()).orElse(new HashMap<>()); try { @@ -208,6 +236,17 @@ private APIGatewayProxyResponseEvent export( return response; } + private static AppMetadata loadMetadata() { + final AppMetadata rv = new AppMetadata(); + // TODO: Load metadata/metadata.xml if it exists, and set as default values + rv.name = null; + rv.costPerRequest = Integer.parseInt(System.getenv().getOrDefault("GATE_APP_COST_PER_REQUEST", "0")); + rv.dailyQuota = Integer.parseUnsignedInt(System.getenv().getOrDefault("GATE_APP_DAILY_QUOTA", "0")); + rv.defaultAnnotations = System.getenv("GATE_APP_DEFAULT_ANNOTATIONS"); + rv.additionalAnnotations = System.getenv("GATE_APP_ADDITIONAL_ANNOTATIONS"); + return rv; + } + private static CorpusController loadApplication() { try { final String gappResourcePah = GATE_APP_NAME + "/application.xgapp"; @@ -222,5 +261,4 @@ private static CorpusController loadApplication() { throw new RuntimeException(e); } } - } diff --git a/src/main/java/co/zeroae/gate/AppMetadata.java b/src/main/java/co/zeroae/gate/AppMetadata.java new file mode 100644 index 0000000..af74639 --- /dev/null +++ b/src/main/java/co/zeroae/gate/AppMetadata.java @@ -0,0 +1,15 @@ +package co.zeroae.gate; +/** + * This class structure must match https://github.com/GateNLP/cloud-client/blob/master/library/src/main/java/uk/ac/gate/cloud/online/ServiceMetadata.java + */ +class AppMetadata { + public String name; + + public String defaultAnnotations; + + public String additionalAnnotations; + + public int costPerRequest; + + public int dailyQuota; +} diff --git a/src/test/java/co/zeroae/gate/AppTest.java b/src/test/java/co/zeroae/gate/AppTest.java index eb737f4..5ccd668 100644 --- a/src/test/java/co/zeroae/gate/AppTest.java +++ b/src/test/java/co/zeroae/gate/AppTest.java @@ -47,6 +47,7 @@ public void setUp() { input_headers.put("Accept", "application/gate+xml"); input = new APIGatewayProxyRequestEvent() .withRequestContext(new APIGatewayProxyRequestEvent.ProxyRequestContext().withRequestId(UUID.randomUUID().toString())) + .withPath("/test") .withHttpMethod("POST") .withHeaders(input_headers) .withBody("This is the default test message. I am an APIGatewayProxyRequestEvent and I love Wanda Vision.") @@ -61,6 +62,14 @@ public void tearDown() { private APIGatewayProxyRequestEvent input = null; private HashMap input_headers = null; + @Test + public void testMetadata() { + input.withPath(input.getPath()+"/metadata"); + final APIGatewayProxyResponseEvent result = app.handleMetadata(input, context); + assertEquals(200, result.getStatusCode().intValue()); + assertTrue(result.getBody().contains("\"name\":\"test\"")); + } + @Test public void successfulResponse() { // Invoke the App