diff --git a/java/google/registry/module/BUILD b/java/google/registry/module/BUILD new file mode 100644 index 000000000..84346bf7f --- /dev/null +++ b/java/google/registry/module/BUILD @@ -0,0 +1,23 @@ +package( + default_visibility = ["//java/google/registry:registry_project"], +) + +licenses(["notice"]) # Apache 2.0 + +java_library( + name = "module", + srcs = glob(["*.java"]), + deps = [ + "//java/google/registry/request", + "//java/google/registry/util", + "@com_google_appengine_api_1_0_sdk", + "@com_google_dagger", + "@com_google_flogger", + "@com_google_flogger_system_backend", + "@com_google_monitoring_client_metrics", + "@javax_inject", + "@javax_servlet_api", + "@joda_time", + "@org_bouncycastle_bcpkix_jdk15on", + ], +) diff --git a/java/google/registry/module/ServletBase.java b/java/google/registry/module/ServletBase.java new file mode 100644 index 000000000..99b2a0dcc --- /dev/null +++ b/java/google/registry/module/ServletBase.java @@ -0,0 +1,83 @@ +// Copyright 2018 The Nomulus Authors. 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. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License 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 google.registry.module; + +import com.google.appengine.api.LifecycleManager; +import com.google.common.flogger.FluentLogger; +import com.google.monitoring.metrics.MetricReporter; +import dagger.Lazy; +import google.registry.request.RequestHandler; +import google.registry.util.SystemClock; +import java.io.IOException; +import java.security.Security; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.joda.time.DateTime; + +/** Base for Servlets that handle all requests to our App Engine modules. */ +public class ServletBase extends HttpServlet { + + private final RequestHandler requestHandler; + private final Lazy metricReporter; + private static final FluentLogger logger = FluentLogger.forEnclosingClass(); + private static final SystemClock clock = new SystemClock(); + + public ServletBase(RequestHandler requestHandler, Lazy metricReporter) { + this.requestHandler = requestHandler; + this.metricReporter = metricReporter; + } + + @Override + public void init() { + Security.addProvider(new BouncyCastleProvider()); + + // If metric reporter failed to instantiate for any reason (bad keyring, bad json credential, + // etc), we log the error but keep the main thread running. Also the shutdown hook will only be + // registered if metric reporter starts up correctly. + try { + metricReporter.get().startAsync().awaitRunning(10, TimeUnit.SECONDS); + logger.atInfo().log("Started up MetricReporter"); + LifecycleManager.getInstance() + .setShutdownHook( + () -> { + try { + metricReporter.get().stopAsync().awaitTerminated(10, TimeUnit.SECONDS); + logger.atInfo().log("Shut down MetricReporter"); + } catch (TimeoutException e) { + logger.atSevere().withCause(e).log("Failed to stop MetricReporter."); + } + }); + } catch (Exception e) { + logger.atSevere().withCause(e).log("Failed to initialize MetricReporter."); + } + } + + @Override + public void service(HttpServletRequest req, HttpServletResponse rsp) throws IOException { + logger.atInfo().log("Received %s request", getClass().getSimpleName()); + DateTime startTime = clock.nowUtc(); + try { + requestHandler.handleRequest(req, rsp); + } finally { + logger.atInfo().log( + "Finished %s request. Latency: %.3fs", + getClass().getSimpleName(), (clock.nowUtc().getMillis() - startTime.getMillis()) / 1000d); + } + } +}