RequestReader
object. This object reads an incoming AwsProxyRequest
- * event and transform it into a Jersey ContainerRequest
object. The object sets three custom properties in the
- * request's PropertiesDelegate
object: The API Gateway request context, the Map of stage variables, and the
- * Lambda context object.
- *
- * The useStageAsBasePath
configuration variable lets you set whether the stage name should be included in the
- * request path passed to the Jersey application handler.
- */
-public class JerseyAwsProxyRequestReader extends RequestReaderContainerRequest
object.
- *
- * @param request The incoming request object
- * @param securityContext A jax-rs SecurityContext object (@see com.amazonaws.serverless.proxy.SecurityContextWriter)
- * @param lambdaContext The AWS Lambda context for the request
- * @param config The container config object, this is passed in by the LambdaContainerHandler
- * @return A populated ContainerRequest object
- * @throws InvalidRequestEventException When the method fails to parse the incoming request
- */
- @Override
- public ContainerRequest readRequest(AwsProxyRequest request, SecurityContext securityContext, Context lambdaContext, ContainerConfig config)
- throws InvalidRequestEventException {
- currentRequest = request;
- currentLambdaContext = lambdaContext;
-
- request.setPath(stripBasePath(request.getPath(), config));
-
- URI basePathUri;
- URI requestPathUri;
- String basePath = "/";
-
- try {
- basePathUri = new URI(basePath);
- } catch (URISyntaxException e) {
- log.error("Could not read base path URI", e);
- throw new InvalidRequestEventException("Error while generating base path URI: " + basePath, e);
- }
-
-
- UriBuilder uriBuilder = UriBuilder.fromPath(request.getPath());
-
- if (request.getQueryStringParameters() != null) {
- for (String paramKey : request.getQueryStringParameters().keySet()) {
- uriBuilder = uriBuilder.queryParam(paramKey, request.getQueryStringParameters().get(paramKey));
- }
- }
-
- requestPathUri = uriBuilder.build();
-
- PropertiesDelegate apiGatewayProperties = new MapPropertiesDelegate();
- apiGatewayProperties.setProperty(API_GATEWAY_CONTEXT_PROPERTY, request.getRequestContext());
- apiGatewayProperties.setProperty(API_GATEWAY_STAGE_VARS_PROPERTY, request.getStageVariables());
- apiGatewayProperties.setProperty(LAMBDA_CONTEXT_PROPERTY, lambdaContext);
-
- ContainerRequest requestContext = new ContainerRequest(basePathUri, requestPathUri, request.getHttpMethod(), securityContext, apiGatewayProperties);
-
- if (request.getBody() != null) {
- if (request.isBase64Encoded()) {
- requestContext.setEntityStream(new ByteArrayInputStream(Base64.getDecoder().decode(request.getBody())));
- } else {
- requestContext.setEntityStream(new ByteArrayInputStream(request.getBody().getBytes()));
- }
- }
-
- if (request.getHeaders() != null) {
- for (final String headerName : request.getHeaders().keySet()) {
- requestContext.headers(headerName, request.getHeaders().get(headerName));
- }
- }
-
- return requestContext;
- }
-
- //-------------------------------------------------------------
- // Methods - Protected
- //-------------------------------------------------------------
-
- @Override
- protected Class extends AwsProxyRequest> getRequestClass() {
- return AwsProxyRequest.class;
- }
-
-
- //-------------------------------------------------------------
- // Methods - Package
- //-------------------------------------------------------------
-
- public static AwsProxyRequest getCurrentRequest() {
- return currentRequest;
- }
-
-
- public static Context getCurrentLambdaContext() {
- return currentLambdaContext;
- }
-}
diff --git a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyResponseWriter.java b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyResponseWriter.java
deleted file mode 100644
index cbf9f18a4..000000000
--- a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyAwsProxyResponseWriter.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
- * with the License. A copy of the License is located at
- *
- * http://aws.amazon.com/apache2.0/
- *
- * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
- * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
- * and limitations under the License.
- */
-package com.amazonaws.serverless.proxy.jersey;
-
-
-import com.amazonaws.serverless.exceptions.InvalidResponseObjectException;
-import com.amazonaws.serverless.proxy.ResponseWriter;
-import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
-import com.amazonaws.services.lambda.runtime.Context;
-
-import java.util.Base64;
-
-
-/**
- * Transforms the data from a JerseyResponseWriter object into a valid AwsProxyResponse object.
- *
- * @see com.amazonaws.serverless.proxy.jersey.JerseyResponseWriter
- * @see AwsProxyResponse
- */
-public class JerseyAwsProxyResponseWriter extends ResponseWriterApplicationHandler
+ * object is re-initialized with the Application
object initially set in the LambdaContainer.getInstance()
+ * call.
+ */
+ @Override
+ public void reload() {
+ Timer.start("JERSEY_RELOAD_DEFAULT");
+ jersey.onShutdown(this);
+
+ jersey = new ApplicationHandler(app);
+
+ jersey.onReload(this);
+ jersey.onStartup(this);
+ Timer.stop("JERSEY_RELOAD_DEFAULT");
+ }
+
+
+ /**
+ * Restarts the application handler and configures a different Application
object. The new application
+ * resets the one currently configured in the container.
+ * @param resourceConfig An initialized Application
+ */
+ @Override
+ public void reload(ResourceConfig resourceConfig) {
+ Timer.start("JERSEY_RELOAD_CONFIG");
+ jersey.onShutdown(this);
+
+ app = resourceConfig;
+ jersey = new ApplicationHandler(resourceConfig);
+
+ jersey.onReload(this);
+ jersey.onStartup(this);
+ Timer.stop("JERSEY_RELOAD_CONFIG");
+ }
+}
diff --git a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java
index 297a59620..ec34f7d0b 100644
--- a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java
+++ b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyLambdaContainerHandler.java
@@ -20,6 +20,12 @@
import com.amazonaws.serverless.proxy.RequestReader;
import com.amazonaws.serverless.proxy.ResponseWriter;
import com.amazonaws.serverless.proxy.SecurityContextWriter;
+import com.amazonaws.serverless.proxy.internal.servlet.AwsHttpServletResponse;
+import com.amazonaws.serverless.proxy.internal.servlet.AwsLambdaServletContainerHandler;
+import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest;
+import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequestReader;
+import com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletResponseWriter;
+import com.amazonaws.serverless.proxy.internal.testutils.Timer;
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
@@ -29,8 +35,11 @@
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.spi.Container;
+import javax.servlet.DispatcherType;
+import javax.servlet.FilterRegistration;
import javax.ws.rs.core.Application;
+import java.util.EnumSet;
import java.util.concurrent.CountDownLatch;
@@ -58,8 +67,7 @@
* @param JerseyLambdaContainerHandler
object
*/
public static JerseyLambdaContainerHandlerApplicationHandler
- *
- * @return The Jersey's ResourceConfig object currently running in the container
- */
- public ResourceConfig getConfiguration() {
- return applicationHandler.getConfiguration();
- }
-
-
- /**
- * The instantiated ApplicationHandler
object used by this container
- *
- * @return Jersey's ApplicationHander object
- */
- public ApplicationHandler getApplicationHandler() {
- return applicationHandler;
- }
-
-
- /**
- * Shuts down and restarts the application handler in the current container. The ApplicationHandler
- * object is re-initialized with the Application
object initially set in the LambdaContainer.getInstance()
- * call.
- */
- public void reload() {
- applicationHandler.onShutdown(this);
-
- this.applicationHandler = new ApplicationHandler(jaxRsApplication);
-
- applicationHandler.onReload(this);
- applicationHandler.onStartup(this);
+ @Override
+ protected AwsHttpServletResponse getContainerResponse(AwsProxyHttpServletRequest request, CountDownLatch latch) {
+ return new AwsHttpServletResponse(request, latch);
}
+ @Override
+ protected void handleRequest(AwsProxyHttpServletRequest httpServletRequest, AwsHttpServletResponse httpServletResponse, Context lambdaContext)
+ throws Exception {
- /**
- * Restarts the application handler and configures a different Application
object. The new application
- * resets the one currently configured in the container.
- * @param resourceConfig An initialized Application
- */
- public void reload(ResourceConfig resourceConfig) {
- applicationHandler.onShutdown(this);
-
- this.jaxRsApplication = resourceConfig;
- this.applicationHandler = new ApplicationHandler(resourceConfig);
-
- applicationHandler.onReload(this);
- applicationHandler.onStartup(this);
- }
+ Timer.start("JERSEY_HANDLE_REQUEST");
+ // this method of the AwsLambdaServletContainerHandler sets the request context
+ super.handleRequest(httpServletRequest, httpServletResponse, lambdaContext);
+ if (!initialized) {
+ Timer.start("JERSEY_COLD_START_INIT");
+ // call the onStartup event if set to give developers a chance to set filters in the context
+ if (startupHandler != null) {
+ startupHandler.onStartup(getServletContext());
+ }
- //-------------------------------------------------------------
- // Methods - Implementation
- //-------------------------------------------------------------
+ // manually add the spark filter to the chain. This should the last one and match all uris
+ FilterRegistration.Dynamic jerseyFilterReg = getServletContext().addFilter("JerseyFilter", jerseyFilter);
+ jerseyFilterReg.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
- @Override
- protected JerseyResponseWriter getContainerResponse(ContainerRequest request, CountDownLatch latch) {
- return new JerseyResponseWriter(latch);
- }
+ initialized = true;
+ Timer.stop("JERSEY_COLD_START_INIT");
+ }
+ httpServletRequest.setServletContext(getServletContext());
- @Override
- protected void handleRequest(ContainerRequest containerRequest, JerseyResponseWriter jerseyResponseWriter, Context lambdaContext) {
- containerRequest.setWriter(jerseyResponseWriter);
-
- applicationHandler.handle(containerRequest);
+ doFilter(httpServletRequest, httpServletResponse, null);
+ Timer.stop("JERSEY_HANDLE_REQUEST");
}
}
diff --git a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyResponseWriter.java b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyServletResponseWriter.java
similarity index 57%
rename from aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyResponseWriter.java
rename to aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyServletResponseWriter.java
index 89a038b1d..8e15112e2 100644
--- a/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyResponseWriter.java
+++ b/aws-serverless-java-container-jersey/src/main/java/com/amazonaws/serverless/proxy/jersey/JerseyServletResponseWriter.java
@@ -13,17 +13,22 @@
package com.amazonaws.serverless.proxy.jersey;
-import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
+import com.amazonaws.serverless.proxy.internal.SecurityUtils;
+import com.amazonaws.serverless.proxy.internal.testutils.Timer;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.glassfish.jersey.server.ContainerException;
import org.glassfish.jersey.server.ContainerResponse;
import org.glassfish.jersey.server.spi.ContainerResponseWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-import javax.ws.rs.core.HttpHeaders;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.InternalServerErrorException;
-import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.OutputStream;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
@@ -35,18 +40,16 @@
* AwsProxyResponse
object. The response object is passed in the constructor alongside an ExceptionHandler
* instance.
*/
-class JerseyResponseWriter
+class JerseyServletResponseWriter
implements ContainerResponseWriter {
//-------------------------------------------------------------
// Variables - Private
//-------------------------------------------------------------
- private CountDownLatch responseMutex;
- private MapFactory
object for HttpServletRequest
objects. This can be used
@@ -48,7 +45,7 @@
public class AwsProxyServletRequestFactory
implements FactoryFactory
object for HttpServletResponse
objects. This can be used
+ * to write data directly to the servlet response for the method, without using Jersey's ContainerResponse
+ *
+ *
+ *
+ * ResourceConfig app = new ResourceConfig().packages("my.app.package")
+ * .register(new AbstractBinder() {
+ * {@literal @}Override
+ * protected void configure() {
+ * bindFactory(AwsProxyServletResponseFactory.class)
+ * .to(HttpServletResponse.class)
+ * .in(RequestScoped.class);
+ * }
+ * });
+ *
+ *
+ */
+public class AwsProxyServletResponseFactory
+ implements FactoryLambdaContainerHandler
object that supports the Spark framework: http://sparkjava.com/
- *
+ * * Because of the way this container is implemented, using reflection to change accessibility of methods in the Spark * framework and inserting itself as the default embedded container, it is important that you initialize the Handler * before declaring your spark routes. - * + *
* This implementation uses the default AwsProxyHttpServletRequest
and Response implementations.
- *
+ *
*
* {@code * // always initialize the handler first @@ -64,10 +69,12 @@ * }); * } *+ * * @param
RequestReader
implementation passed to the constructor
* @param ResponseWriter
implementation in the constructor
*/
-public class SparkLambdaContainerHandlerAwsProxyRequest
* and AwsProxyResponse
objects.
*
* @return a new instance of SparkLambdaContainerHandler
+ *
* @throws ContainerInitializationException Throws this exception if we fail to initialize the Spark container.
- * This could be caused by the introspection used to insert the library as the default embedded container
+ * This could be caused by the introspection used to insert the library as the default embedded container
*/
public static SparkLambdaContainerHandler