mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 16:07:15 +02:00
Isolate customizable code in activity reporting
Modularize the code for DNS count reporting to allow it to be customized for more flexible systems. Tested: Uploaded to alpha with hacks to allow admin initiating and logging from the DnsCountQueryCoordinatorModule, verified that the provider function is invoked and that the action runs successfully. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=225225587
This commit is contained in:
parent
6966151bed
commit
c396957d15
13 changed files with 208 additions and 12 deletions
|
@ -1135,6 +1135,12 @@ public final class RegistryConfig {
|
|||
return config.registryPolicy.allocationTokenCustomLogicClass;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("dnsCountQueryCoordinatorClass")
|
||||
public static String dnsCountQueryCoordinatorClass(RegistryConfigSettings config) {
|
||||
return config.registryPolicy.dnsCountQueryCoordinatorClass;
|
||||
}
|
||||
|
||||
/** Returns the disclaimer text for the exported premium terms. */
|
||||
@Provides
|
||||
@Config("premiumTermsExportDisclaimer")
|
||||
|
|
|
@ -77,6 +77,7 @@ public class RegistryConfigSettings {
|
|||
public String customLogicFactoryClass;
|
||||
public String whoisCommandFactoryClass;
|
||||
public String allocationTokenCustomLogicClass;
|
||||
public String dnsCountQueryCoordinatorClass;
|
||||
public int contactAutomaticTransferDays;
|
||||
public String greetingServerId;
|
||||
public List<String> registrarChangesNotificationEmailAddresses;
|
||||
|
|
|
@ -55,6 +55,10 @@ registryPolicy:
|
|||
# See flows/domain/token/AllocationTokenCustomLogic.java
|
||||
allocationTokenCustomLogicClass: google.registry.flows.domain.token.AllocationTokenCustomLogic
|
||||
|
||||
# Custom logic class for handling DNS query count reporting for ICANN.
|
||||
# See reporting/icann/DnsCountQueryCoordinator.java
|
||||
dnsCountQueryCoordinatorClass: google.registry.reporting.icann.BasicDnsCountQueryCoordinator
|
||||
|
||||
# Length of time after which contact transfers automatically conclude.
|
||||
contactAutomaticTransferDays: 5
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ import google.registry.reporting.billing.BillingModule;
|
|||
import google.registry.reporting.billing.CopyDetailReportsAction;
|
||||
import google.registry.reporting.billing.GenerateInvoicesAction;
|
||||
import google.registry.reporting.billing.PublishInvoicesAction;
|
||||
import google.registry.reporting.icann.DnsCountQueryCoordinatorModule;
|
||||
import google.registry.reporting.icann.IcannReportingModule;
|
||||
import google.registry.reporting.icann.IcannReportingStagingAction;
|
||||
import google.registry.reporting.icann.IcannReportingUploadAction;
|
||||
|
@ -100,6 +101,7 @@ import google.registry.tmch.TmchSmdrlAction;
|
|||
BillingModule.class,
|
||||
CloudDnsWriterModule.class,
|
||||
CronModule.class,
|
||||
DnsCountQueryCoordinatorModule.class,
|
||||
DnsModule.class,
|
||||
DnsUpdateConfigModule.class,
|
||||
DnsUpdateWriterModule.class,
|
||||
|
|
|
@ -29,9 +29,7 @@ import org.joda.time.YearMonth;
|
|||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Utility class that produces SQL queries used to generate activity reports from Bigquery.
|
||||
*/
|
||||
/** Utility class that produces SQL queries used to generate activity reports from Bigquery. */
|
||||
public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
||||
|
||||
// Names for intermediary tables for overall activity reporting query.
|
||||
|
@ -42,20 +40,23 @@ public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
|||
static final String WHOIS_COUNTS = "whois_counts";
|
||||
static final String ACTIVITY_REPORT_AGGREGATION = "activity_report_aggregation";
|
||||
|
||||
@Inject @Config("projectId") String projectId;
|
||||
@Inject
|
||||
@Config("projectId")
|
||||
String projectId;
|
||||
|
||||
@Inject YearMonth yearMonth;
|
||||
|
||||
@Inject ActivityReportingQueryBuilder() {}
|
||||
@Inject DnsCountQueryCoordinator dnsCountQueryCoordinator;
|
||||
|
||||
@Inject
|
||||
ActivityReportingQueryBuilder() {}
|
||||
|
||||
/** Returns the aggregate query which generates the activity report from the saved view. */
|
||||
@Override
|
||||
public String getReportQuery() {
|
||||
return String.format(
|
||||
"#standardSQL\nSELECT * FROM `%s.%s.%s`",
|
||||
projectId,
|
||||
ICANN_REPORTING_DATA_SET,
|
||||
getTableName(ACTIVITY_REPORT_AGGREGATION));
|
||||
projectId, ICANN_REPORTING_DATA_SET, getTableName(ACTIVITY_REPORT_AGGREGATION));
|
||||
}
|
||||
|
||||
/** Sets the month we're doing activity reporting for, and returns the view query map. */
|
||||
|
@ -67,6 +68,10 @@ public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
|||
return createQueryMap(firstDayOfMonth, lastDayOfMonth);
|
||||
}
|
||||
|
||||
public void prepareForQuery() throws Exception {
|
||||
dnsCountQueryCoordinator.prepareForQuery();
|
||||
}
|
||||
|
||||
/** Returns a map from view name to its associated SQL query. */
|
||||
private ImmutableMap<String, String> createQueryMap(
|
||||
LocalDate firstDayOfMonth, LocalDate lastDayOfMonth) {
|
||||
|
@ -80,8 +85,7 @@ public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
|||
.build();
|
||||
queriesBuilder.put(getTableName(REGISTRAR_OPERATING_STATUS), operationalRegistrarsQuery);
|
||||
|
||||
String dnsCountsQuery =
|
||||
SqlTemplate.create(getQueryFromFile("dns_counts.sql")).build();
|
||||
String dnsCountsQuery = dnsCountQueryCoordinator.createQuery();
|
||||
queriesBuilder.put(getTableName(DNS_COUNTS), dnsCountsQuery);
|
||||
|
||||
// Convert reportingMonth into YYYYMMDD format for Bigquery table partition pattern-matching.
|
||||
|
@ -133,7 +137,6 @@ public final class ActivityReportingQueryBuilder implements QueryBuilder {
|
|||
return queriesBuilder.build();
|
||||
}
|
||||
|
||||
|
||||
/** Returns the table name of the query, suffixed with the yearMonth in _yyyyMM format. */
|
||||
private String getTableName(String queryName) {
|
||||
return String.format("%s_%s", queryName, DateTimeFormat.forPattern("yyyyMM").print(yearMonth));
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
// 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.reporting.icann;
|
||||
|
||||
import com.google.common.io.Resources;
|
||||
import google.registry.util.ResourceUtils;
|
||||
import google.registry.util.SqlTemplate;
|
||||
|
||||
/**
|
||||
* DNS Count query for the basic case.
|
||||
*/
|
||||
public class BasicDnsCountQueryCoordinator implements DnsCountQueryCoordinator {
|
||||
|
||||
BasicDnsCountQueryCoordinator(DnsCountQueryCoordinator.Params params) {}
|
||||
|
||||
@Override
|
||||
public String createQuery() {
|
||||
return SqlTemplate.create(
|
||||
ResourceUtils.readResourceUtf8(
|
||||
Resources.getResource(this.getClass(), "sql/" + "dns_counts.sql")))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepareForQuery() throws Exception {}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// 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.reporting.icann;
|
||||
|
||||
import google.registry.bigquery.BigqueryConnection;
|
||||
import org.joda.time.YearMonth;
|
||||
|
||||
/**
|
||||
* Methods for preparing and querying DNS statistics.
|
||||
*
|
||||
* <p>DNS systems may have different ways of providing this information, so it's useful to
|
||||
* modularize this.
|
||||
*
|
||||
* <p>Derived classes must provide a constructor that accepts a
|
||||
* {@link google.registry.reporting.icann.DnsCountQueryCoordinator.Params}. To override this,
|
||||
* define dnsCountQueryCoordinatorClass in your config file.
|
||||
*/
|
||||
public interface DnsCountQueryCoordinator {
|
||||
|
||||
/**
|
||||
* Class to carry parameters for a new coordinator.
|
||||
*
|
||||
* If your report query requires any additional parameters, add them here.
|
||||
*/
|
||||
public class Params {
|
||||
public BigqueryConnection bigquery;
|
||||
|
||||
/** The year and month of the report. */
|
||||
public YearMonth yearMonth;
|
||||
|
||||
/** The Google Cloud project id. */
|
||||
public String projectId;
|
||||
|
||||
public Params(BigqueryConnection bigquery, YearMonth yearMonth, String projectId) {
|
||||
this.bigquery = bigquery;
|
||||
this.yearMonth = yearMonth;
|
||||
this.projectId = projectId;
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates the string used to query bigtable for DNS count information. */
|
||||
String createQuery();
|
||||
|
||||
/** Do any necessry preparation for the DNS query. */
|
||||
void prepareForQuery() throws Exception;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// 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.reporting.icann;
|
||||
|
||||
import static google.registry.util.TypeUtils.getClassFromString;
|
||||
import static google.registry.util.TypeUtils.instantiate;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.bigquery.BigqueryConnection;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import org.joda.time.YearMonth;
|
||||
|
||||
/** Dagger module to provide the DnsCountQueryCoordinator. */
|
||||
@Module
|
||||
public class DnsCountQueryCoordinatorModule {
|
||||
|
||||
@Provides
|
||||
static DnsCountQueryCoordinator provideDnsCountQueryCoordinator(
|
||||
@Config("dnsCountQueryCoordinatorClass") String customClass,
|
||||
BigqueryConnection bigquery,
|
||||
YearMonth yearMonth,
|
||||
@Config("projectId") String projectId) {
|
||||
DnsCountQueryCoordinator.Params params =
|
||||
new DnsCountQueryCoordinator.Params(bigquery, yearMonth, projectId);
|
||||
DnsCountQueryCoordinator result =
|
||||
instantiate(getClassFromString(customClass, DnsCountQueryCoordinator.class), params);
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -83,6 +83,10 @@ public class IcannReportingStager {
|
|||
QueryBuilder queryBuilder =
|
||||
(reportType == ReportType.ACTIVITY) ? activityQueryBuilder : transactionsQueryBuilder;
|
||||
|
||||
if (reportType == ReportType.ACTIVITY) {
|
||||
// Prepare for the DNS count query, which may have special needs.
|
||||
activityQueryBuilder.prepareForQuery();
|
||||
}
|
||||
|
||||
ImmutableMap<String, String> viewQueryMap = queryBuilder.getViewQueryMap();
|
||||
// Generate intermediary views
|
||||
|
|
|
@ -56,6 +56,22 @@ public class TypeUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a class with the specified constructor argument.
|
||||
*
|
||||
* <p>Because we use arg1's type to lookup the constructor, this only works if arg1's class is
|
||||
* exactly the same type as the constructor argument. Subtypes are not allowed.
|
||||
*/
|
||||
public static <T, U> T instantiate(Class<? extends T> clazz, U arg1) {
|
||||
checkArgument(Modifier.isPublic(clazz.getModifiers()),
|
||||
"AppEngine's custom security manager won't let us reflectively access non-public types");
|
||||
try {
|
||||
return clazz.getConstructor(arg1.getClass()).newInstance(arg1);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class referred to by a fully qualified class name string.
|
||||
*
|
||||
|
|
|
@ -31,6 +31,10 @@ public class ActivityReportingQueryBuilderTest {
|
|||
ActivityReportingQueryBuilder queryBuilder = new ActivityReportingQueryBuilder();
|
||||
queryBuilder.yearMonth = new YearMonth(2017, 9);
|
||||
queryBuilder.projectId = "domain-registry-alpha";
|
||||
queryBuilder.dnsCountQueryCoordinator =
|
||||
new BasicDnsCountQueryCoordinator(
|
||||
new BasicDnsCountQueryCoordinator.Params(null, queryBuilder.yearMonth,
|
||||
queryBuilder.projectId));
|
||||
return queryBuilder;
|
||||
}
|
||||
|
||||
|
@ -63,5 +67,4 @@ public class ActivityReportingQueryBuilderTest {
|
|||
.isEqualTo(ReportingTestData.loadFile(testFilename));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -62,6 +62,7 @@ public class IcannReportingStagerTest {
|
|||
ActivityReportingQueryBuilder activityBuilder = new ActivityReportingQueryBuilder();
|
||||
activityBuilder.projectId = "test-project";
|
||||
activityBuilder.yearMonth = new YearMonth(2017, 6);
|
||||
activityBuilder.dnsCountQueryCoordinator = new BasicDnsCountQueryCoordinator(null);
|
||||
action.activityQueryBuilder = activityBuilder;
|
||||
TransactionsReportingQueryBuilder transactionsBuilder = new TransactionsReportingQueryBuilder();
|
||||
transactionsBuilder.projectId = "test-project";
|
||||
|
|
|
@ -52,4 +52,22 @@ public class TypeUtilsTest {
|
|||
.hasMessageThat()
|
||||
.contains("Failed to load class com.fake.company.nonexistent.Class");
|
||||
}
|
||||
|
||||
public static class ExampleClass {
|
||||
String val;
|
||||
|
||||
public ExampleClass(String val) {
|
||||
this.val = val;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_instantiateWithArg() {
|
||||
Class<ExampleClass> clazz =
|
||||
TypeUtils.getClassFromString(
|
||||
"google.registry.util.TypeUtilsTest$ExampleClass", ExampleClass.class);
|
||||
|
||||
ExampleClass result = TypeUtils.instantiate(clazz, "test");
|
||||
assertThat(result.val).isEqualTo("test");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue