diff --git a/common/src/main/java/google/registry/util/Clock.java b/common/src/main/java/google/registry/util/Clock.java index 78372cba4..9943aaa7c 100644 --- a/common/src/main/java/google/registry/util/Clock.java +++ b/common/src/main/java/google/registry/util/Clock.java @@ -15,6 +15,7 @@ package google.registry.util; import java.io.Serializable; +import java.time.Instant; import javax.annotation.concurrent.ThreadSafe; import org.joda.time.DateTime; @@ -30,5 +31,9 @@ import org.joda.time.DateTime; public interface Clock extends Serializable { /** Returns current time in UTC timezone. */ + @Deprecated DateTime nowUtc(); + + /** Returns current Instant (which is always in UTC). */ + Instant now(); } diff --git a/common/src/main/java/google/registry/util/DateTimeUtils.java b/common/src/main/java/google/registry/util/DateTimeUtils.java index b085fbabd..1c7650eda 100644 --- a/common/src/main/java/google/registry/util/DateTimeUtils.java +++ b/common/src/main/java/google/registry/util/DateTimeUtils.java @@ -20,6 +20,9 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; import java.sql.Date; +import java.time.Instant; +import java.time.ZoneOffset; +import javax.annotation.Nullable; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.LocalDate; @@ -28,7 +31,10 @@ import org.joda.time.LocalDate; public abstract class DateTimeUtils { /** The start of the epoch, in a convenient constant. */ - public static final DateTime START_OF_TIME = new DateTime(0, DateTimeZone.UTC); + @Deprecated public static final DateTime START_OF_TIME = new DateTime(0, DateTimeZone.UTC); + + /** The start of the UNIX epoch (which is defined in UTC), in a convenient constant. */ + public static final Instant START_INSTANT = Instant.ofEpochMilli(0); /** * A date in the far future that we can treat as infinity. @@ -37,19 +43,40 @@ public abstract class DateTimeUtils { * but Java uses milliseconds, so this is the largest representable date that will survive a * round-trip through the database. */ + @Deprecated public static final DateTime END_OF_TIME = new DateTime(Long.MAX_VALUE / 1000, DateTimeZone.UTC); + /** + * An instant in the far future that we can treat as infinity. + * + *

This value is (2^63-1)/1000 rounded down. Postgres can store dates as 64 bit microseconds, + * but Java uses milliseconds, so this is the largest representable date that will survive a + * round-trip through the database. + */ + public static final Instant END_INSTANT = Instant.ofEpochMilli(Long.MAX_VALUE / 1000); + /** Returns the earliest of a number of given {@link DateTime} instances. */ public static DateTime earliestOf(DateTime first, DateTime... rest) { + return earliestDateTimeOf(Lists.asList(first, rest)); + } + + /** Returns the earliest of a number of given {@link Instant} instances. */ + public static Instant earliestOf(Instant first, Instant... rest) { return earliestOf(Lists.asList(first, rest)); } /** Returns the earliest element in a {@link DateTime} iterable. */ - public static DateTime earliestOf(Iterable dates) { + public static DateTime earliestDateTimeOf(Iterable dates) { checkArgument(!Iterables.isEmpty(dates)); return Ordering.natural().min(dates); } + /** Returns the earliest element in a {@link Instant} iterable. */ + public static Instant earliestOf(Iterable instants) { + checkArgument(!Iterables.isEmpty(instants)); + return Ordering.natural().min(instants); + } + /** Returns the latest of a number of given {@link DateTime} instances. */ public static DateTime latestOf(DateTime first, DateTime... rest) { return latestOf(Lists.asList(first, rest)); @@ -66,29 +93,63 @@ public abstract class DateTimeUtils { return !timeToCheck.isAfter(timeToCompareTo); } + /** Returns whether the first {@link Instant} is equal to or earlier than the second. */ + public static boolean isBeforeOrAt(Instant timeToCheck, Instant timeToCompareTo) { + return !timeToCheck.isAfter(timeToCompareTo); + } + /** Returns whether the first {@link DateTime} is equal to or later than the second. */ public static boolean isAtOrAfter(DateTime timeToCheck, DateTime timeToCompareTo) { return !timeToCheck.isBefore(timeToCompareTo); } + /** Returns whether the first {@link Instant} is equal to or later than the second. */ + public static boolean isAtOrAfter(Instant timeToCheck, Instant timeToCompareTo) { + return !timeToCheck.isBefore(timeToCompareTo); + } + /** * Adds years to a date, in the {@code Duration} sense of semantic years. Use this instead of * {@link DateTime#plusYears} to ensure that we never end up on February 29. */ + @Deprecated public static DateTime leapSafeAddYears(DateTime now, int years) { checkArgument(years >= 0); return years == 0 ? now : now.plusYears(1).plusYears(years - 1); } + /** + * Adds years to a date, in the {@code Duration} sense of semantic years. Use this instead of + * {@link java.time.ZonedDateTime#plusYears} to ensure that we never end up on February 29. + */ + public static Instant leapSafeAddYears(Instant now, long years) { + checkArgument(years >= 0); + return (years == 0) + ? now + : now.atZone(ZoneOffset.UTC).plusYears(1).plusYears(years - 1).toInstant(); + } + /** * Subtracts years from a date, in the {@code Duration} sense of semantic years. Use this instead * of {@link DateTime#minusYears} to ensure that we never end up on February 29. */ + @Deprecated public static DateTime leapSafeSubtractYears(DateTime now, int years) { checkArgument(years >= 0); return years == 0 ? now : now.minusYears(1).minusYears(years - 1); } + /** + * Subtracts years from a date, in the {@code Duration} sense of semantic years. Use this instead + * of {@link java.time.ZonedDateTime#minusYears} to ensure that we never end up on February 29. + */ + public static Instant leapSafeSubtractYears(Instant now, int years) { + checkArgument(years >= 0); + return (years == 0) + ? now + : now.atZone(ZoneOffset.UTC).minusYears(1).minusYears(years - 1).toInstant(); + } + public static Date toSqlDate(LocalDate localDate) { return new Date(localDate.toDateTimeAtStartOfDay().getMillis()); } @@ -96,4 +157,28 @@ public abstract class DateTimeUtils { public static LocalDate toLocalDate(Date date) { return new LocalDate(date.getTime(), DateTimeZone.UTC); } + + /** Convert a joda {@link DateTime} to a java.time {@link Instant}, null-safe. */ + @Nullable + public static Instant toInstant(@Nullable DateTime dateTime) { + return (dateTime == null) ? null : Instant.ofEpochMilli(dateTime.getMillis()); + } + + /** Convert a java.time {@link Instant} to a joda {@link DateTime}, null-safe. */ + @Nullable + public static DateTime toDateTime(@Nullable Instant instant) { + return (instant == null) ? null : new DateTime(instant.toEpochMilli(), DateTimeZone.UTC); + } + + public static Instant plusYears(Instant instant, int years) { + return instant.atZone(ZoneOffset.UTC).plusYears(years).toInstant(); + } + + public static Instant plusDays(Instant instant, int days) { + return instant.atZone(ZoneOffset.UTC).plusDays(days).toInstant(); + } + + public static Instant minusDays(Instant instant, int days) { + return instant.atZone(ZoneOffset.UTC).minusDays(days).toInstant(); + } } diff --git a/common/src/main/java/google/registry/util/SystemClock.java b/common/src/main/java/google/registry/util/SystemClock.java index eb553678d..52ac9893f 100644 --- a/common/src/main/java/google/registry/util/SystemClock.java +++ b/common/src/main/java/google/registry/util/SystemClock.java @@ -17,6 +17,7 @@ package google.registry.util; import static org.joda.time.DateTimeZone.UTC; import jakarta.inject.Inject; +import java.time.Instant; import javax.annotation.concurrent.ThreadSafe; import org.joda.time.DateTime; @@ -34,4 +35,9 @@ public class SystemClock implements Clock { public DateTime nowUtc() { return DateTime.now(UTC); } + + @Override + public Instant now() { + return Instant.now(); + } } diff --git a/common/src/testing/java/google/registry/testing/FakeClock.java b/common/src/testing/java/google/registry/testing/FakeClock.java index 526f943a2..656ec7109 100644 --- a/common/src/testing/java/google/registry/testing/FakeClock.java +++ b/common/src/testing/java/google/registry/testing/FakeClock.java @@ -19,6 +19,7 @@ import static org.joda.time.DateTimeZone.UTC; import static org.joda.time.Duration.millis; import google.registry.util.Clock; +import java.time.Instant; import java.util.concurrent.atomic.AtomicLong; import javax.annotation.concurrent.ThreadSafe; import org.joda.time.DateTime; @@ -54,6 +55,11 @@ public final class FakeClock implements Clock { return new DateTime(currentTimeMillis.addAndGet(autoIncrementStepMs), UTC); } + @Override + public Instant now() { + return Instant.ofEpochMilli(currentTimeMillis.addAndGet(autoIncrementStepMs)); + } + /** * Sets the increment applied to the clock whenever it is queried. The increment is zero by * default: the clock is left unchanged when queried. diff --git a/core/src/main/java/google/registry/batch/BulkDomainTransferAction.java b/core/src/main/java/google/registry/batch/BulkDomainTransferAction.java index 990428edd..b3bcc419d 100644 --- a/core/src/main/java/google/registry/batch/BulkDomainTransferAction.java +++ b/core/src/main/java/google/registry/batch/BulkDomainTransferAction.java @@ -17,6 +17,7 @@ package google.registry.batch; import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8; import static google.registry.flows.FlowUtils.marshalWithLenientRetry; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; +import static google.registry.util.DateTimeUtils.END_INSTANT; 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; @@ -39,7 +40,6 @@ import google.registry.request.Parameter; import google.registry.request.Response; import google.registry.request.auth.Auth; import google.registry.request.lock.LockHandler; -import google.registry.util.DateTimeUtils; import jakarta.inject.Inject; import jakarta.inject.Named; import java.util.Optional; @@ -212,7 +212,7 @@ public class BulkDomainTransferAction implements Runnable { private boolean shouldSkipDomain(String domainName) { Optional maybeDomain = - ForeignKeyUtils.loadResource(Domain.class, domainName, tm().getTransactionTime()); + ForeignKeyUtils.loadResource(Domain.class, domainName, tm().getTxTime()); if (maybeDomain.isEmpty()) { logger.atWarning().log("Domain '%s' was already deleted", domainName); missingDomains++; @@ -232,7 +232,7 @@ public class BulkDomainTransferAction implements Runnable { return true; } if (domain.getStatusValues().contains(StatusValue.PENDING_DELETE) - || !domain.getDeletionTime().equals(DateTimeUtils.END_OF_TIME)) { + || !domain.getDeletionTime().equals(END_INSTANT)) { logger.atWarning().log("Domain '%s' is in PENDING_DELETE", domainName); pendingDelete++; return true; diff --git a/core/src/main/java/google/registry/batch/DeleteExpiredDomainsAction.java b/core/src/main/java/google/registry/batch/DeleteExpiredDomainsAction.java index 528136034..a23d5ce17 100644 --- a/core/src/main/java/google/registry/batch/DeleteExpiredDomainsAction.java +++ b/core/src/main/java/google/registry/batch/DeleteExpiredDomainsAction.java @@ -18,6 +18,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8; import static google.registry.flows.FlowUtils.marshalWithLenientRetry; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; +import static google.registry.util.DateTimeUtils.END_INSTANT; import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.ResourceUtils.readResourceUtf8; import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; @@ -177,7 +178,7 @@ public class DeleteExpiredDomainsAction implements Runnable { "Failed to delete domain %s because of its autorenew end time: %s.", transDomain.getDomainName(), transDomain.getAutorenewEndTime()); return Optional.empty(); - } else if (domain.getDeletionTime().isBefore(END_OF_TIME)) { + } else if (domain.getDeletionTime().isBefore(END_INSTANT)) { logger.atSevere().log( "Failed to delete domain %s because it was already deleted on %s.", transDomain.getDomainName(), transDomain.getDeletionTime()); diff --git a/core/src/main/java/google/registry/batch/RelockDomainAction.java b/core/src/main/java/google/registry/batch/RelockDomainAction.java index f9a5ab5be..010eef40f 100644 --- a/core/src/main/java/google/registry/batch/RelockDomainAction.java +++ b/core/src/main/java/google/registry/batch/RelockDomainAction.java @@ -188,7 +188,7 @@ public class RelockDomainAction implements Runnable { "Domain %s has a pending delete.", domainName); checkArgument( - !DateTimeUtils.isAtOrAfter(tm().getTransactionTime(), domain.getDeletionTime()), + !DateTimeUtils.isAtOrAfter(tm().getTxTime(), domain.getDeletionTime()), "Domain %s has been deleted.", domainName); checkArgument( diff --git a/core/src/main/java/google/registry/beam/billing/ExpandBillingRecurrencesPipeline.java b/core/src/main/java/google/registry/beam/billing/ExpandBillingRecurrencesPipeline.java index 193103c69..1bfcc1c48 100644 --- a/core/src/main/java/google/registry/beam/billing/ExpandBillingRecurrencesPipeline.java +++ b/core/src/main/java/google/registry/beam/billing/ExpandBillingRecurrencesPipeline.java @@ -24,6 +24,7 @@ import static google.registry.util.CollectionUtils.union; import static google.registry.util.DateTimeUtils.START_OF_TIME; import static google.registry.util.DateTimeUtils.earliestOf; import static google.registry.util.DateTimeUtils.latestOf; +import static google.registry.util.DateTimeUtils.toInstant; import static org.apache.beam.sdk.values.TypeDescriptors.voids; import com.google.common.collect.ImmutableMap; @@ -372,7 +373,7 @@ public class ExpandBillingRecurrencesPipeline implements Serializable { // during ARGP). // // See: DomainFlowUtils#createCancellingRecords - domain.getDeletionTime().isBefore(billingTime) + domain.getDeletionTime().isBefore(toInstant(billingTime)) ? ImmutableSet.of() : ImmutableSet.of( DomainTransactionRecord.create( diff --git a/core/src/main/java/google/registry/flows/ResourceFlowUtils.java b/core/src/main/java/google/registry/flows/ResourceFlowUtils.java index 122d5ded3..101bafa96 100644 --- a/core/src/main/java/google/registry/flows/ResourceFlowUtils.java +++ b/core/src/main/java/google/registry/flows/ResourceFlowUtils.java @@ -16,6 +16,7 @@ package google.registry.flows; import static com.google.common.collect.Sets.intersection; import static google.registry.model.EppResourceUtils.isLinked; +import static google.registry.util.DateTimeUtils.toInstant; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; @@ -44,6 +45,7 @@ import google.registry.model.eppcommon.StatusValue; import google.registry.model.host.Host; import google.registry.model.transfer.TransferStatus; import google.registry.persistence.VKey; +import java.time.Instant; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -89,6 +91,11 @@ public final class ResourceFlowUtils { public static R loadAndVerifyExistence( Class clazz, String targetId, DateTime now) throws ResourceDoesNotExistException { + return loadAndVerifyExistence(clazz, targetId, toInstant(now)); + } + + public static R loadAndVerifyExistence( + Class clazz, String targetId, Instant now) throws ResourceDoesNotExistException { return verifyExistence(clazz, targetId, ForeignKeyUtils.loadResource(clazz, targetId, now)); } @@ -197,8 +204,8 @@ public final class ResourceFlowUtils { * * @param domain is the domain already projected at approvalTime */ - public static DateTime computeExDateForApprovalTime( - DomainBase domain, DateTime approvalTime, Period period) { + public static Instant computeExDateForApprovalTime( + DomainBase domain, Instant approvalTime, Period period) { boolean inAutoRenew = domain.getGracePeriodStatuses().contains(GracePeriodStatus.AUTO_RENEW); // inAutoRenew is set to false if the period is zero because a zero-period transfer should not // subsume an autorenew. diff --git a/core/src/main/java/google/registry/flows/domain/DomainDeleteFlow.java b/core/src/main/java/google/registry/flows/domain/DomainDeleteFlow.java index 6414aa93b..9cb5a7c4b 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainDeleteFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainDeleteFlow.java @@ -236,7 +236,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging } // Cancel any grace periods that were still active, and set the expiration time accordingly. - DateTime newExpirationTime = existingDomain.getRegistrationExpirationTime(); + DateTime newExpirationTime = existingDomain.getRegistrationExpirationDateTime(); for (GracePeriod gracePeriod : existingDomain.getGracePeriods()) { // No cancellation is written if the grace period was not for a billable event. if (gracePeriod.hasBillingEvent()) { @@ -289,7 +289,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging flowCustomLogic.beforeResponse( BeforeResponseParameters.newBuilder() .setResultCode( - newDomain.getDeletionTime().isAfter(now) + newDomain.getDeletionDateTime().isAfter(now) ? SUCCESS_WITH_ACTION_PENDING : SUCCESS) .setResponseExtensions( diff --git a/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java b/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java index fb6b358dc..3a2fdd196 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java +++ b/core/src/main/java/google/registry/flows/domain/DomainFlowUtils.java @@ -503,7 +503,7 @@ public class DomainFlowUtils { .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) .setTargetId(domain.getDomainName()) .setRegistrarId(domain.getCurrentSponsorRegistrarId()) - .setEventTime(domain.getRegistrationExpirationTime()); + .setEventTime(domain.getRegistrationExpirationDateTime()); } /** @@ -514,7 +514,7 @@ public class DomainFlowUtils { return new Autorenew.Builder() .setTargetId(domain.getDomainName()) .setRegistrarId(domain.getCurrentSponsorRegistrarId()) - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setMsg("Domain was auto-renewed."); } @@ -658,7 +658,7 @@ public class DomainFlowUtils { // process, don't count as expired for the purposes of requiring an added year of renewal on // restore because they can't be restored in the first place. boolean isExpired = - domain.isPresent() && domain.get().getRegistrationExpirationTime().isBefore(now); + domain.isPresent() && domain.get().getRegistrationExpirationDateTime().isBefore(now); fees = pricingLogic.getRestorePrice(tld, domainNameString, now, isExpired).getFees(); } case TRANSFER -> { diff --git a/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java b/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java index 15a9b1b48..8815d2ca7 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainInfoFlow.java @@ -122,8 +122,8 @@ public final class DomainInfoFlow implements MutatingFlow { .setNameservers( hostsRequest.requestDelegated() ? domain.loadNameserverHostNames() : null) .setCreationTime(domain.getCreationTime()) - .setLastEppUpdateTime(domain.getLastEppUpdateTime()) - .setRegistrationExpirationTime(domain.getRegistrationExpirationTime()) + .setLastEppUpdateTime(domain.getLastEppUpdateDateTime()) + .setRegistrationExpirationTime(domain.getRegistrationExpirationDateTime()) .setLastTransferTime(domain.getLastTransferTime()); // If authInfo is non-null, then the caller is authorized to see the full information since we diff --git a/core/src/main/java/google/registry/flows/domain/DomainRenewFlow.java b/core/src/main/java/google/registry/flows/domain/DomainRenewFlow.java index ec7d982ca..32278bf53 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainRenewFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainRenewFlow.java @@ -191,7 +191,7 @@ public final class DomainRenewFlow implements MutatingFlow { existingDomain = maybeApplyBulkPricingRemovalToken(existingDomain, allocationToken); DateTime newExpirationTime = - leapSafeAddYears(existingDomain.getRegistrationExpirationTime(), years); // Uncapped + leapSafeAddYears(existingDomain.getRegistrationExpirationDateTime(), years); // Uncapped validateRegistrationPeriod(now, newExpirationTime); Optional feeRenew = eppInput.getSingleExtension(FeeRenewCommandExtension.class); @@ -328,8 +328,9 @@ public final class DomainRenewFlow implements MutatingFlow { // We only allow __REMOVE_BULK_PRICING__ token on bulk pricing domains for now verifyBulkTokenAllowedOnDomain(existingDomain, allocationToken); // If the date they specify doesn't match the expiration, fail. (This is an idempotence check). - if (!command.getCurrentExpirationDate().equals( - existingDomain.getRegistrationExpirationTime().toLocalDate())) { + if (!command + .getCurrentExpirationDate() + .equals(existingDomain.getRegistrationExpirationDateTime().toLocalDate())) { throw new IncorrectCurrentExpirationDateException(); } } diff --git a/core/src/main/java/google/registry/flows/domain/DomainRestoreRequestFlow.java b/core/src/main/java/google/registry/flows/domain/DomainRestoreRequestFlow.java index 29fc413d3..3ec154e7f 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainRestoreRequestFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainRestoreRequestFlow.java @@ -138,7 +138,7 @@ public final class DomainRestoreRequestFlow implements MutatingFlow { Update command = (Update) resourceCommand; DateTime now = tm().getTransactionTime(); Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now); - boolean isExpired = existingDomain.getRegistrationExpirationTime().isBefore(now); + boolean isExpired = existingDomain.getRegistrationExpirationDateTime().isBefore(now); FeesAndCredits feesAndCredits = pricingLogic.getRestorePrice(Tld.get(existingDomain.getTld()), targetId, now, isExpired); Optional feeUpdate = @@ -149,7 +149,7 @@ public final class DomainRestoreRequestFlow implements MutatingFlow { ImmutableSet.Builder entitiesToInsert = new ImmutableSet.Builder<>(); DateTime newExpirationTime = - existingDomain.getRegistrationExpirationTime().plusYears(isExpired ? 1 : 0); + existingDomain.getRegistrationExpirationDateTime().plusYears(isExpired ? 1 : 0); // Restore the expiration time on the deleted domain, except if that's already passed, then add // a year and bill for it immediately, with no grace period. if (isExpired) { diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java index cea6f6568..7b7eb47b3 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferApproveFlow.java @@ -33,6 +33,8 @@ import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_ import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.util.CollectionUtils.union; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.toDateTime; +import static google.registry.util.DateTimeUtils.toInstant; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -193,7 +195,9 @@ public final class DomainTransferApproveFlow implements MutatingFlow { updateAutorenewRecurrenceEndTime( existingDomain, existingBillingRecurrence, now, domainHistoryId); DateTime newExpirationTime = - computeExDateForApprovalTime(existingDomain, now, transferData.getTransferPeriod()); + toDateTime( + computeExDateForApprovalTime( + existingDomain, toInstant(now), transferData.getTransferPeriod())); // Create a new autorenew event starting at the expiration time. BillingRecurrence autorenewEvent = new BillingRecurrence.Builder() @@ -268,8 +272,11 @@ public final class DomainTransferApproveFlow implements MutatingFlow { // been implicitly server approved. tm().delete(existingDomain.getTransferData().getServerApproveEntities()); return responseBuilder - .setResData(createTransferResponse( - targetId, newDomain.getTransferData(), newDomain.getRegistrationExpirationTime())) + .setResData( + createTransferResponse( + targetId, + newDomain.getTransferData(), + newDomain.getRegistrationExpirationDateTime())) .build(); } diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java index b562422b6..3e002f60c 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferQueryFlow.java @@ -15,15 +15,17 @@ package google.registry.flows.domain; import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn; +import static google.registry.flows.ResourceFlowUtils.computeExDateForApprovalTime; import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence; import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo; import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse; +import static google.registry.util.DateTimeUtils.toDateTime; +import static google.registry.util.DateTimeUtils.toInstant; import google.registry.flows.EppException; import google.registry.flows.ExtensionManager; import google.registry.flows.FlowModule.RegistrarId; import google.registry.flows.FlowModule.TargetId; -import google.registry.flows.ResourceFlowUtils; import google.registry.flows.TransactionalFlow; import google.registry.flows.annotations.ReportingSpec; import google.registry.flows.exceptions.NoTransferHistoryToQueryException; @@ -88,11 +90,12 @@ public final class DomainTransferQueryFlow implements TransactionalFlow { } DateTime newExpirationTime = null; if (transferData.getTransferStatus().isApproved()) { - newExpirationTime = transferData.getTransferredRegistrationExpirationTime(); + newExpirationTime = transferData.getTransferredRegistrationExpirationDateTime(); } else if (transferData.getTransferStatus().equals(TransferStatus.PENDING)) { newExpirationTime = - ResourceFlowUtils.computeExDateForApprovalTime( - domain, now, domain.getTransferData().getTransferPeriod()); + toDateTime( + computeExDateForApprovalTime( + domain, toInstant(now), domain.getTransferData().getTransferPeriod())); } return responseBuilder .setResData(createTransferResponse(targetId, transferData, newExpirationTime)) diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferRejectFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferRejectFlow.java index 351ee5e18..39b25d8d5 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferRejectFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferRejectFlow.java @@ -32,6 +32,7 @@ import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_ import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.util.CollectionUtils.union; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.toDateTime; import com.google.common.collect.ImmutableSet; import google.registry.flows.EppException; @@ -53,6 +54,7 @@ import google.registry.model.reporting.IcannReportingTypes.ActivityReportField; import google.registry.model.tld.Tld; import google.registry.model.transfer.TransferStatus; import jakarta.inject.Inject; +import java.time.Instant; import java.util.Optional; import org.joda.time.DateTime; @@ -92,7 +94,7 @@ public final class DomainTransferRejectFlow implements MutatingFlow { extensionManager.register(MetadataExtension.class); validateRegistrarIsLoggedIn(registrarId); extensionManager.validate(); - DateTime now = tm().getTransactionTime(); + Instant now = tm().getTxTime(); Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now); Tld tld = Tld.get(existingDomain.getTld()); HistoryEntryId domainHistoryId = createHistoryEntryId(existingDomain); @@ -107,13 +109,14 @@ public final class DomainTransferRejectFlow implements MutatingFlow { checkAllowedAccessToTld(registrarId, existingDomain.getTld()); } Domain newDomain = - denyPendingTransfer(existingDomain, TransferStatus.CLIENT_REJECTED, now, registrarId); - DomainHistory domainHistory = buildDomainHistory(newDomain, tld, now); + denyPendingTransfer( + existingDomain, TransferStatus.CLIENT_REJECTED, toDateTime(now), registrarId); + DomainHistory domainHistory = buildDomainHistory(newDomain, tld, toDateTime(now)); tm().update(newDomain); tm().insertAll( domainHistory, createGainingTransferPollMessage( - targetId, newDomain.getTransferData(), null, now, domainHistoryId)); + targetId, newDomain.getTransferData(), null, toDateTime(now), domainHistoryId)); // Reopen the autorenew event and poll message that we closed for the implicit transfer. This // may end up recreating the poll message if it was deleted upon the transfer request. BillingRecurrence existingBillingRecurrence = diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java b/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java index db7ce17bf..ad711a9b7 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferRequestFlow.java @@ -35,6 +35,8 @@ 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 google.registry.util.DateTimeUtils.toInstant; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -80,6 +82,7 @@ import google.registry.model.transfer.DomainTransferData.TransferServerApproveEn import google.registry.model.transfer.TransferResponse.DomainTransferResponse; import google.registry.model.transfer.TransferStatus; import jakarta.inject.Inject; +import java.time.Instant; import java.util.Optional; import org.joda.time.DateTime; @@ -230,7 +233,9 @@ public final class DomainTransferRequestFlow implements MutatingFlow { Domain domainAtTransferTime = existingDomain.cloneProjectedAtTime(automaticTransferTime); // The new expiration time if there is a server approval. DateTime serverApproveNewExpirationTime = - computeExDateForApprovalTime(domainAtTransferTime, automaticTransferTime, period); + toDateTime( + computeExDateForApprovalTime( + domainAtTransferTime, toInstant(automaticTransferTime), period)); // Create speculative entities in anticipation of an automatic server approval. ImmutableSet serverApproveEntities = createTransferServerApproveEntities( @@ -287,7 +292,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow { tm().insertAll(domainHistory, requestPollMessage); return responseBuilder .setResultFromCode(SUCCESS_WITH_ACTION_PENDING) - .setResData(createResponse(period, existingDomain, newDomain, now)) + .setResData(createResponse(period, existingDomain, newDomain, toInstant(now))) .setExtensions(createResponseExtensions(feesAndCredits, feeTransfer)) .build(); } @@ -375,14 +380,14 @@ public final class DomainTransferRequestFlow implements MutatingFlow { } private DomainTransferResponse createResponse( - Period period, Domain existingDomain, Domain newDomain, DateTime now) { + Period period, Domain existingDomain, Domain newDomain, Instant now) { // If the registration were approved this instant, this is what the new expiration would be, // because we cap at 10 years from the moment of approval. This is different from the server // approval new expiration time, which is capped at 10 years from the server approve time. - DateTime approveNowExtendedRegistrationTime = + Instant approveNowExtendedRegistrationTime = computeExDateForApprovalTime(existingDomain, now, period); return createTransferResponse( - targetId, newDomain.getTransferData(), approveNowExtendedRegistrationTime); + targetId, newDomain.getTransferData(), toDateTime(approveNowExtendedRegistrationTime)); } private static ImmutableList createResponseExtensions( diff --git a/core/src/main/java/google/registry/flows/domain/DomainTransferUtils.java b/core/src/main/java/google/registry/flows/domain/DomainTransferUtils.java index 60000b224..f9c0ab163 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainTransferUtils.java +++ b/core/src/main/java/google/registry/flows/domain/DomainTransferUtils.java @@ -184,7 +184,7 @@ public final class DomainTransferUtils { HistoryEntryId domainHistoryId) { return new PollMessage.OneTime.Builder() .setRegistrarId(transferData.getGainingRegistrarId()) - .setEventTime(transferData.getPendingTransferExpirationTime()) + .setEventTime(transferData.getPendingTransferExpirationDateTime()) .setMsg(transferData.getTransferStatus().getMessage()) .setResponseData( ImmutableList.of( @@ -206,7 +206,7 @@ public final class DomainTransferUtils { HistoryEntryId domainHistoryId) { return new PollMessage.OneTime.Builder() .setRegistrarId(transferData.getLosingRegistrarId()) - .setEventTime(transferData.getPendingTransferExpirationTime()) + .setEventTime(transferData.getPendingTransferExpirationDateTime()) .setMsg(transferData.getTransferStatus().getMessage()) .setResponseData( ImmutableList.of( @@ -224,7 +224,7 @@ public final class DomainTransferUtils { .setDomainName(targetId) .setGainingRegistrarId(transferData.getGainingRegistrarId()) .setLosingRegistrarId(transferData.getLosingRegistrarId()) - .setPendingTransferExpirationTime(transferData.getPendingTransferExpirationTime()) + .setPendingTransferExpirationTime(transferData.getPendingTransferExpirationDateTime()) .setTransferRequestTime(transferData.getTransferRequestTime()) .setTransferStatus(transferData.getTransferStatus()) .setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime) diff --git a/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java b/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java index 16f89e57b..752c194eb 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainUpdateFlow.java @@ -281,7 +281,7 @@ public final class DomainUpdateFlow implements MutatingFlow { if (superuserExt.get().getAutorenews().isPresent()) { boolean autorenews = superuserExt.get().getAutorenews().get(); domainBuilder.setAutorenewEndTime( - Optional.ofNullable(autorenews ? null : domain.getRegistrationExpirationTime())); + Optional.ofNullable(autorenews ? null : domain.getRegistrationExpirationDateTime())); } } return domainBuilder.build(); diff --git a/core/src/main/java/google/registry/flows/host/HostInfoFlow.java b/core/src/main/java/google/registry/flows/host/HostInfoFlow.java index af5a5b258..4647ade89 100644 --- a/core/src/main/java/google/registry/flows/host/HostInfoFlow.java +++ b/core/src/main/java/google/registry/flows/host/HostInfoFlow.java @@ -99,7 +99,7 @@ public final class HostInfoFlow implements TransactionalFlow { .setCreationRegistrarId(host.getCreationRegistrarId()) .setCreationTime(host.getCreationTime()) .setLastEppUpdateRegistrarId(host.getLastEppUpdateRegistrarId()) - .setLastEppUpdateTime(host.getLastEppUpdateTime()) + .setLastEppUpdateTime(host.getLastEppUpdateDateTime()) .build()) .build(); } diff --git a/core/src/main/java/google/registry/model/EppResource.java b/core/src/main/java/google/registry/model/EppResource.java index ee5c376ef..f8007038f 100644 --- a/core/src/main/java/google/registry/model/EppResource.java +++ b/core/src/main/java/google/registry/model/EppResource.java @@ -25,6 +25,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory. import static google.registry.util.CollectionUtils.nullToEmpty; import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.toInstant; import com.github.benmanes.caffeine.cache.CacheLoader; import com.github.benmanes.caffeine.cache.LoadingCache; @@ -45,6 +46,7 @@ import jakarta.persistence.Enumerated; import jakarta.persistence.MappedSuperclass; import jakarta.persistence.Transient; import java.time.Duration; +import java.time.Instant; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -163,10 +165,15 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B return creationRegistrarId; } - public DateTime getLastEppUpdateTime() { + @Deprecated + public DateTime getLastEppUpdateDateTime() { return lastEppUpdateTime; } + public Instant getLastEppUpdateTime() { + return toInstant(lastEppUpdateTime); + } + public String getLastEppUpdateRegistrarId() { return lastEppUpdateRegistrarId; } @@ -185,13 +192,22 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B return nullToEmptyImmutableCopy(statuses); } - public DateTime getDeletionTime() { + @Deprecated + public DateTime getDeletionDateTime() { return deletionTime; } + public Instant getDeletionTime() { + return toInstant(deletionTime); + } + /** Return a clone of the resource with timed status values modified using the given time. */ + @Deprecated public abstract EppResource cloneProjectedAtTime(DateTime now); + /** Return a clone of the resource with timed status values modified using the given time. */ + public abstract EppResource cloneProjectedAtInstant(Instant now); + /** Get the foreign key string for this resource. */ public abstract String getForeignKey(); diff --git a/core/src/main/java/google/registry/model/EppResourceUtils.java b/core/src/main/java/google/registry/model/EppResourceUtils.java index 4af8c6ccf..c64591ce4 100644 --- a/core/src/main/java/google/registry/model/EppResourceUtils.java +++ b/core/src/main/java/google/registry/model/EppResourceUtils.java @@ -34,6 +34,7 @@ import google.registry.model.transfer.DomainTransferData; import google.registry.model.transfer.TransferStatus; import google.registry.persistence.VKey; import jakarta.persistence.Query; +import java.time.Instant; import java.util.Comparator; import java.util.function.Function; import javax.annotation.Nullable; @@ -83,7 +84,7 @@ public final class EppResourceUtils { * exclusive, which happily maps to the behavior of Interval. */ private static Interval getLifetime(EppResource resource) { - return new Interval(resource.getCreationTime(), resource.getDeletionTime()); + return new Interval(resource.getCreationTime(), resource.getDeletionDateTime()); } public static boolean isActive(EppResource resource, DateTime time) { @@ -108,7 +109,7 @@ public final class EppResourceUtils { builder .removeStatusValue(StatusValue.PENDING_TRANSFER) .setTransferData(transferDataBuilder.build()) - .setLastTransferTime(transferData.getPendingTransferExpirationTime()) + .setLastTransferTime(transferData.getPendingTransferExpirationDateTime()) .setPersistedCurrentSponsorRegistrarId(transferData.getGainingRegistrarId()); } @@ -120,10 +121,10 @@ public final class EppResourceUtils { * */ public static void projectResourceOntoBuilderAtTime( - DomainBase domain, DomainBase.Builder builder, DateTime now) { + DomainBase domain, DomainBase.Builder builder, Instant now) { DomainTransferData transferData = domain.getTransferData(); // If there's a pending transfer that has expired, process it. - DateTime expirationTime = transferData.getPendingTransferExpirationTime(); + Instant expirationTime = transferData.getPendingTransferExpirationTime(); if (TransferStatus.PENDING.equals(transferData.getTransferStatus()) && isBeforeOrAt(expirationTime, now)) { setAutomaticTransferSuccessProperties(builder, transferData); diff --git a/core/src/main/java/google/registry/model/ForeignKeyUtils.java b/core/src/main/java/google/registry/model/ForeignKeyUtils.java index 9a0b08006..ba1ab670b 100644 --- a/core/src/main/java/google/registry/model/ForeignKeyUtils.java +++ b/core/src/main/java/google/registry/model/ForeignKeyUtils.java @@ -35,6 +35,7 @@ import google.registry.persistence.VKey; import google.registry.persistence.transaction.JpaTransactionManager; import google.registry.util.NonFinalForTesting; import java.time.Duration; +import java.time.Instant; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; @@ -81,6 +82,7 @@ public final class ForeignKeyUtils { *

Returns null if no resource with this foreign key was ever created or if the most recently * created resource was deleted before time "now". */ + @Deprecated public static Optional loadResource( Class clazz, String foreignKey, DateTime now) { // Note: no need to project to "now" because loadResources already does @@ -88,6 +90,19 @@ public final class ForeignKeyUtils { loadResources(clazz, ImmutableList.of(foreignKey), now).get(foreignKey)); } + /** + * Loads an {@link EppResource} from the database by foreign key. + * + *

Returns null if no resource with this foreign key was ever created or if the most recently + * created resource was deleted before time "now". + */ + public static Optional loadResource( + Class clazz, String foreignKey, Instant now) { + // Note: no need to project to "now" because loadResources already does + return Optional.ofNullable( + loadResources(clazz, ImmutableList.of(foreignKey), now).get(foreignKey)); + } + /** * Load a map of {@link String} foreign keys to {@link VKey}s to {@link EppResource} that are * active at or after the specified moment in time. @@ -110,13 +125,29 @@ public final class ForeignKeyUtils { * or has been soft-deleted. */ @SuppressWarnings("unchecked") + @Deprecated public static ImmutableMap loadResources( Class clazz, Collection foreignKeys, DateTime now) { return loadMostRecentResourceObjects(clazz, foreignKeys, false).entrySet().stream() - .filter(e -> now.isBefore(e.getValue().getDeletionTime())) + .filter(e -> now.isBefore(e.getValue().getDeletionDateTime())) .collect(toImmutableMap(Entry::getKey, e -> (E) e.getValue().cloneProjectedAtTime(now))); } + /** + * Load a map of {@link String} foreign keys to the {@link EppResource} that are active at or + * after the specified moment in time. + * + *

The returned map will omit any foreign keys for which the {@link EppResource} doesn't exist + * or has been soft-deleted. + */ + @SuppressWarnings("unchecked") + public static ImmutableMap loadResources( + Class clazz, Collection foreignKeys, Instant now) { + return loadMostRecentResourceObjects(clazz, foreignKeys, false).entrySet().stream() + .filter(e -> now.isBefore(e.getValue().getDeletionTime())) + .collect(toImmutableMap(Entry::getKey, e -> (E) e.getValue().cloneProjectedAtInstant(now))); + } + /** * Helper method to load {@link VKey}s to all the most recent {@link EppResource}s for the given * foreign keys, regardless of whether they have been soft-deleted. @@ -397,7 +428,7 @@ public final class ForeignKeyUtils { return (Optional) foreignKeyToResourceCache .get(VKey.create(clazz, foreignKey)) - .filter(e -> now.isBefore(e.getDeletionTime())) + .filter(e -> now.isBefore(e.getDeletionDateTime())) .map(e -> e.cloneProjectedAtTime(now)); } } diff --git a/core/src/main/java/google/registry/model/ResourceTransferUtils.java b/core/src/main/java/google/registry/model/ResourceTransferUtils.java index c6a700266..7d4bc12c6 100644 --- a/core/src/main/java/google/registry/model/ResourceTransferUtils.java +++ b/core/src/main/java/google/registry/model/ResourceTransferUtils.java @@ -50,11 +50,11 @@ public final class ResourceTransferUtils { .setDomainName(domain.getForeignKey()) .setExtendedRegistrationExpirationTime( ADD_EXDATE_STATUSES.contains(transferData.getTransferStatus()) - ? transferData.getTransferredRegistrationExpirationTime() + ? transferData.getTransferredRegistrationExpirationDateTime() : null) .setGainingRegistrarId(transferData.getGainingRegistrarId()) .setLosingRegistrarId(transferData.getLosingRegistrarId()) - .setPendingTransferExpirationTime(transferData.getPendingTransferExpirationTime()) + .setPendingTransferExpirationTime(transferData.getPendingTransferExpirationDateTime()) .setTransferRequestTime(transferData.getTransferRequestTime()) .setTransferStatus(transferData.getTransferStatus()) .build(); diff --git a/core/src/main/java/google/registry/model/billing/BillingCancellation.java b/core/src/main/java/google/registry/model/billing/BillingCancellation.java index 1adc3a8f1..045e87b95 100644 --- a/core/src/main/java/google/registry/model/billing/BillingCancellation.java +++ b/core/src/main/java/google/registry/model/billing/BillingCancellation.java @@ -104,7 +104,7 @@ public class BillingCancellation extends BillingBase { .setRegistrarId(gracePeriod.getRegistrarId()) .setEventTime(eventTime) // The charge being cancelled will take place at the grace period's expiration time. - .setBillingTime(gracePeriod.getExpirationTime()) + .setBillingTime(gracePeriod.getExpirationDateTime()) .setDomainHistoryId(domainHistoryId); // Set the grace period's billing event using the appropriate Cancellation builder method. if (gracePeriod.getBillingEvent() != null) { diff --git a/core/src/main/java/google/registry/model/domain/Domain.java b/core/src/main/java/google/registry/model/domain/Domain.java index 9a9715243..cff00f4db 100644 --- a/core/src/main/java/google/registry/model/domain/Domain.java +++ b/core/src/main/java/google/registry/model/domain/Domain.java @@ -14,6 +14,8 @@ package google.registry.model.domain; +import static google.registry.util.DateTimeUtils.toInstant; + import google.registry.model.EppResource; import google.registry.model.EppResource.ForeignKeyedEppResource; import google.registry.model.annotations.ExternalMessagingName; @@ -37,6 +39,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinTable; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; +import java.time.Instant; import java.util.Set; import org.hibernate.Hibernate; import org.joda.time.DateTime; @@ -153,6 +156,11 @@ public class Domain extends DomainBase implements ForeignKeyedEppResource { @Override public Domain cloneProjectedAtTime(final DateTime now) { + return cloneDomainProjectedAtTime(this, toInstant(now)); + } + + @Override + public Domain cloneProjectedAtInstant(final Instant now) { return cloneDomainProjectedAtTime(this, now); } diff --git a/core/src/main/java/google/registry/model/domain/DomainBase.java b/core/src/main/java/google/registry/model/domain/DomainBase.java index 573f5d213..1f051b567 100644 --- a/core/src/main/java/google/registry/model/domain/DomainBase.java +++ b/core/src/main/java/google/registry/model/domain/DomainBase.java @@ -32,9 +32,14 @@ import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.earliestOf; import static google.registry.util.DateTimeUtils.isBeforeOrAt; import static google.registry.util.DateTimeUtils.leapSafeAddYears; +import static google.registry.util.DateTimeUtils.plusYears; +import static google.registry.util.DateTimeUtils.toDateTime; +import static google.registry.util.DateTimeUtils.toInstant; import static google.registry.util.DomainNameUtils.canonicalizeHostname; import static google.registry.util.DomainNameUtils.getTldFromDomainName; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; +import static java.time.ZoneOffset.UTC; +import static java.time.temporal.ChronoUnit.YEARS; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; @@ -79,13 +84,13 @@ import jakarta.persistence.Enumerated; import jakarta.persistence.Id; import jakarta.persistence.MappedSuperclass; import jakarta.persistence.Transient; +import java.time.Instant; import java.util.HashSet; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; import org.hibernate.collection.spi.PersistentSet; import org.joda.time.DateTime; -import org.joda.time.Interval; /** * A persistable domain resource including mutable and non-mutable fields. @@ -285,10 +290,15 @@ public class DomainBase extends EppResource { return nullToEmptyImmutableCopy(subordinateHosts); } - public DateTime getRegistrationExpirationTime() { + @Deprecated + public DateTime getRegistrationExpirationDateTime() { return registrationExpirationTime; } + public Instant getRegistrationExpirationTime() { + return toInstant(registrationExpirationTime); + } + public VKey getDeletePollMessage() { return deletePollMessage; } @@ -436,6 +446,11 @@ public class DomainBase extends EppResource { @Override public DomainBase cloneProjectedAtTime(final DateTime now) { + return cloneDomainProjectedAtTime(this, toInstant(now)); + } + + @Override + public DomainBase cloneProjectedAtInstant(final Instant now) { return cloneDomainProjectedAtTime(this, now); } @@ -444,9 +459,9 @@ public class DomainBase extends EppResource { * parallels the logic in {@code DomainTransferApproveFlow} which handles explicit client * approvals. */ - static T cloneDomainProjectedAtTime(T domain, DateTime now) { + static T cloneDomainProjectedAtTime(T domain, Instant now) { DomainTransferData transferData = domain.getTransferData(); - DateTime transferExpirationTime = transferData.getPendingTransferExpirationTime(); + Instant transferExpirationTime = transferData.getPendingTransferExpirationTime(); // If there's a pending transfer that has expired, handle it. if (TransferStatus.PENDING.equals(transferData.getTransferStatus()) @@ -459,7 +474,7 @@ public class DomainBase extends EppResource { T domainAtTransferTime = cloneDomainProjectedAtTime(domain, transferExpirationTime.minusMillis(1)); - DateTime expirationDate = transferData.getTransferredRegistrationExpirationTime(); + Instant expirationDate = transferData.getTransferredRegistrationExpirationTime(); if (expirationDate == null) { // Extend the registration by the correct number of years from the expiration time // that was current on the domain right before the transfer, capped at 10 years from @@ -478,7 +493,7 @@ public class DomainBase extends EppResource { Builder builder = domainAtTransferTime .asBuilder() - .setRegistrationExpirationTime(expirationDate) + .setRegistrationExpirationTime(toDateTime(expirationDate)) // Set the speculatively-written new autorenew events as the domain's autorenew // events. .setAutorenewBillingEvent(transferData.getServerApproveAutorenewEvent()) @@ -492,8 +507,8 @@ public class DomainBase extends EppResource { GracePeriod.create( GracePeriodStatus.TRANSFER, domain.getRepoId(), - transferExpirationTime.plus( - Tld.get(domain.getTld()).getTransferGracePeriodLength()), + toDateTime(transferExpirationTime) + .plus(Tld.get(domain.getTld()).getTransferGracePeriodLength()), transferData.getGainingRegistrarId(), transferData.getServerApproveBillingEvent()))); } else { @@ -503,32 +518,33 @@ public class DomainBase extends EppResource { // Set all remaining transfer properties. setAutomaticTransferSuccessProperties(builder, transferData); builder - .setLastEppUpdateTime(transferExpirationTime) + .setLastEppUpdateTime(toDateTime(transferExpirationTime)) .setLastEppUpdateRegistrarId(transferData.getGainingRegistrarId()); // Finish projecting to now. - return (T) builder.build().cloneProjectedAtTime(now); + return (T) builder.build().cloneProjectedAtInstant(now); } - Optional newLastEppUpdateTime = Optional.empty(); + Optional newLastEppUpdateTime = Optional.empty(); // There is no transfer. Do any necessary autorenews for active domains. Builder builder = domain.asBuilder(); if (isBeforeOrAt(domain.getRegistrationExpirationTime(), now) - && END_OF_TIME.equals(domain.getDeletionTime())) { + && END_OF_TIME.equals(domain.getDeletionDateTime())) { // Autorenew by the number of years between the old expiration time and now. - DateTime lastAutorenewTime = + Instant lastAutorenewTime = leapSafeAddYears( domain.getRegistrationExpirationTime(), - new Interval(domain.getRegistrationExpirationTime(), now).toPeriod().getYears()); - DateTime newExpirationTime = lastAutorenewTime.plusYears(1); + YEARS.between(domain.getRegistrationExpirationTime().atZone(UTC), now.atZone(UTC))); + Instant newExpirationTime = plusYears(lastAutorenewTime, 1); builder - .setRegistrationExpirationTime(newExpirationTime) + .setRegistrationExpirationTime(toDateTime(newExpirationTime)) .addGracePeriod( GracePeriod.createForRecurrence( GracePeriodStatus.AUTO_RENEW, domain.getRepoId(), - lastAutorenewTime.plus(Tld.get(domain.getTld()).getAutoRenewGracePeriodLength()), + toDateTime(lastAutorenewTime) + .plus(Tld.get(domain.getTld()).getAutoRenewGracePeriodLength()), domain.getCurrentSponsorRegistrarId(), domain.getAutorenewBillingEvent())); newLastEppUpdateTime = Optional.of(lastAutorenewTime); @@ -551,10 +567,10 @@ public class DomainBase extends EppResource { // id, so we have to do the comparison instead of having one variable just storing the most // recent time. if (newLastEppUpdateTime.isPresent()) { - if (domain.getLastEppUpdateTime() == null + if (domain.getLastEppUpdateDateTime() == null || newLastEppUpdateTime.get().isAfter(domain.getLastEppUpdateTime())) { builder - .setLastEppUpdateTime(newLastEppUpdateTime.get()) + .setLastEppUpdateTime(toDateTime(newLastEppUpdateTime.get())) .setLastEppUpdateRegistrarId(domain.getCurrentSponsorRegistrarId()); } } @@ -567,8 +583,8 @@ public class DomainBase extends EppResource { } /** Return what the expiration time would be if the given number of years were added to it. */ - public static DateTime extendRegistrationWithCap( - DateTime now, DateTime currentExpirationTime, @Nullable Integer extendedRegistrationYears) { + public static Instant extendRegistrationWithCap( + Instant now, Instant currentExpirationTime, @Nullable Integer extendedRegistrationYears) { // We must cap registration at the max years (aka 10), even if that truncates the last year. return earliestOf( leapSafeAddYears( @@ -826,16 +842,16 @@ public class DomainBase extends EppResource { .setDomainName(domainBase.getDomainName()) .setDeletePollMessage(domainBase.getDeletePollMessage()) .setDsData(domainBase.getDsData()) - .setDeletionTime(domainBase.getDeletionTime()) + .setDeletionTime(domainBase.getDeletionDateTime()) .setGracePeriods(domainBase.getGracePeriods()) .setIdnTableName(domainBase.getIdnTableName()) .setLastTransferTime(domainBase.getLastTransferTime()) .setLaunchNotice(domainBase.getLaunchNotice()) .setLastEppUpdateRegistrarId(domainBase.getLastEppUpdateRegistrarId()) - .setLastEppUpdateTime(domainBase.getLastEppUpdateTime()) + .setLastEppUpdateTime(domainBase.getLastEppUpdateDateTime()) .setNameservers(domainBase.getNameservers()) .setPersistedCurrentSponsorRegistrarId(domainBase.getPersistedCurrentSponsorRegistrarId()) - .setRegistrationExpirationTime(domainBase.getRegistrationExpirationTime()) + .setRegistrationExpirationTime(domainBase.getRegistrationExpirationDateTime()) .setRepoId(domainBase.getRepoId()) .setSmdId(domainBase.getSmdId()) .setSubordinateHosts(domainBase.getSubordinateHosts()) diff --git a/core/src/main/java/google/registry/model/domain/GracePeriodBase.java b/core/src/main/java/google/registry/model/domain/GracePeriodBase.java index a53abe457..cca7742ed 100644 --- a/core/src/main/java/google/registry/model/domain/GracePeriodBase.java +++ b/core/src/main/java/google/registry/model/domain/GracePeriodBase.java @@ -14,6 +14,8 @@ package google.registry.model.domain; +import static google.registry.util.DateTimeUtils.toInstant; + import google.registry.model.ImmutableObject; import google.registry.model.UnsafeSerializable; import google.registry.model.billing.BillingEvent; @@ -30,6 +32,7 @@ import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; import jakarta.persistence.MappedSuperclass; import jakarta.persistence.Transient; +import java.time.Instant; import org.joda.time.DateTime; /** Base class containing common fields and methods for {@link GracePeriod}. */ @@ -90,10 +93,15 @@ public class GracePeriodBase extends ImmutableObject implements UnsafeSerializab return domainRepoId; } - public DateTime getExpirationTime() { + @Deprecated + public DateTime getExpirationDateTime() { return expirationTime; } + public Instant getExpirationTime() { + return toInstant(expirationTime); + } + public String getRegistrarId() { return clientId; } diff --git a/core/src/main/java/google/registry/model/host/HostBase.java b/core/src/main/java/google/registry/model/host/HostBase.java index 8b70e49fc..66480452b 100644 --- a/core/src/main/java/google/registry/model/host/HostBase.java +++ b/core/src/main/java/google/registry/model/host/HostBase.java @@ -33,6 +33,7 @@ import jakarta.persistence.Column; import jakarta.persistence.Convert; import jakarta.persistence.MappedSuperclass; import java.net.InetAddress; +import java.time.Instant; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; @@ -132,6 +133,11 @@ public class HostBase extends EppResource { return this; } + @Override + public EppResource cloneProjectedAtInstant(Instant now) { + return this; + } + @Override public Builder asBuilder() { return new Builder<>(clone(this)); @@ -232,13 +238,13 @@ public class HostBase extends EppResource { public B copyFrom(HostBase hostBase) { return setCreationRegistrarId(hostBase.getCreationRegistrarId()) .setCreationTime(hostBase.getCreationTime()) - .setDeletionTime(hostBase.getDeletionTime()) + .setDeletionTime(hostBase.getDeletionDateTime()) .setHostName(hostBase.getHostName()) .setInetAddresses(hostBase.getInetAddresses()) .setLastTransferTime(hostBase.getLastTransferTime()) .setLastSuperordinateChange(hostBase.getLastSuperordinateChange()) .setLastEppUpdateRegistrarId(hostBase.getLastEppUpdateRegistrarId()) - .setLastEppUpdateTime(hostBase.getLastEppUpdateTime()) + .setLastEppUpdateTime(hostBase.getLastEppUpdateDateTime()) .setPersistedCurrentSponsorRegistrarId(hostBase.getPersistedCurrentSponsorRegistrarId()) .setRepoId(hostBase.getRepoId()) .setSuperordinateDomain(hostBase.getSuperordinateDomain()) diff --git a/core/src/main/java/google/registry/model/poll/PollMessage.java b/core/src/main/java/google/registry/model/poll/PollMessage.java index 2e73951e3..161722661 100644 --- a/core/src/main/java/google/registry/model/poll/PollMessage.java +++ b/core/src/main/java/google/registry/model/poll/PollMessage.java @@ -437,7 +437,7 @@ public abstract class PollMessage extends ImmutableObject .setTransferStatus(transferResponse.getTransferStatus()) .setTransferRequestTime(transferResponse.getTransferRequestTime()) .setPendingTransferExpirationTime( - transferResponse.getPendingTransferExpirationTime()) + transferResponse.getPendingTransferExpirationDateTime()) .setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime) .build(); } diff --git a/core/src/main/java/google/registry/model/transfer/BaseTransferObject.java b/core/src/main/java/google/registry/model/transfer/BaseTransferObject.java index 9c55b52a1..e1a0a04c1 100644 --- a/core/src/main/java/google/registry/model/transfer/BaseTransferObject.java +++ b/core/src/main/java/google/registry/model/transfer/BaseTransferObject.java @@ -14,6 +14,8 @@ package google.registry.model.transfer; +import static google.registry.util.DateTimeUtils.toInstant; + import google.registry.model.Buildable.GenericBuilder; import google.registry.model.ImmutableObject; import google.registry.model.UnsafeSerializable; @@ -23,6 +25,7 @@ import jakarta.persistence.Enumerated; import jakarta.persistence.MappedSuperclass; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlTransient; +import java.time.Instant; import org.joda.time.DateTime; /** Fields common to {@link DomainTransferData} and {@link TransferResponse}. */ @@ -73,10 +76,15 @@ public abstract class BaseTransferObject extends ImmutableObject implements Unsa return losingClientId; } - public DateTime getPendingTransferExpirationTime() { + @Deprecated + public DateTime getPendingTransferExpirationDateTime() { return pendingTransferExpirationTime; } + public Instant getPendingTransferExpirationTime() { + return toInstant(pendingTransferExpirationTime); + } + /** Base class for builders of {@link BaseTransferObject} subclasses. */ public abstract static class Builder> extends GenericBuilder { diff --git a/core/src/main/java/google/registry/model/transfer/DomainTransferData.java b/core/src/main/java/google/registry/model/transfer/DomainTransferData.java index 7ecb17e26..a56c3889d 100644 --- a/core/src/main/java/google/registry/model/transfer/DomainTransferData.java +++ b/core/src/main/java/google/registry/model/transfer/DomainTransferData.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.ImmutableList.toImmutableList; import static google.registry.util.CollectionUtils.isNullOrEmpty; import static google.registry.util.CollectionUtils.nullToEmpty; +import static google.registry.util.DateTimeUtils.toInstant; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -41,6 +42,7 @@ import jakarta.persistence.Column; import jakarta.persistence.Convert; import jakarta.persistence.Embeddable; import jakarta.persistence.Embedded; +import java.time.Instant; import java.util.Set; import javax.annotation.Nullable; import org.joda.time.DateTime; @@ -168,10 +170,16 @@ public class DomainTransferData extends BaseTransferObject implements Buildable } @Nullable - public DateTime getTransferredRegistrationExpirationTime() { + @Deprecated + public DateTime getTransferredRegistrationExpirationDateTime() { return transferredRegistrationExpirationTime; } + @Nullable + public Instant getTransferredRegistrationExpirationTime() { + return toInstant(transferredRegistrationExpirationTime); + } + @Nullable public VKey getServerApproveBillingEvent() { return serverApproveBillingEvent; diff --git a/core/src/main/java/google/registry/persistence/transaction/JpaTransactionManagerImpl.java b/core/src/main/java/google/registry/persistence/transaction/JpaTransactionManagerImpl.java index f1633b7c1..4502a7d39 100644 --- a/core/src/main/java/google/registry/persistence/transaction/JpaTransactionManagerImpl.java +++ b/core/src/main/java/google/registry/persistence/transaction/JpaTransactionManagerImpl.java @@ -21,6 +21,7 @@ import static com.google.common.collect.ImmutableMap.toImmutableMap; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static google.registry.config.RegistryConfig.getHibernateAllowNestedTransactions; import static google.registry.persistence.transaction.DatabaseException.throwIfSqlException; +import static google.registry.util.DateTimeUtils.toDateTime; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; import static java.util.AbstractMap.SimpleEntry; import static java.util.stream.Collectors.joining; @@ -61,6 +62,7 @@ import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.time.Instant; import java.util.Calendar; import java.util.Collections; import java.util.Date; @@ -340,6 +342,11 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager { @Override public DateTime getTransactionTime() { + return toDateTime(getTxTime()); + } + + @Override + public Instant getTxTime() { assertInTransaction(); TransactionInfo txnInfo = transactionInfo.get(); if (txnInfo.transactionTime == null) { @@ -746,7 +753,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager { private static class TransactionInfo { EntityManager entityManager; boolean inTransaction = false; - DateTime transactionTime; + Instant transactionTime; Supplier idProvider; // The set of entity objects that have been either persisted (via insert()) or merged (via @@ -759,7 +766,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager { private void start(Clock clock, Supplier idProvider) { checkArgumentNotNull(clock); inTransaction = true; - transactionTime = clock.nowUtc(); + transactionTime = clock.now(); this.idProvider = idProvider; } diff --git a/core/src/main/java/google/registry/persistence/transaction/TransactionManager.java b/core/src/main/java/google/registry/persistence/transaction/TransactionManager.java index 8cd63befe..aa49bb9b7 100644 --- a/core/src/main/java/google/registry/persistence/transaction/TransactionManager.java +++ b/core/src/main/java/google/registry/persistence/transaction/TransactionManager.java @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableMap; import google.registry.model.ImmutableObject; import google.registry.persistence.PersistenceModule.TransactionIsolationLevel; import google.registry.persistence.VKey; +import java.time.Instant; import java.util.NoSuchElementException; import java.util.Optional; import java.util.concurrent.Callable; @@ -129,8 +130,12 @@ public interface TransactionManager { void reTransact(ThrowingRunnable work); /** Returns the time associated with the start of this particular transaction attempt. */ + @Deprecated DateTime getTransactionTime(); + /** Returns the Instant associated with the start of this particular transaction attempt. */ + Instant getTxTime(); + /** Persists a new entity in the database, throws exception if the entity already exists. */ void insert(Object entity); diff --git a/core/src/main/java/google/registry/rdap/RdapActionBase.java b/core/src/main/java/google/registry/rdap/RdapActionBase.java index 2b23be750..94804bf0a 100644 --- a/core/src/main/java/google/registry/rdap/RdapActionBase.java +++ b/core/src/main/java/google/registry/rdap/RdapActionBase.java @@ -17,6 +17,7 @@ package google.registry.rdap; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN; import static google.registry.request.Actions.getPathForAction; +import static google.registry.util.DateTimeUtils.toInstant; import static google.registry.util.DomainNameUtils.canonicalizeHostname; import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; @@ -241,7 +242,7 @@ public abstract class RdapActionBase implements Runnable { * is authorized to do so. */ boolean isAuthorized(EppResource eppResource) { - return getRequestTime().isBefore(eppResource.getDeletionTime()) + return toInstant(getRequestTime()).isBefore(eppResource.getDeletionTime()) || (shouldIncludeDeleted() && rdapAuthorization.isAuthorizedForRegistrar( eppResource.getPersistedCurrentSponsorRegistrarId())); diff --git a/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java b/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java index 9ba0d7c7b..44fcf0744 100644 --- a/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java +++ b/core/src/main/java/google/registry/rdap/RdapJsonFormatter.java @@ -318,7 +318,7 @@ public class RdapJsonFormatter { .build(), Event.builder() .setEventAction(EventAction.EXPIRATION) - .setEventDate(domain.getRegistrationExpirationTime()) + .setEventDate(domain.getRegistrationExpirationDateTime()) .build(), // RDAP response profile section 1.5: // The topmost object in the RDAP response MUST contain an event of "eventAction" type @@ -361,7 +361,7 @@ public class RdapJsonFormatter { makeStatusValueList( allStatusValues, false, // isRedacted - domain.getDeletionTime().isBefore(getRequestTime())); + domain.getDeletionDateTime().isBefore(getRequestTime())); builder.statusBuilder().addAll(status); if (status.isEmpty()) { logger.atWarning().log( @@ -447,7 +447,7 @@ public class RdapJsonFormatter { makeStatusValueList( statuses.build(), false, // isRedacted - host.getDeletionTime().isBefore(getRequestTime()))); + host.getDeletionDateTime().isBefore(getRequestTime()))); } // For query responses - we MUST have all the ip addresses: RDAP Response Profile 4.2. @@ -761,7 +761,9 @@ public class RdapJsonFormatter { ImmutableList.Builder eventsBuilder = new ImmutableList.Builder<>(); DateTime creationTime = resource.getCreationTime(); DateTime lastChangeTime = - resource.getLastEppUpdateTime() == null ? creationTime : resource.getLastEppUpdateTime(); + resource.getLastEppUpdateDateTime() == null + ? creationTime + : resource.getLastEppUpdateDateTime(); // The order of the elements is stable - it's the order in which the enum elements are defined // in EventAction for (EventAction rdapEventAction : EventAction.values()) { diff --git a/core/src/main/java/google/registry/rde/DomainToXjcConverter.java b/core/src/main/java/google/registry/rde/DomainToXjcConverter.java index fe671a28d..89f4be1a0 100644 --- a/core/src/main/java/google/registry/rde/DomainToXjcConverter.java +++ b/core/src/main/java/google/registry/rde/DomainToXjcConverter.java @@ -94,13 +94,13 @@ final class DomainToXjcConverter { // identifying the end (expiration) of the domain name object's // registration period. This element MUST be present if the domain // name has been allocated. - bean.setExDate(model.getRegistrationExpirationTime()); + bean.setExDate(model.getRegistrationExpirationDateTime()); // o An OPTIONAL element that contains the date and time of // the most recent domain-name-object modification. This element // MUST NOT be present if the domain name object has never been // modified. - bean.setUpDate(model.getLastEppUpdateTime()); + bean.setUpDate(model.getLastEppUpdateDateTime()); // o An OPTIONAL element that contains the identifier of the // registrar that last updated the domain name object. This element @@ -228,8 +228,8 @@ final class DomainToXjcConverter { bean.setReRr(RdeUtils.makeXjcRdeRrType(model.getGainingRegistrarId())); bean.setAcRr(RdeUtils.makeXjcRdeRrType(model.getLosingRegistrarId())); bean.setReDate(model.getTransferRequestTime()); - bean.setAcDate(model.getPendingTransferExpirationTime()); - bean.setExDate(model.getTransferredRegistrationExpirationTime()); + bean.setAcDate(model.getPendingTransferExpirationDateTime()); + bean.setExDate(model.getTransferredRegistrationExpirationDateTime()); return bean; } diff --git a/core/src/main/java/google/registry/rde/HostToXjcConverter.java b/core/src/main/java/google/registry/rde/HostToXjcConverter.java index 3f75703ee..f822871aa 100644 --- a/core/src/main/java/google/registry/rde/HostToXjcConverter.java +++ b/core/src/main/java/google/registry/rde/HostToXjcConverter.java @@ -70,7 +70,7 @@ final class HostToXjcConverter { bean.setName(model.getHostName()); bean.setRoid(model.getRepoId()); bean.setCrDate(model.getCreationTime()); - bean.setUpDate(model.getLastEppUpdateTime()); + bean.setUpDate(model.getLastEppUpdateDateTime()); bean.setCrRr(RdeAdapter.convertRr(model.getCreationRegistrarId(), null)); bean.setUpRr(RdeAdapter.convertRr(model.getLastEppUpdateRegistrarId(), null)); bean.setCrRr(RdeAdapter.convertRr(model.getCreationRegistrarId(), null)); diff --git a/core/src/main/java/google/registry/tools/GenerateDnsReportCommand.java b/core/src/main/java/google/registry/tools/GenerateDnsReportCommand.java index f4aad1d54..88e0a3679 100644 --- a/core/src/main/java/google/registry/tools/GenerateDnsReportCommand.java +++ b/core/src/main/java/google/registry/tools/GenerateDnsReportCommand.java @@ -81,7 +81,7 @@ final class GenerateDnsReportCommand implements Command { .list()); for (Domain domain : domains) { // Skip deleted domains and domains that don't get published to DNS. - if (isBeforeOrAt(domain.getDeletionTime(), now) || !domain.shouldPublishToDns()) { + if (isBeforeOrAt(domain.getDeletionDateTime(), now) || !domain.shouldPublishToDns()) { continue; } write(domain); @@ -90,7 +90,7 @@ final class GenerateDnsReportCommand implements Command { Iterable nameservers = tm().transact(() -> tm().loadAllOf(Host.class)); for (Host nameserver : nameservers) { // Skip deleted hosts and external hosts. - if (isBeforeOrAt(nameserver.getDeletionTime(), now) + if (isBeforeOrAt(nameserver.getDeletionDateTime(), now) || nameserver.getInetAddresses().isEmpty()) { continue; } diff --git a/core/src/main/java/google/registry/tools/RenewDomainCommand.java b/core/src/main/java/google/registry/tools/RenewDomainCommand.java index 81f262634..838db13ce 100644 --- a/core/src/main/java/google/registry/tools/RenewDomainCommand.java +++ b/core/src/main/java/google/registry/tools/RenewDomainCommand.java @@ -81,7 +81,7 @@ final class RenewDomainCommand extends MutatingEppToolCommand { SoyMapData soyMapData = new SoyMapData( "domainName", domain.getDomainName(), - "expirationDate", domain.getRegistrationExpirationTime().toString(DATE_FORMATTER), + "expirationDate", domain.getRegistrationExpirationDateTime().toString(DATE_FORMATTER), "period", String.valueOf(period)); if (requestedByRegistrar != null) { diff --git a/core/src/main/java/google/registry/tools/UniformRapidSuspensionCommand.java b/core/src/main/java/google/registry/tools/UniformRapidSuspensionCommand.java index 1f3368ef2..77290a852 100644 --- a/core/src/main/java/google/registry/tools/UniformRapidSuspensionCommand.java +++ b/core/src/main/java/google/registry/tools/UniformRapidSuspensionCommand.java @@ -163,7 +163,7 @@ final class UniformRapidSuspensionCommand extends MutatingEppToolCommand { domain.getDomainName(), "expirationDate", domain - .getRegistrationExpirationTime() + .getRegistrationExpirationDateTime() .toString(DateTimeFormat.forPattern("YYYY-MM-dd")), // period is the number of years to renew the registration for "period", diff --git a/core/src/main/java/google/registry/tools/UnrenewDomainCommand.java b/core/src/main/java/google/registry/tools/UnrenewDomainCommand.java index 29613a8ec..06866ebca 100644 --- a/core/src/main/java/google/registry/tools/UnrenewDomainCommand.java +++ b/core/src/main/java/google/registry/tools/UnrenewDomainCommand.java @@ -99,8 +99,9 @@ class UnrenewDomainCommand extends ConfirmingCommand { domainsWithDisallowedStatusesBuilder.putAll( domainName, Sets.intersection(domain.get().getStatusValues(), DISALLOWED_STATUSES)); if (isBeforeOrAt( - leapSafeSubtractYears(domain.get().getRegistrationExpirationTime(), period), now)) { - domainsExpiringTooSoonBuilder.put(domainName, domain.get().getRegistrationExpirationTime()); + leapSafeSubtractYears(domain.get().getRegistrationExpirationDateTime(), period), now)) { + domainsExpiringTooSoonBuilder.put( + domainName, domain.get().getRegistrationExpirationDateTime()); } } @@ -143,7 +144,7 @@ class UnrenewDomainCommand extends ConfirmingCommand { DateTime now = clock.nowUtc(); for (String domainName : mainParameters) { Domain domain = ForeignKeyUtils.loadResource(Domain.class, domainName, now).get(); - DateTime previousTime = domain.getRegistrationExpirationTime(); + DateTime previousTime = domain.getRegistrationExpirationDateTime(); DateTime newTime = leapSafeSubtractYears(previousTime, period); resultBuilder.append( String.format( @@ -179,12 +180,12 @@ class UnrenewDomainCommand extends ConfirmingCommand { "Domain %s has prohibited status values", domainName); checkState( - leapSafeSubtractYears(domain.getRegistrationExpirationTime(), period).isAfter(now), + leapSafeSubtractYears(domain.getRegistrationExpirationDateTime(), period).isAfter(now), "Domain %s expires too soon", domainName); DateTime newExpirationTime = - leapSafeSubtractYears(domain.getRegistrationExpirationTime(), period); + leapSafeSubtractYears(domain.getRegistrationExpirationDateTime(), period); DomainHistory domainHistory = new DomainHistory.Builder() .setDomain(domain) diff --git a/core/src/main/java/google/registry/tools/UpdateRecurrenceCommand.java b/core/src/main/java/google/registry/tools/UpdateRecurrenceCommand.java index 871201482..73a300ae8 100644 --- a/core/src/main/java/google/registry/tools/UpdateRecurrenceCommand.java +++ b/core/src/main/java/google/registry/tools/UpdateRecurrenceCommand.java @@ -16,7 +16,9 @@ package google.registry.tools; import static com.google.common.base.Preconditions.checkArgument; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; +import static google.registry.util.DateTimeUtils.END_INSTANT; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.toDateTime; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; @@ -31,6 +33,7 @@ import google.registry.model.domain.DomainHistory; import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry.HistoryEntryId; import google.registry.model.transfer.TransferStatus; +import java.time.Instant; import java.util.List; import java.util.Optional; import javax.annotation.Nullable; @@ -161,7 +164,7 @@ public class UpdateRecurrenceCommand extends ConfirmingCommand { private ImmutableMap loadDomainsAndRecurrences() { ImmutableMap.Builder result = new ImmutableMap.Builder<>(); - DateTime now = tm().getTransactionTime(); + Instant now = tm().getTxTime(); for (String domainName : mainParameters) { Domain domain = ForeignKeyUtils.loadResource(Domain.class, domainName, now) @@ -171,7 +174,7 @@ public class UpdateRecurrenceCommand extends ConfirmingCommand { String.format( "Domain %s does not exist or has been deleted", domainName))); checkArgument( - domain.getDeletionTime().equals(END_OF_TIME), + domain.getDeletionTime().equals(END_INSTANT), "Domain %s has already had a deletion time set", domainName); checkArgument( @@ -184,7 +187,7 @@ public class UpdateRecurrenceCommand extends ConfirmingCommand { domainAutorenewEndTime.ifPresent( endTime -> checkArgument( - endTime.isAfter(now), + endTime.isAfter(toDateTime(now)), "Domain %s autorenew ended prior to now at %s", domainName, endTime)); diff --git a/core/src/test/java/google/registry/batch/DeleteExpiredDomainsActionTest.java b/core/src/test/java/google/registry/batch/DeleteExpiredDomainsActionTest.java index 6fe869496..0315dedd6 100644 --- a/core/src/test/java/google/registry/batch/DeleteExpiredDomainsActionTest.java +++ b/core/src/test/java/google/registry/batch/DeleteExpiredDomainsActionTest.java @@ -24,6 +24,7 @@ import static google.registry.testing.DatabaseHelper.loadByEntity; import static google.registry.testing.DatabaseHelper.persistActiveDomain; import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.plusDays; import com.google.common.collect.ImmutableSet; import google.registry.flows.DaggerEppTestComponent; @@ -117,7 +118,7 @@ class DeleteExpiredDomainsActionTest { assertThat(loadByEntity(notYetExpiredDomain)).isEqualTo(notYetExpiredDomain); Domain reloadedExpiredDomain = loadByEntity(pendingExpirationDomain); assertThat(reloadedExpiredDomain.getStatusValues()).contains(PENDING_DELETE); - assertThat(reloadedExpiredDomain.getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35)); + assertThat(reloadedExpiredDomain.getDeletionTime()).isEqualTo(plusDays(clock.now(), 35)); } @Test diff --git a/core/src/test/java/google/registry/batch/DeleteProberDataActionTest.java b/core/src/test/java/google/registry/batch/DeleteProberDataActionTest.java index 9c11baa01..96c2d0c98 100644 --- a/core/src/test/java/google/registry/batch/DeleteProberDataActionTest.java +++ b/core/src/test/java/google/registry/batch/DeleteProberDataActionTest.java @@ -26,7 +26,7 @@ import static google.registry.testing.DatabaseHelper.persistActiveHost; import static google.registry.testing.DatabaseHelper.persistDeletedDomain; import static google.registry.testing.DatabaseHelper.persistDomainAsDeleted; import static google.registry.testing.DatabaseHelper.persistResource; -import static google.registry.util.DateTimeUtils.END_OF_TIME; +import static google.registry.util.DateTimeUtils.END_INSTANT; import static org.joda.time.DateTimeZone.UTC; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -47,6 +47,7 @@ import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationT import google.registry.testing.DatabaseHelper; import google.registry.testing.SystemPropertyExtension; import google.registry.util.RegistryEnvironment; +import java.time.Instant; import java.util.Optional; import java.util.Set; import org.joda.money.Money; @@ -201,7 +202,7 @@ class DeleteProberDataActionTest { .setCreationTimeForTest(DateTime.now(UTC).minusYears(1)) .build()); action.run(); - DateTime timeAfterDeletion = DateTime.now(UTC); + Instant timeAfterDeletion = Instant.now(); assertThat(ForeignKeyUtils.loadResource(Domain.class, "blah.ib-any.test", timeAfterDeletion)) .isEmpty(); assertThat(loadByEntity(domain).getDeletionTime()).isLessThan(timeAfterDeletion); @@ -217,7 +218,7 @@ class DeleteProberDataActionTest { .setCreationTimeForTest(DateTime.now(UTC).minusYears(1)) .build()); action.run(); - DateTime timeAfterDeletion = DateTime.now(UTC); + Instant timeAfterDeletion = Instant.now(); resetAction(); action.run(); assertThat(ForeignKeyUtils.loadResource(Domain.class, "blah.ib-any.test", timeAfterDeletion)) @@ -237,7 +238,7 @@ class DeleteProberDataActionTest { Optional domain = ForeignKeyUtils.loadResource(Domain.class, "blah.ib-any.test", DateTime.now(UTC)); assertThat(domain).isPresent(); - assertThat(domain.get().getDeletionTime()).isEqualTo(END_OF_TIME); + assertThat(domain.get().getDeletionTime()).isEqualTo(END_INSTANT); } @Test @@ -250,7 +251,7 @@ class DeleteProberDataActionTest { .build()); action.isDryRun = true; action.run(); - assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(END_OF_TIME); + assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(END_INSTANT); } @Test diff --git a/core/src/test/java/google/registry/beam/resave/ResaveAllEppResourcesPipelineTest.java b/core/src/test/java/google/registry/beam/resave/ResaveAllEppResourcesPipelineTest.java index c87216be0..b9d8f59a5 100644 --- a/core/src/test/java/google/registry/beam/resave/ResaveAllEppResourcesPipelineTest.java +++ b/core/src/test/java/google/registry/beam/resave/ResaveAllEppResourcesPipelineTest.java @@ -25,6 +25,8 @@ import static google.registry.testing.DatabaseHelper.persistActiveHost; import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources; import static google.registry.testing.DatabaseHelper.persistDomainWithPendingTransfer; import static google.registry.testing.DatabaseHelper.persistNewRegistrars; +import static google.registry.util.DateTimeUtils.plusYears; +import static google.registry.util.DateTimeUtils.toInstant; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -113,11 +115,12 @@ public class ResaveAllEppResourcesPipelineTest { DateTime now = fakeClock.nowUtc(); Domain domain = persistDomainWithDependentResources("domain", "tld", now, now, now.plusYears(1)); - assertThat(domain.getRegistrationExpirationTime()).isEqualTo(now.plusYears(1)); + assertThat(domain.getRegistrationExpirationTime()).isEqualTo(plusYears(toInstant(now), 1)); fakeClock.advanceBy(Duration.standardDays(500)); runPipeline(); Domain postPipeline = loadByEntity(domain); - assertThat(postPipeline.getRegistrationExpirationTime()).isEqualTo(now.plusYears(2)); + assertThat(postPipeline.getRegistrationExpirationTime()) + .isEqualTo(plusYears(toInstant(now), 2)); } @Test diff --git a/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java b/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java index fb45f3473..3d3540ab8 100644 --- a/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java +++ b/core/src/test/java/google/registry/flows/EppLifecycleDomainTest.java @@ -488,7 +488,7 @@ class EppLifecycleDomainTest extends EppTestCase { // Make sure that in the future, the domain expiration is unchanged after deletion Domain clonedDomain = domain.cloneProjectedAtTime(deleteTime.plusYears(5)); - assertThat(clonedDomain.getRegistrationExpirationTime()).isEqualTo(createTime.plusYears(2)); + assertThat(clonedDomain.getRegistrationExpirationDateTime()).isEqualTo(createTime.plusYears(2)); } @Test diff --git a/core/src/test/java/google/registry/flows/FlowTestCase.java b/core/src/test/java/google/registry/flows/FlowTestCase.java index ba2b31f61..4daf414b2 100644 --- a/core/src/test/java/google/registry/flows/FlowTestCase.java +++ b/core/src/test/java/google/registry/flows/FlowTestCase.java @@ -182,7 +182,7 @@ public abstract class FlowTestCase { GracePeriod.create( entry.getKey().getType(), entry.getKey().getDomainRepoId(), - entry.getKey().getExpirationTime(), + entry.getKey().getExpirationDateTime(), entry.getKey().getRegistrarId(), null, 1L), diff --git a/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java index f1ae4f485..6c402def6 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainCreateFlowTest.java @@ -361,7 +361,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase @Nullable Money renewalPrice) throws Exception { assertMutatingFlow(true); - DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationTime(); + DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationDateTime(); DateTime newExpiration = currentExpiration.plusYears(renewalYears); runFlowAssertResponse( CommitMode.LIVE, userPrivileges, loadFile(responseFilename, substitutions)); @@ -303,7 +303,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase .setFlags(ImmutableSet.of(Flag.AUTO_RENEW)) .setTargetId(getUniqueIdFromCommand()) .setRegistrarId("TheRegistrar") - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setRecurrenceEndTime(END_OF_TIME) .setDomainHistory(historyEntryDomainRenew) .build()); @@ -313,7 +313,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase new PollMessage.Autorenew.Builder() .setTargetId(getUniqueIdFromCommand()) .setRegistrarId("TheRegistrar") - .setEventTime(domain.getRegistrationExpirationTime()) + .setEventTime(domain.getRegistrationExpirationDateTime()) .setAutorenewEndTime(END_OF_TIME) .setMsg("Domain was auto-renewed.") .setHistoryEntry(historyEntryDomainRenew) @@ -817,7 +817,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase new PollMessage.Autorenew.Builder() .setTargetId(getUniqueIdFromCommand()) .setRegistrarId("TheRegistrar") - .setEventTime(reloadResourceByForeignKey().getRegistrationExpirationTime()) + .setEventTime(reloadResourceByForeignKey().getRegistrationExpirationDateTime()) .setAutorenewEndTime(END_OF_TIME) .setMsg("Domain was auto-renewed.") .setHistoryEntry(historyEntryDomainRenew) diff --git a/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java index 69c28ee89..35eeb1399 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java @@ -201,7 +201,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase originalGracePeriods = domain.getGracePeriods(); DomainTransferData originalTransferData = domain.getTransferData(); runFlowAssertResponse(loadFile("domain_transfer_cancel_response.xml")); diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java index 523120f4a..b96a4f412 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferQueryFlowTest.java @@ -143,7 +143,8 @@ class DomainTransferQueryFlowTest persistResource( domain .asBuilder() - .setRegistrationExpirationTime(domain.getRegistrationExpirationTime().plusYears(9)) + .setRegistrationExpirationTime( + domain.getRegistrationExpirationDateTime().plusYears(9)) .build()); doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response_10_years.xml", 1); } @@ -233,7 +234,7 @@ class DomainTransferQueryFlowTest // Set the clock to just past the extended registration time. We'd expect the domain to have // auto-renewed once, but the transfer query response should be the same. clock.setTo(EXTENDED_REGISTRATION_EXPIRATION_TIME.plusMillis(1)); - assertThat(domain.cloneProjectedAtTime(clock.nowUtc()).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(clock.nowUtc()).getRegistrationExpirationDateTime()) .isEqualTo(EXTENDED_REGISTRATION_EXPIRATION_TIME.plusYears(1)); doSuccessfulTest( "domain_transfer_query.xml", "domain_transfer_query_response_server_approved.xml", 2); diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java index f26b460d4..e3bac6216 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferRejectFlowTest.java @@ -88,7 +88,7 @@ class DomainTransferRejectFlowTest assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1); // Setup done; run the test. assertMutatingFlow(true); - DateTime originalExpirationTime = domain.getRegistrationExpirationTime(); + DateTime originalExpirationTime = domain.getRegistrationExpirationDateTime(); ImmutableSet originalGracePeriods = domain.getGracePeriods(); DomainTransferData originalTransferData = domain.getTransferData(); runFlowAssertResponse(loadFile(expectedXmlFilename)); diff --git a/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java index 70ad4517e..7afa97cd6 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainTransferRequestFlowTest.java @@ -244,7 +244,8 @@ class DomainTransferRequestFlowTest .setTransferPeriod(expectedPeriod) .setTransferStatus(TransferStatus.SERVER_APPROVED) .setPendingTransferExpirationTime(automaticTransferTime) - .setTransferredRegistrationExpirationTime(domain.getRegistrationExpirationTime()) + .setTransferredRegistrationExpirationTime( + domain.getRegistrationExpirationDateTime()) // Server-approve entity fields should all be nulled out. .build()); } @@ -542,7 +543,7 @@ class DomainTransferRequestFlowTest doSuccessfulTest( commandFilename, expectedXmlFilename, - domain.getRegistrationExpirationTime().plusYears(1), + domain.getRegistrationExpirationDateTime().plusYears(1), substitutions, Optional.empty()); } @@ -551,7 +552,9 @@ class DomainTransferRequestFlowTest throws Exception { clock.advanceOneMilli(); doSuccessfulTest( - commandFilename, expectedXmlFilename, domain.getRegistrationExpirationTime().plusYears(1)); + commandFilename, + expectedXmlFilename, + domain.getRegistrationExpirationDateTime().plusYears(1)); } private void doSuccessfulSuperuserExtensionTest( @@ -812,7 +815,7 @@ class DomainTransferRequestFlowTest doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_nonzero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(0), + domain.getRegistrationExpirationDateTime().plusYears(0), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "5"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -826,7 +829,7 @@ class DomainTransferRequestFlowTest doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_zero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(0), + domain.getRegistrationExpirationDateTime().plusYears(0), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "0"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -841,7 +844,7 @@ class DomainTransferRequestFlowTest doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_one_year_period_nonzero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(1), + domain.getRegistrationExpirationDateTime().plusYears(1), ImmutableMap.of("PERIOD", "1", "AUTOMATIC_TRANSFER_LENGTH", "5"), Optional.empty(), Period.create(1, Unit.YEARS), @@ -873,7 +876,7 @@ class DomainTransferRequestFlowTest doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_autorenew_grace.xml", - domain.getRegistrationExpirationTime(), + domain.getRegistrationExpirationDateTime(), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "0"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -922,7 +925,7 @@ class DomainTransferRequestFlowTest doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_zero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(0), + domain.getRegistrationExpirationDateTime().plusYears(0), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "0"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -939,7 +942,7 @@ class DomainTransferRequestFlowTest doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_zero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(0), + domain.getRegistrationExpirationDateTime().plusYears(0), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "0"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -977,7 +980,7 @@ class DomainTransferRequestFlowTest doSuccessfulTest( "domain_transfer_request_separate_fees.xml", "domain_transfer_request_response_fees.xml", - domain.getRegistrationExpirationTime().plusYears(1), + domain.getRegistrationExpirationDateTime().plusYears(1), new ImmutableMap.Builder() .put("DOMAIN", "expensive-domain.foo") .put("YEARS", "1") @@ -1409,7 +1412,7 @@ class DomainTransferRequestFlowTest doSuccessfulSuperuserExtensionTest( "domain_transfer_request_superuser_extension.xml", "domain_transfer_request_response_su_ext_zero_period_zero_transfer_length.xml", - domain.getRegistrationExpirationTime().plusYears(0), + domain.getRegistrationExpirationDateTime().plusYears(0), ImmutableMap.of("PERIOD", "0", "AUTOMATIC_TRANSFER_LENGTH", "0"), Optional.empty(), Period.create(0, Unit.YEARS), @@ -2024,7 +2027,7 @@ class DomainTransferRequestFlowTest doSuccessfulTest( "domain_transfer_request_separate_fees.xml", "domain_transfer_request_response_fees.xml", - domain.getRegistrationExpirationTime().plusYears(1), + domain.getRegistrationExpirationDateTime().plusYears(1), new ImmutableMap.Builder() .put("DOMAIN", "expensive-domain.foo") .put("YEARS", "1") diff --git a/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java b/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java index 084cd4192..2103b06d4 100644 --- a/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java +++ b/core/src/test/java/google/registry/flows/host/HostUpdateFlowTest.java @@ -256,7 +256,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase { .and() .hasPersistedCurrentSponsorRegistrarId("NewRegistrar") .and() - .hasLastTransferTime(domain.getTransferData().getPendingTransferExpirationTime()) + .hasLastTransferTime(domain.getTransferData().getPendingTransferExpirationDateTime()) .and() .hasOnlyOneHistoryEntryWhich() .hasType(HistoryEntry.Type.HOST_UPDATE); diff --git a/core/src/test/java/google/registry/model/domain/DomainTest.java b/core/src/test/java/google/registry/model/domain/DomainTest.java index e6e81d9a1..ad04eb1d0 100644 --- a/core/src/test/java/google/registry/model/domain/DomainTest.java +++ b/core/src/test/java/google/registry/model/domain/DomainTest.java @@ -31,6 +31,10 @@ import static google.registry.testing.DomainSubject.assertAboutDomains; import static google.registry.testing.SqlHelper.saveRegistrar; import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME; +import static google.registry.util.DateTimeUtils.minusDays; +import static google.registry.util.DateTimeUtils.plusDays; +import static google.registry.util.DateTimeUtils.plusYears; +import static google.registry.util.DateTimeUtils.toDateTime; import static org.joda.money.CurrencyUnit.USD; import static org.joda.time.DateTimeZone.UTC; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -67,6 +71,8 @@ import google.registry.persistence.transaction.JpaTestExtensions; import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationWithCoverageExtension; import google.registry.testing.DatabaseHelper; import google.registry.testing.FakeClock; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.Optional; import org.joda.money.Money; import org.joda.time.DateTime; @@ -386,7 +392,7 @@ public class DomainTest { .isEqualTo(TransferStatus.SERVER_APPROVED); assertThat(domain.getCurrentSponsorRegistrarId()).isEqualTo("TheRegistrar"); assertThat(domain.getLastTransferTime()).isEqualTo(fakeClock.nowUtc().plusDays(1)); - assertThat(domain.getRegistrationExpirationTime()).isEqualTo(newExpirationTime); + assertThat(domain.getRegistrationExpirationDateTime()).isEqualTo(newExpirationTime); assertThat(domain.getAutorenewBillingEvent()).isEqualTo(newAutorenewEvent); } @@ -479,56 +485,57 @@ public class DomainTest { } private void setupPendingTransferDomain( - DateTime oldExpirationTime, DateTime transferRequestTime, DateTime transferSuccessTime) { + Instant oldExpirationTime, Instant transferRequestTime, Instant transferSuccessTime) { domain = domain .asBuilder() - .setRegistrationExpirationTime(oldExpirationTime) + .setRegistrationExpirationTime(toDateTime(oldExpirationTime)) .setTransferData( domain .getTransferData() .asBuilder() .setTransferStatus(TransferStatus.PENDING) - .setTransferRequestTime(transferRequestTime) - .setPendingTransferExpirationTime(transferSuccessTime) + .setTransferRequestTime(toDateTime(transferRequestTime)) + .setPendingTransferExpirationTime(toDateTime(transferSuccessTime)) .build()) - .setLastEppUpdateTime(transferRequestTime) + .setLastEppUpdateTime(toDateTime(transferRequestTime)) .setLastEppUpdateRegistrarId(domain.getTransferData().getGainingRegistrarId()) .build(); } @Test void testEppLastUpdateTimeAndClientId_autoRenewBeforeTransferSuccess() { - DateTime now = fakeClock.nowUtc(); - DateTime transferRequestDateTime = now.plusDays(1); - DateTime autorenewDateTime = now.plusDays(3); - DateTime transferSuccessDateTime = now.plusDays(5); + Instant now = fakeClock.now(); + Instant transferRequestDateTime = plusDays(now, 1); + Instant autorenewDateTime = plusDays(now, 3); + Instant transferSuccessDateTime = plusDays(now, 5); setupPendingTransferDomain(autorenewDateTime, transferRequestDateTime, transferSuccessDateTime); - Domain beforeAutoRenew = domain.cloneProjectedAtTime(autorenewDateTime.minusDays(1)); + Domain beforeAutoRenew = domain.cloneProjectedAtInstant(minusDays(autorenewDateTime, 1)); assertThat(beforeAutoRenew.getLastEppUpdateTime()).isEqualTo(transferRequestDateTime); assertThat(beforeAutoRenew.getLastEppUpdateRegistrarId()).isEqualTo("TheRegistrar"); // If autorenew happens before transfer succeeds(before transfer grace period starts as well), // lastEppUpdateRegistrarId should still be the current sponsor client id - Domain afterAutoRenew = domain.cloneProjectedAtTime(autorenewDateTime.plusDays(1)); + Domain afterAutoRenew = domain.cloneProjectedAtInstant(plusDays(autorenewDateTime, 1)); assertThat(afterAutoRenew.getLastEppUpdateTime()).isEqualTo(autorenewDateTime); assertThat(afterAutoRenew.getLastEppUpdateRegistrarId()).isEqualTo("NewRegistrar"); } @Test void testEppLastUpdateTimeAndClientId_autoRenewAfterTransferSuccess() { - DateTime now = fakeClock.nowUtc(); - DateTime transferRequestDateTime = now.plusDays(1); - DateTime autorenewDateTime = now.plusDays(3); - DateTime transferSuccessDateTime = now.plusDays(5); + Instant now = fakeClock.now(); + Instant transferRequestDateTime = plusDays(now, 1); + Instant autorenewDateTime = plusDays(now, 3); + Instant transferSuccessDateTime = plusDays(now, 5); setupPendingTransferDomain(autorenewDateTime, transferRequestDateTime, transferSuccessDateTime); - Domain beforeAutoRenew = domain.cloneProjectedAtTime(autorenewDateTime.minusDays(1)); + Domain beforeAutoRenew = domain.cloneProjectedAtInstant(minusDays(autorenewDateTime, 1)); assertThat(beforeAutoRenew.getLastEppUpdateTime()).isEqualTo(transferRequestDateTime); assertThat(beforeAutoRenew.getLastEppUpdateRegistrarId()).isEqualTo("TheRegistrar"); - Domain afterTransferSuccess = domain.cloneProjectedAtTime(transferSuccessDateTime.plusDays(1)); + Domain afterTransferSuccess = + domain.cloneProjectedAtInstant(plusDays(transferSuccessDateTime, 1)); assertThat(afterTransferSuccess.getLastEppUpdateTime()).isEqualTo(transferSuccessDateTime); assertThat(afterTransferSuccess.getLastEppUpdateRegistrarId()).isEqualTo("TheRegistrar"); } @@ -552,11 +559,11 @@ public class DomainTest { setupUnmodifiedDomain(autorenewDateTime); Domain beforeAutoRenew = domain.cloneProjectedAtTime(autorenewDateTime.minusDays(1)); - assertThat(beforeAutoRenew.getLastEppUpdateTime()).isEqualTo(null); + assertThat(beforeAutoRenew.getLastEppUpdateDateTime()).isEqualTo(null); assertThat(beforeAutoRenew.getLastEppUpdateRegistrarId()).isEqualTo(null); Domain afterAutoRenew = domain.cloneProjectedAtTime(autorenewDateTime.plusDays(1)); - assertThat(afterAutoRenew.getLastEppUpdateTime()).isEqualTo(autorenewDateTime); + assertThat(afterAutoRenew.getLastEppUpdateDateTime()).isEqualTo(autorenewDateTime); assertThat(afterAutoRenew.getLastEppUpdateRegistrarId()).isEqualTo("NewRegistrar"); } @@ -633,9 +640,9 @@ public class DomainTest { @Test void testRenewalsHappenAtExpiration() { - Domain renewed = domain.cloneProjectedAtTime(domain.getRegistrationExpirationTime()); + Domain renewed = domain.cloneProjectedAtInstant(domain.getRegistrationExpirationTime()); assertThat(renewed.getRegistrationExpirationTime()) - .isEqualTo(domain.getRegistrationExpirationTime().plusYears(1)); + .isEqualTo(plusYears(domain.getRegistrationExpirationTime(), 1)); assertThat(renewed.getLastEppUpdateTime()).isEqualTo(domain.getRegistrationExpirationTime()); assertThat(getOnlyElement(renewed.getGracePeriods()).getType()) .isEqualTo(GracePeriodStatus.AUTO_RENEW); @@ -656,15 +663,16 @@ public class DomainTest { .setRegistrationExpirationTime(DateTime.parse("2004-02-29T22:00:00.0Z")) .build(); Domain renewed = - domain.cloneProjectedAtTime(domain.getRegistrationExpirationTime().plusYears(4)); - assertThat(renewed.getRegistrationExpirationTime().getDayOfMonth()).isEqualTo(28); + domain.cloneProjectedAtInstant(plusYears(domain.getRegistrationExpirationTime(), 4)); + assertThat(renewed.getRegistrationExpirationTime().atZone(ZoneOffset.UTC).getDayOfMonth()) + .isEqualTo(28); } @Test void testMultipleAutoRenews() { // Change the registry so that renewal costs change every year to make sure we are using the // autorenew time as the lookup time for the cost. - DateTime oldExpirationTime = domain.getRegistrationExpirationTime(); + DateTime oldExpirationTime = domain.getRegistrationExpirationDateTime(); persistResource( Tld.get("com") .asBuilder() @@ -680,9 +688,10 @@ public class DomainTest { .build()) .build()); Domain renewedThreeTimes = domain.cloneProjectedAtTime(oldExpirationTime.plusYears(2)); - assertThat(renewedThreeTimes.getRegistrationExpirationTime()) + assertThat(renewedThreeTimes.getRegistrationExpirationDateTime()) .isEqualTo(oldExpirationTime.plusYears(3)); - assertThat(renewedThreeTimes.getLastEppUpdateTime()).isEqualTo(oldExpirationTime.plusYears(2)); + assertThat(renewedThreeTimes.getLastEppUpdateDateTime()) + .isEqualTo(oldExpirationTime.plusYears(2)); assertThat(renewedThreeTimes.getGracePeriods()) .containsExactly( GracePeriod.createForRecurrence( @@ -730,7 +739,7 @@ public class DomainTest { .setDeletionTime(now.minusDays(10)) .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE, StatusValue.INACTIVE)) .build()); - assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime()) .isEqualTo(now.minusDays(1)); } @@ -746,7 +755,7 @@ public class DomainTest { .setDeletionTime(now.plusDays(20)) .setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE, StatusValue.INACTIVE)) .build()); - assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime()) .isEqualTo(now.plusDays(1)); } @@ -773,7 +782,7 @@ public class DomainTest { .setTransferData(transferData) .build()); - assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime()) .isEqualTo(newExpiration); } @@ -801,7 +810,7 @@ public class DomainTest { .setTransferData(transferData) .build()); - assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime()) .isEqualTo(newExpiration); } @@ -843,7 +852,7 @@ public class DomainTest { assertThat(domain.getCurrentBulkToken()).isPresent(); Domain clonedDomain = domain.cloneProjectedAtTime(now); - assertThat(clonedDomain.getRegistrationExpirationTime()).isEqualTo(newExpiration); + assertThat(clonedDomain.getRegistrationExpirationDateTime()).isEqualTo(newExpiration); assertThat(clonedDomain.getCurrentBulkToken()).isEmpty(); } @@ -868,7 +877,7 @@ public class DomainTest { .setTransferData(transferData) .build()); - assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationTime()) + assertThat(domain.cloneProjectedAtTime(now).getRegistrationExpirationDateTime()) .isEqualTo(previousExpiration); } @@ -906,7 +915,7 @@ public class DomainTest { .build()); Domain clonedDomain = domain.cloneProjectedAtTime(now); - assertThat(clonedDomain.getRegistrationExpirationTime()).isEqualTo(previousExpiration); + assertThat(clonedDomain.getRegistrationExpirationDateTime()).isEqualTo(previousExpiration); assertThat(clonedDomain.getCurrentBulkToken().get()).isEqualTo(allocationToken.createVKey()); } @@ -943,8 +952,8 @@ public class DomainTest { .setAutorenewBillingEvent(recurrenceBillKey) .build()); Domain clone = domain.cloneProjectedAtTime(now); - assertThat(clone.getRegistrationExpirationTime()) - .isEqualTo(domain.getRegistrationExpirationTime().plusYears(1)); + assertThat(clone.getRegistrationExpirationDateTime()) + .isEqualTo(domain.getRegistrationExpirationDateTime().plusYears(1)); // Transferring removes the AUTORENEW grace period and adds a TRANSFER grace period assertThat(getOnlyElement(clone.getGracePeriods()).getType()) .isEqualTo(GracePeriodStatus.TRANSFER); diff --git a/core/src/test/java/google/registry/model/domain/GracePeriodTest.java b/core/src/test/java/google/registry/model/domain/GracePeriodTest.java index bc79c043a..8453d28dd 100644 --- a/core/src/test/java/google/registry/model/domain/GracePeriodTest.java +++ b/core/src/test/java/google/registry/model/domain/GracePeriodTest.java @@ -68,7 +68,7 @@ public class GracePeriodTest { assertThat(gracePeriod.getBillingEvent()).isEqualTo(onetime.createVKey()); assertThat(gracePeriod.getBillingRecurrence()).isNull(); assertThat(gracePeriod.getRegistrarId()).isEqualTo("TheRegistrar"); - assertThat(gracePeriod.getExpirationTime()).isEqualTo(now.plusDays(1)); + assertThat(gracePeriod.getExpirationDateTime()).isEqualTo(now.plusDays(1)); assertThat(gracePeriod.hasBillingEvent()).isTrue(); } @@ -82,7 +82,7 @@ public class GracePeriodTest { assertThat(gracePeriod.getBillingEvent()).isNull(); assertThat(gracePeriod.getBillingRecurrence()).isEqualTo(recurrenceKey); assertThat(gracePeriod.getRegistrarId()).isEqualTo("TheRegistrar"); - assertThat(gracePeriod.getExpirationTime()).isEqualTo(now.plusDays(1)); + assertThat(gracePeriod.getExpirationDateTime()).isEqualTo(now.plusDays(1)); assertThat(gracePeriod.hasBillingEvent()).isTrue(); } @@ -96,7 +96,7 @@ public class GracePeriodTest { assertThat(gracePeriod.getBillingEvent()).isNull(); assertThat(gracePeriod.getBillingRecurrence()).isNull(); assertThat(gracePeriod.getRegistrarId()).isEqualTo("TheRegistrar"); - assertThat(gracePeriod.getExpirationTime()).isEqualTo(now); + assertThat(gracePeriod.getExpirationDateTime()).isEqualTo(now); assertThat(gracePeriod.hasBillingEvent()).isFalse(); } diff --git a/core/src/test/java/google/registry/testing/AbstractEppResourceSubject.java b/core/src/test/java/google/registry/testing/AbstractEppResourceSubject.java index baebec91b..a8a039c4d 100644 --- a/core/src/test/java/google/registry/testing/AbstractEppResourceSubject.java +++ b/core/src/test/java/google/registry/testing/AbstractEppResourceSubject.java @@ -148,15 +148,15 @@ abstract class AbstractEppResourceSubject< } public And hasDeletionTime(DateTime deletionTime) { - return hasValue(deletionTime, actual.getDeletionTime(), "getDeletionTime()"); + return hasValue(deletionTime, actual.getDeletionDateTime(), "getDeletionTime()"); } public And hasLastEppUpdateTime(DateTime lastUpdateTime) { - return hasValue(lastUpdateTime, actual.getLastEppUpdateTime(), "has lastEppUpdateTime"); + return hasValue(lastUpdateTime, actual.getLastEppUpdateDateTime(), "has lastEppUpdateTime"); } public And hasLastEppUpdateTimeAtLeast(DateTime before) { - DateTime lastEppUpdateTime = actual.getLastEppUpdateTime(); + DateTime lastEppUpdateTime = actual.getLastEppUpdateDateTime(); check("getLastEppUpdateTime()").that(lastEppUpdateTime).isAtLeast(before); return andChainer(); } diff --git a/core/src/test/java/google/registry/testing/DomainSubject.java b/core/src/test/java/google/registry/testing/DomainSubject.java index 0036528ba..507a548c9 100644 --- a/core/src/test/java/google/registry/testing/DomainSubject.java +++ b/core/src/test/java/google/registry/testing/DomainSubject.java @@ -78,7 +78,7 @@ public final class DomainSubject extends AbstractEppResourceSubject hasRegistrationExpirationTime(DateTime expiration) { return hasValue( - expiration, actual.getRegistrationExpirationTime(), "getRegistrationExpirationTime()"); + expiration, actual.getRegistrationExpirationDateTime(), "getRegistrationExpirationTime()"); } public And hasLastTransferTime(DateTime lastTransferTime) { diff --git a/core/src/test/java/google/registry/tools/UnrenewDomainCommandTest.java b/core/src/test/java/google/registry/tools/UnrenewDomainCommandTest.java index 9f4d161c8..378231a46 100644 --- a/core/src/test/java/google/registry/tools/UnrenewDomainCommandTest.java +++ b/core/src/test/java/google/registry/tools/UnrenewDomainCommandTest.java @@ -78,12 +78,12 @@ public class UnrenewDomainCommandTest extends CommandTestCase earliestOf(ImmutableList.of())); + assertThrows(IllegalArgumentException.class, () -> latestOf(ImmutableList.of())); } @Test @@ -107,4 +125,32 @@ class DateTimeUtilsTest { Date date = Date.valueOf("2020-02-29"); assertThat(toLocalDate(date)).isEqualTo(LocalDate.parse("2020-02-29")); } + + @Test + void test_startOfTimeConstants_areTheSame() { + assertThat(toInstant(START_OF_TIME)).isEqualTo(START_INSTANT); + assertThat(toDateTime(START_INSTANT)).isEqualTo(START_OF_TIME); + assertThat(toInstant(toDateTime(START_INSTANT))).isEqualTo(START_INSTANT); + assertThat(toDateTime(toInstant(START_OF_TIME))).isEqualTo(START_OF_TIME); + } + + @Test + void test_endOfTimeConstants_areTheSame() { + assertThat(toInstant(END_OF_TIME)).isEqualTo(END_INSTANT); + assertThat(toDateTime(END_INSTANT)).isEqualTo(END_OF_TIME); + assertThat(toInstant(toDateTime(END_INSTANT))).isEqualTo(END_INSTANT); + assertThat(toDateTime(toInstant(END_OF_TIME))).isEqualTo(END_OF_TIME); + } + + @Test + void test_instantConversionMethods_workCorrectly() { + assertThat(toInstant(DateTime.parse("2024-03-27T10:15:30.105Z"))) + .isEqualTo(Instant.parse("2024-03-27T10:15:30.105Z")); + assertThat(toDateTime(Instant.parse("2024-03-27T10:15:30.105Z"))) + .isEqualTo(DateTime.parse("2024-03-27T10:15:30.105Z")); + assertThat(toInstant(toDateTime(Instant.parse("2024-03-27T10:15:30.105Z")))) + .isEqualTo(Instant.parse("2024-03-27T10:15:30.105Z")); + assertThat(toDateTime(toInstant(DateTime.parse("2024-03-27T10:15:30.105Z")))) + .isEqualTo(DateTime.parse("2024-03-27T10:15:30.105Z")); + } }