diff --git a/java/com/google/domain/registry/env/common/backend/WEB-INF/web.xml b/java/com/google/domain/registry/env/common/backend/WEB-INF/web.xml index 937f65f5b..2961f4218 100644 --- a/java/com/google/domain/registry/env/common/backend/WEB-INF/web.xml +++ b/java/com/google/domain/registry/env/common/backend/WEB-INF/web.xml @@ -13,13 +13,8 @@ 1 - - - metrics - com.google.domain.registry.monitoring.whitebox.MetricsTaskServlet - - metrics + backend-servlet /_dr/task/metrics diff --git a/java/com/google/domain/registry/module/backend/BackendRequestComponent.java b/java/com/google/domain/registry/module/backend/BackendRequestComponent.java index 82b29bd3d..cbe89ac48 100644 --- a/java/com/google/domain/registry/module/backend/BackendRequestComponent.java +++ b/java/com/google/domain/registry/module/backend/BackendRequestComponent.java @@ -40,7 +40,9 @@ import com.google.domain.registry.flows.async.DeleteContactResourceAction; import com.google.domain.registry.flows.async.DeleteHostResourceAction; import com.google.domain.registry.flows.async.DnsRefreshForHostRenameAction; import com.google.domain.registry.mapreduce.MapreduceModule; +import com.google.domain.registry.monitoring.whitebox.MetricsExportAction; import com.google.domain.registry.monitoring.whitebox.VerifyEntityIntegrityAction; +import com.google.domain.registry.monitoring.whitebox.WhiteboxModule; import com.google.domain.registry.rde.BrdaCopyAction; import com.google.domain.registry.rde.RdeModule; import com.google.domain.registry.rde.RdeReportAction; @@ -73,6 +75,7 @@ import dagger.Subcomponent; RequestModule.class, SheetModule.class, TmchModule.class, + WhiteboxModule.class, }) interface BackendRequestComponent { BigqueryPollJobAction bigqueryPollJobAction(); @@ -86,6 +89,7 @@ interface BackendRequestComponent { ExportCommitLogDiffAction exportCommitLogDiffAction(); ExportDomainListsAction exportDomainListsAction(); ExportReservedTermsAction exportReservedTermsAction(); + MetricsExportAction metricsExportAction(); NordnUploadAction nordnUploadAction(); NordnVerifyAction nordnVerifyAction(); PublishDnsUpdatesAction publishDnsUpdatesAction(); diff --git a/java/com/google/domain/registry/monitoring/whitebox/Metrics.java b/java/com/google/domain/registry/monitoring/whitebox/Metrics.java index 114be6860..c9b16c57e 100644 --- a/java/com/google/domain/registry/monitoring/whitebox/Metrics.java +++ b/java/com/google/domain/registry/monitoring/whitebox/Metrics.java @@ -66,7 +66,7 @@ public abstract class Metrics { public void export() { try { String hostname = modulesService.getVersionHostname("backend", null); - TaskOptions opts = withUrl(MetricsTaskServlet.PATH) + TaskOptions opts = withUrl(MetricsExportAction.PATH) .header("Host", hostname) .param("insertId", idGenerator.get()) .param("startTime", toBigqueryTimestamp(startTimeMillis, TimeUnit.MILLISECONDS)) diff --git a/java/com/google/domain/registry/monitoring/whitebox/MetricsTaskServlet.java b/java/com/google/domain/registry/monitoring/whitebox/MetricsExportAction.java similarity index 59% rename from java/com/google/domain/registry/monitoring/whitebox/MetricsTaskServlet.java rename to java/com/google/domain/registry/monitoring/whitebox/MetricsExportAction.java index 079348bd2..ab8a97b64 100644 --- a/java/com/google/domain/registry/monitoring/whitebox/MetricsTaskServlet.java +++ b/java/com/google/domain/registry/monitoring/whitebox/MetricsExportAction.java @@ -14,7 +14,11 @@ package com.google.domain.registry.monitoring.whitebox; -import static com.google.domain.registry.util.HttpServletUtils.getRequiredParameterValue; +import static com.google.common.base.Predicates.in; +import static com.google.common.base.Predicates.not; +import static com.google.common.collect.Multimaps.filterKeys; +import static com.google.domain.registry.request.Action.Method.POST; +import static com.google.domain.registry.util.FormattingLogger.getLoggerForCallerClass; import com.google.api.services.bigquery.Bigquery; import com.google.api.services.bigquery.model.TableDataInsertAllRequest; @@ -24,69 +28,58 @@ import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; import com.google.domain.registry.bigquery.BigqueryFactory; -import com.google.domain.registry.config.RegistryEnvironment; +import com.google.domain.registry.config.ConfigModule.Config; +import com.google.domain.registry.request.Action; +import com.google.domain.registry.request.Parameter; +import com.google.domain.registry.request.ParameterMap; import com.google.domain.registry.util.FormattingLogger; -import com.google.domain.registry.util.NonFinalForTesting; import java.io.IOException; +import java.util.Map; import java.util.Set; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.inject.Inject; -/** Servlet for exporting metrics to BigQuery. */ -public class MetricsTaskServlet extends HttpServlet { +/** Action for exporting metrics to BigQuery. */ +@Action(path = MetricsExportAction.PATH, method = POST) +public class MetricsExportAction implements Runnable { public static final String PATH = "/_dr/task/metrics"; - - private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); + private static final FormattingLogger logger = getLoggerForCallerClass(); private static final String DATASET_ID = "metrics"; - private static final String PROJECT_ID = RegistryEnvironment.get().config().getProjectId(); - private static final Set SPECIAL_PARAMS = ImmutableSet.of("tableId", "insertId"); - @NonFinalForTesting - private static BigqueryFactory bigqueryFactory = new BigqueryFactory(); - - /** Returns a filtered {@link ImmutableMap} from an {@link HttpServletRequest} */ - private static ImmutableMap getFilteredMapFromRequest( - HttpServletRequest req, - Set filter) { - ImmutableMap.Builder b = new ImmutableMap.Builder<>(); - - @SuppressWarnings({"cast", "unchecked"}) // Return type is always a Set. - Set parameterKeys = req.getParameterMap().keySet(); - - for (String key : Sets.difference(parameterKeys, filter)) { - b.put(key, req.getParameter(key)); - } - - return b.build(); - } + @Inject @Parameter("tableId") String tableId; + @Inject @Parameter("insertId") String insertId; + @Inject @Config("projectId") String projectId; + @Inject BigqueryFactory bigqueryFactory; + @Inject @ParameterMap ImmutableListMultimap parameters; + @Inject MetricsExportAction() {} /** Exports metrics to BigQuery. */ @Override - public void doPost(HttpServletRequest req, HttpServletResponse rsp) throws IOException { + public void run() { try { - final String tableId = getRequiredParameterValue(req, "tableId"); - ImmutableMap fields = getFilteredMapFromRequest(req, SPECIAL_PARAMS); - Bigquery bigquery = bigqueryFactory.create(PROJECT_ID, DATASET_ID, tableId); - + Bigquery bigquery = bigqueryFactory.create(projectId, DATASET_ID, tableId); + // Filter out the special parameters that the Action is called with. Everything that's left + // is returned in a Map that is suitable to pass to Bigquery as row data. + Map jsonRows = + ImmutableMap.copyOf( + filterKeys(parameters, not(in(SPECIAL_PARAMS))).entries()); TableDataInsertAllResponse response = bigquery.tabledata() .insertAll( - PROJECT_ID, + projectId, DATASET_ID, tableId, new TableDataInsertAllRequest() .setRows( ImmutableList.of(new TableDataInsertAllRequest.Rows() - .setInsertId(req.getParameter("insertId")) - .setJson(fields)))) + .setInsertId(insertId) + .setJson(jsonRows)))) .execute(); if (response.getInsertErrors() != null && !response.getInsertErrors().isEmpty()) { diff --git a/java/com/google/domain/registry/monitoring/whitebox/WhiteboxComponent.java b/java/com/google/domain/registry/monitoring/whitebox/WhiteboxComponent.java index b6d7ea184..d6a32235c 100644 --- a/java/com/google/domain/registry/monitoring/whitebox/WhiteboxComponent.java +++ b/java/com/google/domain/registry/monitoring/whitebox/WhiteboxComponent.java @@ -17,6 +17,7 @@ package com.google.domain.registry.monitoring.whitebox; import com.google.domain.registry.bigquery.BigqueryModule; import com.google.domain.registry.config.ConfigModule; import com.google.domain.registry.request.Modules.DatastoreServiceModule; +import com.google.domain.registry.util.SystemSleeper.SystemSleeperModule; import dagger.Component; @@ -29,6 +30,7 @@ import javax.inject.Singleton; BigqueryModule.class, ConfigModule.class, DatastoreServiceModule.class, + SystemSleeperModule.class, WhiteboxModule.class }) interface WhiteboxComponent { diff --git a/java/com/google/domain/registry/monitoring/whitebox/WhiteboxModule.java b/java/com/google/domain/registry/monitoring/whitebox/WhiteboxModule.java index d506b578a..3f4ce059a 100644 --- a/java/com/google/domain/registry/monitoring/whitebox/WhiteboxModule.java +++ b/java/com/google/domain/registry/monitoring/whitebox/WhiteboxModule.java @@ -14,21 +14,36 @@ package com.google.domain.registry.monitoring.whitebox; +import static com.google.domain.registry.request.RequestParameters.extractRequiredParameter; + import com.google.common.base.Supplier; -import com.google.domain.registry.util.Sleeper; -import com.google.domain.registry.util.SystemSleeper; +import com.google.domain.registry.request.Parameter; import dagger.Module; import dagger.Provides; import java.util.UUID; +import javax.servlet.http.HttpServletRequest; + /** * Dagger module for injecting common settings for Whitebox tasks. */ @Module public class WhiteboxModule { + @Provides + @Parameter("tableId") + static String provideTableId(HttpServletRequest req) { + return extractRequiredParameter(req, "tableId"); + } + + @Provides + @Parameter("insertId") + static String provideInsertId(HttpServletRequest req) { + return extractRequiredParameter(req, "insertId"); + } + @Provides static Supplier provideIdGenerator() { return new Supplier() { @@ -38,9 +53,4 @@ public class WhiteboxModule { } }; } - - @Provides - static Sleeper provideSleeper(SystemSleeper systemSleeper) { - return systemSleeper; - } } diff --git a/java/com/google/domain/registry/util/HttpServletUtils.java b/java/com/google/domain/registry/util/HttpServletUtils.java index a463de4cd..234d6a0e2 100644 --- a/java/com/google/domain/registry/util/HttpServletUtils.java +++ b/java/com/google/domain/registry/util/HttpServletUtils.java @@ -29,7 +29,10 @@ public final class HttpServletUtils { /** * Returns the value of the given request's first {@code name} parameter, or throws * {@code IllegalArgumentException} if the parameter is not present. + * + * @deprecated in favor of RequestParameters.extractRequiredParameter */ + @Deprecated public static String getRequiredParameterValue(HttpServletRequest req, String name) { return checkArgumentNotNull(req.getParameter(name), "Missing required parameter: %s", name); } diff --git a/javatests/com/google/domain/registry/monitoring/whitebox/MetricsTaskServletTest.java b/javatests/com/google/domain/registry/monitoring/whitebox/MetricsExportActionTest.java similarity index 65% rename from javatests/com/google/domain/registry/monitoring/whitebox/MetricsTaskServletTest.java rename to javatests/com/google/domain/registry/monitoring/whitebox/MetricsExportActionTest.java index 746277ce0..cc41ceed7 100644 --- a/javatests/com/google/domain/registry/monitoring/whitebox/MetricsTaskServletTest.java +++ b/javatests/com/google/domain/registry/monitoring/whitebox/MetricsExportActionTest.java @@ -14,6 +14,7 @@ package com.google.domain.registry.monitoring.whitebox; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -28,10 +29,9 @@ import com.google.api.services.bigquery.model.TableDataInsertAllRequest; import com.google.api.services.bigquery.model.TableDataInsertAllResponse; import com.google.api.services.bigquery.model.TableDataInsertAllResponse.InsertErrors; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableListMultimap; import com.google.domain.registry.bigquery.BigqueryFactory; import com.google.domain.registry.testing.AppEngineRule; -import com.google.domain.registry.testing.InjectRule; import org.junit.Before; import org.junit.Rule; @@ -42,17 +42,9 @@ import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** Unit tests for {@link MetricsTaskServlet}. */ +/** Unit tests for {@link MetricsExportAction}. */ @RunWith(MockitoJUnitRunner.class) -public class MetricsTaskServletTest { +public class MetricsExportActionTest { @Rule public ExpectedException thrown = ExpectedException.none(); @@ -63,9 +55,6 @@ public class MetricsTaskServletTest { .withTaskQueue() .build(); - @Rule - public final InjectRule inject = new InjectRule(); - @Mock BigqueryFactory bigqueryFactory; @@ -78,42 +67,23 @@ public class MetricsTaskServletTest { @Mock InsertAll insertAll; - @Mock - private HttpServletRequest req; + private TableDataInsertAllResponse response = new TableDataInsertAllResponse(); + private long currentTimeMillis = 1000000000000L; - @Mock - private HttpServletResponse rsp; + private ImmutableListMultimap parameters = + new ImmutableListMultimap.Builder() + .put("startTime", String.valueOf(MILLISECONDS.toSeconds(currentTimeMillis - 100))) + .put("endTime", String.valueOf(MILLISECONDS.toSeconds(currentTimeMillis))) + .put("jobname", "test job") + .put("status", "success") + .put("tld", "test") + .build(); - private final StringWriter httpOutput = new StringWriter(); - - TableDataInsertAllResponse response = new TableDataInsertAllResponse(); - long currentTimeMillis = 1000000000000L; - - Map params = new ImmutableMap.Builder() - .put("tableId", "eppMetrics") - .put("insertId", "insert id") - .put("startTime", String.valueOf(TimeUnit.MILLISECONDS.toSeconds(currentTimeMillis - 100))) - .put("endTime", String.valueOf(TimeUnit.MILLISECONDS.toSeconds(currentTimeMillis))) - .put("jobname", "test job") - .put("status", "success") - .put("tld", "test").build(); - - MetricsTaskServlet servlet; + MetricsExportAction action; @Before public void setup() throws Exception { - when(req.getMethod()).thenReturn("POST"); - when(req.getParameterMap()).thenReturn(params); - - for (String key : params.keySet()) { - when(req.getParameter(key)).thenReturn((String) params.get(key)); - } - - when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput)); - - inject.setStaticField(MetricsTaskServlet.class, "bigqueryFactory", bigqueryFactory); - when(bigqueryFactory.create(anyString(), anyString(), anyString())) - .thenReturn(bigquery); + when(bigqueryFactory.create(anyString(), anyString(), anyString())).thenReturn(bigquery); when(bigqueryFactory.create( anyString(), Matchers.any(HttpTransport.class), @@ -127,14 +97,19 @@ public class MetricsTaskServletTest { anyString(), anyString(), Matchers.any(TableDataInsertAllRequest.class))).thenReturn(insertAll); - servlet = new MetricsTaskServlet(); + action = new MetricsExportAction(); + action.bigqueryFactory = bigqueryFactory; + action.insertId = "insert id"; + action.parameters = parameters; + action.projectId = "project id"; + action.tableId = "eppMetrics"; } @Test public void testSuccess_nullErrors() throws Exception { when(insertAll.execute()).thenReturn(response); response.setInsertErrors(null); - servlet.service(req, rsp); + action.run(); verify(insertAll).execute(); } @@ -142,7 +117,7 @@ public class MetricsTaskServletTest { public void testSuccess_emptyErrors() throws Exception { when(insertAll.execute()).thenReturn(response); response.setInsertErrors(ImmutableList.of()); - servlet.service(req, rsp); + action.run(); verify(insertAll).execute(); } @@ -150,6 +125,6 @@ public class MetricsTaskServletTest { public void testFailure_errors() throws Exception { when(insertAll.execute()).thenReturn(response); response.setInsertErrors(ImmutableList.of(new InsertErrors())); - servlet.service(req, rsp); + action.run(); } }