Refactor bsa, dns, batch, and reporting packages to java.time (#3031)

This commit migrates the BSA, DNS, batch, and reporting packages from Joda-Time
to java.time. Key changes include:

- Updated Sleeper, Clock, and BigqueryUtils to use java.time types natively.
- Refactored models like RdeRevision and Tld to eliminate redundant Joda
  conversions, utilizing new DateTimeUtils static utilities for LocalDate.
- Improved test safety by replacing dynamic Instant.now() calls with static
  parsed constants.
- Migrated temporal arithmetic in test suites to use DateTimeUtils convenience
  methods (plusDays, minusDays).
- Updated BigqueryUtils serialization to preserve millisecond precision and
  formatting for large years, ensuring consistency with previous Joda behavior.
- Enhanced code readability by converting long concatenated strings to Java
  text blocks in LordnLogTest.
- Resolved environmental test failures in SyncRegistrarsSheetTest by
  synchronizing the FakeClock with the JPA extension.
- Updated project engineering standards (GEMINI.md) to prefer Truth's
  .hasValue() for Optional assertions.

Verified with a clean full build and all relevant test suites passing.
This commit is contained in:
Ben McIlwain
2026-05-06 21:44:40 +00:00
committed by GitHub
parent 81b3a2fc5b
commit 74f9f5d478
221 changed files with 1786 additions and 1587 deletions
@@ -26,8 +26,8 @@ import google.registry.model.EppResource;
import google.registry.persistence.VKey;
import google.registry.request.Action;
import jakarta.inject.Inject;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import java.time.Duration;
import java.time.Instant;
/** Helper class to enqueue tasks for handling asynchronous operations in flows. */
public final class AsyncTaskEnqueuer {
@@ -41,7 +41,7 @@ public final class AsyncTaskEnqueuer {
public static final String QUEUE_ASYNC_ACTIONS = "async-actions";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Duration MAX_ASYNC_ETA = Duration.standardDays(30);
private static final Duration MAX_ASYNC_ETA = Duration.ofDays(30);
private final CloudTasksUtils cloudTasksUtils;
@@ -58,12 +58,12 @@ public final class AsyncTaskEnqueuer {
*/
public void enqueueAsyncResave(
VKey<? extends EppResource> entityKey,
DateTime now,
ImmutableSortedSet<DateTime> whenToResave) {
DateTime firstResave = whenToResave.first();
Instant now,
ImmutableSortedSet<Instant> whenToResave) {
Instant firstResave = whenToResave.first();
checkArgument(isBeforeOrAt(now, firstResave), "Can't enqueue a resave to run in the past");
Duration etaDuration = new Duration(now, firstResave);
if (etaDuration.isLongerThan(MAX_ASYNC_ETA)) {
Duration etaDuration = Duration.between(now, firstResave);
if (etaDuration.compareTo(MAX_ASYNC_ETA) > 0) {
logger.atInfo().log(
"Ignoring async re-save of %s; %s is past the ETA threshold of %s.",
entityKey, firstResave, MAX_ASYNC_ETA);
@@ -24,9 +24,9 @@ import static google.registry.request.RequestParameters.extractOptionalBooleanPa
import static google.registry.request.RequestParameters.extractOptionalInstantParameter;
import static google.registry.request.RequestParameters.extractOptionalIntParameter;
import static google.registry.request.RequestParameters.extractOptionalParameter;
import static google.registry.request.RequestParameters.extractRequiredDatetimeParameter;
import static google.registry.request.RequestParameters.extractRequiredInstantParameter;
import static google.registry.request.RequestParameters.extractRequiredParameter;
import static google.registry.request.RequestParameters.extractSetOfDatetimeParameters;
import static google.registry.request.RequestParameters.extractSetOfInstantParameters;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -44,7 +44,6 @@ import jakarta.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import org.joda.time.DateTime;
/** Dagger module for injecting common settings for batch actions. */
@Module
@@ -98,14 +97,14 @@ public class BatchModule {
@Provides
@Parameter(PARAM_REQUESTED_TIME)
static DateTime provideRequestedTime(HttpServletRequest req) {
return extractRequiredDatetimeParameter(req, PARAM_REQUESTED_TIME);
static Instant provideRequestedTime(HttpServletRequest req) {
return extractRequiredInstantParameter(req, PARAM_REQUESTED_TIME);
}
@Provides
@Parameter(PARAM_RESAVE_TIMES)
static ImmutableSet<DateTime> provideResaveTimes(HttpServletRequest req) {
return extractSetOfDatetimeParameters(req, PARAM_RESAVE_TIMES);
static ImmutableSet<Instant> provideResaveTimes(HttpServletRequest req) {
return extractSetOfInstantParameters(req, PARAM_RESAVE_TIMES);
}
@Provides
@@ -42,10 +42,10 @@ import google.registry.request.auth.Auth;
import google.registry.request.lock.LockHandler;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import org.joda.time.Duration;
/**
* An action that transfers a set of domains from one registrar to another.
@@ -158,7 +158,7 @@ public class BulkDomainTransferAction implements Runnable {
return null;
};
if (!lockHandler.executeWithLocks(runner, null, Duration.standardHours(1), LOCK_NAME)) {
if (!lockHandler.executeWithLocks(runner, null, Duration.ofHours(1), LOCK_NAME)) {
// Send a 200-series status code to prevent this conflicting action from retrying.
response.setStatus(SC_NO_CONTENT);
response.setPayload("Could not acquire lock; already running?");
@@ -52,11 +52,11 @@ import jakarta.inject.Inject;
import java.io.Serial;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Arrays;
import java.util.Optional;
import java.util.Random;
import java.util.function.Supplier;
import org.joda.time.Duration;
/** Utilities for dealing with Cloud Tasks. */
public class CloudTasksUtils implements Serializable {
@@ -251,7 +251,7 @@ public class CloudTasksUtils implements Serializable {
method,
service,
params,
Duration.millis(random.nextInt((int) SECONDS.toMillis(jitterSeconds.get()))));
Duration.ofMillis(random.nextInt((int) SECONDS.toMillis(jitterSeconds.get()))));
}
/**
@@ -302,12 +302,12 @@ public class CloudTasksUtils implements Serializable {
Action.Service service,
Multimap<String, String> params,
Duration delay) {
if (delay.isEqual(Duration.ZERO)) {
if (delay.isZero()) {
return createTask(path, method, service, params);
}
checkArgument(delay.isLongerThan(Duration.ZERO), "Negative duration is not supported.");
checkArgument(!delay.isNegative(), "Negative duration is not supported.");
return Task.newBuilder(createTask(path, method, service, params))
.setScheduleTime(Timestamps.fromMillis(clock.nowUtc().plus(delay).getMillis()))
.setScheduleTime(Timestamps.fromMillis(clock.now().plus(delay).toEpochMilli()))
.build();
}
@@ -42,11 +42,11 @@ import google.registry.request.auth.Auth;
import google.registry.request.lock.LockHandler;
import google.registry.util.Clock;
import jakarta.inject.Inject;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import org.joda.time.Duration;
/**
* An action that deletes all non-renewing domains whose expiration dates have now passed.
@@ -116,7 +116,7 @@ public class DeleteExpiredDomainsAction implements Runnable {
return null;
};
if (!lockHandler.executeWithLocks(runner, null, Duration.standardHours(1), LOCK_NAME)) {
if (!lockHandler.executeWithLocks(runner, null, Duration.ofHours(1), LOCK_NAME)) {
// Send a 200-series status code to prevent this conflicting action from retrying.
response.setStatus(SC_NO_CONTENT);
response.setPayload("Could not acquire lock; already running?");
@@ -115,7 +115,7 @@ public class DeleteLoadTestDataAction implements Runnable {
VKey<Host> hostVKey = host.createVKey();
// We can remove hosts from linked domains, so we should do so then delete the hosts
ImmutableSet<VKey<Domain>> linkedDomains =
EppResourceUtils.getLinkedDomainKeys(hostVKey, clock.nowUtc(), null);
EppResourceUtils.getLinkedDomainKeys(hostVKey, clock.now(), null);
tm().loadByKeys(linkedDomains)
.values()
.forEach(
@@ -218,7 +218,7 @@ public class DeleteProberDataAction implements Runnable {
// successfully soft-delete the domain (thus leaving its DNS entry published). We soft-delete
// it now so that the DNS entry can be handled. The domain will then be hard-deleted the next
// time the job is run.
if (EppResourceUtils.isActive(domain, tm().getTransactionTime())) {
if (EppResourceUtils.isActive(domain, tm().getTxTime())) {
if (isDryRun) {
logger.atInfo().log(
"Would soft-delete the active domain: %s (%s).",
@@ -111,7 +111,7 @@ public class ExpandBillingRecurrencesAction implements Runnable {
() ->
tm().loadByKeyIfPresent(Cursor.createGlobalVKey(RECURRING_BILLING))
.orElse(Cursor.createGlobal(RECURRING_BILLING, START_INSTANT))
.getCursorTimeInstant()));
.getCursorTime()));
checkArgument(
startTime.isBefore(endTime),
"Start time (%s) must be before end time (%s)",
@@ -18,6 +18,8 @@ import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST;
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
import static google.registry.util.DateTimeUtils.isAtOrAfter;
import static google.registry.util.DateTimeUtils.toJodaDuration;
import static jakarta.servlet.http.HttpServletResponse.SC_NO_CONTENT;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
@@ -36,13 +38,12 @@ import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.tools.DomainLockUtils;
import google.registry.util.DateTimeUtils;
import google.registry.util.EmailMessage;
import jakarta.inject.Inject;
import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
import java.time.Duration;
import java.util.Optional;
import org.joda.time.Duration;
/** Task that re-locks a previously-Registry-Locked domain after a predetermined period of time. */
@Action(
@@ -59,8 +60,8 @@ public class RelockDomainAction implements Runnable {
static final int ATTEMPTS_BEFORE_SLOWDOWN = 36; // every ten minutes for six hours then every hour
static final int FAILURES_BEFORE_EMAIL = 2; // email after three failures, one half hour
private static final Duration TEN_MINUTES = Duration.standardMinutes(10);
private static final Duration ONE_HOUR = Duration.standardHours(1);
private static final Duration TEN_MINUTES = Duration.ofMinutes(10);
private static final Duration ONE_HOUR = Duration.ofHours(1);
private static final String RELOCK_SUCCESS_EMAIL_TEMPLATE =
"""
@@ -188,7 +189,7 @@ public class RelockDomainAction implements Runnable {
"Domain %s has a pending delete.",
domainName);
checkArgument(
!DateTimeUtils.isAtOrAfter(tm().getTxTime(), domain.getDeletionTime()),
!isAtOrAfter(tm().getTxTime(), domain.getDeletionTime()),
"Domain %s has been deleted.",
domainName);
checkArgument(
@@ -237,7 +238,8 @@ public class RelockDomainAction implements Runnable {
}
}
Duration timeBeforeRetry = previousAttempts < ATTEMPTS_BEFORE_SLOWDOWN ? TEN_MINUTES : ONE_HOUR;
domainLockUtils.enqueueDomainRelock(timeBeforeRetry, oldUnlockRevisionId, previousAttempts + 1);
domainLockUtils.enqueueDomainRelock(
toJodaDuration(timeBeforeRetry), oldUnlockRevisionId, previousAttempts + 1);
}
private void sendSuccessEmail(RegistryLock oldLock) {
@@ -30,8 +30,8 @@ import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import jakarta.inject.Inject;
import java.time.Instant;
import java.util.Optional;
import org.joda.time.DateTime;
/**
* An action that re-saves a given entity, typically after a certain amount of time has passed.
@@ -50,16 +50,16 @@ public class ResaveEntityAction implements Runnable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final String resourceKey;
private final DateTime requestedTime;
private final ImmutableSortedSet<DateTime> resaveTimes;
private final Instant requestedTime;
private final ImmutableSortedSet<Instant> resaveTimes;
private final AsyncTaskEnqueuer asyncTaskEnqueuer;
private final Response response;
@Inject
ResaveEntityAction(
@Parameter(PARAM_RESOURCE_KEY) String resourceKey,
@Parameter(PARAM_REQUESTED_TIME) DateTime requestedTime,
@Parameter(PARAM_RESAVE_TIMES) ImmutableSet<DateTime> resaveTimes,
@Parameter(PARAM_REQUESTED_TIME) Instant requestedTime,
@Parameter(PARAM_RESAVE_TIMES) ImmutableSet<Instant> resaveTimes,
AsyncTaskEnqueuer asyncTaskEnqueuer,
Response response) {
this.resourceKey = resourceKey;
@@ -17,8 +17,8 @@ package google.registry.batch;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.toDateTime;
import static google.registry.util.DateTimeUtils.toInstant;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import static java.time.ZoneOffset.UTC;
import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
import static org.apache.http.HttpStatus.SC_OK;
@@ -43,11 +43,10 @@ import google.registry.util.EmailMessage;
import jakarta.inject.Inject;
import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;
import java.time.Duration;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
/** An action that sends notification emails to registrars whose certificates are expiring soon. */
@Action(
@@ -57,6 +56,7 @@ import org.joda.time.format.DateTimeFormatter;
public class SendExpiringCertificateNotificationEmailAction implements Runnable {
public static final String PATH = "/_dr/task/sendExpiringCertificateNotificationEmail";
/**
* Used as an offset when storing the last notification email sent date.
*
@@ -65,10 +65,11 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
* next day at 2am, the date difference will be less than a day, which will lead to the date
* difference between two successive email sent date being the expected email interval days + 1;
*/
protected static final Duration UPDATE_TIME_OFFSET = Duration.standardMinutes(10);
protected static final Duration UPDATE_TIME_OFFSET = Duration.ofMinutes(10);
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd");
private static final DateTimeFormatter DATE_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(UTC);
private final CertificateChecker certificateChecker;
private final String expirationWarningEmailBodyText;
@@ -149,19 +150,19 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
@VisibleForTesting
boolean sendNotificationEmail(
Registrar registrar,
DateTime lastExpiringCertNotificationSentDate,
Instant lastExpiringCertNotificationSentDate,
CertificateType certificateType,
Optional<String> certificate) {
if (certificate.isEmpty()
|| !certificateChecker.shouldReceiveExpiringNotification(
lastExpiringCertNotificationSentDate, certificate.get())) {
toDateTime(lastExpiringCertNotificationSentDate), certificate.get())) {
return false;
}
try {
ImmutableSet<InternetAddress> recipients = getEmailAddresses(registrar, Type.TECH);
ImmutableSet<InternetAddress> ccs = getEmailAddresses(registrar, Type.ADMIN);
DateTime expirationDate =
new DateTime(certificateChecker.getCertificate(certificate.get()).getNotAfter());
Instant expirationDate =
certificateChecker.getCertificate(certificate.get()).getNotAfter().toInstant();
logger.atInfo().log(
" %s SSL certificate of registrar '%s' will expire on %s.",
certificateType.getDisplayName(), registrar.getRegistrarName(), expirationDate);
@@ -190,9 +191,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
* for applicable certificate.
*/
updateLastNotificationSentDate(
registrar,
clock.nowUtc().minusMinutes((int) UPDATE_TIME_OFFSET.getStandardMinutes()),
certificateType);
registrar, clock.now().minus(UPDATE_TIME_OFFSET), certificateType);
return true;
} catch (Exception e) {
throw new RuntimeException(
@@ -205,29 +204,29 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
/** Updates the last notification sent date in database. */
@VisibleForTesting
void updateLastNotificationSentDate(
Registrar registrar, DateTime now, CertificateType certificateType) {
Registrar registrar, Instant now, CertificateType certificateType) {
try {
tm().transact(
() -> {
Registrar.Builder newRegistrar = tm().loadByEntity(registrar).asBuilder();
switch (certificateType) {
case PRIMARY -> {
newRegistrar.setLastExpiringCertNotificationSentDate(toInstant(now));
newRegistrar.setLastExpiringCertNotificationSentDate(now);
tm().put(newRegistrar.build());
logger.atInfo().log(
"Updated last notification email sent date to %s for %s certificate of "
+ "registrar %s.",
DATE_FORMATTER.print(now),
DATE_FORMATTER.format(now),
certificateType.getDisplayName(),
registrar.getRegistrarName());
}
case FAILOVER -> {
newRegistrar.setLastExpiringFailoverCertNotificationSentDate(toInstant(now));
newRegistrar.setLastExpiringFailoverCertNotificationSentDate(now);
tm().put(newRegistrar.build());
logger.atInfo().log(
"Updated last notification email sent date to %s for %s certificate of "
+ "registrar %s.",
DATE_FORMATTER.print(now),
DATE_FORMATTER.format(now),
certificateType.getDisplayName(),
registrar.getRegistrarName());
}
@@ -257,7 +256,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
if (registrarInfo.isCertExpiring()
&& sendNotificationEmail(
registrar,
toDateTime(registrar.getLastExpiringCertNotificationSentDate()),
registrar.getLastExpiringCertNotificationSentDate(),
CertificateType.PRIMARY,
registrar.getClientCertificate())) {
numEmailsSent++;
@@ -265,7 +264,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
if (registrarInfo.isFailOverCertExpiring()
&& sendNotificationEmail(
registrar,
toDateTime(registrar.getLastExpiringFailoverCertNotificationSentDate()),
registrar.getLastExpiringFailoverCertNotificationSentDate(),
CertificateType.FAILOVER,
registrar.getFailoverClientCertificate())) {
numEmailsSent++;
@@ -300,7 +299,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
@VisibleForTesting
@SuppressWarnings("lgtm[java/dereferenced-value-may-be-null]")
String getEmailBody(
String registrarName, CertificateType type, DateTime expirationDate, String registrarId) {
String registrarName, CertificateType type, Instant expirationDate, String registrarId) {
checkArgumentNotNull(expirationDate, "Expiration date cannot be null");
checkArgumentNotNull(type, "Certificate type cannot be null");
checkArgumentNotNull(registrarId, "Registrar Id cannot be null");
@@ -308,7 +307,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
expirationWarningEmailBodyText,
registrarName,
type.getDisplayName(),
DATE_FORMATTER.print(expirationDate),
DATE_FORMATTER.format(expirationDate),
registrarId);
}
@@ -40,12 +40,12 @@ import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.lock.LockHandler;
import jakarta.inject.Inject;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.Function;
import org.joda.time.Duration;
@Action(
service = Action.Service.BACKEND,
@@ -99,7 +99,7 @@ public class SyncRemoteCacheAction implements Runnable {
return null;
};
if (!lockHandler.executeWithLocks(runner, null, Duration.standardHours(1), LOCK_NAME)) {
if (!lockHandler.executeWithLocks(runner, null, Duration.ofHours(1), LOCK_NAME)) {
// Send a 200-series status code to prevent this conflicting action from retrying.
response.setStatus(SC_NO_CONTENT);
response.setPayload("Could not acquire lock; already running?");
@@ -184,7 +184,7 @@ public class SyncRemoteCacheAction implements Runnable {
private Instant getPreviousCursorTime(Cursor.CursorType cursorType) {
return tm().loadByKeyIfPresent(Cursor.createGlobalVKey(cursorType))
.map(Cursor::getCursorTimeInstant)
.map(Cursor::getCursorTime)
.orElse(START_INSTANT);
}
@@ -15,6 +15,7 @@
package google.registry.beam;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.util.DateTimeUtils.LOWERCASE_TIMESTAMP_FORMATTER;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
@@ -61,7 +62,7 @@ public class BeamUtils {
// with a letter and ending with a letter or number. So we replace the "T" and "Z" in ISO 8601
// with lowercase letters.
String jobName =
String.format("%s-%s", prefix, clock.nowUtc().toString("yyyy-MM-dd't'HH-mm-ss'z'"));
String.format("%s-%s", prefix, LOWERCASE_TIMESTAMP_FORMATTER.format(clock.now()));
checkArgument(
Pattern.compile("^[a-z][-a-z0-9]*[a-z0-9]*").matcher(jobName).matches(),
"The job name %s is illegal, it consists of only characters [-a-z0-9], "
@@ -14,6 +14,7 @@
package google.registry.beam.billing;
import static java.time.ZoneOffset.UTC;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
@@ -22,7 +23,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;
@@ -70,7 +70,7 @@ public record BillingEvent(
String flags) {
private static final DateTimeFormatter DATE_TIME_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss 'UTC'").withZone(ZoneOffset.UTC);
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss 'UTC'").withZone(UTC);
private static final Pattern SYNTHETIC_REGEX = Pattern.compile("SYNTHETIC", Pattern.LITERAL);
@@ -164,13 +164,10 @@ public record BillingEvent(
/** Returns the grouping key for this {@code BillingEvent}, to generate the overall invoice. */
InvoiceGroupingKey getInvoiceGroupingKey() {
return new InvoiceGroupingKey(
ZonedDateTime.ofInstant(billingTime(), ZoneOffset.UTC)
.toLocalDate()
.withDayOfMonth(1)
.toString(),
ZonedDateTime.ofInstant(billingTime(), UTC).toLocalDate().withDayOfMonth(1).toString(),
years() == 0
? ""
: ZonedDateTime.ofInstant(billingTime(), ZoneOffset.UTC)
: ZonedDateTime.ofInstant(billingTime(), UTC)
.toLocalDate()
.withDayOfMonth(1)
.plusYears(years())
@@ -445,7 +445,7 @@ public class ExpandBillingRecurrencesPipeline implements Serializable {
Cursor.createGlobalVKey(RECURRING_BILLING))
.orElse(
Cursor.createGlobal(RECURRING_BILLING, START_INSTANT))
.getCursorTimeInstant();
.getCursorTime();
if (!currentCursorTime.equals(startTime)) {
throw new IllegalStateException(
String.format(
@@ -56,6 +56,8 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.Security;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import org.apache.beam.sdk.options.PipelineOptions;
import org.apache.beam.sdk.transforms.DoFn;
@@ -66,8 +68,6 @@ import org.apache.beam.sdk.values.PCollection;
import org.apache.beam.sdk.values.PDone;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.joda.time.DateTime;
import org.joda.time.Duration;
public class RdeIO {
@@ -163,7 +163,7 @@ public class RdeIO {
// Determine some basic things about the deposit.
final RdeMode mode = key.mode();
final String tld = key.tld();
final DateTime watermark = key.watermark();
final Instant watermark = key.watermark();
final int revision =
Optional.ofNullable(key.revision())
.orElseGet(() -> RdeRevision.getNextRevision(tld, watermark, mode));
@@ -259,7 +259,7 @@ public class RdeIO {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final long serialVersionUID = 5822176227753327224L;
private static final Duration ENQUEUE_DELAY = Duration.standardMinutes(1);
private static final Duration ENQUEUE_DELAY = Duration.ofMinutes(1);
private final CloudTasksUtils cloudTasksUtils;
@@ -276,9 +276,9 @@ public class RdeIO {
Tld tld = Tld.get(key.tld());
Optional<Cursor> cursor =
tm().loadByKeyIfPresent(Cursor.createScopedVKey(key.cursor(), tld));
DateTime position = getCursorTimeOrStartOfTime(cursor);
Instant position = getCursorTimeOrStartOfTime(cursor);
checkState(key.interval() != null, "Interval must be present");
DateTime newPosition = key.watermark().plus(key.interval());
Instant newPosition = key.watermark().plus(key.interval());
if (!position.isBefore(newPosition)) {
logger.atWarning().log("Cursor has already been rolled forward.");
return;
@@ -27,7 +27,6 @@ import static google.registry.beam.rde.RdePipeline.TupleTags.REVISION_ID;
import static google.registry.beam.rde.RdePipeline.TupleTags.SUPERORDINATE_DOMAINS;
import static google.registry.model.reporting.HistoryEntryDao.RESOURCE_TYPES_TO_HISTORY_TYPES;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.toInstant;
import static google.registry.util.SafeSerializationUtils.safeDeserializeCollection;
import static google.registry.util.SafeSerializationUtils.serializeCollection;
import static google.registry.util.SerializeUtils.decodeBase64;
@@ -72,6 +71,7 @@ import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import java.io.IOException;
import java.io.Serializable;
import java.time.Instant;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.PipelineResult;
import org.apache.beam.sdk.coders.KvCoder;
@@ -97,7 +97,6 @@ import org.apache.beam.sdk.values.PCollectionTuple;
import org.apache.beam.sdk.values.TupleTag;
import org.apache.beam.sdk.values.TupleTagList;
import org.apache.beam.sdk.values.TypeDescriptor;
import org.joda.time.DateTime;
/**
* Definition of a Dataflow Flex template, which generates RDE/BRDA deposits.
@@ -171,7 +170,7 @@ public class RdePipeline implements Serializable {
private final transient RdePipelineOptions options;
private final ValidationMode mode;
private final ImmutableSet<PendingDeposit> pendingDeposits;
private final DateTime watermark;
private final Instant watermark;
private final String rdeBucket;
private final byte[] stagingKeyBytes;
private final GcsUtils gcsUtils;
@@ -190,7 +189,7 @@ public class RdePipeline implements Serializable {
this.options = options;
this.mode = ValidationMode.valueOf(options.getValidationMode());
this.pendingDeposits = decodePendingDeposits(options.getPendings());
ImmutableSet<DateTime> potentialWatermarks =
ImmutableSet<Instant> potentialWatermarks =
pendingDeposits.stream()
.map(PendingDeposit::watermark)
.distinct()
@@ -324,7 +323,7 @@ public class RdePipeline implements Serializable {
? "AND resource.tld IN " + "(SELECT id FROM Tld WHERE tldType = 'REAL')"
: ""))
.replace("%entity%", historyClass.getSimpleName()),
ImmutableMap.of("watermark", toInstant(watermark)),
ImmutableMap.of("watermark", watermark),
Object[].class,
row -> KV.of((String) row[0], (long) row[1]))
.withCoder(KvCoder.of(StringUtf8Coder.of(), VarLongCoder.of())));
@@ -365,7 +364,7 @@ public class RdePipeline implements Serializable {
tm().loadByKey(
VKey.create(historyEntryClazz, new HistoryEntryId(repoId, revisionId))))
.getResourceAtPointInTime()
.map(resource -> resource.cloneProjectedAtTime(toInstant(watermark)))
.map(resource -> resource.cloneProjectedAtTime(watermark))
.get();
}
@@ -103,7 +103,7 @@ public class ResaveAllEppResourcesPipeline implements Serializable {
* transfers, grace periods).
*
* <p>The logic of what might have changed is paraphrased from {@link
* DomainBase#cloneProjectedAtTime(DateTime)}.
* DomainBase#cloneProjectedAtTime(Instant)}.
*/
private void fastResaveDomains(Pipeline pipeline) {
Read<String, String> repoIdRead =
@@ -14,6 +14,7 @@
package google.registry.beam.spec11;
import static google.registry.util.DateTimeUtils.toJodaInstant;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.http.HttpStatus.SC_OK;
@@ -22,7 +23,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.CharStreams;
import google.registry.util.Clock;
import google.registry.util.DateTimeUtils;
import google.registry.util.Retrier;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -132,9 +132,7 @@ public class SafeBrowsingTransforms {
if (!domainNameInfoBuffer.isEmpty()) {
ImmutableSet<KV<DomainNameInfo, ThreatMatch>> results = evaluateAndFlush();
results.forEach(
(kv) ->
context.output(
kv, DateTimeUtils.toJodaInstant(clock.now()), GlobalWindow.INSTANCE));
(kv) -> context.output(kv, toJodaInstant(clock.now()), GlobalWindow.INSTANCE));
}
}
@@ -64,19 +64,19 @@ import google.registry.util.SqlTemplate;
import google.registry.util.SystemSleeper;
import jakarta.inject.Inject;
import java.io.IOException;
import java.time.Duration;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import javax.annotation.Nullable;
import org.joda.time.Duration;
/** Class encapsulating parameters and state for accessing the Bigquery API. */
public class BigqueryConnection implements AutoCloseable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Duration MIN_POLL_INTERVAL = Duration.millis(500);
private static final Duration MIN_POLL_INTERVAL = Duration.ofMillis(500);
@NonFinalForTesting
private static Sleeper sleeper = new SystemSleeper();
@@ -88,7 +88,7 @@ public class BigqueryConnection implements AutoCloseable {
private static final String TEMP_DATASET_NAME = "__temp__";
/** Default time to live for temporary tables. */
private static final Duration TEMP_TABLE_TTL = Duration.standardHours(24);
private static final Duration TEMP_TABLE_TTL = Duration.ofHours(24);
/** Bigquery client instance wrapped by this class. */
private final Bigquery bigquery;
@@ -109,7 +109,7 @@ public class BigqueryConnection implements AutoCloseable {
private boolean overwrite = false;
/** Duration to wait between polls for job status. */
private Duration pollInterval = Duration.millis(1000);
private Duration pollInterval = Duration.ofSeconds(1);
BigqueryConnection(Bigquery bigquery, Clock clock) {
this.bigquery = bigquery;
@@ -146,9 +146,9 @@ public class BigqueryConnection implements AutoCloseable {
public Builder setPollInterval(Duration pollInterval) {
checkArgument(
!pollInterval.isShorterThan(MIN_POLL_INTERVAL),
pollInterval.compareTo(MIN_POLL_INTERVAL) >= 0,
"poll interval must be at least %s ms",
MIN_POLL_INTERVAL.getMillis());
MIN_POLL_INTERVAL.toMillis());
instance.pollInterval = pollInterval;
return this;
}
@@ -225,7 +225,7 @@ public class BigqueryConnection implements AutoCloseable {
}
public Builder timeToLive(Duration duration) {
this.table.setExpirationTime(clock.nowUtc().plus(duration).getMillis());
this.table.setExpirationTime(clock.now().plus(duration).toEpochMilli());
return this;
}
@@ -14,13 +14,16 @@
package google.registry.bigquery;
import static java.time.ZoneOffset.UTC;
import static java.time.temporal.ChronoUnit.MICROS;
import com.google.api.services.bigquery.model.JobReference;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.SignStyle;
import java.time.temporal.ChronoField;
import java.util.concurrent.TimeUnit;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.joda.time.format.DateTimeParser;
import org.joda.time.format.ISODateTimeFormat;
/** Utilities related to Bigquery. */
public class BigqueryUtils {
@@ -67,47 +70,56 @@ public class BigqueryUtils {
*
* <p>The general format definition is "YYYY-MM-DD HH:MM:SS.SSS[ ZZ]", where the fractional
* seconds portion can have 0-6 decimal places (although we restrict it to 0-3 here since Joda
* DateTime only supports up to millisecond precision) and the zone if not specified defaults to
* Instant only supports up to millisecond precision) and the zone if not specified defaults to
* UTC.
*
* <p>Although we expect a zone specification of "UTC" when parsing, we don't emit it when
* printing because in some cases BigQuery does not allow any time zone specification (instead it
* assumes UTC for whatever input you provide) for input timestamp strings (see b/16380363).
*
* @see <a href="https://cloud.google.com/bigquery/data-types#timestamp-type">
* BigQuery Data Types - TIMESTAMP</a>
* @see <a href="https://cloud.google.com/bigquery/data-types#timestamp-type">BigQuery Data Types
* - TIMESTAMP</a>
*/
public static final DateTimeFormatter BIGQUERY_TIMESTAMP_FORMAT = new DateTimeFormatterBuilder()
.append(ISODateTimeFormat.date())
.appendLiteral(' ')
.append(
// For printing, always print out the milliseconds.
ISODateTimeFormat.hourMinuteSecondMillis().getPrinter(),
// For parsing, we need a series of parsers to correctly handle the milliseconds.
new DateTimeParser[] {
// Try to parse the time with milliseconds first, which requires at least one
// fractional second digit, and if that fails try to parse without milliseconds.
ISODateTimeFormat.hourMinuteSecondMillis().getParser(),
ISODateTimeFormat.hourMinuteSecond().getParser()})
// Print UTC as the empty string since BigQuery's TIMESTAMP() function does not accept any
// time zone specification, but require "UTC" on parsing. Since we force this formatter to
// always use UTC below, the other arguments do not matter. If b/16380363 ever gets resolved
// this could be simplified to appendLiteral(" UTC").
.appendTimeZoneOffset("", " UTC", false, 1, 1)
.toFormatter()
.withZoneUTC();
private static final DateTimeFormatter BIGQUERY_TIMESTAMP_PARSER =
new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.NOT_NEGATIVE)
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH, 2)
.appendLiteral(' ')
.appendPattern("HH:mm:ss")
.optionalStart()
.appendFraction(ChronoField.MILLI_OF_SECOND, 0, 3, true)
.optionalEnd()
.appendLiteral(" UTC")
.toFormatter()
.withZone(UTC);
private static final DateTimeFormatter BIGQUERY_TIMESTAMP_PRINTER =
new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.NOT_NEGATIVE)
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH, 2)
.appendLiteral(' ')
.appendPattern("HH:mm:ss")
.appendFraction(ChronoField.MILLI_OF_SECOND, 3, 3, true)
.toFormatter()
.withZone(UTC);
/**
* Returns the human-readable string version of the given DateTime, suitable for conversion
* within BigQuery from a string literal into a BigQuery timestamp type.
* Returns the human-readable string version of the given Instant, suitable for conversion within
* BigQuery from a string literal into a BigQuery timestamp type.
*/
public static String toBigqueryTimestampString(DateTime dateTime) {
return BIGQUERY_TIMESTAMP_FORMAT.print(dateTime);
public static String toBigqueryTimestampString(Instant dateTime) {
return BIGQUERY_TIMESTAMP_PRINTER.format(dateTime);
}
/** Returns the DateTime for a given human-readable string-formatted BigQuery timestamp. */
public static DateTime fromBigqueryTimestampString(String timestampString) {
return BIGQUERY_TIMESTAMP_FORMAT.parseDateTime(timestampString);
/** Returns the Instant for a given human-readable string-formatted BigQuery timestamp. */
public static Instant fromBigqueryTimestampString(String timestampString) {
return BIGQUERY_TIMESTAMP_PARSER.parse(timestampString, Instant::from);
}
/**
@@ -123,15 +135,16 @@ public class BigqueryUtils {
}
/**
* Converts a {@link DateTime} into a numeric string that BigQuery understands as a timestamp:
* the decimal number of seconds since the epoch, precise up to microseconds.
* Converts a time into a numeric string that BigQuery understands as a timestamp: the decimal
* number of seconds since the epoch, precise up to microseconds.
*
* <p>Note that since {@code DateTime} only stores milliseconds, the last 3 digits will be zero.
* <p>Note that while {@code Instant} supports nanosecond precision, BigQuery only supports
* microsecond precision, so the sub-microsecond precision is truncated.
*
* @see <a href="https://developers.google.com/bigquery/timestamp">Data Types</a>
*/
public static String toBigqueryTimestamp(DateTime dateTime) {
return toBigqueryTimestamp(dateTime.getMillis(), TimeUnit.MILLISECONDS);
public static String toBigqueryTimestamp(Instant dateTime) {
return toBigqueryTimestamp(MICROS.between(Instant.EPOCH, dateTime), TimeUnit.MICROSECONDS);
}
/**
@@ -116,7 +116,7 @@ public class BsaDownloadAction implements Runnable {
Void runWithinLock() {
// Cannot enroll new TLDs after download starts. This may change if b/309175410 is fixed.
if (!Tlds.hasActiveBsaEnrollment(clock.nowUtc())) {
if (!Tlds.hasActiveBsaEnrollment(clock.now())) {
logger.atInfo().log("No TLDs enrolled with BSA. Quitting.");
return null;
}
@@ -179,9 +179,7 @@ public class BsaDownloadAction implements Runnable {
gcsClient.writeUnblockableDomains(
schedule.jobName(),
batches
.map(
batch ->
applyLabelDiff(batch, lazyIdnChecker.get(), schedule, clock.nowUtc()))
.map(batch -> applyLabelDiff(batch, lazyIdnChecker.get(), schedule, clock.now()))
.flatMap(ImmutableList::stream));
}
schedule.updateJobStage(DownloadStage.REPORT_START_OF_ORDER_PROCESSING);
@@ -17,8 +17,8 @@ package google.registry.bsa;
import google.registry.config.RegistryConfig.Config;
import google.registry.request.lock.LockHandler;
import jakarta.inject.Inject;
import java.time.Duration;
import java.util.concurrent.Callable;
import org.joda.time.Duration;
/** Helper for guarding all BSA related work with a common lock. */
public class BsaLock {
@@ -67,7 +67,7 @@ public class BsaRefreshAction implements Runnable {
GcsClient gcsClient,
BsaReportSender bsaReportSender,
@Config("bsaTxnBatchSize") int transactionBatchSize,
@Config("domainCreateTxnCommitTimeLag") org.joda.time.Duration domainCreateTxnCommitTimeLag,
@Config("domainCreateTxnCommitTimeLag") Duration domainCreateTxnCommitTimeLag,
BsaEmailSender emailSender,
BsaLock bsaLock,
Clock clock,
@@ -76,7 +76,7 @@ public class BsaRefreshAction implements Runnable {
this.gcsClient = gcsClient;
this.bsaReportSender = bsaReportSender;
this.transactionBatchSize = transactionBatchSize;
this.domainCreateTxnCommitTimeLag = Duration.ofMillis(domainCreateTxnCommitTimeLag.getMillis());
this.domainCreateTxnCommitTimeLag = domainCreateTxnCommitTimeLag;
this.emailSender = emailSender;
this.bsaLock = bsaLock;
this.clock = clock;
@@ -88,14 +88,14 @@ public class BsaValidateAction implements Runnable {
IdnChecker idnChecker,
BsaEmailSender emailSender,
@Config("bsaTxnBatchSize") int transactionBatchSize,
@Config("bsaValidationMaxStaleness") org.joda.time.Duration maxStaleness,
@Config("bsaValidationMaxStaleness") Duration maxStaleness,
Clock clock,
Response response) {
this.gcsClient = gcsClient;
this.idnChecker = idnChecker;
this.emailSender = emailSender;
this.transactionBatchSize = transactionBatchSize;
this.maxStaleness = Duration.ofMillis(maxStaleness.getMillis());
this.maxStaleness = maxStaleness;
this.clock = clock;
this.response = response;
}
@@ -29,7 +29,7 @@ import google.registry.tldconfig.idn.IdnLabelValidator;
import google.registry.tldconfig.idn.IdnTableEnum;
import google.registry.util.Clock;
import jakarta.inject.Inject;
import org.joda.time.DateTime;
import java.time.Instant;
/**
* Checks labels' validity wrt Idns in TLDs enrolled with BSA.
@@ -45,7 +45,7 @@ public class IdnChecker {
@Inject
IdnChecker(Clock clock) {
this.idnToTlds = getIdnToTldMap(clock.nowUtc());
this.idnToTlds = getIdnToTldMap(clock.now());
allTlds = idnToTlds.values().stream().flatMap(ImmutableSet::stream).collect(toImmutableSet());
}
@@ -79,7 +79,7 @@ public class IdnChecker {
return Sets.difference(allTlds, getSupportingTlds(idnTables)).immutableCopy();
}
private static ImmutableMap<IdnTableEnum, ImmutableSet<Tld>> getIdnToTldMap(DateTime now) {
private static ImmutableMap<IdnTableEnum, ImmutableSet<Tld>> getIdnToTldMap(Instant now) {
var idnToTldMap = new ImmutableMultimap.Builder<IdnTableEnum, Tld>();
Tlds.getTldEntitiesOfType(TldType.REAL).stream()
.filter(tld -> isEnrolledWithBsa(tld, now))
@@ -20,7 +20,6 @@ import static google.registry.bsa.BsaStringUtils.DOMAIN_JOINER;
import static google.registry.flows.domain.DomainFlowUtils.isReserved;
import static google.registry.model.tld.Tlds.findTldForName;
import static google.registry.model.tld.label.ReservedList.loadReservedLists;
import static google.registry.util.DateTimeUtils.toInstant;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.InternetDomainName;
@@ -35,7 +34,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import org.joda.time.DateTime;
/**
* Utility for looking up reserved domain names.
@@ -47,15 +45,6 @@ public final class ReservedDomainsUtils {
private ReservedDomainsUtils() {}
/**
* @deprecated Use {@link #getAllReservedNames(Instant)}
*/
@Deprecated
@SuppressWarnings("InlineMeSuggester")
public static Stream<String> getAllReservedNames(DateTime now) {
return getAllReservedNames(toInstant(now));
}
public static Stream<String> getAllReservedNames(Instant now) {
return Tlds.getTldEntitiesOfType(TldType.REAL).stream()
.filter(tld -> Tld.isEnrolledWithBsa(tld, now))
@@ -74,15 +63,6 @@ public final class ReservedDomainsUtils {
.collect(toImmutableSet());
}
/**
* @deprecated Use {@link #getAllReservedDomainsInTld(Tld, Instant)}
*/
@Deprecated
@SuppressWarnings("InlineMeSuggester")
static ImmutableSet<String> getAllReservedDomainsInTld(Tld tld, DateTime now) {
return getAllReservedDomainsInTld(tld, toInstant(now));
}
/**
* Returns true if {@code domain} is a reserved name that can be registered right now (e.g.,
* during sunrise or with allocation token), therefore unblockable.
@@ -95,13 +75,4 @@ public final class ReservedDomainsUtils {
InternetDomainName.from(domain),
Objects.equals(tld.getTldState(now), TldState.START_DATE_SUNRISE));
}
/**
* @deprecated Use {@link #isReservedDomain(String, Instant)}
*/
@Deprecated
@SuppressWarnings("InlineMeSuggester")
public static boolean isReservedDomain(String domain, DateTime now) {
return isReservedDomain(domain, toInstant(now));
}
}
@@ -31,12 +31,12 @@ import jakarta.inject.Inject;
import java.io.IOException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import javax.net.ssl.HttpsURLConnection;
import org.joda.time.Duration;
import org.joda.time.Instant;
/**
* A credential for accessing the BSA API.
@@ -104,7 +104,7 @@ public class BsaCredential {
}
private void ensureAuthTokenValid() throws IOException, GeneralSecurityException {
Instant now = Instant.ofEpochMilli(clock.nowUtc().getMillis());
Instant now = clock.now();
if (authToken != null && lastRefreshTime.plus(authTokenExpiry).isAfter(now)) {
logger.atInfo().log("AuthToken still valid, reusing.");
return;
@@ -20,7 +20,6 @@ import static google.registry.bsa.DownloadStage.DONE;
import static google.registry.bsa.DownloadStage.NOP;
import static google.registry.bsa.persistence.RefreshScheduler.fetchMostRecentRefresh;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static org.joda.time.Duration.standardSeconds;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
@@ -28,9 +27,9 @@ import google.registry.bsa.persistence.DownloadSchedule.CompletedJob;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.Clock;
import jakarta.inject.Inject;
import java.time.Duration;
import java.util.Objects;
import java.util.Optional;
import org.joda.time.Duration;
/**
* Assigns work for each cron invocation of the BSA Download job.
@@ -57,7 +56,7 @@ import org.joda.time.Duration;
public final class DownloadScheduler {
/** Allows a new download to proceed if the cron job fires a little early due to NTP drift. */
private static final Duration CRON_JITTER = standardSeconds(5);
private static final Duration CRON_JITTER = Duration.ofSeconds(5);
private final Duration downloadInterval;
private final Duration maxNopInterval;
@@ -117,8 +116,8 @@ public final class DownloadScheduler {
private boolean isTimeAgain(BsaDownload mostRecent, Duration interval) {
return mostRecent
.getCreationTime()
.plusMillis(interval.getMillis())
.minusMillis(CRON_JITTER.getMillis())
.plusMillis(interval.toMillis())
.minusMillis(CRON_JITTER.toMillis())
.isBefore(clock.now());
}
@@ -37,9 +37,9 @@ import google.registry.bsa.api.UnblockableDomain.Reason;
import google.registry.model.ForeignKeyUtils;
import google.registry.model.domain.Domain;
import google.registry.model.tld.Tld;
import java.time.Instant;
import java.util.Map;
import java.util.stream.Stream;
import org.joda.time.DateTime;
/** Applies the BSA label diffs from the latest BSA download. */
public final class LabelDiffUpdates {
@@ -60,7 +60,7 @@ public final class LabelDiffUpdates {
ImmutableList<BlockLabel> labels,
IdnChecker idnChecker,
DownloadSchedule schedule,
DateTime now) {
Instant now) {
ImmutableList.Builder<UnblockableDomain> nonBlockedDomains = new ImmutableList.Builder<>();
ImmutableMap<LabelType, ImmutableList<BlockLabel>> labelsByType =
ImmutableMap.copyOf(
@@ -134,7 +134,7 @@ public final class LabelDiffUpdates {
}
static ImmutableList<UnblockableDomain> tallyUnblockableDomainsForNewLabels(
ImmutableList<BlockLabel> labels, IdnChecker idnChecker, DateTime now) {
ImmutableList<BlockLabel> labels, IdnChecker idnChecker, Instant now) {
ImmutableList.Builder<UnblockableDomain> nonBlockedDomains = new ImmutableList.Builder<>();
for (BlockLabel label : labels) {
@@ -225,7 +225,7 @@ public final class RegistryConfig {
*/
@Provides
@Config("databaseRetention")
public static Duration provideDatabaseRetention() {
public static java.time.Duration provideDatabaseRetention() {
return getDatabaseRetention();
}
@@ -281,8 +281,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("brdaInterval")
public static Duration provideBrdaInterval() {
return Duration.standardDays(7);
public static java.time.Duration provideBrdaInterval() {
return java.time.Duration.ofDays(7);
}
/**
@@ -315,8 +315,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("publishDnsUpdatesLockDuration")
public static Duration providePublishDnsUpdatesLockDuration() {
return Duration.standardMinutes(3);
public static java.time.Duration providePublishDnsUpdatesLockDuration() {
return java.time.Duration.ofMinutes(3);
}
/**
@@ -343,8 +343,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("readDnsRefreshRequestsActionRuntime")
public static Duration provideReadDnsRefreshRequestsRuntime() {
return Duration.standardSeconds(45);
public static java.time.Duration provideReadDnsRefreshRequestsRuntime() {
return java.time.Duration.ofSeconds(45);
}
/**
@@ -354,8 +354,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("dnsDefaultATtl")
public static Duration provideDnsDefaultATtl() {
return Duration.standardHours(1);
public static java.time.Duration provideDnsDefaultATtl() {
return java.time.Duration.ofHours(1);
}
/**
@@ -365,8 +365,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("dnsDefaultNsTtl")
public static Duration provideDnsDefaultNsTtl() {
return Duration.standardHours(3);
public static java.time.Duration provideDnsDefaultNsTtl() {
return java.time.Duration.ofHours(3);
}
/**
@@ -376,8 +376,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("dnsDefaultDsTtl")
public static Duration provideDnsDefaultDsTtl() {
return Duration.standardHours(1);
public static java.time.Duration provideDnsDefaultDsTtl() {
return java.time.Duration.ofHours(1);
}
@Provides
@@ -757,8 +757,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("rdeInterval")
public static Duration provideRdeInterval() {
return Duration.standardDays(1);
public static java.time.Duration provideRdeInterval() {
return java.time.Duration.ofDays(1);
}
/**
@@ -768,8 +768,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("rdeReportLockTimeout")
public static Duration provideRdeReportLockTimeout() {
return Duration.standardMinutes(1);
public static java.time.Duration provideRdeReportLockTimeout() {
return java.time.Duration.ofMinutes(1);
}
/**
@@ -792,8 +792,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("rdeUploadLockTimeout")
public static Duration provideRdeUploadLockTimeout() {
return Duration.standardMinutes(30);
public static java.time.Duration provideRdeUploadLockTimeout() {
return java.time.Duration.ofMinutes(30);
}
/**
@@ -805,8 +805,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("rdeUploadSftpCooldown")
public static Duration provideRdeUploadSftpCooldown() {
return Duration.standardHours(2);
public static java.time.Duration provideRdeUploadSftpCooldown() {
return java.time.Duration.ofHours(2);
}
/**
@@ -841,8 +841,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("sheetLockTimeout")
public static Duration provideSheetLockTimeout() {
return Duration.standardHours(1);
public static java.time.Duration provideSheetLockTimeout() {
return java.time.Duration.ofHours(1);
}
/**
@@ -865,8 +865,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("emailThrottleDuration")
public static Duration provideEmailThrottleSeconds(RegistryConfigSettings config) {
return Duration.standardSeconds(config.misc.emailThrottleSeconds);
public static java.time.Duration provideEmailThrottleSeconds(RegistryConfigSettings config) {
return java.time.Duration.ofSeconds(config.misc.emailThrottleSeconds);
}
/**
@@ -946,8 +946,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("sshTimeout")
public static Duration provideSshTimeout() {
return Duration.standardSeconds(30);
public static java.time.Duration provideSshTimeout() {
return java.time.Duration.ofSeconds(30);
}
/**
@@ -957,8 +957,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("transactionCooldown")
public static Duration provideTransactionCooldown() {
return Duration.standardMinutes(5);
public static java.time.Duration provideTransactionCooldown() {
return java.time.Duration.ofMinutes(5);
}
/**
@@ -1327,15 +1327,15 @@ public final class RegistryConfig {
@Provides
@Config("bsaLockLeaseExpiry")
public static Duration provideBsaLockLeaseExpiry(RegistryConfigSettings config) {
return Duration.standardMinutes(config.bsa.bsaLockLeaseExpiryMinutes);
public static java.time.Duration provideBsaLockLeaseExpiry(RegistryConfigSettings config) {
return java.time.Duration.ofMinutes(config.bsa.bsaLockLeaseExpiryMinutes);
}
/** Returns the desired interval between successive BSA downloads. */
@Provides
@Config("bsaDownloadInterval")
public static Duration provideBsaDownloadInterval(RegistryConfigSettings config) {
return Duration.standardMinutes(config.bsa.bsaDownloadIntervalMinutes);
public static java.time.Duration provideBsaDownloadInterval(RegistryConfigSettings config) {
return java.time.Duration.ofMinutes(config.bsa.bsaDownloadIntervalMinutes);
}
/**
@@ -1344,8 +1344,8 @@ public final class RegistryConfig {
*/
@Provides
@Config("bsaMaxNopInterval")
public static Duration provideBsaMaxNopInterval(RegistryConfigSettings config) {
return Duration.standardHours(config.bsa.bsaMaxNopIntervalHours);
public static java.time.Duration provideBsaMaxNopInterval(RegistryConfigSettings config) {
return java.time.Duration.ofHours(config.bsa.bsaMaxNopIntervalHours);
}
@Provides
@@ -1356,14 +1356,16 @@ public final class RegistryConfig {
@Provides
@Config("domainCreateTxnCommitTimeLag")
public static Duration provideDomainCreateTxnCommitTimeLag(RegistryConfigSettings config) {
return Duration.standardSeconds(config.bsa.domainCreateTxnCommitTimeLagSeconds);
public static java.time.Duration provideDomainCreateTxnCommitTimeLag(
RegistryConfigSettings config) {
return java.time.Duration.ofSeconds(config.bsa.domainCreateTxnCommitTimeLagSeconds);
}
@Provides
@Config("bsaValidationMaxStaleness")
public static Duration provideBsaValidationMaxStaleness(RegistryConfigSettings config) {
return Duration.standardSeconds(config.bsa.bsaValidationMaxStalenessSeconds);
public static java.time.Duration provideBsaValidationMaxStaleness(
RegistryConfigSettings config) {
return java.time.Duration.ofSeconds(config.bsa.bsaValidationMaxStalenessSeconds);
}
@Provides
@@ -1374,8 +1376,8 @@ public final class RegistryConfig {
@Provides
@Config("bsaAuthTokenExpiry")
public static Duration provideBsaAuthTokenExpiry(RegistryConfigSettings config) {
return Duration.standardSeconds(config.bsa.authTokenExpirySeconds);
public static java.time.Duration provideBsaAuthTokenExpiry(RegistryConfigSettings config) {
return java.time.Duration.ofSeconds(config.bsa.authTokenExpirySeconds);
}
@Provides
@@ -1488,8 +1490,8 @@ public final class RegistryConfig {
*
* @see google.registry.tools.server.GenerateZoneFilesAction
*/
public static Duration getDatabaseRetention() {
return Duration.standardDays(30);
public static java.time.Duration getDatabaseRetention() {
return java.time.Duration.ofDays(30);
}
public static boolean areServersLocal() {
@@ -26,7 +26,7 @@ import com.google.monitoring.metrics.LabelDescriptor;
import com.google.monitoring.metrics.MetricRegistryImpl;
import google.registry.util.RegistryEnvironment;
import jakarta.inject.Inject;
import org.joda.time.Duration;
import java.time.Duration;
/** DNS instrumentation. */
// TODO(b/67947699):Once load testing is done, revisit these to rename them and delete the ones that
@@ -239,15 +239,15 @@ public class DnsMetrics {
int batchSize = numberOfDomains + numberOfHosts;
processingTimePerCommitDist.record(
processingDuration.getMillis(), tld, status.name(), dnsWriter);
processingDuration.toMillis(), tld, status.name(), dnsWriter);
processingTimePerItemDist.record(
processingDuration.getMillis(), batchSize, tld, status.name(), dnsWriter);
processingDuration.toMillis(), batchSize, tld, status.name(), dnsWriter);
if (batchSize > 0) {
normalizedProcessingTimePerCommitDist.record(
processingDuration.getMillis() / (double) batchSize, tld, status.name(), dnsWriter);
processingDuration.toMillis() / (double) batchSize, tld, status.name(), dnsWriter);
normalizedProcessingTimePerItemDist.record(
processingDuration.getMillis() / (double) batchSize,
processingDuration.toMillis() / (double) batchSize,
batchSize,
tld,
status.name(),
@@ -267,7 +267,7 @@ public class DnsMetrics {
Duration timeSinceUpdateRequest,
Duration timeSinceActionEnqueued) {
updateRequestLatency.record(
timeSinceUpdateRequest.getMillis(), numberOfItems, tld, status.name(), dnsWriter);
publishQueueDelay.record(timeSinceActionEnqueued.getMillis(), tld, status.name(), dnsWriter);
timeSinceUpdateRequest.toMillis(), numberOfItems, tld, status.name(), dnsWriter);
publishQueueDelay.record(timeSinceActionEnqueued.toMillis(), tld, status.name(), dnsWriter);
}
}
@@ -32,9 +32,9 @@ import google.registry.dns.writer.DnsWriterZone;
import google.registry.request.Parameter;
import google.registry.request.RequestParameters;
import jakarta.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.Optional;
import java.util.Set;
import org.joda.time.DateTime;
/** Dagger module for the dns package. */
@Module
@@ -68,15 +68,15 @@ public abstract class DnsModule {
@Provides
@Parameter(PARAM_PUBLISH_TASK_ENQUEUED)
static DateTime provideCreateTime(HttpServletRequest req) {
return DateTime.parse(extractRequiredParameter(req, PARAM_PUBLISH_TASK_ENQUEUED));
static Instant provideCreateTime(HttpServletRequest req) {
return Instant.parse(extractRequiredParameter(req, PARAM_PUBLISH_TASK_ENQUEUED));
}
// TODO: Retire the old header after DNS pull queue migration.
@Provides
@Parameter(PARAM_REFRESH_REQUEST_TIME)
static DateTime provideItemsCreateTime(HttpServletRequest req) {
return DateTime.parse(
static Instant provideItemsCreateTime(HttpServletRequest req) {
return Instant.parse(
extractOptionalParameter(req, "itemsCreated")
.orElse(extractRequiredParameter(req, PARAM_REFRESH_REQUEST_TIME)));
}
@@ -17,6 +17,7 @@ package google.registry.dns;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.persistence.PersistenceModule.TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.toJavaDuration;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
@@ -24,10 +25,10 @@ import com.google.common.net.InternetDomainName;
import google.registry.model.common.DnsRefreshRequest;
import google.registry.model.tld.Tld;
import google.registry.model.tld.Tlds;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Optional;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/** Utility class to handle DNS refresh requests. */
public final class DnsUtils {
@@ -42,13 +43,13 @@ public final class DnsUtils {
// Throws an IllegalArgumentException if the name is not under a managed TLD -- we only update
// DNS for names that are under our management.
String tld = Tlds.findTldForNameOrThrow(InternetDomainName.from(name)).toString();
tm().insert(new DnsRefreshRequest(type, name, tld, tm().getTransactionTime().plus(delay)));
tm().insert(new DnsRefreshRequest(type, name, tld, tm().getTxTime().plus(delay)));
}
private static void requestDnsRefresh(
ImmutableCollection<String> names, TargetType type, Duration delay) {
tm().assertInTransaction();
DateTime requestTime = tm().getTransactionTime().plus(delay);
Instant requestTime = tm().getTxTime().plus(delay);
tm().insertAll(
names.stream()
.map(
@@ -103,7 +104,7 @@ public final class DnsUtils {
return tm().transact(
TRANSACTION_REPEATABLE_READ,
() -> {
DateTime transactionTime = tm().getTransactionTime();
Instant transactionTime = tm().getTxTime();
ImmutableList<DnsRefreshRequest> requests =
tm().query(
"FROM DnsRefreshRequest WHERE tld = :tld "
@@ -150,10 +151,10 @@ public final class DnsUtils {
if (tldName.isPresent()) {
Tld tld = Tld.get(tldName.get().toString());
if (tld.getDnsAPlusAaaaTtl().isPresent()) {
dnsAPlusAaaaTtl = tld.getDnsAPlusAaaaTtl().get();
dnsAPlusAaaaTtl = toJavaDuration(tld.getDnsAPlusAaaaTtl().get());
}
}
return dnsAPlusAaaaTtl.getStandardSeconds();
return dnsAPlusAaaaTtl.toSeconds();
}
/** The possible values of the {@code DNS_TARGET_TYPE_PARAM} parameter. */
@@ -63,11 +63,11 @@ import google.registry.util.DomainNameUtils;
import google.registry.util.EmailMessage;
import jakarta.inject.Inject;
import jakarta.mail.internet.InternetAddress;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/** Task that sends domain and host updates to the DNS server. */
@Action(
@@ -100,8 +100,8 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
*/
private final String dnsWriter;
private final DateTime enqueuedTime;
private final DateTime itemsCreateTime;
private final Instant enqueuedTime;
private final Instant itemsCreateTime;
private final int lockIndex;
private final int numPublishLocks;
private final Set<String> domains;
@@ -121,8 +121,8 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
@Inject
public PublishDnsUpdatesAction(
@Parameter(PARAM_DNS_WRITER) String dnsWriter,
@Parameter(PARAM_PUBLISH_TASK_ENQUEUED) DateTime enqueuedTime,
@Parameter(PARAM_REFRESH_REQUEST_TIME) DateTime itemsCreateTime,
@Parameter(PARAM_PUBLISH_TASK_ENQUEUED) Instant enqueuedTime,
@Parameter(PARAM_REFRESH_REQUEST_TIME) Instant itemsCreateTime,
@Parameter(PARAM_LOCK_INDEX) int lockIndex,
@Parameter(PARAM_NUM_PUBLISH_LOCKS) int numPublishLocks,
@Parameter(PARAM_DOMAINS) Set<String> domains,
@@ -167,15 +167,15 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
}
private void recordActionResult(ActionStatus status) {
DateTime now = clock.nowUtc();
Instant now = clock.now();
dnsMetrics.recordActionResult(
tld,
dnsWriter,
status,
nullToEmpty(domains).size() + nullToEmpty(hosts).size(),
new Duration(itemsCreateTime, now),
new Duration(enqueuedTime, now));
Duration.between(itemsCreateTime, now),
Duration.between(enqueuedTime, now));
logger.atInfo().log(
"publishDnsWriter latency statistics: TLD: %s, dnsWriter: %s, actionStatus: %s, "
+ "numItems: %d, timeSinceCreation: %s, timeInQueue: %s.",
@@ -183,8 +183,8 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
dnsWriter,
status,
nullToEmpty(domains).size() + nullToEmpty(hosts).size(),
new Duration(itemsCreateTime, now),
new Duration(enqueuedTime, now));
Duration.between(itemsCreateTime, now),
Duration.between(enqueuedTime, now));
}
/** Runs the task. */
@@ -237,7 +237,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
.ifPresent(
dn -> {
Optional<Domain> domain =
ForeignKeyUtils.loadResource(Domain.class, dn, clock.nowUtc());
ForeignKeyUtils.loadResource(Domain.class, dn, clock.now());
if (domain.isPresent()) {
notifyWithEmailAboutDnsUpdateFailure(
domain.get().getCurrentSponsorRegistrarId(), dn, false);
@@ -250,8 +250,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
.findFirst()
.ifPresent(
hn -> {
Optional<Host> host =
ForeignKeyUtils.loadResource(Host.class, hn, clock.nowUtc());
Optional<Host> host = ForeignKeyUtils.loadResource(Host.class, hn, clock.now());
if (host.isPresent()) {
notifyWithEmailAboutDnsUpdateFailure(
host.get().getPersistedCurrentSponsorRegistrarId(), hn, true);
@@ -336,7 +335,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
.put(PARAM_DNS_WRITER, dnsWriter)
.put(PARAM_LOCK_INDEX, Integer.toString(lockIndex))
.put(PARAM_NUM_PUBLISH_LOCKS, Integer.toString(numPublishLocks))
.put(PARAM_PUBLISH_TASK_ENQUEUED, clock.nowUtc().toString())
.put(PARAM_PUBLISH_TASK_ENQUEUED, clock.now().toString())
.put(PARAM_REFRESH_REQUEST_TIME, itemsCreateTime.toString())
.put(PARAM_DOMAINS, Joiner.on(",").join(domains))
.put(PARAM_HOSTS, Joiner.on(",").join(hosts))
@@ -374,7 +373,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
/** Steps through the domain and host refreshes contained in the parameters and processes them. */
private void processBatch() {
DateTime timeAtStart = clock.nowUtc();
Instant timeAtStart = clock.now();
DnsWriter writer = dnsWriterProxy.getByClassNameForTld(dnsWriter, tld);
@@ -426,7 +425,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
actionStatus = ActionStatus.SUCCESS;
} finally {
recordActionResult(actionStatus);
Duration duration = new Duration(timeAtStart, clock.nowUtc());
Duration duration = Duration.between(timeAtStart, clock.now());
dnsMetrics.recordCommit(
tld, dnsWriter, commitStatus, duration, domainsPublished, hostsPublished);
logger.atInfo().log(
@@ -28,7 +28,7 @@ import static google.registry.dns.DnsUtils.deleteRequests;
import static google.registry.dns.DnsUtils.readAndUpdateRequestsWithLatestProcessTime;
import static google.registry.request.Action.Method.POST;
import static google.registry.request.RequestParameters.PARAM_TLD;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
import static google.registry.util.DateTimeUtils.END_INSTANT;
import static google.registry.util.DomainNameUtils.getSecondLevelDomain;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -49,10 +49,10 @@ import google.registry.request.Parameter;
import google.registry.request.auth.Auth;
import google.registry.util.Clock;
import jakarta.inject.Inject;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Optional;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Action for fanning out DNS refresh tasks by TLD, using data taken from {@link DnsRefreshRequest}
@@ -104,11 +104,11 @@ public final class ReadDnsRefreshRequestsAction implements Runnable {
logger.atInfo().log("The queue updated is paused for TLD: %s.", tld);
return;
}
DateTime requestedEndTime = clock.nowUtc().plus(requestedMaximumDuration);
Instant requestedEndTime = clock.now().plus(requestedMaximumDuration);
// See getLockIndex(), requests are evenly distributed to [1, numDnsPublishLocks], so each
// bucket would be roughly the size of tldUpdateBatchSize.
int processBatchSize = tldUpdateBatchSize * Tld.get(tld).getNumDnsPublishLocks();
while (requestedEndTime.isAfter(clock.nowUtc())) {
while (requestedEndTime.isAfter(clock.now())) {
ImmutableList<DnsRefreshRequest> requests =
readAndUpdateRequestsWithLatestProcessTime(
tld, requestedMaximumDuration, processBatchSize);
@@ -165,7 +165,7 @@ public final class ReadDnsRefreshRequestsAction implements Runnable {
void enqueueUpdates(int lockIndex, int numPublishLocks, Collection<DnsRefreshRequest> requests) {
ImmutableList.Builder<String> domainsBuilder = new ImmutableList.Builder<>();
ImmutableList.Builder<String> hostsBuilder = new ImmutableList.Builder<>();
DateTime earliestRequestTime = END_OF_TIME;
Instant earliestRequestTime = END_INSTANT;
for (DnsRefreshRequest request : requests) {
if (request.getRequestTime().isBefore(earliestRequestTime)) {
earliestRequestTime = request.getRequestTime();
@@ -189,7 +189,7 @@ public final class ReadDnsRefreshRequestsAction implements Runnable {
.put(PARAM_DNS_WRITER, dnsWriter)
.put(PARAM_LOCK_INDEX, Integer.toString(lockIndex))
.put(PARAM_NUM_PUBLISH_LOCKS, Integer.toString(numPublishLocks))
.put(PARAM_PUBLISH_TASK_ENQUEUED, clock.nowUtc().toString())
.put(PARAM_PUBLISH_TASK_ENQUEUED, clock.now().toString())
.put(PARAM_REFRESH_REQUEST_TIME, earliestRequestTime.toString())
.put(PARAM_DOMAINS, Joiner.on(',').join(domains))
.put(PARAM_HOSTS, Joiner.on(',').join(hosts))
@@ -78,7 +78,7 @@ public final class RefreshDnsAction implements Runnable {
private <T extends EppResource & ForeignKeyedEppResource>
T loadAndVerifyExistence(Class<T> clazz, String foreignKey) {
return ForeignKeyUtils.loadResource(clazz, foreignKey, clock.nowUtc())
return ForeignKeyUtils.loadResource(clazz, foreignKey, clock.now())
.orElseThrow(
() ->
new NotFoundException(
@@ -30,7 +30,7 @@ import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import jakarta.inject.Inject;
import org.joda.time.DateTime;
import java.time.Instant;
@Action(
service = Action.Service.BACKEND,
@@ -56,7 +56,7 @@ public class RefreshDnsOnHostRenameAction implements Runnable {
public void run() {
tm().transact(
() -> {
DateTime now = tm().getTransactionTime();
Instant now = tm().getTxTime();
Host host = tm().loadByKeyIfPresent(hostKey).orElse(null);
boolean hostValid = true;
String failureMessage = null;
@@ -44,6 +44,7 @@ import google.registry.model.tld.Tld;
import google.registry.model.tld.Tlds;
import google.registry.util.Clock;
import google.registry.util.Concurrent;
import google.registry.util.DateTimeUtils;
import google.registry.util.Retrier;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@@ -51,6 +52,7 @@ import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.time.Duration;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.HashMap;
import java.util.HashSet;
@@ -59,7 +61,6 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import org.joda.time.Duration;
/**
* {@link DnsWriter} implementation that talks to Google Cloud DNS.
@@ -123,8 +124,7 @@ public class CloudDnsWriter extends BaseDnsWriter {
String absoluteDomainName = getAbsoluteHostName(domainName);
// Load the target domain. Note that it can be absent if this domain was just deleted.
Optional<Domain> domain =
ForeignKeyUtils.loadResource(Domain.class, domainName, clock.nowUtc());
Optional<Domain> domain = ForeignKeyUtils.loadResource(Domain.class, domainName, clock.now());
// Return early if no DNS records should be published.
// desiredRecordsBuilder is populated with an empty set to indicate that all existing records
@@ -148,7 +148,12 @@ public class CloudDnsWriter extends BaseDnsWriter {
domainRecords.add(
new ResourceRecordSet()
.setName(absoluteDomainName)
.setTtl((int) tld.getDnsDsTtl().orElse(defaultDsTtl).getStandardSeconds())
.setTtl(
(int)
tld.getDnsDsTtl()
.map(DateTimeUtils::toJavaDuration)
.orElse(defaultDsTtl)
.toSeconds())
.setType("DS")
.setKind("dns#resourceRecordSet")
.setRrdatas(ImmutableList.copyOf(dsRrData)));
@@ -171,7 +176,12 @@ public class CloudDnsWriter extends BaseDnsWriter {
domainRecords.add(
new ResourceRecordSet()
.setName(absoluteDomainName)
.setTtl((int) tld.getDnsNsTtl().orElse(defaultNsTtl).getStandardSeconds())
.setTtl(
(int)
tld.getDnsNsTtl()
.map(DateTimeUtils::toJavaDuration)
.orElse(defaultNsTtl)
.toSeconds())
.setType("NS")
.setKind("dns#resourceRecordSet")
.setRrdatas(ImmutableList.copyOf(nsRrData)));
@@ -190,7 +200,7 @@ public class CloudDnsWriter extends BaseDnsWriter {
// Load the target host. Note that it can be absent if this host was just deleted.
// desiredRecords is populated with an empty set to indicate that all existing records
// should be deleted.
Optional<Host> host = ForeignKeyUtils.loadResource(Host.class, hostName, clock.nowUtc());
Optional<Host> host = ForeignKeyUtils.loadResource(Host.class, hostName, clock.now());
// Return early if the host is deleted.
if (host.isEmpty()) {
@@ -28,8 +28,8 @@ import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.time.Duration;
import javax.net.SocketFactory;
import org.joda.time.Duration;
import org.xbill.DNS.Message;
import org.xbill.DNS.Opcode;
@@ -76,7 +76,7 @@ public class DnsMessageTransport {
@Config("dnsUpdateTimeout") Duration updateTimeout) {
this.factory = factory;
this.updateHost = updateHost;
this.updateTimeout = Ints.checkedCast(updateTimeout.getMillis());
this.updateTimeout = Ints.checkedCast(updateTimeout.toMillis());
}
/**
@@ -17,7 +17,7 @@ package google.registry.dns.writer.dnsupdate;
import dagger.Module;
import dagger.Provides;
import google.registry.config.RegistryConfig.Config;
import org.joda.time.Duration;
import java.time.Duration;
/** Dagger module that provides DNS configuration settings. */
@Module
@@ -39,6 +39,6 @@ public class DnsUpdateConfigModule {
@Provides
@Config("dnsUpdateTimeout")
public static Duration provideDnsUpdateTimeout() {
return Duration.standardSeconds(30);
return Duration.ofSeconds(30);
}
}
@@ -34,13 +34,14 @@ import google.registry.model.host.Host;
import google.registry.model.tld.Tld;
import google.registry.model.tld.Tlds;
import google.registry.util.Clock;
import google.registry.util.DateTimeUtils;
import jakarta.inject.Inject;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.time.Duration;
import java.util.Optional;
import org.joda.time.Duration;
import org.xbill.DNS.AAAARecord;
import org.xbill.DNS.ARecord;
import org.xbill.DNS.DClass;
@@ -130,7 +131,7 @@ public class DnsUpdateWriter extends BaseDnsWriter {
*/
private void publishDomain(String domainName, String requestingHostName) {
Optional<Domain> domainOptional =
ForeignKeyUtils.loadResource(Domain.class, domainName, clock.nowUtc());
ForeignKeyUtils.loadResource(Domain.class, domainName, clock.now());
update.delete(toAbsoluteName(domainName), Type.ANY);
// If the domain is now deleted, then don't update DNS for it.
if (domainOptional.isPresent()) {
@@ -194,7 +195,10 @@ public class DnsUpdateWriter extends BaseDnsWriter {
new DSRecord(
toAbsoluteName(domain.getDomainName()),
DClass.IN,
tld.getDnsDsTtl().orElse(dnsDefaultDsTtl).getStandardSeconds(),
tld.getDnsDsTtl()
.map(DateTimeUtils::toJavaDuration)
.orElse(dnsDefaultDsTtl)
.toSeconds(),
signerData.getKeyTag(),
signerData.getAlgorithm(),
signerData.getDigestType(),
@@ -219,7 +223,7 @@ public class DnsUpdateWriter extends BaseDnsWriter {
private void addInBailiwickNameServerSet(Domain domain, Update update) {
for (String hostName :
intersection(domain.loadNameserverHostNames(), domain.getSubordinateHosts())) {
Optional<Host> host = ForeignKeyUtils.loadResource(Host.class, hostName, clock.nowUtc());
Optional<Host> host = ForeignKeyUtils.loadResource(Host.class, hostName, clock.now());
checkState(host.isPresent(), "Host %s cannot be loaded", hostName);
update.add(makeAddressSet(host.get()));
update.add(makeV6AddressSet(host.get()));
@@ -234,7 +238,10 @@ public class DnsUpdateWriter extends BaseDnsWriter {
new NSRecord(
toAbsoluteName(domain.getDomainName()),
DClass.IN,
tld.getDnsNsTtl().orElse(dnsDefaultNsTtl).getStandardSeconds(),
tld.getDnsNsTtl()
.map(DateTimeUtils::toJavaDuration)
.orElse(dnsDefaultNsTtl)
.toSeconds(),
toAbsoluteName(hostName));
nameServerSet.addRR(record);
}
@@ -47,8 +47,6 @@ import java.time.Instant;
import java.util.List;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.TupleTransformer;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
/**
* An action that exports the list of active domains on all real TLDs to Google Drive and GCS.
@@ -175,8 +173,7 @@ public class ExportDomainListsAction implements Runnable {
@Override
public String transformTuple(Object[] domainResult, String[] strings) {
String domainName = (String) domainResult[0];
Instant deletionInstant = (Instant) domainResult[1];
DateTime deletionTime = new DateTime(deletionInstant.toEpochMilli(), DateTimeZone.UTC);
Instant deletionTime = (Instant) domainResult[1];
String[] domainStatuses = (String[]) domainResult[2];
String gracePeriodType = (String) domainResult[3];
boolean inPendingDelete =
@@ -26,6 +26,7 @@ import static google.registry.model.registrar.RegistrarPoc.Type.TECH;
import static google.registry.model.registrar.RegistrarPoc.Type.WHOIS;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.START_INSTANT;
import static google.registry.util.DateTimeUtils.isAtOrAfter;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
@@ -37,7 +38,6 @@ import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.util.Clock;
import google.registry.util.DateTimeUtils;
import jakarta.inject.Inject;
import java.io.IOException;
import java.time.Instant;
@@ -63,9 +63,9 @@ class SyncRegistrarsSheet {
boolean wereRegistrarsModified() {
Optional<Cursor> cursor =
tm().transact(() -> tm().loadByKeyIfPresent(Cursor.createGlobalVKey(SYNC_REGISTRAR_SHEET)));
Instant lastUpdateTime = cursor.isEmpty() ? START_INSTANT : cursor.get().getCursorTimeInstant();
Instant lastUpdateTime = cursor.isEmpty() ? START_INSTANT : cursor.get().getCursorTime();
for (Registrar registrar : Registrar.loadAllCached()) {
if (DateTimeUtils.isAtOrAfter(registrar.getLastUpdateTime(), lastUpdateTime)) {
if (isAtOrAfter(registrar.getLastUpdateTime(), lastUpdateTime)) {
return true;
}
}
@@ -30,10 +30,10 @@ import google.registry.request.auth.Auth;
import google.registry.request.lock.LockHandler;
import jakarta.inject.Inject;
import java.io.IOException;
import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.Callable;
import javax.annotation.Nullable;
import org.joda.time.Duration;
/**
* Action for synchronizing the registrars spreadsheet.
@@ -42,6 +42,7 @@ import static google.registry.util.CollectionUtils.nullToEmpty;
import static google.registry.util.CollectionUtils.union;
import static google.registry.util.DateTimeUtils.toDateTime;
import static google.registry.util.DateTimeUtils.toInstant;
import static java.time.ZoneOffset.UTC;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -101,7 +102,6 @@ import google.registry.model.tld.Tld.TldType;
import google.registry.model.transfer.TransferStatus;
import jakarta.inject.Inject;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
@@ -194,9 +194,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
} else {
Instant redemptionTime = now.plusMillis(redemptionGracePeriodLength.getMillis());
asyncTaskEnqueuer.enqueueAsyncResave(
existingDomain.createVKey(),
toDateTime(now),
ImmutableSortedSet.of(toDateTime(redemptionTime), toDateTime(deletionTime)));
existingDomain.createVKey(), now, ImmutableSortedSet.of(redemptionTime, deletionTime));
builder
.setDeletionTime(deletionTime)
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
@@ -253,14 +251,11 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
// This can be either add grace periods or renew grace periods.
BillingEvent billingEvent = tm().loadByKey(gracePeriod.getBillingEvent());
newExpirationTime =
newExpirationTime
.atZone(ZoneOffset.UTC)
.minusYears(billingEvent.getPeriodYears())
.toInstant();
newExpirationTime.atZone(UTC).minusYears(billingEvent.getPeriodYears()).toInstant();
} else if (gracePeriod.getBillingRecurrence() != null) {
// Take 1 year off the registration if in the autorenew grace period (no need to load the
// recurrence billing event; all autorenews are for 1 year).
newExpirationTime = newExpirationTime.atZone(ZoneOffset.UTC).minusYears(1).toInstant();
newExpirationTime = newExpirationTime.atZone(UTC).minusYears(1).toInstant();
}
}
}
@@ -44,6 +44,7 @@ import static google.registry.util.DateTimeUtils.END_INSTANT;
import static google.registry.util.DateTimeUtils.isAtOrAfter;
import static google.registry.util.DateTimeUtils.minusDays;
import static google.registry.util.DomainNameUtils.ACE_PREFIX;
import static java.time.ZoneOffset.UTC;
import static java.util.stream.Collectors.joining;
import com.google.common.base.CharMatcher;
@@ -124,7 +125,6 @@ import google.registry.tools.DigestType;
import google.registry.util.Idn;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry;
@@ -848,10 +848,7 @@ public class DomainFlowUtils {
*/
public static void validateRegistrationPeriod(Instant now, Instant newExpirationTime)
throws EppException {
if (now.atZone(ZoneOffset.UTC)
.plusYears(MAX_REGISTRATION_YEARS)
.toInstant()
.isBefore(newExpirationTime)) {
if (now.atZone(UTC).plusYears(MAX_REGISTRATION_YEARS).toInstant().isBefore(newExpirationTime)) {
throw new ExceedsMaxRegistrationYearsException();
}
}
@@ -35,6 +35,7 @@ import static google.registry.flows.domain.token.AllocationTokenFlowUtils.verify
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_RENEW;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.toDateTime;
import static java.time.ZoneOffset.UTC;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -87,7 +88,6 @@ import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.tld.Tld;
import jakarta.inject.Inject;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.Optional;
import org.joda.money.Money;
import org.joda.time.Duration;
@@ -194,7 +194,7 @@ public final class DomainRenewFlow implements MutatingFlow {
Instant newExpirationTime =
existingDomain
.getRegistrationExpirationTime()
.atZone(ZoneOffset.UTC)
.atZone(UTC)
.plusYears(years)
.toInstant(); // Uncapped
validateRegistrationPeriod(now, newExpirationTime);
@@ -31,6 +31,7 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyRegistrarIsActi
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_RESTORE;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.END_INSTANT;
import static java.time.ZoneOffset.UTC;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -70,7 +71,6 @@ import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
import google.registry.model.tld.Tld;
import jakarta.inject.Inject;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.Optional;
import org.joda.money.Money;
@@ -152,7 +152,7 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
Instant newExpirationTime =
existingDomain
.getRegistrationExpirationTime()
.atZone(ZoneOffset.UTC)
.atZone(UTC)
.plusYears(isExpired ? 1 : 0)
.toInstant();
// Restore the expiration time on the deleted domain, except if that's already passed, then add
@@ -35,7 +35,7 @@ import static google.registry.flows.domain.DomainTransferUtils.createTransferSer
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.toDateTime;
import static java.time.temporal.ChronoUnit.DAYS;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -82,7 +82,6 @@ import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
import google.registry.model.transfer.TransferStatus;
import jakarta.inject.Inject;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Optional;
/**
@@ -220,8 +219,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
.map(
domainTransferRequestSuperuserExtension ->
now.plus(
domainTransferRequestSuperuserExtension.getAutomaticTransferLength(),
ChronoUnit.DAYS))
domainTransferRequestSuperuserExtension.getAutomaticTransferLength(), DAYS))
.orElseGet(() -> now.plusMillis(tld.getAutomaticTransferLength().getMillis()));
// If the domain will be in the auto-renew grace period at the moment of transfer, the transfer
// will subsume the autorenew, so we don't add the normal extra year from the transfer.
@@ -284,9 +282,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
DomainHistory domainHistory = buildDomainHistory(newDomain, tld, now, period);
asyncTaskEnqueuer.enqueueAsyncResave(
newDomain.createVKey(),
toDateTime(now),
ImmutableSortedSet.of(toDateTime(automaticTransferTime)));
newDomain.createVKey(), now, ImmutableSortedSet.of(automaticTransferTime));
tm().put(newDomain);
tm().putAll(serverApproveEntities);
tm().insertAll(domainHistory, requestPollMessage);
@@ -83,7 +83,7 @@ public final class PollAckFlow implements MutatingFlow {
throw new InvalidMessageIdException(messageId);
}
final Instant now = tm().getTxTime();
Instant now = tm().getTxTime();
// Load the message to be acked. If a message is queued to be delivered in the future, we treat
// it as if it doesn't exist yet. Same for if the message ID year isn't the same as the actual
@@ -17,8 +17,6 @@ package google.registry.model.common;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.util.DateTimeUtils.START_INSTANT;
import static google.registry.util.DateTimeUtils.toDateTime;
import static google.registry.util.DateTimeUtils.toInstant;
import google.registry.model.ImmutableObject;
import google.registry.model.UnsafeSerializable;
@@ -35,7 +33,6 @@ import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import java.time.Instant;
import java.util.Optional;
import org.joda.time.DateTime;
/**
* Shared entity for date cursors.
@@ -156,15 +153,6 @@ public class Cursor extends UpdateAutoTimestampEntity {
return getUpdateTimestamp().getTimestamp();
}
/**
* @deprecated Use {@link #getLastUpdateTime()}
*/
@Deprecated
@SuppressWarnings("InlineMeSuggester")
public DateTime getLastUpdateDateTime() {
return toDateTime(getUpdateTimestamp().getTimestamp());
}
public String getScope() {
return scope;
}
@@ -189,30 +177,12 @@ public class Cursor extends UpdateAutoTimestampEntity {
return create(cursorType, cursorTime, GLOBAL);
}
/**
* @deprecated Use {@link #createGlobal(CursorType, Instant)}
*/
@Deprecated
@SuppressWarnings("InlineMeSuggester")
public static Cursor createGlobal(CursorType cursorType, DateTime cursorTime) {
return createGlobal(cursorType, toInstant(cursorTime));
}
/** Creates a new cursor instance with a given {@link Tld} scope. */
public static Cursor createScoped(CursorType cursorType, Instant cursorTime, Tld scope) {
checkNotNull(scope, "Cursor scope cannot be null");
return create(cursorType, cursorTime, scope.getTldStr());
}
/**
* @deprecated Use {@link #createScoped(CursorType, Instant, Tld)}
*/
@Deprecated
@SuppressWarnings("InlineMeSuggester")
public static Cursor createScoped(CursorType cursorType, DateTime cursorTime, Tld scope) {
return createScoped(cursorType, toInstant(cursorTime), scope);
}
/**
* Creates a new cursor instance with a given TLD scope, or global if the scope is {@link
* #GLOBAL}.
@@ -230,29 +200,11 @@ public class Cursor extends UpdateAutoTimestampEntity {
/**
* Returns the current time for a given cursor, or {@code START_INSTANT} if the cursor is null.
*/
public static Instant getCursorTimeOrStartOfTimeInstant(Optional<Cursor> cursor) {
return cursor.map(Cursor::getCursorTimeInstant).orElse(START_INSTANT);
public static Instant getCursorTimeOrStartOfTime(Optional<Cursor> cursor) {
return cursor.map(Cursor::getCursorTime).orElse(START_INSTANT);
}
/**
* @deprecated Use {@link #getCursorTimeOrStartOfTimeInstant(Optional)}
*/
@Deprecated
@SuppressWarnings("InlineMeSuggester")
public static DateTime getCursorTimeOrStartOfTime(Optional<Cursor> cursor) {
return toDateTime(getCursorTimeOrStartOfTimeInstant(cursor));
}
/**
* @deprecated Use {@link #getCursorTimeInstant()}
*/
@Deprecated
@SuppressWarnings("InlineMeSuggester")
public DateTime getCursorTime() {
return toDateTime(cursorTime);
}
public Instant getCursorTimeInstant() {
public Instant getCursorTime() {
return cursorTime;
}
@@ -16,7 +16,7 @@ package google.registry.model.common;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static google.registry.util.DateTimeUtils.START_INSTANT;
import google.registry.dns.DnsUtils.TargetType;
import google.registry.dns.PublishDnsUpdatesAction;
@@ -31,8 +31,8 @@ import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.Table;
import java.time.Instant;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
@Entity
@Table(indexes = {@Index(columnList = "requestTime"), @Index(columnList = "lastProcessTime")})
@@ -54,10 +54,10 @@ public class DnsRefreshRequest extends ImmutableObject {
private String tld;
@Column(nullable = false)
private DateTime requestTime;
private Instant requestTime;
@Column(nullable = false)
private DateTime lastProcessTime;
private Instant lastProcessTime;
public TargetType getType() {
return type;
@@ -71,7 +71,7 @@ public class DnsRefreshRequest extends ImmutableObject {
return tld;
}
public DateTime getRequestTime() {
public Instant getRequestTime() {
return requestTime;
}
@@ -86,7 +86,7 @@ public class DnsRefreshRequest extends ImmutableObject {
* there are concurrent reads that all attempt to read the rows with oldest {@link #requestTime},
* or another read that comes too early after the previous read.
*/
public DateTime getLastProcessTime() {
public Instant getLastProcessTime() {
return lastProcessTime;
}
@@ -102,8 +102,8 @@ public class DnsRefreshRequest extends ImmutableObject {
TargetType type,
String name,
String tld,
DateTime requestTime,
DateTime lastProcessTime) {
Instant requestTime,
Instant lastProcessTime) {
checkNotNull(type, "Target type cannot be null");
checkNotNull(name, "Domain/host name cannot be null");
checkNotNull(tld, "TLD cannot be null");
@@ -119,11 +119,11 @@ public class DnsRefreshRequest extends ImmutableObject {
this.lastProcessTime = lastProcessTime;
}
public DnsRefreshRequest(TargetType type, String name, String tld, DateTime requestTime) {
this(null, type, name, tld, requestTime, START_OF_TIME);
public DnsRefreshRequest(TargetType type, String name, String tld, Instant requestTime) {
this(null, type, name, tld, requestTime, START_INSTANT);
}
public DnsRefreshRequest updateProcessTime(DateTime processTime) {
public DnsRefreshRequest updateProcessTime(Instant processTime) {
checkArgument(
processTime.isAfter(getRequestTime()),
"Process time %s must be later than request time %s",
@@ -22,6 +22,7 @@ import static google.registry.util.DateTimeUtils.isAtOrAfter;
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
import static google.registry.util.DateTimeUtils.minusYears;
import static google.registry.util.DateTimeUtils.plusYears;
import static java.time.ZoneOffset.UTC;
import com.google.common.base.Splitter;
import com.google.common.collect.ContiguousSet;
@@ -32,7 +33,6 @@ import jakarta.persistence.Embeddable;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.List;
@@ -63,7 +63,7 @@ public class TimeOfYear extends ImmutableObject implements UnsafeSerializable {
* February 28. It is impossible to construct a {@link TimeOfYear} for February 29th.
*/
public static TimeOfYear fromInstant(Instant instant) {
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC);
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant, UTC);
int month = zdt.getMonthValue();
int day = zdt.getDayOfMonth();
if (month == 2 && day == 29) {
@@ -88,8 +88,8 @@ public class TimeOfYear extends ImmutableObject implements UnsafeSerializable {
Range<Instant> normalizedRange = range.intersection(Range.closed(START_INSTANT, END_INSTANT));
Range<Integer> yearRange =
Range.closed(
ZonedDateTime.ofInstant(normalizedRange.lowerEndpoint(), ZoneOffset.UTC).getYear(),
ZonedDateTime.ofInstant(normalizedRange.upperEndpoint(), ZoneOffset.UTC).getYear());
ZonedDateTime.ofInstant(normalizedRange.lowerEndpoint(), UTC).getYear(),
ZonedDateTime.ofInstant(normalizedRange.upperEndpoint(), UTC).getYear());
return ContiguousSet.create(yearRange, integers()).stream()
.map(this::toInstantWithYear)
.filter(normalizedRange)
@@ -107,20 +107,18 @@ public class TimeOfYear extends ImmutableObject implements UnsafeSerializable {
int millis = Integer.parseInt(monthDayMillis.get(2));
return LocalDate.of(year, month, day)
.atTime(LocalTime.ofNanoOfDay(millis * 1000000L))
.toInstant(ZoneOffset.UTC);
.toInstant(UTC);
}
/** Get the first {@link Instant} with this month/day/millis that is at or after the start. */
public Instant getNextInstanceAtOrAfter(Instant start) {
Instant withSameYear =
toInstantWithYear(ZonedDateTime.ofInstant(start, ZoneOffset.UTC).getYear());
Instant withSameYear = toInstantWithYear(ZonedDateTime.ofInstant(start, UTC).getYear());
return isAtOrAfter(withSameYear, start) ? withSameYear : plusYears(withSameYear, 1);
}
/** Get the first {@link Instant} with this month/day/millis that is at or before the end. */
public Instant getLastInstanceBeforeOrAt(Instant end) {
Instant withSameYear =
toInstantWithYear(ZonedDateTime.ofInstant(end, ZoneOffset.UTC).getYear());
Instant withSameYear = toInstantWithYear(ZonedDateTime.ofInstant(end, UTC).getYear());
return isBeforeOrAt(withSameYear, end) ? withSameYear : minusYears(withSameYear, 1);
}
@@ -14,9 +14,10 @@
package google.registry.model.poll;
import static java.time.ZoneOffset.UTC;
import com.google.common.base.Splitter;
import google.registry.persistence.VKey;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.List;
@@ -45,8 +46,7 @@ public final class PollMessageExternalKeyConverter {
public static String makePollMessageExternalId(PollMessage pollMessage) {
return String.format(
"%d-%d",
pollMessage.getId(),
ZonedDateTime.ofInstant(pollMessage.getEventTime(), ZoneOffset.UTC).getYear());
pollMessage.getId(), ZonedDateTime.ofInstant(pollMessage.getEventTime(), UTC).getYear());
}
/**
@@ -16,38 +16,39 @@ package google.registry.model.rde;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.time.ZoneOffset.UTC;
import static java.time.temporal.ChronoUnit.DAYS;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
/** Utility class for generating RDE filenames and string IDs. */
public final class RdeNamingUtils {
private static final DateTimeFormatter DATE_FORMATTER = ISODateTimeFormat.date();
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE;
/**
* Returns extensionless RDE filename in format {@code <gTLD>_<YYYY-MM-DD>_<type>_S<#>_R<rev>}.
*
* <p>This naming scheme is defined in the {@code gTLD_Applicant_Guidebook_full.pdf}.
*/
public static
String makeRydeFilename(String tld, DateTime date, RdeMode mode, int series, int revision) {
public static String makeRydeFilename(
String tld, Instant date, RdeMode mode, int series, int revision) {
checkArgument(series >= 1, "series >= 1");
checkArgument(revision >= 0, "revision >= 0");
return String.format("%s_S%d_R%d", makePartialName(tld, date, mode), series, revision);
}
/** Returns same thing as {@link #makeRydeFilename} except without the series and revision. */
public static String makePartialName(String tld, DateTime date, RdeMode mode) {
public static String makePartialName(String tld, Instant date, RdeMode mode) {
return String.format("%s_%s_%s",
checkNotNull(tld), formatDate(date), mode.getFilenameComponent());
}
/** Returns date as a hyphened string with ISO-8601 ordering, e.g. {@code 1984-12-18}. */
private static String formatDate(DateTime date) {
checkArgument(date.withTimeAtStartOfDay().equals(date), "Not midnight: %s", date);
return DATE_FORMATTER.print(date);
private static String formatDate(Instant date) {
checkArgument(date.truncatedTo(DAYS).equals(date), "Not midnight: %s", date);
return DATE_FORMATTER.withZone(UTC).format(date);
}
private RdeNamingUtils() {}
@@ -17,11 +17,11 @@ package google.registry.model.rde;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.model.rde.RdeNamingUtils.makePartialName;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.toJodaLocalDate;
import com.google.common.base.VerifyException;
import google.registry.model.ImmutableObject;
import google.registry.model.UpdateAutoTimestampEntity;
import google.registry.model.rde.RdeRevision.RdeRevisionId;
import google.registry.persistence.VKey;
import google.registry.persistence.converter.LocalDateConverter;
import jakarta.persistence.Column;
@@ -32,8 +32,8 @@ import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import java.io.Serializable;
import java.time.Instant;
import java.util.Optional;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
/**
@@ -44,7 +44,7 @@ import org.joda.time.LocalDate;
* flag is included in the generated XML.
*/
@Entity
@IdClass(RdeRevisionId.class)
@IdClass(RdeRevision.RdeRevisionId.class)
public final class RdeRevision extends UpdateAutoTimestampEntity {
@Id String tld;
@@ -82,15 +82,15 @@ public final class RdeRevision extends UpdateAutoTimestampEntity {
*
* @return {@code 0} for first deposit generation and {@code >0} for resends
*/
public static int getNextRevision(String tld, DateTime date, RdeMode mode) {
RdeRevisionId sqlKey = RdeRevisionId.create(tld, date.toLocalDate(), mode);
public static int getNextRevision(String tld, Instant date, RdeMode mode) {
RdeRevisionId revisionId = RdeRevisionId.create(tld, toJodaLocalDate(date), mode);
Optional<RdeRevision> revisionOptional =
tm().transact(() -> tm().loadByKeyIfPresent(VKey.create(RdeRevision.class, sqlKey)));
tm().transact(() -> tm().loadByKeyIfPresent(VKey.create(RdeRevision.class, revisionId)));
return revisionOptional.map(rdeRevision -> rdeRevision.revision + 1).orElse(0);
}
/** Returns the latest revision of the report already generated for the given triplet. */
public static Optional<Integer> getCurrentRevision(String tld, DateTime date, RdeMode mode) {
public static Optional<Integer> getCurrentRevision(String tld, Instant date, RdeMode mode) {
int nextRevision = getNextRevision(tld, date, mode);
if (nextRevision == 0) {
return Optional.empty();
@@ -107,12 +107,12 @@ public final class RdeRevision extends UpdateAutoTimestampEntity {
* @throws IllegalStateException if not in a transaction
* @throws VerifyException if the state doesn't meet the above criteria
*/
public static void saveRevision(String tld, DateTime date, RdeMode mode, int revision) {
public static void saveRevision(String tld, Instant date, RdeMode mode, int revision) {
checkArgument(revision >= 0, "Negative revision: %s", revision);
tm().assertInTransaction();
RdeRevisionId sqlKey = RdeRevisionId.create(tld, date.toLocalDate(), mode);
RdeRevisionId revisionId = RdeRevisionId.create(tld, toJodaLocalDate(date), mode);
Optional<RdeRevision> revisionOptional =
tm().loadByKeyIfPresent(VKey.create(RdeRevision.class, sqlKey));
tm().loadByKeyIfPresent(VKey.create(RdeRevision.class, revisionId));
if (revision == 0) {
revisionOptional.ifPresent(
rdeRevision -> {
@@ -133,8 +133,7 @@ public final class RdeRevision extends UpdateAutoTimestampEntity {
revision - 1,
revisionOptional.get());
}
RdeRevision object = create(tld, date.toLocalDate(), mode, revision);
tm().put(object);
tm().put(RdeRevision.create(tld, toJodaLocalDate(date), mode, revision));
}
/** Class to represent the composite primary key of {@link RdeRevision} entity. */
@@ -34,11 +34,11 @@ import jakarta.persistence.IdClass;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import java.util.concurrent.Callable;
import javax.annotation.Nullable;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* A lock on some shared resource.
@@ -79,11 +79,11 @@ public class Lock extends ImmutableObject implements Serializable {
/** When the lock can be considered implicitly released. */
@Column(nullable = false)
DateTime expirationTime;
Instant expirationTime;
/** When was the lock acquired. Used for logging. */
@Column(nullable = false)
DateTime acquiredTime;
Instant acquiredTime;
/** The resource name used to create the lock. */
@Column(nullable = false)
@@ -95,7 +95,7 @@ public class Lock extends ImmutableObject implements Serializable {
@Id
String scope;
public DateTime getExpirationTime() {
public Instant getExpirationTime() {
return expirationTime;
}
@@ -109,10 +109,7 @@ public class Lock extends ImmutableObject implements Serializable {
* namespace).
*/
private static Lock create(
String resourceName,
String scope,
DateTime acquiredTime,
Duration leaseLength) {
String resourceName, String scope, Instant acquiredTime, Duration leaseLength) {
checkArgument(!Strings.isNullOrEmpty(resourceName), "resourceName cannot be null or empty");
Lock instance = new Lock();
// Add the scope to the Lock's id so that it is unique for locks acquiring the same resource
@@ -130,7 +127,7 @@ public class Lock extends ImmutableObject implements Serializable {
}
record AcquireResult(
DateTime transactionTime,
Instant transactionTime,
@Nullable Lock existingLock,
@Nullable Lock newLock,
LockState lockState) {}
@@ -138,7 +135,7 @@ public class Lock extends ImmutableObject implements Serializable {
private static void logAcquireResult(AcquireResult acquireResult) {
try {
Lock lock = acquireResult.existingLock();
DateTime now = acquireResult.transactionTime();
Instant now = acquireResult.transactionTime();
switch (acquireResult.lockState()) {
case IN_USE ->
logger.atInfo().log(
@@ -170,7 +167,7 @@ public class Lock extends ImmutableObject implements Serializable {
String scope = tld != null ? tld : GLOBAL;
Callable<AcquireResult> lockAcquirer =
() -> {
DateTime now = tm().getTransactionTime();
Instant now = tm().getTxTime();
// Checking if an unexpired lock still exists - if so, the lock can't be acquired.
Lock lock =
@@ -233,7 +230,7 @@ public class Lock extends ImmutableObject implements Serializable {
tm().delete(key);
lockMetrics.recordRelease(
resourceName, scope, new Duration(acquiredTime, tm().getTransactionTime()));
resourceName, scope, Duration.between(acquiredTime, tm().getTxTime()));
} else {
logger.atSevere().log(
"The lock we acquired was transferred to someone else before we"
@@ -22,8 +22,8 @@ import com.google.monitoring.metrics.IncrementableMetric;
import com.google.monitoring.metrics.LabelDescriptor;
import com.google.monitoring.metrics.MetricRegistryImpl;
import google.registry.model.server.Lock.LockState;
import java.time.Duration;
import javax.annotation.Nullable;
import org.joda.time.Duration;
/** Metrics for lock contention. */
class LockMetrics {
@@ -67,6 +67,6 @@ class LockMetrics {
}
void recordRelease(String resourceName, @Nullable String tld, Duration duration) {
lockLifetimeMetric.record(duration.getMillis(), String.valueOf(tld), resourceName);
lockLifetimeMetric.record(duration.toMillis(), String.valueOf(tld), resourceName);
}
}
@@ -40,12 +40,12 @@ import google.registry.request.lock.LockHandler;
import google.registry.util.Clock;
import jakarta.inject.Inject;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
import org.joda.time.Duration;
/** Metrics Exporter for MoSAPI. */
public class MosApiMetrics {
@@ -67,7 +67,7 @@ public class MosApiMetrics {
// Lock Constants
private static final String LOCK_NAME = "MosApiMetricCreation";
private static final Duration LOCK_LEASE_TIME = Duration.standardHours(1);
private static final Duration LOCK_LEASE_TIME = Duration.ofHours(1);
// Metric Names
private static final String METRIC_TLD_STATUS = "tld_status";
private static final String METRIC_SERVICE_STATUS = "service_status";
@@ -13,7 +13,6 @@
// limitations under the License.
package google.registry.persistence.converter;
import static org.joda.time.DateTimeZone.UTC;
import jakarta.persistence.AttributeConverter;
@@ -14,7 +14,9 @@
package google.registry.persistence.converter;
import google.registry.util.DateTimeUtils;
import static google.registry.util.DateTimeUtils.toLocalDate;
import static google.registry.util.DateTimeUtils.toSqlDate;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.sql.Date;
@@ -26,11 +28,11 @@ public class LocalDateConverter implements AttributeConverter<LocalDate, Date> {
@Override
public Date convertToDatabaseColumn(LocalDate attribute) {
return attribute == null ? null : DateTimeUtils.toSqlDate(attribute);
return attribute == null ? null : toSqlDate(attribute);
}
@Override
public LocalDate convertToEntityAttribute(Date dbData) {
return dbData == null ? null : DateTimeUtils.toLocalDate(dbData);
return dbData == null ? null : toLocalDate(dbData);
}
}
@@ -14,6 +14,7 @@
package google.registry.rde;
import static google.registry.model.common.Cursor.CursorType.BRDA;
import static google.registry.model.common.Cursor.getCursorTimeOrStartOfTime;
import static google.registry.model.rde.RdeMode.THIN;
@@ -40,11 +41,11 @@ import jakarta.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.Instant;
import java.util.Optional;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.joda.time.DateTime;
/**
* Action that re-encrypts a BRDA escrow deposit and puts it into the upload bucket.
@@ -77,7 +78,11 @@ public final class BrdaCopyAction implements Runnable {
@Inject @Config("brdaBucket") String brdaBucket;
@Inject @Config("rdeBucket") String stagingBucket;
@Inject @Parameter(RequestParameters.PARAM_TLD) String tld;
@Inject @Parameter(RdeModule.PARAM_WATERMARK) DateTime watermark;
@Inject
@Parameter(RdeModule.PARAM_WATERMARK)
Instant watermark;
@Inject @Parameter(RdeModule.PARAM_PREFIX) Optional<String> prefix;
@Inject @Key("brdaReceiverKey") PGPPublicKey receiverKey;
@Inject @Key("brdaSigningKey") PGPKeyPair signingKey;
@@ -98,7 +103,7 @@ public final class BrdaCopyAction implements Runnable {
// Not urgent since file writes on GCS are atomic.
Optional<Cursor> cursor =
tm().transact(() -> tm().loadByKeyIfPresent(Cursor.createScopedVKey(BRDA, Tld.get(tld))));
DateTime brdaCursorTime = getCursorTimeOrStartOfTime(cursor);
Instant brdaCursorTime = getCursorTimeOrStartOfTime(cursor);
if (isBeforeOrAt(brdaCursorTime, watermark)) {
throw new NoContentException(
String.format(
@@ -15,6 +15,7 @@
package google.registry.rde;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static java.time.temporal.ChronoUnit.DAYS;
import com.google.common.flogger.FluentLogger;
import google.registry.model.common.Cursor;
@@ -25,9 +26,9 @@ import google.registry.request.HttpException.ServiceUnavailableException;
import google.registry.request.lock.LockHandler;
import google.registry.util.Clock;
import jakarta.inject.Inject;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.Callable;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Runner applying guaranteed reliability to an {@link EscrowTask}.
@@ -61,7 +62,7 @@ class EscrowTaskRunner {
*
* @param watermark the logical time for a point-in-time view of the database.
*/
void runWithLock(DateTime watermark) throws Exception;
void runWithLock(Instant watermark) throws Exception;
}
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -88,8 +89,8 @@ class EscrowTaskRunner {
Callable<Void> lockRunner =
() -> {
logger.atInfo().log("Performing escrow for TLD '%s'.", tld.getTld());
DateTime startOfToday = clock.nowUtc().withTimeAtStartOfDay();
DateTime nextRequiredRun =
Instant startOfToday = clock.now().truncatedTo(DAYS);
Instant nextRequiredRun =
tm().transact(() -> tm().loadByKeyIfPresent(Cursor.createScopedVKey(cursorType, tld)))
.map(Cursor::getCursorTime)
.orElse(startOfToday);
@@ -98,7 +99,7 @@ class EscrowTaskRunner {
}
logger.atInfo().log("Current cursor is: %s.", nextRequiredRun);
task.runWithLock(nextRequiredRun);
DateTime nextRun = nextRequiredRun.plus(interval);
Instant nextRun = nextRequiredRun.plus(interval);
logger.atInfo().log("Rolling cursor forward to %s.", nextRun);
tm().transact(() -> tm().put(Cursor.createScoped(cursorType, nextRun, tld)));
return null;
@@ -36,10 +36,10 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.Instant;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.joda.time.DateTime;
/**
* Utility class for reading and writing data in the ghostryde container format.
@@ -116,7 +116,8 @@ public final class Ghostryde {
* set them to a constant value.
*/
static final String INNER_FILENAME = "file.xml";
static final DateTime INNER_MODIFICATION_TIME = DateTime.parse("2000-01-01TZ");
static final Instant INNER_MODIFICATION_TIME = Instant.parse("2000-01-01T00:00:00Z");
/** Creates a ghostryde file from an in-memory byte array. */
public static byte[] encode(byte[] data, PGPPublicKey key) throws IOException {
@@ -29,7 +29,7 @@ import google.registry.xjc.rdehost.XjcRdeHost;
import google.registry.xjc.rdehost.XjcRdeHostElement;
import java.net.Inet6Address;
import java.net.InetAddress;
import org.joda.time.DateTime;
import java.time.Instant;
/** Utility class that turns a {@link Host} resource into {@link XjcRdeHostElement}. */
final class HostToXjcConverter {
@@ -52,7 +52,7 @@ final class HostToXjcConverter {
convertHostCommon(
model,
superordinateDomain.getCurrentSponsorRegistrarId(),
toDateTime(model.computeLastTransferTime(superordinateDomain)));
model.computeLastTransferTime(superordinateDomain));
if (superordinateDomain.getStatusValues().contains(StatusValue.PENDING_TRANSFER)) {
bean.getStatuses().add(convertStatusValue(StatusValue.PENDING_TRANSFER));
}
@@ -62,13 +62,11 @@ final class HostToXjcConverter {
/** Converts {@link Host} to {@link XjcRdeHost}. */
static XjcRdeHost convertExternalHost(Host model) {
return convertHostCommon(
model,
model.getPersistedCurrentSponsorRegistrarId(),
toDateTime(model.getLastTransferTime()));
model, model.getPersistedCurrentSponsorRegistrarId(), model.getLastTransferTime());
}
private static XjcRdeHost convertHostCommon(
Host model, String registrarId, DateTime lastTransferTime) {
Host model, String registrarId, Instant lastTransferTime) {
XjcRdeHost bean = new XjcRdeHost();
bean.setName(model.getHostName());
bean.setRoid(model.getRepoId());
@@ -78,7 +76,7 @@ final class HostToXjcConverter {
bean.setUpRr(RdeAdapter.convertRr(model.getLastEppUpdateRegistrarId(), null));
bean.setCrRr(RdeAdapter.convertRr(model.getCreationRegistrarId(), null));
bean.setClID(registrarId);
bean.setTrDate(lastTransferTime);
bean.setTrDate(toDateTime(lastTransferTime));
for (StatusValue status : model.getStatusValues()) {
// TODO(b/34844887): Remove when PENDING_TRANSFER is not persisted on host resources.
if (status.equals(StatusValue.PENDING_TRANSFER)) {
@@ -25,7 +25,7 @@ import google.registry.config.RegistryConfig.Config;
import jakarta.inject.Inject;
import java.io.Closeable;
import java.net.URI;
import org.joda.time.Duration;
import java.time.Duration;
/**
* SFTP connection {@link Session} delegate that implements {@link Closeable}.
@@ -67,9 +67,9 @@ final class JSchSshSession implements Closeable {
if (url.getPass().isPresent()) {
session.setPassword(url.getPass().get());
}
session.setTimeout((int) sshTimeout.getMillis());
session.connect((int) sshTimeout.getMillis());
return new JSchSshSession(session, url, (int) sshTimeout.getMillis());
session.setTimeout((int) sshTimeout.toMillis());
session.connect((int) sshTimeout.toMillis());
return new JSchSshSession(session, url, (int) sshTimeout.toMillis());
}
}
@@ -20,8 +20,8 @@ import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpProgressMonitor;
import google.registry.util.Clock;
import jakarta.inject.Inject;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import java.time.Duration;
import java.time.Instant;
/** A progress monitor for SFTP operations that writes status to logs periodically. */
public class LoggingSftpProgressMonitor implements SftpProgressMonitor {
@@ -32,7 +32,7 @@ public class LoggingSftpProgressMonitor implements SftpProgressMonitor {
private final Clock clock;
private long bytesOfLastLog = 0;
private int callsSinceLastLog = 0;
private DateTime timeOfLastLog;
private Instant timeOfLastLog;
@Inject
LoggingSftpProgressMonitor(Clock clock) {
@@ -49,7 +49,7 @@ public class LoggingSftpProgressMonitor implements SftpProgressMonitor {
@Override
public void init(int op, String src, String dest, long max) {
timeOfLastLog = clock.nowUtc();
timeOfLastLog = clock.now();
logger.atInfo().log(
"Initiating SFTP transfer from '%s' to '%s' using mode %s, max size %,d bytes.",
src, dest, OPERATION_MODES.getOrDefault(op, "(unknown)"), max);
@@ -60,11 +60,11 @@ public class LoggingSftpProgressMonitor implements SftpProgressMonitor {
callsSinceLastLog++;
long bytesSinceLastLog = count - bytesOfLastLog;
if (bytesSinceLastLog > LOGGING_CHUNK_SIZE_BYTES) {
DateTime now = clock.nowUtc();
Instant now = clock.now();
logger.atInfo().log(
"%,d more bytes transmitted in %,d ms; %,d bytes in total. [%,d calls to count()]",
bytesSinceLastLog,
new Duration(timeOfLastLog, now).getMillis(),
Duration.between(timeOfLastLog, now).toMillis(),
count,
callsSinceLastLog);
bytesOfLastLog = count;
@@ -22,6 +22,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serial;
import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import javax.annotation.Nullable;
import org.apache.beam.sdk.coders.AtomicCoder;
@@ -29,8 +31,6 @@ import org.apache.beam.sdk.coders.BooleanCoder;
import org.apache.beam.sdk.coders.NullableCoder;
import org.apache.beam.sdk.coders.StringUtf8Coder;
import org.apache.beam.sdk.coders.VarIntCoder;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Container representing a single RDE or BRDA XML escrow deposit that needs to be created.
@@ -68,8 +68,8 @@ public record PendingDeposit(
@Nullable Integer revision)
implements Serializable {
public DateTime watermark() {
return DateTime.parse(watermarkStr);
public Instant watermark() {
return Instant.parse(watermarkStr);
}
public Duration interval() {
@@ -79,14 +79,14 @@ public record PendingDeposit(
@Serial private static final long serialVersionUID = 3141095605225904433L;
public static PendingDeposit create(
String tld, DateTime watermark, RdeMode mode, CursorType cursor, Duration interval) {
String tld, Instant watermark, RdeMode mode, CursorType cursor, Duration interval) {
return new PendingDeposit(
false, tld, watermark.toString(), mode, cursor, interval.toString(), null, null);
}
public static PendingDeposit createInManualOperation(
String tld,
DateTime watermark,
Instant watermark,
RdeMode mode,
String directoryWithTrailingSlash,
@Nullable Integer revision) {
@@ -17,6 +17,9 @@ package google.registry.rde;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
import static google.registry.util.DateTimeUtils.plusDays;
import static java.time.ZoneOffset.UTC;
import static java.time.temporal.ChronoUnit.DAYS;
import com.google.common.collect.ImmutableSetMultimap;
import google.registry.config.RegistryConfig.Config;
@@ -28,9 +31,9 @@ import google.registry.model.tld.Tld.TldType;
import google.registry.model.tld.Tlds;
import google.registry.util.Clock;
import jakarta.inject.Inject;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Utility class that determines which RDE or BRDA deposits need to be created.
@@ -64,25 +67,22 @@ public final class PendingDepositChecker {
return new ImmutableSetMultimap.Builder<String, PendingDeposit>()
.putAll(
getTldsAndWatermarksPendingDeposit(
RdeMode.FULL,
CursorType.RDE_STAGING,
rdeInterval,
clock.nowUtc().withTimeAtStartOfDay()))
RdeMode.FULL, CursorType.RDE_STAGING, rdeInterval, clock.now().truncatedTo(DAYS)))
.putAll(
getTldsAndWatermarksPendingDeposit(
RdeMode.THIN,
CursorType.BRDA,
brdaInterval,
advanceToDayOfWeek(clock.nowUtc().withTimeAtStartOfDay(), brdaDayOfWeek)))
advanceToDayOfWeek(clock.now().truncatedTo(DAYS), brdaDayOfWeek)))
.build();
}
private ImmutableSetMultimap<String, PendingDeposit> getTldsAndWatermarksPendingDeposit(
RdeMode mode, CursorType cursorType, Duration interval, DateTime startingPoint) {
checkArgument(interval.isLongerThan(Duration.ZERO));
RdeMode mode, CursorType cursorType, Duration interval, Instant startingPoint) {
checkArgument(interval.compareTo(Duration.ZERO) > 0);
ImmutableSetMultimap.Builder<String, PendingDeposit> builder =
new ImmutableSetMultimap.Builder<>();
DateTime now = clock.nowUtc();
Instant now = clock.now();
for (String tldStr : Tlds.getTldsOfType(TldType.REAL)) {
Tld tld = Tld.get(tldStr);
if (!tld.getEscrowEnabled()) {
@@ -91,9 +91,9 @@ public final class PendingDepositChecker {
// Avoid creating a transaction unless absolutely necessary.
Optional<Cursor> maybeCursor =
tm().transact(() -> tm().loadByKeyIfPresent(Cursor.createScopedVKey(cursorType, tld)));
DateTime cursorValue = maybeCursor.map(Cursor::getCursorTime).orElse(startingPoint);
Instant cursorValue = maybeCursor.map(Cursor::getCursorTime).orElse(startingPoint);
if (isBeforeOrAt(cursorValue, now)) {
DateTime watermark =
Instant watermark =
maybeCursor
.map(Cursor::getCursorTime)
.orElse(transactionallyInitializeCursor(tld, cursorType, startingPoint));
@@ -105,8 +105,8 @@ public final class PendingDepositChecker {
return builder.build();
}
private DateTime transactionallyInitializeCursor(
final Tld tld, final CursorType cursorType, final DateTime initialValue) {
private Instant transactionallyInitializeCursor(
Tld tld, CursorType cursorType, Instant initialValue) {
return tm().transact(
() -> {
Optional<Cursor> maybeCursor =
@@ -119,9 +119,9 @@ public final class PendingDepositChecker {
});
}
private static DateTime advanceToDayOfWeek(DateTime date, int dayOfWeek) {
while (date.getDayOfWeek() != dayOfWeek) {
date = date.plusDays(1);
private static Instant advanceToDayOfWeek(Instant date, int dayOfWeek) {
while (date.atZone(UTC).getDayOfWeek().getValue() != dayOfWeek) {
date = plusDays(date, 1);
}
return date;
}
@@ -14,6 +14,8 @@
package google.registry.rde;
import static google.registry.util.DateTimeUtils.toDateTime;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import google.registry.model.rde.RdeMode;
@@ -23,11 +25,11 @@ import google.registry.xjc.rdeheader.XjcRdeHeaderCount;
import google.registry.xjc.rdeheader.XjcRdeHeaderElement;
import google.registry.xjc.rdereport.XjcRdeReport;
import jakarta.inject.Inject;
import java.time.Instant;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.concurrent.NotThreadSafe;
import org.joda.time.DateTime;
/** Utility class for generating a single {@link XjcRdeHeader} while marshalling a deposit. */
@NotThreadSafe
@@ -61,13 +63,12 @@ public final class RdeCounter {
}
/** Returns an ICANN notification report as a JAXB object. */
public XjcRdeReport
makeReport(String id, DateTime watermark, XjcRdeHeader header, int revision) {
public XjcRdeReport makeReport(String id, Instant watermark, XjcRdeHeader header, int revision) {
XjcRdeReport report = new XjcRdeReport();
report.setId(id);
report.setKind(XjcRdeDepositTypeType.FULL);
report.setCrDate(watermark);
report.setWatermark(watermark);
report.setCrDate(toDateTime(watermark));
report.setWatermark(toDateTime(watermark));
report.setVersion(ICANN_REPORT_SPEC_VERSION);
report.setRydeSpecEscrow(URI_ESCROW);
report.setRydeSpecMapping(URI_MAPPING);
@@ -15,6 +15,7 @@
package google.registry.rde;
import static com.google.common.base.Verify.verify;
import static google.registry.util.DateTimeUtils.toDateTime;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.flogger.FluentLogger;
@@ -41,9 +42,9 @@ import jakarta.xml.bind.MarshalException;
import java.io.ByteArrayOutputStream;
import java.io.Serial;
import java.io.Serializable;
import java.time.Instant;
import java.util.Collection;
import javax.annotation.concurrent.NotThreadSafe;
import org.joda.time.DateTime;
/** XML document <i>fragment</i> marshaller for RDE. */
@NotThreadSafe
@@ -61,7 +62,7 @@ public final class RdeMarshaller implements Serializable {
/** Returns top-portion of XML document. */
public String makeHeader(
String depositId, DateTime watermark, Collection<String> uris, int revision) {
String depositId, Instant watermark, Collection<String> uris, int revision) {
// We can't make JAXB marshal half an element. So we're going to use a kludge where we provide
// it with the minimum data necessary to marshal a deposit, and then cut it up by manually.
XjcRdeMenuType menu = new XjcRdeMenuType();
@@ -74,7 +75,7 @@ public final class RdeMarshaller implements Serializable {
contents.getContents().add(new XjcRdePolicyElement(policy));
XjcRdeDeposit deposit = new XjcRdeDeposit();
deposit.setId(depositId);
deposit.setWatermark(watermark);
deposit.setWatermark(toDateTime(watermark));
deposit.setType(XjcRdeDepositTypeType.FULL);
if (revision > 0) {
deposit.setResend(revision);
@@ -17,8 +17,8 @@ package google.registry.rde;
import static google.registry.request.RequestParameters.extractBooleanParameter;
import static google.registry.request.RequestParameters.extractOptionalIntParameter;
import static google.registry.request.RequestParameters.extractOptionalParameter;
import static google.registry.request.RequestParameters.extractRequiredDatetimeParameter;
import static google.registry.request.RequestParameters.extractSetOfDatetimeParameters;
import static google.registry.request.RequestParameters.extractRequiredInstantParameter;
import static google.registry.request.RequestParameters.extractSetOfInstantParameters;
import static google.registry.request.RequestParameters.extractSetOfParameters;
import com.google.common.collect.ImmutableSet;
@@ -28,8 +28,8 @@ import dagger.Module;
import dagger.Provides;
import google.registry.request.Parameter;
import jakarta.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.util.Optional;
import org.joda.time.DateTime;
/** Dagger module for RDE package. */
@Module
@@ -49,14 +49,14 @@ public abstract class RdeModule {
@Provides
@Parameter(PARAM_WATERMARK)
static DateTime provideWatermark(HttpServletRequest req) {
return extractRequiredDatetimeParameter(req, PARAM_WATERMARK);
static Instant provideWatermark(HttpServletRequest req) {
return extractRequiredInstantParameter(req, PARAM_WATERMARK);
}
@Provides
@Parameter(PARAM_WATERMARKS)
static ImmutableSet<DateTime> provideWatermarks(HttpServletRequest req) {
return extractSetOfDatetimeParameters(req, PARAM_WATERMARKS);
static ImmutableSet<Instant> provideWatermarks(HttpServletRequest req) {
return extractSetOfInstantParameters(req, PARAM_WATERMARKS);
}
@Provides
@@ -14,6 +14,7 @@
package google.registry.rde;
import static com.google.common.base.Verify.verify;
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
import static google.registry.model.common.Cursor.getCursorTimeOrStartOfTime;
@@ -44,10 +45,10 @@ import google.registry.request.auth.Auth;
import jakarta.inject.Inject;
import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Action that uploads a small XML RDE report to ICANN after {@link RdeUploadAction} has finished.
@@ -81,13 +82,13 @@ public final class RdeReportAction implements Runnable, EscrowTask {
}
@Override
public void runWithLock(DateTime watermark) throws Exception {
public void runWithLock(Instant watermark) throws Exception {
Optional<Cursor> cursor =
tm().transact(
() ->
tm().loadByKeyIfPresent(
Cursor.createScopedVKey(CursorType.RDE_UPLOAD, Tld.get(tld))));
DateTime cursorTime = getCursorTimeOrStartOfTime(cursor);
Instant cursorTime = getCursorTimeOrStartOfTime(cursor);
if (isBeforeOrAt(cursorTime, watermark)) {
throw new NoContentException(
String.format(
@@ -18,11 +18,13 @@ import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMulti
import static google.registry.beam.BeamUtils.createJobName;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.POST;
import static google.registry.util.DateTimeUtils.LOWERCASE_TIMESTAMP_FORMATTER;
import static google.registry.xml.ValidationMode.LENIENT;
import static google.registry.xml.ValidationMode.STRICT;
import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static jakarta.servlet.http.HttpServletResponse.SC_NO_CONTENT;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.util.function.Function.identity;
import com.google.api.services.dataflow.Dataflow;
@@ -59,9 +61,9 @@ import google.registry.util.RegistryEnvironment;
import google.registry.xml.ValidationMode;
import jakarta.inject.Inject;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Action that kicks off a Dataflow job to stage escrow deposit XML files on GCS for RDE/BRDA for
@@ -237,7 +239,11 @@ public final class RdeStagingAction implements Runnable {
@Inject @Parameter(RdeModule.PARAM_DIRECTORY) Optional<String> directory;
@Inject @Parameter(RdeModule.PARAM_MODE) ImmutableSet<String> modeStrings;
@Inject @Parameter(RequestParameters.PARAM_TLDS) ImmutableSet<String> tlds;
@Inject @Parameter(RdeModule.PARAM_WATERMARKS) ImmutableSet<DateTime> watermarks;
@Inject
@Parameter(RdeModule.PARAM_WATERMARKS)
ImmutableSet<Instant> watermarks;
@Inject @Parameter(RdeModule.PARAM_REVISION) Optional<Integer> revision;
@Inject @Parameter(RdeModule.PARAM_LENIENT) boolean lenient;
@Inject @Key("rdeStagingEncryptionKey") byte[] stagingKeyBytes;
@@ -271,7 +277,7 @@ public final class RdeStagingAction implements Runnable {
.setJobName(
createJobName(
String.format(
"rde-%s", watermark.toString("yyyy-MM-dd't'HH-mm-ss'z'")),
"rde-%s", LOWERCASE_TIMESTAMP_FORMATTER.format(watermark)),
clock))
.setContainerSpecGcsPath(
String.format("%s/%s_metadata.json", stagingBucketUrl, PIPELINE_NAME))
@@ -340,7 +346,7 @@ public final class RdeStagingAction implements Runnable {
Multimaps.filterValues(
pendingDepositChecker.getTldsAndWatermarksPendingDepositForRdeAndBrda(),
pending -> {
if (clock.nowUtc().isBefore(pending.watermark().plus(transactionCooldown))) {
if (clock.now().isBefore(pending.watermark().plus(transactionCooldown))) {
logger.atInfo().log(
"Ignoring within %s cooldown: %s", transactionCooldown, pending);
return false;
@@ -384,8 +390,8 @@ public final class RdeStagingAction implements Runnable {
// In theory, BRDA deposits should be on a specific day of the week, but in manual mode, let the
// user create deposits on other days. But dates should definitely be at the start of the day;
// otherwise, confusion is likely.
for (DateTime watermark : watermarks) {
if (!watermark.equals(watermark.withTimeAtStartOfDay())) {
for (Instant watermark : watermarks) {
if (!watermark.equals(watermark.truncatedTo(DAYS))) {
throw new BadRequestException("Watermarks must be at the start of a day.");
}
}
@@ -398,7 +404,7 @@ public final class RdeStagingAction implements Runnable {
new ImmutableSetMultimap.Builder<>();
for (String tld : tlds) {
for (DateTime watermark : watermarks) {
for (Instant watermark : watermarks) {
for (RdeMode mode : modes) {
pendingsBuilder.put(
tld,
@@ -14,6 +14,7 @@
package google.registry.rde;
import static com.google.common.base.Verify.verify;
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
import static com.jcraft.jsch.ChannelSftp.OVERWRITE;
@@ -25,7 +26,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
import static google.registry.rde.RdeModule.RDE_REPORT_QUEUE;
import static google.registry.rde.RdeUtils.findMostRecentPrefixForWatermark;
import static google.registry.request.Action.Method.POST;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static google.registry.util.DateTimeUtils.START_INSTANT;
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
import static java.util.Arrays.asList;
@@ -65,12 +66,12 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Action that securely uploads an RDE XML file from Cloud Storage to a trusted third party (such as
@@ -133,7 +134,7 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
}
@Override
public void runWithLock(final DateTime watermark) throws Exception {
public void runWithLock(Instant watermark) throws Exception {
// If a prefix is not provided,try to determine the prefix. This should only happen when the RDE
// upload cron job runs to catch up any un-retried (i. e. expected) RDE failures.
String actualPrefix =
@@ -142,7 +143,7 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
Optional<Cursor> cursor =
tm().transact(
() -> tm().loadByKeyIfPresent(Cursor.createScopedVKey(RDE_STAGING, Tld.get(tld))));
DateTime stagingCursorTime = getCursorTimeOrStartOfTime(cursor);
Instant stagingCursorTime = getCursorTimeOrStartOfTime(cursor);
if (isBeforeOrAt(stagingCursorTime, watermark)) {
throw new NoContentException(
String.format(
@@ -150,23 +151,23 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
+ "last RDE staging completion was before %s",
tld, watermark, stagingCursorTime));
}
DateTime sftpCursorTime =
Instant sftpCursorTime =
tm().transact(
() ->
tm().loadByKeyIfPresent(Cursor.createScopedVKey(RDE_UPLOAD_SFTP, Tld.get(tld))))
.map(Cursor::getCursorTime)
.orElse(START_OF_TIME);
Duration timeSinceLastSftp = new Duration(sftpCursorTime, clock.nowUtc());
if (timeSinceLastSftp.isShorterThan(sftpCooldown)) {
.orElse(START_INSTANT);
Duration timeSinceLastSftp = Duration.between(sftpCursorTime, clock.now());
if (timeSinceLastSftp.compareTo(sftpCooldown) < 0) {
throw new NoContentException(
String.format(
"Waiting on %d minute SFTP cooldown for TLD %s to send %s upload; "
+ "last upload attempt was at %s (%d minutes ago)",
sftpCooldown.getStandardMinutes(),
sftpCooldown.toMinutes(),
tld,
watermark,
sftpCursorTime,
timeSinceLastSftp.getStandardMinutes()));
timeSinceLastSftp.toMinutes()));
}
int revision =
RdeRevision.getCurrentRevision(tld, watermark, FULL)
@@ -189,10 +190,7 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
logger.atInfo().log(
"Updating RDE cursor '%s' for TLD '%s' following successful upload.", RDE_UPLOAD_SFTP, tld);
tm().transact(
() ->
tm().put(
Cursor.createScoped(
RDE_UPLOAD_SFTP, tm().getTransactionTime(), Tld.get(tld))));
() -> tm().put(Cursor.createScoped(RDE_UPLOAD_SFTP, tm().getTxTime(), Tld.get(tld))));
response.setContentType(PLAIN_TEXT_UTF_8);
response.setPayload(String.format("OK %s %s\n", tld, watermark));
}
@@ -222,7 +220,7 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
*/
@VisibleForTesting
private void upload(
BlobId xmlFile, long xmlLength, DateTime watermark, String name, String nameWithoutPrefix)
BlobId xmlFile, long xmlLength, Instant watermark, String name, String nameWithoutPrefix)
throws Exception {
logger.atInfo().log("Uploading XML file '%s' to remote path '%s'.", xmlFile, uploadUrl);
try (InputStream gcsInput = gcsUtils.openInputStream(xmlFile);
@@ -14,6 +14,7 @@
package google.registry.rde;
import static google.registry.util.DateTimeUtils.LOWERCASE_TIMESTAMP_FORMATTER;
import static google.registry.util.HexDumper.dumpHex;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -28,10 +29,7 @@ import google.registry.xml.XmlException;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.joda.time.DateTime;
import org.joda.time.ReadableInstant;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import java.time.Instant;
/** Helper methods for RDE. */
public final class RdeUtils {
@@ -42,15 +40,11 @@ public final class RdeUtils {
/** Regular expression for extracting creation timestamp from a raw XML deposit. */
private static final Pattern WATERMARK_PATTERN = Pattern.compile("[<:]watermark>\\s*([^<\\s]+)");
/** Standard ISO date/time formatter without milliseconds. Used for watermarks. */
private static final DateTimeFormatter DATETIME_FORMATTER =
ISODateTimeFormat.dateTimeNoMillis().withZoneUTC();
/**
* Look at some bytes from {@code xmlInput} to ensure it appears to be a FULL XML deposit and
* then use a regular expression to extract the watermark timestamp which is returned.
* Look at some bytes from {@code xmlInput} to ensure it appears to be a FULL XML deposit and then
* use a regular expression to extract the watermark timestamp which is returned.
*/
public static DateTime peekWatermark(BufferedInputStream xmlInput)
public static Instant peekWatermark(BufferedInputStream xmlInput)
throws IOException, XmlException {
xmlInput.mark(PEEK_SIZE);
byte[] peek = new byte[PEEK_SIZE];
@@ -70,16 +64,16 @@ public final class RdeUtils {
if (!watermarkMatcher.find()) {
throw new XmlException("Could not find RDE watermark in XML");
}
return DATETIME_FORMATTER.parseDateTime(watermarkMatcher.group(1));
return Instant.parse(watermarkMatcher.group(1));
}
/** Find the most recent folder in the given GCS bucket for the given watermark. */
public static String findMostRecentPrefixForWatermark(
DateTime watermark, String bucket, String tld, GcsUtils gcsUtils) throws NoContentException {
Instant watermark, String bucket, String tld, GcsUtils gcsUtils) throws NoContentException {
// The prefix is always in the format of: rde-2022-02-21t00-00-00z-2022-02-21t00-07-33z, where
// the first datetime is the watermark and the second one is the time when the RDE beam job
// launched. We search for the latest folder that starts with "rde-[watermark]".
String partialPrefix = String.format("rde-%s", watermark.toString("yyyy-MM-dd't'HH-mm-ss'z'"));
String partialPrefix = String.format("rde-%s", LOWERCASE_TIMESTAMP_FORMATTER.format(watermark));
String latestFilenameSuffix = null;
try {
latestFilenameSuffix =
@@ -106,8 +100,8 @@ public final class RdeUtils {
* big-endian byte-array which is then converted to a base32 string without padding that's no
* longer than 13 chars because {@code 13 = Ceiling[Log[32, 2^64]]}. How lucky!
*/
public static String timestampToId(ReadableInstant timestamp) {
byte[] bytes = ByteBuffer.allocate(8).putLong(timestamp.getMillis()).array();
public static String timestampToId(Instant timestamp) {
byte[] bytes = ByteBuffer.allocate(8).putLong(timestamp.toEpochMilli()).array();
return BaseEncoding.base32().omitPadding().encode(bytes);
}
@@ -26,12 +26,12 @@ import com.google.common.io.Closer;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.time.Instant;
import java.util.Collection;
import javax.annotation.concurrent.NotThreadSafe;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.joda.time.DateTime;
/**
* Stream that performs the full RyDE encryption.
@@ -63,7 +63,7 @@ public final class RydeEncoder extends FilterOutputStream {
OutputStream sigOutput,
long dataLength,
String filenamePrefix,
DateTime modified,
Instant modified,
PGPKeyPair signingKey,
Collection<PGPPublicKey> receiverKeys) {
super(null);
@@ -110,7 +110,7 @@ public final class RydeEncoder extends FilterOutputStream {
OutputStream sigOutput;
Long dataLength;
String filenamePrefix;
DateTime modified;
Instant modified;
PGPKeyPair signingKey;
ImmutableList<PGPPublicKey> receiverKeys;
@@ -131,7 +131,7 @@ public final class RydeEncoder extends FilterOutputStream {
}
/** Sets the information about the unencoded data that will follow. */
public Builder setFileMetadata(String filenamePrefix, long dataLength, DateTime modified) {
public Builder setFileMetadata(String filenamePrefix, long dataLength, Instant modified) {
this.filenamePrefix = filenamePrefix;
this.dataLength = dataLength;
this.modified = modified;
@@ -15,18 +15,18 @@
package google.registry.rde;
import static org.bouncycastle.openpgp.PGPLiteralData.BINARY;
import static org.joda.time.DateTimeZone.UTC;
import google.registry.util.ImprovedInputStream;
import google.registry.util.ImprovedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Timestamp;
import java.time.Instant;
import javax.annotation.CheckReturnValue;
import javax.annotation.WillNotClose;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
import org.joda.time.DateTime;
/**
* Input/Output stream for reading/writing PGP literal data layer.
@@ -54,12 +54,12 @@ final class RydeFileEncoding {
*/
@CheckReturnValue
static ImprovedOutputStream openPgpFileWriter(
@WillNotClose OutputStream os, String filename, DateTime modified) {
@WillNotClose OutputStream os, String filename, Instant modified) {
try {
return new ImprovedOutputStream(
"PgpFileWriter",
new PGPLiteralDataGenerator()
.open(os, BINARY, filename, modified.toDate(), new byte[BUFFER_SIZE]));
.open(os, BINARY, filename, Timestamp.from(modified), new byte[BUFFER_SIZE]));
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -68,12 +68,12 @@ final class RydeFileEncoding {
/** Input stream to a PGP file's data that also holds the file's metadata. */
static class PgpFileInputStream extends ImprovedInputStream {
private final String filename;
private final DateTime modified;
private final Instant modified;
private PgpFileInputStream(PGPLiteralData literal) {
super("PgpFileReader", literal.getDataStream());
filename = literal.getFileName();
modified = new DateTime(literal.getModificationTime(), UTC);
modified = literal.getModificationTime().toInstant();
}
/** Returns the name of the original file. */
@@ -82,7 +82,7 @@ final class RydeFileEncoding {
}
/** Returns the time this file was created or modified. */
DateTime getModified() {
Instant getModified() {
return modified;
}
}
@@ -16,6 +16,8 @@ package google.registry.rde;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static google.registry.util.DateTimeUtils.toDateTime;
import static google.registry.util.DateTimeUtils.toInstant;
import com.google.common.io.ByteStreams;
import google.registry.util.ImprovedInputStream;
@@ -24,9 +26,9 @@ import google.registry.util.PosixTarHeader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.Instant;
import javax.annotation.CheckReturnValue;
import javax.annotation.WillNotClose;
import org.joda.time.DateTime;
/** Single-file POSIX tar archive creator that wraps an {@link OutputStream}. */
final class RydeTar {
@@ -41,18 +43,19 @@ final class RydeTar {
*/
@CheckReturnValue
static ImprovedOutputStream openTarWriter(
@WillNotClose OutputStream os, long expectedSize, String filename, DateTime modified) {
@WillNotClose OutputStream os, long expectedSize, String filename, Instant modified) {
checkArgument(expectedSize >= 0);
checkArgument(filename.endsWith(".xml"),
"Ryde expects tar archive to contain a filename with an '.xml' extension.");
try {
os.write(new PosixTarHeader.Builder()
.setName(filename)
.setSize(expectedSize)
.setMtime(modified)
.build()
.getBytes());
os.write(
new PosixTarHeader.Builder()
.setName(filename)
.setSize(expectedSize)
.setMtime(toDateTime(modified))
.build()
.getBytes());
return new ImprovedOutputStream("RydeTarWriter", os) {
/** Writes the end of archive marker. */
@Override
@@ -92,8 +95,8 @@ final class RydeTar {
}
/** Returns the creation/modification time of the file archived in this TAR. */
DateTime getModified() {
return header.getMtime();
Instant getModified() {
return toInstant(header.getMtime());
}
}
@@ -17,6 +17,7 @@ package google.registry.reporting;
import static google.registry.request.RequestParameters.extractOptionalBooleanParameter;
import static google.registry.request.RequestParameters.extractOptionalParameter;
import static google.registry.request.RequestParameters.extractRequiredParameter;
import static java.time.ZoneOffset.UTC;
import com.google.api.services.dataflow.Dataflow;
import dagger.Module;
@@ -28,11 +29,11 @@ import google.registry.request.Parameter;
import google.registry.util.Clock;
import google.registry.util.GoogleCredentialsBundle;
import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Optional;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.joda.time.YearMonth;
import org.joda.time.format.ISODateTimeFormat;
/** Dagger module for injecting common settings for all reporting tasks. */
@Module
@@ -84,8 +85,9 @@ public class ReportingModule {
static Optional<YearMonth> provideYearMonthOptional(HttpServletRequest req) {
Optional<String> optionalYearMonthStr = extractOptionalParameter(req, PARAM_YEAR_MONTH);
try {
return optionalYearMonthStr.map(s -> YearMonth.parse(s, ISODateTimeFormat.yearMonth()));
} catch (IllegalArgumentException e) {
return optionalYearMonthStr.map(
s -> YearMonth.parse(s, DateTimeFormatter.ofPattern("yyyy-MM")));
} catch (IllegalArgumentException | DateTimeParseException e) {
throw new BadRequestException(
String.format(
"yearMonth must be in yyyy-MM format, got %s instead",
@@ -101,7 +103,7 @@ public class ReportingModule {
static YearMonth provideYearMonth(
@Parameter(PARAM_YEAR_MONTH) Optional<YearMonth> yearMonthOptional,
@Parameter(PARAM_DATE) LocalDate date) {
return yearMonthOptional.orElseGet(() -> new YearMonth(date.minusMonths(1)));
return yearMonthOptional.orElseGet(() -> YearMonth.from(date.minusMonths(1)));
}
/** Extracts an optional date in yyyy-MM-dd format from the request. */
@@ -110,8 +112,8 @@ public class ReportingModule {
static Optional<LocalDate> provideDateOptional(HttpServletRequest req) {
Optional<String> optionalDateString = extractOptionalParameter(req, PARAM_DATE);
try {
return optionalDateString.map(s -> LocalDate.parse(s, ISODateTimeFormat.yearMonthDay()));
} catch (IllegalArgumentException e) {
return optionalDateString.map(s -> LocalDate.parse(s, DateTimeFormatter.ISO_LOCAL_DATE));
} catch (IllegalArgumentException | DateTimeParseException e) {
throw new BadRequestException(
String.format(
"date must be in yyyy-MM-dd format, got %s instead",
@@ -127,8 +129,7 @@ public class ReportingModule {
@Provides
@Parameter(PARAM_DATE)
static LocalDate provideDate(HttpServletRequest req, Clock clock) {
return provideDateOptional(req)
.orElseGet(() -> new LocalDate(clock.nowUtc(), DateTimeZone.UTC));
return provideDateOptional(req).orElseGet(() -> LocalDate.ofInstant(clock.now(), UTC));
}
/** Constructs a {@link Dataflow} API client with default settings. */
@@ -28,8 +28,8 @@ import google.registry.reporting.billing.BillingModule.InvoiceDirectoryPrefix;
import google.registry.util.EmailMessage;
import jakarta.inject.Inject;
import jakarta.mail.internet.InternetAddress;
import java.time.YearMonth;
import java.util.Optional;
import org.joda.time.YearMonth;
/** Utility functions for sending emails involving monthly invoices. */
public class BillingEmailUtils {
@@ -25,7 +25,7 @@ import jakarta.inject.Qualifier;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import org.joda.time.YearMonth;
import java.time.YearMonth;
/** Module for dependencies required by monthly billing actions. */
@Module
@@ -39,8 +39,8 @@ import google.registry.util.Clock;
import google.registry.util.RegistryEnvironment;
import jakarta.inject.Inject;
import java.io.IOException;
import org.joda.time.Duration;
import org.joda.time.YearMonth;
import java.time.Duration;
import java.time.YearMonth;
/**
* Invokes the {@code InvoicingPipeline} beam template via the REST api, and enqueues the {@link
@@ -114,7 +114,7 @@ public class GenerateInvoicesAction implements Runnable {
String.format("%s/%s_metadata.json", stagingBucketUrl, PIPELINE_NAME))
.setParameters(
new ImmutableMap.Builder<String, String>()
.put("yearMonth", yearMonth.toString("yyyy-MM"))
.put("yearMonth", yearMonth.toString())
.put("invoiceFilePrefix", invoiceFilePrefix)
.put("billingBucketUrl", billingBucketUrl)
.put("registryEnvironment", RegistryEnvironment.get().name())
@@ -145,7 +145,7 @@ public class GenerateInvoicesAction implements Runnable {
jobId,
ReportingModule.PARAM_YEAR_MONTH,
yearMonth.toString()),
Duration.standardMinutes(ReportingModule.ENQUEUE_DELAY_MINUTES)));
Duration.ofMinutes(ReportingModule.ENQUEUE_DELAY_MINUTES)));
}
response.setStatus(SC_OK);
response.setPayload(String.format("Launched invoicing pipeline: %s", jobId));
@@ -35,7 +35,7 @@ import google.registry.request.Response;
import google.registry.request.auth.Auth;
import jakarta.inject.Inject;
import java.io.IOException;
import org.joda.time.YearMonth;
import java.time.YearMonth;
/**
* Uploads the results of the {@link google.registry.beam.billing.InvoicingPipeline}.
@@ -23,10 +23,9 @@ import google.registry.config.RegistryConfig.Config;
import google.registry.util.SqlTemplate;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.joda.time.LocalDate;
import org.joda.time.YearMonth;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
/** Utility class that produces SQL queries used to generate activity reports from Bigquery. */
public final class ActivityReportingQueryBuilder implements QueryBuilder {
@@ -64,9 +63,9 @@ public final class ActivityReportingQueryBuilder implements QueryBuilder {
/** Sets the month we're doing activity reporting for, and returns the view query map. */
@Override
public ImmutableMap<String, String> getViewQueryMap(YearMonth yearMonth) {
LocalDate firstDayOfMonth = yearMonth.toLocalDate(1);
LocalDate firstDayOfMonth = yearMonth.atDay(1);
// The pattern-matching is inclusive, so we subtract 1 day to only report that month's data.
LocalDate lastDayOfMonth = yearMonth.toLocalDate(1).plusMonths(1).minusDays(1);
LocalDate lastDayOfMonth = yearMonth.atDay(1).plusMonths(1).minusDays(1);
ImmutableMap.Builder<String, String> queriesBuilder = ImmutableMap.builder();
String operationalRegistrarsQuery;
@@ -81,20 +80,20 @@ public final class ActivityReportingQueryBuilder implements QueryBuilder {
queriesBuilder.put(getTableName(DNS_COUNTS, yearMonth), dnsCountsQuery);
// Convert reportingMonth into YYYYMMDD format for Bigquery table partition pattern-matching.
DateTimeFormatter logTableFormatter = DateTimeFormat.forPattern("yyyyMMdd");
DateTimeFormatter logTableFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
String monthlyLogsQuery =
SqlTemplate.create(getQueryFromFile(MONTHLY_LOGS + ".sql"))
.put("PROJECT_ID", projectId)
.put("FIRST_DAY_OF_MONTH", logTableFormatter.print(firstDayOfMonth))
.put("LAST_DAY_OF_MONTH", logTableFormatter.print(lastDayOfMonth))
.put("FIRST_DAY_OF_MONTH", logTableFormatter.format(firstDayOfMonth))
.put("LAST_DAY_OF_MONTH", logTableFormatter.format(lastDayOfMonth))
.build();
queriesBuilder.put(getTableName(MONTHLY_LOGS, yearMonth), monthlyLogsQuery);
String eppQuery =
SqlTemplate.create(getQueryFromFile(EPP_METRICS + ".sql"))
.put("PROJECT_ID", projectId)
.put("FIRST_DAY_OF_MONTH", logTableFormatter.print(firstDayOfMonth))
.put("LAST_DAY_OF_MONTH", logTableFormatter.print(lastDayOfMonth))
.put("FIRST_DAY_OF_MONTH", logTableFormatter.format(firstDayOfMonth))
.put("LAST_DAY_OF_MONTH", logTableFormatter.format(lastDayOfMonth))
.build();
queriesBuilder.put(getTableName(EPP_METRICS, yearMonth), eppQuery);
@@ -18,9 +18,9 @@ import com.google.common.io.Resources;
import google.registry.bigquery.BigqueryUtils.TableType;
import google.registry.util.ResourceUtils;
import google.registry.util.SqlTemplate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ExecutionException;
import org.joda.time.YearMonth;
import org.joda.time.format.DateTimeFormat;
/**
* DNS Count query that relies on a table Cloud DNS publishes internally to Google.
@@ -76,7 +76,7 @@ public class CloudDnsCountQueryCoordinator extends DnsCountQueryCoordinator {
.put("PROJECT_ID", projectId)
.put("DATASET_ID", icannReportingDataSet)
.put("TABLE_ID", TABLE_ID)
.put("YEAR_MONTH", DateTimeFormat.forPattern("yyyyMM").print(yearMonth));
.put("YEAR_MONTH", DateTimeFormatter.ofPattern("yyyyMM").format(yearMonth));
return queryTemplate.build();
}
}
@@ -25,7 +25,7 @@ import google.registry.bigquery.BigqueryConnection;
import google.registry.config.RegistryConfig.Config;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.joda.time.YearMonth;
import java.time.YearMonth;
/**
* Methods for preparing and querying DNS statistics.
@@ -16,7 +16,7 @@ package google.registry.reporting.icann;
import google.registry.util.ResourceUtils;
import google.registry.util.SqlTemplate;
import org.joda.time.YearMonth;
import java.time.YearMonth;
/** DNS Count query where returned values are all -1. */
public class DummyDnsCountQueryCoordinator extends DnsCountQueryCoordinator {
@@ -40,9 +40,9 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.List;
import org.joda.time.YearMonth;
import org.joda.time.format.DateTimeFormat;
/**
* Class that uploads a CSV file to ICANN's endpoint via an HTTP PUT call.
@@ -148,7 +148,7 @@ public class IcannHttpReporter {
ReportType reportType = ReportType.valueOf(Ascii.toUpperCase(elements.get(0)));
// Re-add hyphen between year and month, because ICANN is inconsistent between filename and URL
String yearMonth =
YearMonth.parse(elements.get(1), DateTimeFormat.forPattern("yyyyMM")).toString("yyyy-MM");
YearMonth.parse(elements.get(1), DateTimeFormatter.ofPattern("yyyyMM")).toString();
return new URL(String.format("%s/%s/%s", getUrlPrefix(reportType), tld, yearMonth));
}
@@ -28,8 +28,8 @@ import google.registry.request.HttpException.BadRequestException;
import google.registry.request.Parameter;
import jakarta.inject.Named;
import jakarta.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.Optional;
import org.joda.time.Duration;
/** Module for dependencies required by ICANN monthly transactions/activity reporting. */
@Module
@@ -101,7 +101,7 @@ public final class IcannReportingModule {
.setExecutorService(MoreExecutors.newDirectExecutorService())
.setDatasetId(icannReportingDataSet)
.setOverwrite(true)
.setPollInterval(Duration.standardSeconds(1))
.setPollInterval(Duration.ofSeconds(1))
.build();
} catch (Throwable e) {
throw new RuntimeException("Could not initialize BigqueryConnection!", e);
@@ -38,6 +38,8 @@ import google.registry.gcs.GcsUtils;
import google.registry.reporting.icann.IcannReportingModule.ReportType;
import jakarta.inject.Inject;
import java.io.IOException;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -47,8 +49,6 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import org.joda.time.YearMonth;
import org.joda.time.format.DateTimeFormat;
/**
* Class containing methods for staging ICANN monthly reports on GCS.
@@ -258,7 +258,7 @@ public class IcannReportingStager {
"%s-%s-%s.csv",
tld,
Ascii.toLowerCase(reportType.toString()),
DateTimeFormat.forPattern("yyyyMM").print(yearMonth));
DateTimeFormatter.ofPattern("yyyyMM").format(yearMonth));
final BlobId gcsFilename =
BlobId.of(reportingBucket, String.format("%s/%s", subdir, reportFilename));
gcsUtils.createFromBytes(gcsFilename, reportBytes);
@@ -41,10 +41,10 @@ import google.registry.util.EmailMessage;
import google.registry.util.Retrier;
import jakarta.inject.Inject;
import jakarta.mail.internet.InternetAddress;
import java.time.Duration;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import org.joda.time.Duration;
import org.joda.time.YearMonth;
import org.joda.time.format.DateTimeFormat;
/**
* Action that generates monthly ICANN activity and transactions reports.
@@ -138,7 +138,7 @@ public final class IcannReportingStagingAction implements Runnable {
cloudTasksUtils.enqueue(
CRON_QUEUE,
cloudTasksUtils.createTaskWithDelay(
IcannReportingUploadAction.class, POST, null, Duration.standardMinutes(2)));
IcannReportingUploadAction.class, POST, null, Duration.ofMinutes(2)));
} else {
logger.atInfo().log("Would have enqueued report upload");
}
@@ -166,6 +166,7 @@ public final class IcannReportingStagingAction implements Runnable {
return IcannReportingModule.checkSubdirValid(
overrideSubdir.orElse(
String.format(
"%s/%s", DEFAULT_SUBDIR, DateTimeFormat.forPattern("yyyy-MM").print(yearMonth))));
"%s/%s",
DEFAULT_SUBDIR, DateTimeFormatter.ofPattern("yyyy-MM").format(yearMonth))));
}
}
@@ -18,6 +18,7 @@ import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import static java.time.ZoneOffset.UTC;
import com.google.cloud.storage.BlobId;
import com.google.common.collect.ImmutableMap;
@@ -46,11 +47,11 @@ import jakarta.inject.Inject;
import jakarta.mail.internet.InternetAddress;
import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* Action that uploads the monthly activity/transactions reports from GCS to ICANN via an HTTP PUT.
@@ -105,14 +106,13 @@ public final class IcannReportingUploadAction implements Runnable {
* staging action is scheduled to run at 9AM UTC on that day, and there is no reason to run the
* upload job before that. See {@code icannReportingStaging} in {@code cloud-scheduler.xml}.
*/
private static DateTime getScheduledTimeForCurrentMonth(DateTime time) {
return time.withDayOfMonth(2).withHourOfDay(10).withMinuteOfHour(0).plusMonths(1);
private static Instant getScheduledTimeForCurrentMonth(Instant time) {
return time.atZone(UTC).withDayOfMonth(2).withHour(10).withMinute(0).plusMonths(1).toInstant();
}
@Override
public void run() {
if (!lockHandler.executeWithLocks(
this::runWithLock, null, Duration.standardHours(2), LOCK_NAME)) {
if (!lockHandler.executeWithLocks(this::runWithLock, null, Duration.ofHours(2), LOCK_NAME)) {
throw new ServiceUnavailableException(String.format("Lock for %s already in use", LOCK_NAME));
}
}
@@ -124,7 +124,7 @@ public final class IcannReportingUploadAction implements Runnable {
// If cursor time is before now, upload the corresponding report
cursors.entrySet().stream()
.filter(entry -> entry.getKey().getCursorTime().isBefore(clock.nowUtc()))
.filter(entry -> entry.getKey().getCursorTime().isBefore(clock.now()))
.forEach(entry -> uploadReport(entry.getKey(), entry.getValue(), reportSummaryBuilder));
// Send email of which reports were uploaded
emailUploadResults(reportSummaryBuilder.build());
@@ -136,13 +136,15 @@ public final class IcannReportingUploadAction implements Runnable {
/** Uploads the report and rolls forward the cursor for that report. */
private void uploadReport(
Cursor cursor, String tldStr, ImmutableMap.Builder<String, Boolean> reportSummaryBuilder) {
DateTime cursorTime = cursor.getCursorTime();
Instant cursorTime = cursor.getCursorTime();
CursorType cursorType = cursor.getType();
DateTime cursorTimeMinusMonth = cursorTime.withDayOfMonth(1).minusMonths(1);
Instant cursorTimeMinusMonth =
cursorTime.atZone(UTC).withDayOfMonth(1).minusMonths(1).toInstant();
String reportSubdir =
String.format(
"icann/monthly/%d-%02d",
cursorTimeMinusMonth.getYear(), cursorTimeMinusMonth.getMonthOfYear());
cursorTimeMinusMonth.atZone(UTC).getYear(),
cursorTimeMinusMonth.atZone(UTC).getMonthValue());
String filename = getFileName(cursorType, cursorTime, tldStr);
final BlobId gcsFilename =
BlobId.of(reportingBucket, String.format("%s/%s", reportSubdir, filename));
@@ -154,7 +156,7 @@ public final class IcannReportingUploadAction implements Runnable {
"Could not upload %s report for %s because file %s (object %s in bucket %s) did not"
+ " exist.",
cursorType, tldStr, filename, gcsFilename.getName(), gcsFilename.getBucket());
if (clock.nowUtc().dayOfMonth().get() == 1) {
if (clock.now().atZone(UTC).getDayOfMonth() == 1) {
logger.atInfo().log("%s This report may not have been staged yet.", logMessage);
} else {
logger.atSevere().log(logMessage);
@@ -202,14 +204,15 @@ public final class IcannReportingUploadAction implements Runnable {
reportSummaryBuilder.put(filename, success);
}
private String getFileName(CursorType cursorType, DateTime cursorTime, String tld) {
DateTime cursorTimeMinusMonth = cursorTime.withDayOfMonth(1).minusMonths(1);
private String getFileName(CursorType cursorType, Instant cursorTime, String tld) {
Instant cursorTimeMinusMonth =
cursorTime.atZone(UTC).withDayOfMonth(1).minusMonths(1).toInstant();
return String.format(
"%s%s%d%02d.csv",
tld,
(cursorType.equals(CursorType.ICANN_UPLOAD_ACTIVITY) ? "-activity-" : "-transactions-"),
cursorTimeMinusMonth.year().get(),
cursorTimeMinusMonth.monthOfYear().get());
cursorTimeMinusMonth.atZone(UTC).getYear(),
cursorTimeMinusMonth.atZone(UTC).getMonthValue());
}
/** Returns a map of each cursor to the tld. */
@@ -260,7 +263,7 @@ public final class IcannReportingUploadAction implements Runnable {
cursorMap.getOrDefault(
key,
Cursor.createScoped(
type, getScheduledTimeForCurrentMonth(clock.nowUtc()), registry));
type, getScheduledTimeForCurrentMonth(clock.now()), registry));
if (!cursorMap.containsValue(cursor)) {
tm().put(cursor);
}
@@ -15,7 +15,7 @@
package google.registry.reporting.icann;
import com.google.common.collect.ImmutableMap;
import org.joda.time.YearMonth;
import java.time.YearMonth;
/** Interface defining the necessary methods to construct ICANN reporting SQL queries. */
public interface QueryBuilder {
@@ -17,8 +17,8 @@ package google.registry.reporting.icann;
import com.google.common.io.Resources;
import google.registry.util.ResourceUtils;
import java.net.URL;
import org.joda.time.YearMonth;
import org.joda.time.format.DateTimeFormat;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
final class QueryBuilderUtils {
@@ -26,7 +26,8 @@ final class QueryBuilderUtils {
/** Returns the table name of the query, suffixed with the yearMonth in _yyyyMM format. */
static String getTableName(String queryName, YearMonth yearMonth) {
return String.format("%s_%s", queryName, DateTimeFormat.forPattern("yyyyMM").print(yearMonth));
return String.format(
"%s_%s", queryName, DateTimeFormatter.ofPattern("yyyyMM").format(yearMonth));
}
/** Returns {@link String} for file in {@code reporting/sql/} directory. */
@@ -17,17 +17,17 @@ package google.registry.reporting.icann;
import static google.registry.reporting.icann.IcannReportingModule.ICANN_REPORTING_DATA_SET;
import static google.registry.reporting.icann.QueryBuilderUtils.getQueryFromFile;
import static google.registry.reporting.icann.QueryBuilderUtils.getTableName;
import static java.time.ZoneOffset.UTC;
import com.google.common.collect.ImmutableMap;
import google.registry.config.RegistryConfig.Config;
import google.registry.util.SqlTemplate;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.joda.time.DateTime;
import org.joda.time.LocalTime;
import org.joda.time.YearMonth;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.time.Duration;
import java.time.Instant;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
/**
* Utility class that produces SQL queries used to generate activity reports from Bigquery.
@@ -65,9 +65,10 @@ public final class TransactionsReportingQueryBuilder implements QueryBuilder {
@Override
public ImmutableMap<String, String> getViewQueryMap(YearMonth yearMonth) {
// Set the earliest date to to yearMonth on day 1 at 00:00:00
DateTime earliestReportTime = yearMonth.toLocalDate(1).toDateTime(new LocalTime(0, 0, 0));
Instant earliestReportTime = yearMonth.atDay(1).atTime(0, 0, 0).toInstant(UTC);
// Set the latest date to yearMonth on the last day at 23:59:59.999
DateTime latestReportTime = earliestReportTime.plusMonths(1).minusMillis(1);
Instant latestReportTime =
earliestReportTime.atZone(UTC).plusMonths(1).minus(Duration.ofMillis(1)).toInstant();
ImmutableMap.Builder<String, String> queriesBuilder = ImmutableMap.builder();
String registrarIanaIdQuery =
@@ -82,38 +83,39 @@ public final class TransactionsReportingQueryBuilder implements QueryBuilder {
.build();
queriesBuilder.put(getTableName(TOTAL_DOMAINS, yearMonth), totalDomainsQuery);
DateTimeFormatter timestampFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
DateTimeFormatter timestampFormatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(UTC);
String totalNameserversQuery =
SqlTemplate.create(getQueryFromFile(TOTAL_NAMESERVERS + ".sql"))
.put("PROJECT_ID", projectId)
.put("LATEST_REPORT_TIME", timestampFormatter.print(latestReportTime))
.put("LATEST_REPORT_TIME", timestampFormatter.format(latestReportTime))
.build();
queriesBuilder.put(getTableName(TOTAL_NAMESERVERS, yearMonth), totalNameserversQuery);
String transactionCountsQuery =
SqlTemplate.create(getQueryFromFile(TRANSACTION_COUNTS + ".sql"))
.put("PROJECT_ID", projectId)
.put("EARLIEST_REPORT_TIME", timestampFormatter.print(earliestReportTime))
.put("LATEST_REPORT_TIME", timestampFormatter.print(latestReportTime))
.put("EARLIEST_REPORT_TIME", timestampFormatter.format(earliestReportTime))
.put("LATEST_REPORT_TIME", timestampFormatter.format(latestReportTime))
.build();
queriesBuilder.put(getTableName(TRANSACTION_COUNTS, yearMonth), transactionCountsQuery);
String transactionTransferLosingQuery =
SqlTemplate.create(getQueryFromFile(TRANSACTION_TRANSFER_LOSING + ".sql"))
.put("PROJECT_ID", projectId)
.put("EARLIEST_REPORT_TIME", timestampFormatter.print(earliestReportTime))
.put("LATEST_REPORT_TIME", timestampFormatter.print(latestReportTime))
.put("EARLIEST_REPORT_TIME", timestampFormatter.format(earliestReportTime))
.put("LATEST_REPORT_TIME", timestampFormatter.format(latestReportTime))
.build();
queriesBuilder.put(
getTableName(TRANSACTION_TRANSFER_LOSING, yearMonth), transactionTransferLosingQuery);
// Log table suffixes use YYYYMMDD format
DateTimeFormatter logTableFormatter = DateTimeFormat.forPattern("yyyyMMdd");
DateTimeFormatter logTableFormatter = DateTimeFormatter.ofPattern("yyyyMMdd").withZone(UTC);
String attemptedAddsQuery =
SqlTemplate.create(getQueryFromFile(ATTEMPTED_ADDS + ".sql"))
.put("PROJECT_ID", projectId)
.put("FIRST_DAY_OF_MONTH", logTableFormatter.print(earliestReportTime))
.put("LAST_DAY_OF_MONTH", logTableFormatter.print(latestReportTime))
.put("FIRST_DAY_OF_MONTH", logTableFormatter.format(earliestReportTime))
.put("LAST_DAY_OF_MONTH", logTableFormatter.format(latestReportTime))
.build();
queriesBuilder.put(getTableName(ATTEMPTED_ADDS, yearMonth), attemptedAddsQuery);
@@ -39,8 +39,8 @@ import google.registry.util.Clock;
import google.registry.util.RegistryEnvironment;
import jakarta.inject.Inject;
import java.io.IOException;
import org.joda.time.Duration;
import org.joda.time.LocalDate;
import java.time.Duration;
import java.time.LocalDate;
/**
* Invokes the {@code Spec11Pipeline} Beam template via the REST api.
@@ -140,7 +140,7 @@ public class GenerateSpec11ReportAction implements Runnable {
jobId,
ReportingModule.PARAM_DATE,
date.toString()),
Duration.standardMinutes(ReportingModule.ENQUEUE_DELAY_MINUTES)));
Duration.ofMinutes(ReportingModule.ENQUEUE_DELAY_MINUTES)));
}
response.setStatus(SC_OK);
response.setPayload(String.format("Launched Spec11 pipeline: %s", jobId));
@@ -43,9 +43,9 @@ import google.registry.request.Response;
import google.registry.request.auth.Auth;
import jakarta.inject.Inject;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Optional;
import java.util.Set;
import org.joda.time.LocalDate;
import org.json.JSONException;
/**
@@ -41,10 +41,10 @@ import google.registry.util.Sleeper;
import jakarta.inject.Inject;
import jakarta.mail.MessagingException;
import jakarta.mail.internet.InternetAddress;
import java.time.Duration;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import org.joda.time.Duration;
import org.joda.time.LocalDate;
/** Provides e-mail functionality for Spec11 tasks, such as sending Spec11 reports to registrars. */
public class Spec11EmailUtils {
@@ -103,11 +103,7 @@ public class Spec11EmailUtils {
RegistrarThreatMatches filteredMatches = filterOutNonPublishedMatches(registrarThreatMatches);
if (!filteredMatches.threatMatches().isEmpty()) {
if (numRegistrarsEmailed > 0) {
try {
sleeper.sleep(emailThrottleDuration);
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
sleeper.sleepInterruptibly(emailThrottleDuration);
}
try {
// Handle exceptions individually per registrar so that one failed email doesn't prevent

Some files were not shown because too many files have changed in this diff Show More