mirror of
https://github.com/google/nomulus
synced 2026-05-16 12:51:47 +00:00
Compare commits
10 Commits
nomulus-20
...
nomulus-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60d3653b46 | ||
|
|
80eefc6498 | ||
|
|
74f9f5d478 | ||
|
|
81b3a2fc5b | ||
|
|
f44642fe28 | ||
|
|
6e77a6b0e7 | ||
|
|
859f356466 | ||
|
|
fa15a66d9a | ||
|
|
76131fbd4e | ||
|
|
1196cd163b |
25
GEMINI.md
25
GEMINI.md
@@ -16,7 +16,11 @@ This document outlines foundational mandates, architectural patterns, and projec
|
||||
## 2. Time and Precision Handling (java.time Migration)
|
||||
|
||||
- **Idiomatic java.time Usage:** Avoid redundant conversions between `Instant` and `DateTime`. If a field or parameter is an `Instant`, use it directly. Do not convert to `DateTime` just to call a deprecated method if an `Instant` alternative exists or can be easily created. Furthermore, you should not call `toInstant()` or `toDateTime()` conversion methods when not strictly necessary; always prefer to use an alternative method that returns the correct type if one exists (e.g. use `tm().getTxTime()` which returns an `Instant` instead of calling `tm().getTransactionTime().toInstant()`).
|
||||
- **CRITICAL MISTAKE TO AVOID:** NEVER use `toInstant(clock.nowUtc())` or `toInstant(fakeClock.nowUtc())`. Both `Clock` and `FakeClock` have a `now()` method that natively returns a `java.time.Instant`. You MUST use `clock.now()` or `fakeClock.now()` directly. Converting `nowUtc()` to an Instant is an embarrassing mistake that demonstrates a lack of basic codebase familiarity.
|
||||
- **CRITICAL MISTAKES TO AVOID:**
|
||||
- NEVER use `toInstant(clock.nowUtc())` or `toInstant(fakeClock.nowUtc())`. Both `Clock` and `FakeClock` have a `now()` method that natively returns a `java.time.Instant`. You MUST use `clock.now()` or `fakeClock.now()` directly.
|
||||
- NEVER double-wrap conversions like `toInstant(toDateTime(...))` or `toDateTime(toInstant(...))`.
|
||||
- NEVER mark method parameters or local variables as `final` unnecessarily, as it clutters the codebase. For class fields and constants, use `final` where applicable (i.e. when the field is assigned once and never mutated) to enforce and communicate immutability.
|
||||
- When using test helpers like `assertThatCommand().atTime(...)` or `ForeignKeyUtils.loadResource(...)`, ALWAYS use the `Instant` overloads. DO NOT wrap `Instant` instances in `toDateTime(...)` just to pass them to deprecated overloads.
|
||||
- **UTC Timezones:** Do not use `ZoneId.of("UTC")`. Use a statically imported `UTC` from `ZoneOffset` instead (`import static java.time.ZoneOffset.UTC;`).
|
||||
- **Millisecond Precision:** Always truncate `Instant.now()` to milliseconds (using `.truncatedTo(ChronoUnit.MILLIS)`) to maintain consistency with Joda `DateTime` and the PostgreSQL schema (which enforces millisecond precision via JPA converters).
|
||||
- **Clock Injection:**
|
||||
@@ -73,6 +77,7 @@ Based on historical PR reviews, avoid the following common mistakes:
|
||||
- **Immutable Types:** Declare variables, fields, and return types explicitly as Guava immutable types (e.g., `ImmutableList<T>`, `ImmutableMap<K, V>`) instead of their generic interfaces (`List<T>`, `Map<K, V>`) to clearly communicate immutability contracts to callers. Use `toImmutableList()` and `toImmutableMap()` collectors in streams rather than manually accumulating into an `ArrayList` or `HashMap`.
|
||||
- **Constructors:** Do not perform heavy logic, I/O, or external API calls inside constructors. Initialization logic should be deferred or handled in a factory method or a dedicated startup routine.
|
||||
- **Exception Handling:** Do not catch generic `Exception` or `Throwable` if a more specific exception is expected. Never "log and re-throw" the same exception; either handle it entirely (and log), or throw it up the chain. For batch processes, catch exceptions at the individual item/chunk level so one failure doesn't abort the entire batch.
|
||||
- **Optional Assertions:** Prefer Truth's `.hasValue(...)` over `.isEqualTo(Optional.of(...))` for cleaner and more descriptive assertions on `Optional` types.
|
||||
- **Fail Fast:** Validate inputs and fail fast (using `Preconditions.checkArgument` or similar) at the highest level possible rather than passing invalid state (like `null`s) deeper into business logic.
|
||||
- **Magic Numbers:** Always document magic numbers or hardcoded limits (like `50.0` or `30`) with inline comments explaining the rationale.
|
||||
- **Null Safety and Optional:** Prefer using `Optional` for any variable that is expected to potentially be null. For any other variable that can be null but cannot use an `Optional` (e.g., function parameters or return types where `Optional` is not idiomatic), it MUST be annotated with `@Nullable`. Always use the `javax.annotation.Nullable` annotation.
|
||||
@@ -115,6 +120,7 @@ Before finalizing any PR or declaring a task complete, you MUST perform a thorou
|
||||
5. **Diff Scope:** Are there any formatting-only changes in files that I did not functionally modify? If so, revert them. Does the total line count of the diff align with the approved scope (e.g., ~1,000 lines for migrations)?
|
||||
6. **Commit Message:** Does the commit message title fit within 50 characters? Does the body encapsulate the entirety of the changes across the diff cleanly and professionally?
|
||||
7. **Missing Tests & Coverage:** *Perform a structured check for any new methods or modified behavior.* Did I add a new utility method (like `plusMonths(Instant, int)`) or change core logic? If so, I MUST open the corresponding test file and write tests to cover the new functionality (including edge cases, negative values, and leap years) before considering the task complete. A code review is not thorough if it only checks for compilation. I must actively ensure every new branch of logic has a test.
|
||||
8. **Package Lock:** Did I include `console-webapp/package-lock.json` in my diff? If so, I MUST revert it (`git checkout console-webapp/package-lock.json`) unless I explicitly intended to modify NPM dependencies. This file is often modified by the build process and should not be committed accidentally.
|
||||
|
||||
Only after actively confirming these checks against your diff are you permitted to finalize the task.
|
||||
|
||||
@@ -135,32 +141,37 @@ This project treats Error Prone warnings as errors.
|
||||
### 3. Build Strategy
|
||||
- **Surgical Changes**: In large-scale migrations, focus on "leaf" nodes first (Utilities -> Models -> Flows -> Actions).
|
||||
- **PR Size**: Minimize PR size by retaining Joda-Time bridge methods for high-level "Action" and "Flow" classes unless a full migration is requested. Reverting changes to DNS and Reporting logic while updating the underlying models is a valid strategy to keep PRs reviewable.
|
||||
- **Validation**: Always run `./gradlew build -x test` before attempting to run unit tests. Unit tests will not run if there are compilation errors in any part of the `core` module. Before finalizing a PR or declaring a task done, you MUST run the entire build using `./gradlew build` and verify that it succeeds completely without errors. Do not declare success if formatting checks (e.g., `spotlessCheck` or `javaIncrementalFormatCheck`) or tests fail. If formatting fails, run `./gradlew spotlessApply` and then re-run `./gradlew build` to verify everything passes.
|
||||
- **Validation**: Always run `./gradlew build -x test` before attempting to run unit tests. Unit tests will not run if there are compilation errors in any part of the `core` module. Before finalizing a PR or declaring a task done, you MUST verify your changes. **Prefer scoped builds** (e.g., `./gradlew :core:build`) if you are only modifying backend Java code. Running the global `./gradlew build` triggers the frontend `console-webapp` build, which unnecessarily runs `npmInstallDeps` and modifies `package-lock.json`. If you must run a global build, you must revert `console-webapp/package-lock.json` afterwards. Do not declare success if formatting checks (e.g., `spotlessCheck` or `javaIncrementalFormatCheck`) or tests fail. If formatting fails, run `./gradlew spotlessApply` and then re-run your build command to verify everything passes.
|
||||
|
||||
## 🚫 Common Pitfalls to Avoid
|
||||
|
||||
- **Mixing Joda and Java Durations:** Methods like `Tld.get().getRenewGracePeriodLength()` return a **Joda** `Duration`, which cannot be passed directly to `Instant.plus(...)` because it doesn't implement `TemporalAmount`. You MUST use `.plusMillis(duration.getMillis())` instead.
|
||||
- **Serialization Precision (`.000Z`):** When asserting against or generating XML/YAML files, remember that millisecond precision (`.000Z`) is required. Always use `DateTimeUtils.formatInstant(...)` to format `Instant` objects (it preserves the `.000Z` suffix) instead of `Instant.toString()` (which drops it for exact seconds). We have added custom Jackson `InstantKeySerializer`s for this purpose, but you must keep this precision in mind when manually updating `.xml` or `.yaml` test data.
|
||||
- **Static Imports:** Methods like `toDateTime`, `toInstant`, `plusYears`, `plusMonths`, and `minusDays` from `DateTimeUtils` MUST be statically imported. Do NOT use them fully qualified (e.g., `DateTimeUtils.plusMonths(...)`).
|
||||
|
||||
- **Redundant Parses:** Never write `toDateTime(Instant.parse(...))` or `toInstant(DateTime.parse(...))`. If you need a `DateTime`, use `DateTime.parse(...)` directly. If you need an `Instant`, use `Instant.parse(...)` directly.
|
||||
- **cloneProjectedAtTime vs cloneProjectedAtInstant:** When converting tests and logic that use `clock.now()` to project resource state into the future or past, do not wrap the Java `Instant` in `toDateTime()` just to call `cloneProjectedAtTime()`. Instead, switch the method call to use the native `cloneProjectedAtInstant()` method which is available on all `EppResource` models.
|
||||
- **Do not go in circles with the build:** If you see an `InlineMeSuggester` error, apply the suppression to **ALL** similar methods in that file and related files in one turn. Do not fix them one by one.
|
||||
- **Do not go in circles with the build:** If you see an `InlineMeSuggester` error, apply the suppression to **ALL** similar methods in that file and related files in one turn. Do not fix them one by one. Furthermore, do not run a global `./gradlew build` when a scoped `./gradlew :core:build` or `./gradlew :core:test` is faster and more appropriate. Run global builds only when doing final verification.
|
||||
- **Exception Conversion in Tests:** When migrating time types (e.g., from Joda `DateTime` to Java `Instant`), be extremely careful with tests that verify parsing failures (e.g., `assertThrows(IllegalArgumentException.class, ...)`). Joda's `DateTime.parse()` throws an `IllegalArgumentException` on failure, but `Instant.parse()` throws a `java.time.format.DateTimeParseException`. You must update the expected exception type in these tests to ensure they actually test the correct behavior, and verify the tests are not failing prematurely on the first line if it contains invalid data meant to be ignored.
|
||||
- Dagger/AutoValue corruption: If you modify a builder or a component incorrectly, Dagger will fail to generate code, leading to hundreds of "cannot find symbol" errors. If this happens, `git checkout` the last working state of the specific file and re-apply changes more surgically.
|
||||
- **`replace` tool context**: When using `replace` on large files (like `Tld.java` or `DomainBase.java`), provide significant surrounding context. These files have many similar method signatures (getters/setters) that can lead to incorrect replacements.
|
||||
|
||||
---
|
||||
|
||||
# GitHub and Pull Request Protocol
|
||||
## GitHub and Pull Request Protocol
|
||||
|
||||
This protocol defines the standard for interacting with GitHub repositories and processing Pull Request (PR) feedback.
|
||||
|
||||
## 1. Interaction via `gh` CLI
|
||||
### 1. Interaction via `gh` CLI
|
||||
- **Primary Tool:** ALWAYS use the `gh` CLI for all GitHub-related operations (listing PRs, viewing PR content, checking status, adding comments).
|
||||
- **Credential Safety:** Never expose tokens or credentials in shell commands.
|
||||
|
||||
## 2. Processing PR Feedback
|
||||
### 2. Processing PR Feedback
|
||||
- **Systematic Review:** When asked to address PR comments, first fetch all comments using `gh pr view <number> --json reviews,comments`.
|
||||
- **Minimal Scope Expansion:** Address comments surgically. If a fix requires changes beyond a few lines or expands the PR's original scope significantly, DO NOT implement it without explicit user approval. Instead, report the issue to the user.
|
||||
- **Verification:** After addressing feedback, run the full build (`./gradlew build`) and relevant tests to ensure no regressions were introduced.
|
||||
|
||||
## 3. PR Lifecycle Management
|
||||
### 3. PR Lifecycle Management
|
||||
- **One Commit Per PR:** Ensure all changes are squashed into a single, clean commit. Use `git commit --amend --no-edit` for follow-up fixes.
|
||||
- **Clean Workspace:** Always run `git status` and verify the repository state before declaring a task complete.
|
||||
- **Package Lock:** The Gradle build automatically modifies `console-webapp/package-lock.json` via the `npmInstallDeps` task. ALWAYS revert this file (`git checkout console-webapp/package-lock.json`) before staging changes or finalizing a commit unless you explicitly modified NPM dependencies.
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -30,14 +31,14 @@ import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.ReadableDuration;
|
||||
|
||||
/** Utilities methods and constants related to Joda {@link DateTime} objects. */
|
||||
public abstract class DateTimeUtils {
|
||||
|
||||
/** The start of the epoch, in a convenient constant. */
|
||||
@Deprecated public static final DateTime START_OF_TIME = new DateTime(0, DateTimeZone.UTC);
|
||||
@Deprecated public static final DateTime START_OF_TIME = new DateTime(0, 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);
|
||||
@@ -49,8 +50,7 @@ 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);
|
||||
@Deprecated public static final DateTime END_OF_TIME = new DateTime(Long.MAX_VALUE / 1000, UTC);
|
||||
|
||||
/**
|
||||
* An instant in the far future that we can treat as infinity.
|
||||
@@ -69,13 +69,22 @@ public abstract class DateTimeUtils {
|
||||
* <p>Handles large/negative years by using a sign prefix if necessary, compatible with {@link
|
||||
* Instant#parse}.
|
||||
*/
|
||||
public static final DateTimeFormatter ISO_8601_FORMATTER =
|
||||
private static final DateTimeFormatter ISO_8601_FORMATTER =
|
||||
new DateTimeFormatterBuilder()
|
||||
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.NORMAL)
|
||||
.appendPattern("-MM-dd'T'HH:mm:ss.SSS'Z'")
|
||||
.toFormatter()
|
||||
.withZone(ZoneOffset.UTC);
|
||||
|
||||
/** A formatter that produces lowercase, filename-safe and job-name-safe timestamps. */
|
||||
public static final DateTimeFormatter LOWERCASE_TIMESTAMP_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd't'HH-mm-ss'z'").withZone(ZoneOffset.UTC);
|
||||
|
||||
/** Formats an {@link Instant} to an ISO-8601 string. */
|
||||
public static String formatInstant(Instant instant) {
|
||||
return ISO_8601_FORMATTER.format(instant);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ISO-8601 string to an {@link Instant}.
|
||||
*
|
||||
@@ -142,6 +151,18 @@ public abstract class DateTimeUtils {
|
||||
return !timeToCheck.isAfter(timeToCompareTo);
|
||||
}
|
||||
|
||||
/** Converts a Joda-Time Duration to a java.time.Duration. */
|
||||
@Nullable
|
||||
public static java.time.Duration toJavaDuration(@Nullable ReadableDuration duration) {
|
||||
return duration == null ? null : java.time.Duration.ofMillis(duration.getMillis());
|
||||
}
|
||||
|
||||
/** Converts a java.time.Duration to a Joda-Time Duration. */
|
||||
@Nullable
|
||||
public static org.joda.time.Duration toJodaDuration(@Nullable java.time.Duration duration) {
|
||||
return duration == null ? null : org.joda.time.Duration.millis(duration.toMillis());
|
||||
}
|
||||
|
||||
/** 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);
|
||||
@@ -170,7 +191,7 @@ public abstract class DateTimeUtils {
|
||||
* 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 plusYears(Instant now, long years) {
|
||||
public static Instant plusYears(Instant now, int years) {
|
||||
checkArgument(years >= 0);
|
||||
return (years == 0)
|
||||
? now
|
||||
@@ -232,7 +253,17 @@ public abstract class DateTimeUtils {
|
||||
}
|
||||
|
||||
public static LocalDate toLocalDate(Date date) {
|
||||
return new LocalDate(date.getTime(), DateTimeZone.UTC);
|
||||
return new LocalDate(date.getTime(), UTC);
|
||||
}
|
||||
|
||||
/** Converts a java.time.LocalDate to a Joda-Time LocalDate. */
|
||||
public static LocalDate toJodaLocalDate(java.time.LocalDate localDate) {
|
||||
return new LocalDate(localDate.getYear(), localDate.getMonthValue(), localDate.getDayOfMonth());
|
||||
}
|
||||
|
||||
/** Converts an Instant to a Joda-Time LocalDate in UTC. */
|
||||
public static LocalDate toJodaLocalDate(Instant instant) {
|
||||
return new LocalDate(instant.toEpochMilli(), UTC);
|
||||
}
|
||||
|
||||
/** Convert a joda {@link DateTime} to a java.time {@link Instant}, null-safe. */
|
||||
@@ -244,7 +275,7 @@ public abstract class DateTimeUtils {
|
||||
/** 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);
|
||||
return (instant == null) ? null : new DateTime(instant.toEpochMilli(), UTC);
|
||||
}
|
||||
|
||||
/** Convert a java.time {@link java.time.Instant} to a joda {@link org.joda.time.Instant}. */
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.util;
|
||||
|
||||
import java.time.Duration;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.ReadableDuration;
|
||||
|
||||
@@ -32,6 +33,15 @@ public interface Sleeper {
|
||||
*/
|
||||
void sleep(ReadableDuration duration) throws InterruptedException;
|
||||
|
||||
/**
|
||||
* Puts the current thread to sleep.
|
||||
*
|
||||
* @throws InterruptedException if this thread was interrupted
|
||||
*/
|
||||
default void sleep(Duration duration) throws InterruptedException {
|
||||
sleep(DateTimeUtils.toJodaDuration(duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the current thread to sleep, ignoring interrupts.
|
||||
*
|
||||
@@ -42,6 +52,18 @@ public interface Sleeper {
|
||||
*/
|
||||
void sleepUninterruptibly(ReadableDuration duration);
|
||||
|
||||
/**
|
||||
* Puts the current thread to sleep, ignoring interrupts.
|
||||
*
|
||||
* <p>If {@link InterruptedException} was caught, then {@code Thread.currentThread().interrupt()}
|
||||
* will be called at the end of the {@code duration}.
|
||||
*
|
||||
* @see com.google.common.util.concurrent.Uninterruptibles#sleepUninterruptibly
|
||||
*/
|
||||
default void sleepUninterruptibly(Duration duration) {
|
||||
sleepUninterruptibly(DateTimeUtils.toJodaDuration(duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the current thread to interruptible sleep.
|
||||
*
|
||||
@@ -57,4 +79,20 @@ public interface Sleeper {
|
||||
throw new RuntimeException("Interrupted.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the current thread to interruptible sleep.
|
||||
*
|
||||
* <p>This is a convenience method for {@link #sleep} that properly converts an {@link
|
||||
* InterruptedException} to a {@link RuntimeException}.
|
||||
*/
|
||||
default void sleepInterruptibly(Duration duration) {
|
||||
try {
|
||||
sleep(duration);
|
||||
} catch (InterruptedException e) {
|
||||
// Restore current thread's interrupted state.
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("Interrupted.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
|
||||
package google.registry.util;
|
||||
|
||||
import static java.time.temporal.ChronoUnit.MILLIS;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -43,6 +43,6 @@ public class SystemClock implements Clock {
|
||||
// (which uses millisecond precision via DateTimeConverter). This prevents subtle comparison
|
||||
// bugs where a high-precision Instant would be considered "after" a truncated database
|
||||
// timestamp.
|
||||
return Instant.now().truncatedTo(ChronoUnit.MILLIS);
|
||||
return Instant.now().truncatedTo(MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
package google.registry.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.util.DateTimeUtils.toJavaDuration;
|
||||
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.Serializable;
|
||||
import java.time.Duration;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.ReadableDuration;
|
||||
|
||||
@@ -41,6 +41,6 @@ public final class SystemSleeper implements Sleeper, Serializable {
|
||||
@Override
|
||||
public void sleepUninterruptibly(ReadableDuration duration) {
|
||||
checkArgument(duration.getMillis() >= 0);
|
||||
Uninterruptibles.sleepUninterruptibly(Duration.ofMillis(duration.getMillis()));
|
||||
Uninterruptibles.sleepUninterruptibly(toJavaDuration(duration));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +89,11 @@ public final class FakeClock implements Clock {
|
||||
currentTimeMillis.addAndGet(duration.getMillis());
|
||||
}
|
||||
|
||||
/** Advances clock by some duration. */
|
||||
public void advanceBy(java.time.Duration duration) {
|
||||
currentTimeMillis.addAndGet(duration.toMillis());
|
||||
}
|
||||
|
||||
/** Sets the time to the specified instant. */
|
||||
public void setTo(ReadableInstant time) {
|
||||
currentTimeMillis.set(time.getMillis());
|
||||
|
||||
@@ -104,7 +104,7 @@ PRESUBMITS = {
|
||||
|
||||
# System.(out|err).println should only appear in tools/ or load-testing/
|
||||
PresubmitCheck(
|
||||
r".*\bSystem\.(out|err)\.print", "java", {
|
||||
r".*\bSystem\s*\.\s*(?:out|err)\s*\.\s*print.*", "java", {
|
||||
"/tools/", "/example/", "/load-testing/",
|
||||
"RegistryTestServerMain.java", "TestServerExtension.java"
|
||||
}):
|
||||
@@ -139,7 +139,7 @@ PRESUBMITS = {
|
||||
):
|
||||
"All soy templates must use strict autoescaping",
|
||||
PresubmitCheck(
|
||||
r".*\nimport (static )?.*\.shaded\..*",
|
||||
r".*\nimport\s+(?:static\s+)?.*\.shaded\..*",
|
||||
"java",
|
||||
{"/node_modules/"},
|
||||
):
|
||||
@@ -163,7 +163,7 @@ PRESUBMITS = {
|
||||
):
|
||||
"Use status code from jakarta.servlet.http.HttpServletResponse.",
|
||||
PresubmitCheck(
|
||||
r".*mock\(Response\.class\).*",
|
||||
r".*mock\(\s*Response\.class\s*\).*",
|
||||
"java",
|
||||
{"/node_modules/"},
|
||||
):
|
||||
@@ -181,13 +181,122 @@ PRESUBMITS = {
|
||||
):
|
||||
"Do not use javax.inject.* Use jakarta.inject.* instead.",
|
||||
PresubmitCheck(
|
||||
r".*import jakarta.persistence.(Pre|Post)(Persist|Load|Remove|Update);",
|
||||
r".*import\s+jakarta\.persistence\.(?:Pre|Post)(?:Persist|Load|Remove|Update)\s*;",
|
||||
"java",
|
||||
{"EntityCallbacksListener.java"},
|
||||
):
|
||||
"Hibernate lifecycle events aren't called for embedded entities, so it's "
|
||||
"usually best to avoid them. Instead, use the annotations defined in "
|
||||
"EntityCallbacksListener.java"
|
||||
"EntityCallbacksListener.java",
|
||||
PresubmitCheck(
|
||||
r".*\.isEqualTo\(\s*Optional\.of\(.*",
|
||||
"java",
|
||||
{},
|
||||
):
|
||||
"Do not use .isEqualTo(Optional.of(...)). Use Truth's .hasValue(...) instead.",
|
||||
# TODO: Remove the java.time migration presubmit checks below once the entire codebase has been migrated to java.time.
|
||||
PresubmitCheck(
|
||||
r".*toDateTime\(\s*toInstant\(.*",
|
||||
"java",
|
||||
{"DateTimeUtilsTest.java"},
|
||||
):
|
||||
"Do not double-wrap toDateTime(toInstant(...)).",
|
||||
PresubmitCheck(
|
||||
r".*toInstant\(\s*toDateTime\(.*",
|
||||
"java",
|
||||
{"DateTimeUtilsTest.java"},
|
||||
):
|
||||
"Do not double-wrap toInstant(toDateTime(...)).",
|
||||
PresubmitCheck(
|
||||
r".*toInstant\([^;]*[cC]lock\.nowUtc\(\).*",
|
||||
"java",
|
||||
{},
|
||||
):
|
||||
"Do not use toInstant(clock.nowUtc()). Use clock.now() instead.",
|
||||
PresubmitCheck(
|
||||
r".*toDateTime\([^;]*[cC]lock\.now\(\).*",
|
||||
"java",
|
||||
{},
|
||||
):
|
||||
"Do not use toDateTime(clock.now()). Use clock.nowUtc() instead.",
|
||||
PresubmitCheck(
|
||||
r".*toInstant\([^;]*tm\(\)\.getTransactionTime\(\).*",
|
||||
"java",
|
||||
{},
|
||||
):
|
||||
"Do not use toInstant(tm().getTransactionTime()). Use tm().getTxTime() instead.",
|
||||
PresubmitCheck(
|
||||
r".*toDateTime\([^;]*tm\(\)\.getTxTime\(\).*",
|
||||
"java",
|
||||
{},
|
||||
):
|
||||
"Do not use toDateTime(tm().getTxTime()). Use tm().getTransactionTime() instead.",
|
||||
PresubmitCheck(
|
||||
r".*\(\s*Instant\s*\)\s*(?:this\.)?(?:fakeClock|clock)\.now\(\s*\).*",
|
||||
"java",
|
||||
{},
|
||||
):
|
||||
"Do not unnecessarily cast clock.now() to Instant.",
|
||||
PresubmitCheck(
|
||||
r".*toDateTime\(\s*Instant\.now\(.*",
|
||||
"java",
|
||||
{},
|
||||
):
|
||||
"Do not wrap Instant.now() in toDateTime. Use DateTime.now(UTC) directly.",
|
||||
PresubmitCheck(
|
||||
r".*toInstant\(\s*DateTime\.now\(.*",
|
||||
"java",
|
||||
{},
|
||||
):
|
||||
"Do not wrap DateTime.now() in toInstant. Use Instant.now().truncatedTo(ChronoUnit.MILLIS) directly.",
|
||||
PresubmitCheck(
|
||||
r".*toDateTime\(\s*Instant\.parse\(.*",
|
||||
"java",
|
||||
{"DateTimeUtilsTest.java"},
|
||||
):
|
||||
"Do not wrap Instant.parse in toDateTime. Use DateTime.parse directly.",
|
||||
PresubmitCheck(
|
||||
r".*toInstant\(\s*DateTime\.parse\(.*",
|
||||
"java",
|
||||
{"DateTimeUtilsTest.java"},
|
||||
):
|
||||
"Do not wrap DateTime.parse in toInstant. Use Instant.parse directly.",
|
||||
PresubmitCheck(
|
||||
r".*cloneProjectedAtTime\(\s*toDateTime\(.*",
|
||||
"java",
|
||||
{},
|
||||
):
|
||||
"Do not use cloneProjectedAtTime(toDateTime(...)). Use cloneProjectedAtInstant(...) instead.",
|
||||
PresubmitCheck(
|
||||
r".*ZoneId\.of\(\s*\"UTC\"\s*\).*",
|
||||
"java",
|
||||
{},
|
||||
):
|
||||
"Do not use ZoneId.of(\"UTC\"). Use java.time.ZoneOffset.UTC.",
|
||||
PresubmitCheck(
|
||||
r".*toDateTime\(\s*END_INSTANT\s*\).*",
|
||||
"java",
|
||||
{"DateTimeUtilsTest.java"},
|
||||
):
|
||||
"Do not wrap END_INSTANT in toDateTime. Use END_OF_TIME.",
|
||||
PresubmitCheck(
|
||||
r".*toInstant\(\s*END_OF_TIME\s*\).*",
|
||||
"java",
|
||||
{"DateTimeUtilsTest.java"},
|
||||
):
|
||||
"Do not wrap END_OF_TIME in toInstant. Use END_INSTANT.",
|
||||
PresubmitCheck(
|
||||
r".*toDateTime\(\s*START_INSTANT\s*\).*",
|
||||
"java",
|
||||
{"DateTimeUtilsTest.java"},
|
||||
):
|
||||
"Do not wrap START_INSTANT in toDateTime. Use START_OF_TIME.",
|
||||
PresubmitCheck(
|
||||
r".*toInstant\(\s*START_OF_TIME\s*\).*",
|
||||
"java",
|
||||
{"DateTimeUtilsTest.java"},
|
||||
):
|
||||
"Do not wrap START_OF_TIME in toInstant. Use START_INSTANT."
|
||||
}
|
||||
|
||||
# Note that this regex only works for one kind of Flyway file. If we want to
|
||||
|
||||
123
console-webapp/package-lock.json
generated
123
console-webapp/package-lock.json
generated
@@ -628,6 +628,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/@types/node": {
|
||||
"version": "25.6.0",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/node/-/node-25.6.0.tgz",
|
||||
"integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/@vitejs/plugin-basic-ssl": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.0.tgz",
|
||||
@@ -641,6 +653,24 @@
|
||||
"vite": "^6.0.0 || ^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/chokidar": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/chokidar/-/chokidar-5.0.0.tgz",
|
||||
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"readdirp": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||
@@ -664,6 +694,22 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/readdirp": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/readdirp/-/readdirp-5.0.0.tgz",
|
||||
"integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
@@ -697,6 +743,15 @@
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/undici-types": {
|
||||
"version": "7.19.2",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/undici-types/-/undici-types-7.19.2.tgz",
|
||||
"integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/vite": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz",
|
||||
@@ -916,6 +971,24 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/chokidar": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/chokidar/-/chokidar-5.0.0.tgz",
|
||||
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"readdirp": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/cli-spinners": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz",
|
||||
@@ -1019,6 +1092,22 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/readdirp": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/readdirp/-/readdirp-5.0.0.tgz",
|
||||
"integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
@@ -4606,6 +4695,24 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@schematics/angular/node_modules/chokidar": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/chokidar/-/chokidar-5.0.0.tgz",
|
||||
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"readdirp": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@schematics/angular/node_modules/cli-spinners": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz",
|
||||
@@ -4709,6 +4816,22 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/@schematics/angular/node_modules/readdirp": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/readdirp/-/readdirp-5.0.0.tgz",
|
||||
"integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 20.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@schematics/angular/node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
|
||||
@@ -579,6 +579,11 @@ if (environment == 'alpha') {
|
||||
mainClass: 'google.registry.beam.resave.ResaveAllEppResourcesPipeline',
|
||||
metaData: 'google/registry/beam/resave_all_epp_resources_pipeline_metadata.json'
|
||||
],
|
||||
smokeTest:
|
||||
[
|
||||
mainClass: 'google.registry.beam.common.SmokeTestPipeline',
|
||||
metaData: 'google/registry/beam/smoke_test_pipeline_metadata.json'
|
||||
],
|
||||
]
|
||||
project.tasks.create("stageBeamPipelines") {
|
||||
doLast {
|
||||
|
||||
@@ -26,8 +26,8 @@ import google.registry.model.EppResource;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.request.Action;
|
||||
import jakarta.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
/** Helper class to enqueue tasks for handling asynchronous operations in flows. */
|
||||
public final class AsyncTaskEnqueuer {
|
||||
@@ -41,7 +41,7 @@ public final class AsyncTaskEnqueuer {
|
||||
public static final String QUEUE_ASYNC_ACTIONS = "async-actions";
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private static final Duration MAX_ASYNC_ETA = Duration.standardDays(30);
|
||||
private static final Duration MAX_ASYNC_ETA = Duration.ofDays(30);
|
||||
|
||||
private final CloudTasksUtils cloudTasksUtils;
|
||||
|
||||
@@ -58,12 +58,12 @@ public final class AsyncTaskEnqueuer {
|
||||
*/
|
||||
public void enqueueAsyncResave(
|
||||
VKey<? extends EppResource> entityKey,
|
||||
DateTime now,
|
||||
ImmutableSortedSet<DateTime> whenToResave) {
|
||||
DateTime firstResave = whenToResave.first();
|
||||
Instant now,
|
||||
ImmutableSortedSet<Instant> whenToResave) {
|
||||
Instant firstResave = whenToResave.first();
|
||||
checkArgument(isBeforeOrAt(now, firstResave), "Can't enqueue a resave to run in the past");
|
||||
Duration etaDuration = new Duration(now, firstResave);
|
||||
if (etaDuration.isLongerThan(MAX_ASYNC_ETA)) {
|
||||
Duration etaDuration = Duration.between(now, firstResave);
|
||||
if (etaDuration.compareTo(MAX_ASYNC_ETA) > 0) {
|
||||
logger.atInfo().log(
|
||||
"Ignoring async re-save of %s; %s is past the ETA threshold of %s.",
|
||||
entityKey, firstResave, MAX_ASYNC_ETA);
|
||||
|
||||
@@ -24,9 +24,9 @@ import static google.registry.request.RequestParameters.extractOptionalBooleanPa
|
||||
import static google.registry.request.RequestParameters.extractOptionalInstantParameter;
|
||||
import static google.registry.request.RequestParameters.extractOptionalIntParameter;
|
||||
import static google.registry.request.RequestParameters.extractOptionalParameter;
|
||||
import static google.registry.request.RequestParameters.extractRequiredDatetimeParameter;
|
||||
import static google.registry.request.RequestParameters.extractRequiredInstantParameter;
|
||||
import static google.registry.request.RequestParameters.extractRequiredParameter;
|
||||
import static google.registry.request.RequestParameters.extractSetOfDatetimeParameters;
|
||||
import static google.registry.request.RequestParameters.extractSetOfInstantParameters;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -44,7 +44,6 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Dagger module for injecting common settings for batch actions. */
|
||||
@Module
|
||||
@@ -98,14 +97,14 @@ public class BatchModule {
|
||||
|
||||
@Provides
|
||||
@Parameter(PARAM_REQUESTED_TIME)
|
||||
static DateTime provideRequestedTime(HttpServletRequest req) {
|
||||
return extractRequiredDatetimeParameter(req, PARAM_REQUESTED_TIME);
|
||||
static Instant provideRequestedTime(HttpServletRequest req) {
|
||||
return extractRequiredInstantParameter(req, PARAM_REQUESTED_TIME);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter(PARAM_RESAVE_TIMES)
|
||||
static ImmutableSet<DateTime> provideResaveTimes(HttpServletRequest req) {
|
||||
return extractSetOfDatetimeParameters(req, PARAM_RESAVE_TIMES);
|
||||
static ImmutableSet<Instant> provideResaveTimes(HttpServletRequest req) {
|
||||
return extractSetOfInstantParameters(req, PARAM_RESAVE_TIMES);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -42,10 +42,10 @@ import google.registry.request.auth.Auth;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.logging.Level;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* An action that transfers a set of domains from one registrar to another.
|
||||
@@ -158,7 +158,7 @@ public class BulkDomainTransferAction implements Runnable {
|
||||
return null;
|
||||
};
|
||||
|
||||
if (!lockHandler.executeWithLocks(runner, null, Duration.standardHours(1), LOCK_NAME)) {
|
||||
if (!lockHandler.executeWithLocks(runner, null, Duration.ofHours(1), LOCK_NAME)) {
|
||||
// Send a 200-series status code to prevent this conflicting action from retrying.
|
||||
response.setStatus(SC_NO_CONTENT);
|
||||
response.setPayload("Could not acquire lock; already running?");
|
||||
|
||||
@@ -32,8 +32,8 @@ import google.registry.request.auth.Auth;
|
||||
import google.registry.ui.server.SendEmailUtils;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Days;
|
||||
|
||||
/**
|
||||
* An action that checks all {@link BulkPricingPackage} objects for compliance with their max create
|
||||
@@ -111,8 +111,7 @@ public class CheckBulkComplianceAction implements Runnable {
|
||||
+ " 'DOMAIN_CREATE'",
|
||||
Long.class)
|
||||
.setParameter("token", bulkPricingPackage.getToken())
|
||||
.setParameter(
|
||||
"lastBilling", minusYears(bulkPricingPackage.getNextBillingDateInstant(), 1))
|
||||
.setParameter("lastBilling", minusYears(bulkPricingPackage.getNextBillingDate(), 1))
|
||||
.getSingleResult();
|
||||
if (creates > bulkPricingPackage.getMaxCreates()) {
|
||||
long overage = creates - bulkPricingPackage.getMaxCreates();
|
||||
@@ -186,7 +185,7 @@ public class CheckBulkComplianceAction implements Runnable {
|
||||
int daysSinceLastNotification =
|
||||
bulkPricingPackage
|
||||
.getLastNotificationSent()
|
||||
.map(sentDate -> Days.daysBetween(sentDate, clock.nowUtc()).getDays())
|
||||
.map(sentDate -> (int) Duration.between(sentDate, clock.now()).toDays())
|
||||
.orElse(Integer.MAX_VALUE);
|
||||
// Send a warning email if 30-39 days since last notification and an upgrade email if 40+ days
|
||||
if (daysSinceLastNotification >= THIRTY_DAYS) {
|
||||
@@ -222,7 +221,7 @@ public class CheckBulkComplianceAction implements Runnable {
|
||||
bulkPricingPackage.getMaxDomains(),
|
||||
activeDomains);
|
||||
sendNotification(bulkToken, emailSubject, body, registrar.get());
|
||||
tm().put(bulkPricingPackage.asBuilder().setLastNotificationSent(clock.nowUtc()).build());
|
||||
tm().put(bulkPricingPackage.asBuilder().setLastNotificationSent(clock.now()).build());
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
String.format("Could not find registrar for bulk token %s", bulkToken));
|
||||
|
||||
@@ -52,11 +52,11 @@ import jakarta.inject.Inject;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.function.Supplier;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Utilities for dealing with Cloud Tasks. */
|
||||
public class CloudTasksUtils implements Serializable {
|
||||
@@ -251,7 +251,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
method,
|
||||
service,
|
||||
params,
|
||||
Duration.millis(random.nextInt((int) SECONDS.toMillis(jitterSeconds.get()))));
|
||||
Duration.ofMillis(random.nextInt((int) SECONDS.toMillis(jitterSeconds.get()))));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,12 +302,12 @@ public class CloudTasksUtils implements Serializable {
|
||||
Action.Service service,
|
||||
Multimap<String, String> params,
|
||||
Duration delay) {
|
||||
if (delay.isEqual(Duration.ZERO)) {
|
||||
if (delay.isZero()) {
|
||||
return createTask(path, method, service, params);
|
||||
}
|
||||
checkArgument(delay.isLongerThan(Duration.ZERO), "Negative duration is not supported.");
|
||||
checkArgument(!delay.isNegative(), "Negative duration is not supported.");
|
||||
return Task.newBuilder(createTask(path, method, service, params))
|
||||
.setScheduleTime(Timestamps.fromMillis(clock.nowUtc().plus(delay).getMillis()))
|
||||
.setScheduleTime(Timestamps.fromMillis(clock.now().plus(delay).toEpochMilli()))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,11 +42,11 @@ import google.registry.request.auth.Auth;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.logging.Level;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* An action that deletes all non-renewing domains whose expiration dates have now passed.
|
||||
@@ -116,7 +116,7 @@ public class DeleteExpiredDomainsAction implements Runnable {
|
||||
return null;
|
||||
};
|
||||
|
||||
if (!lockHandler.executeWithLocks(runner, null, Duration.standardHours(1), LOCK_NAME)) {
|
||||
if (!lockHandler.executeWithLocks(runner, null, Duration.ofHours(1), LOCK_NAME)) {
|
||||
// Send a 200-series status code to prevent this conflicting action from retrying.
|
||||
response.setStatus(SC_NO_CONTENT);
|
||||
response.setPayload("Could not acquire lock; already running?");
|
||||
@@ -172,7 +172,7 @@ public class DeleteExpiredDomainsAction implements Runnable {
|
||||
() -> {
|
||||
Domain transDomain = tm().loadByKey(domain.createVKey());
|
||||
if (domain.getAutorenewEndTime().isEmpty()
|
||||
|| domain.getAutorenewEndTime().get().isAfter(tm().getTransactionTime())) {
|
||||
|| domain.getAutorenewEndTime().get().isAfter(tm().getTxTime())) {
|
||||
logger.atSevere().log(
|
||||
"Failed to delete domain %s because of its autorenew end time: %s.",
|
||||
transDomain.getDomainName(), transDomain.getAutorenewEndTime());
|
||||
|
||||
@@ -115,7 +115,7 @@ public class DeleteLoadTestDataAction implements Runnable {
|
||||
VKey<Host> hostVKey = host.createVKey();
|
||||
// We can remove hosts from linked domains, so we should do so then delete the hosts
|
||||
ImmutableSet<VKey<Domain>> linkedDomains =
|
||||
EppResourceUtils.getLinkedDomainKeys(hostVKey, clock.nowUtc(), null);
|
||||
EppResourceUtils.getLinkedDomainKeys(hostVKey, clock.now(), null);
|
||||
tm().loadByKeys(linkedDomains)
|
||||
.values()
|
||||
.forEach(
|
||||
|
||||
@@ -218,7 +218,7 @@ public class DeleteProberDataAction implements Runnable {
|
||||
// successfully soft-delete the domain (thus leaving its DNS entry published). We soft-delete
|
||||
// it now so that the DNS entry can be handled. The domain will then be hard-deleted the next
|
||||
// time the job is run.
|
||||
if (EppResourceUtils.isActive(domain, tm().getTransactionTime())) {
|
||||
if (EppResourceUtils.isActive(domain, tm().getTxTime())) {
|
||||
if (isDryRun) {
|
||||
logger.atInfo().log(
|
||||
"Would soft-delete the active domain: %s (%s).",
|
||||
|
||||
@@ -111,7 +111,7 @@ public class ExpandBillingRecurrencesAction implements Runnable {
|
||||
() ->
|
||||
tm().loadByKeyIfPresent(Cursor.createGlobalVKey(RECURRING_BILLING))
|
||||
.orElse(Cursor.createGlobal(RECURRING_BILLING, START_INSTANT))
|
||||
.getCursorTimeInstant()));
|
||||
.getCursorTime()));
|
||||
checkArgument(
|
||||
startTime.isBefore(endTime),
|
||||
"Start time (%s) must be before end time (%s)",
|
||||
|
||||
@@ -18,6 +18,8 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static google.registry.util.DateTimeUtils.isAtOrAfter;
|
||||
import static google.registry.util.DateTimeUtils.toJodaDuration;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_NO_CONTENT;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
@@ -36,13 +38,12 @@ import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import google.registry.util.EmailMessage;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Task that re-locks a previously-Registry-Locked domain after a predetermined period of time. */
|
||||
@Action(
|
||||
@@ -59,8 +60,8 @@ public class RelockDomainAction implements Runnable {
|
||||
|
||||
static final int ATTEMPTS_BEFORE_SLOWDOWN = 36; // every ten minutes for six hours then every hour
|
||||
static final int FAILURES_BEFORE_EMAIL = 2; // email after three failures, one half hour
|
||||
private static final Duration TEN_MINUTES = Duration.standardMinutes(10);
|
||||
private static final Duration ONE_HOUR = Duration.standardHours(1);
|
||||
private static final Duration TEN_MINUTES = Duration.ofMinutes(10);
|
||||
private static final Duration ONE_HOUR = Duration.ofHours(1);
|
||||
|
||||
private static final String RELOCK_SUCCESS_EMAIL_TEMPLATE =
|
||||
"""
|
||||
@@ -134,7 +135,7 @@ public class RelockDomainAction implements Runnable {
|
||||
String.format("Unknown revision ID %d", oldUnlockRevisionId)));
|
||||
domain =
|
||||
tm().loadByKey(VKey.create(Domain.class, oldLock.getRepoId()))
|
||||
.cloneProjectedAtTime(tm().getTransactionTime());
|
||||
.cloneProjectedAtTime(tm().getTxTime());
|
||||
} catch (Throwable t) {
|
||||
handleTransientFailure(Optional.ofNullable(oldLock), t);
|
||||
return;
|
||||
@@ -188,7 +189,7 @@ public class RelockDomainAction implements Runnable {
|
||||
"Domain %s has a pending delete.",
|
||||
domainName);
|
||||
checkArgument(
|
||||
!DateTimeUtils.isAtOrAfter(tm().getTxTime(), domain.getDeletionTime()),
|
||||
!isAtOrAfter(tm().getTxTime(), domain.getDeletionTime()),
|
||||
"Domain %s has been deleted.",
|
||||
domainName);
|
||||
checkArgument(
|
||||
@@ -237,7 +238,8 @@ public class RelockDomainAction implements Runnable {
|
||||
}
|
||||
}
|
||||
Duration timeBeforeRetry = previousAttempts < ATTEMPTS_BEFORE_SLOWDOWN ? TEN_MINUTES : ONE_HOUR;
|
||||
domainLockUtils.enqueueDomainRelock(timeBeforeRetry, oldUnlockRevisionId, previousAttempts + 1);
|
||||
domainLockUtils.enqueueDomainRelock(
|
||||
toJodaDuration(timeBeforeRetry), oldUnlockRevisionId, previousAttempts + 1);
|
||||
}
|
||||
|
||||
private void sendSuccessEmail(RegistryLock oldLock) {
|
||||
|
||||
@@ -30,8 +30,8 @@ import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An action that re-saves a given entity, typically after a certain amount of time has passed.
|
||||
@@ -50,16 +50,16 @@ public class ResaveEntityAction implements Runnable {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private final String resourceKey;
|
||||
private final DateTime requestedTime;
|
||||
private final ImmutableSortedSet<DateTime> resaveTimes;
|
||||
private final Instant requestedTime;
|
||||
private final ImmutableSortedSet<Instant> resaveTimes;
|
||||
private final AsyncTaskEnqueuer asyncTaskEnqueuer;
|
||||
private final Response response;
|
||||
|
||||
@Inject
|
||||
ResaveEntityAction(
|
||||
@Parameter(PARAM_RESOURCE_KEY) String resourceKey,
|
||||
@Parameter(PARAM_REQUESTED_TIME) DateTime requestedTime,
|
||||
@Parameter(PARAM_RESAVE_TIMES) ImmutableSet<DateTime> resaveTimes,
|
||||
@Parameter(PARAM_REQUESTED_TIME) Instant requestedTime,
|
||||
@Parameter(PARAM_RESAVE_TIMES) ImmutableSet<Instant> resaveTimes,
|
||||
AsyncTaskEnqueuer asyncTaskEnqueuer,
|
||||
Response response) {
|
||||
this.resourceKey = resourceKey;
|
||||
@@ -83,7 +83,7 @@ public class ResaveEntityAction implements Runnable {
|
||||
resourceKey);
|
||||
return;
|
||||
}
|
||||
tm().put(entity.get().cloneProjectedAtTime(tm().getTransactionTime()));
|
||||
tm().put(entity.get().cloneProjectedAtTime(tm().getTxTime()));
|
||||
if (!resaveTimes.isEmpty()) {
|
||||
asyncTaskEnqueuer.enqueueAsyncResave(
|
||||
VKey.createEppVKeyFromString(resourceKey), requestedTime, resaveTimes);
|
||||
|
||||
@@ -16,7 +16,9 @@ package google.registry.batch;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
|
||||
import static org.apache.http.HttpStatus.SC_OK;
|
||||
|
||||
@@ -41,11 +43,10 @@ import google.registry.util.EmailMessage;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
/** An action that sends notification emails to registrars whose certificates are expiring soon. */
|
||||
@Action(
|
||||
@@ -55,6 +56,7 @@ import org.joda.time.format.DateTimeFormatter;
|
||||
public class SendExpiringCertificateNotificationEmailAction implements Runnable {
|
||||
|
||||
public static final String PATH = "/_dr/task/sendExpiringCertificateNotificationEmail";
|
||||
|
||||
/**
|
||||
* Used as an offset when storing the last notification email sent date.
|
||||
*
|
||||
@@ -63,10 +65,11 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
* next day at 2am, the date difference will be less than a day, which will lead to the date
|
||||
* difference between two successive email sent date being the expected email interval days + 1;
|
||||
*/
|
||||
protected static final Duration UPDATE_TIME_OFFSET = Duration.standardMinutes(10);
|
||||
protected static final Duration UPDATE_TIME_OFFSET = Duration.ofMinutes(10);
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd");
|
||||
private static final DateTimeFormatter DATE_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(UTC);
|
||||
|
||||
private final CertificateChecker certificateChecker;
|
||||
private final String expirationWarningEmailBodyText;
|
||||
@@ -128,11 +131,11 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
registrar,
|
||||
registrar.getClientCertificate().isPresent()
|
||||
&& certificateChecker.shouldReceiveExpiringNotification(
|
||||
registrar.getLastExpiringCertNotificationSentDate(),
|
||||
toDateTime(registrar.getLastExpiringCertNotificationSentDate()),
|
||||
registrar.getClientCertificate().get()),
|
||||
registrar.getFailoverClientCertificate().isPresent()
|
||||
&& certificateChecker.shouldReceiveExpiringNotification(
|
||||
registrar.getLastExpiringFailoverCertNotificationSentDate(),
|
||||
toDateTime(registrar.getLastExpiringFailoverCertNotificationSentDate()),
|
||||
registrar.getFailoverClientCertificate().get())))
|
||||
.filter(
|
||||
registrarInfo ->
|
||||
@@ -147,19 +150,19 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
@VisibleForTesting
|
||||
boolean sendNotificationEmail(
|
||||
Registrar registrar,
|
||||
DateTime lastExpiringCertNotificationSentDate,
|
||||
Instant lastExpiringCertNotificationSentDate,
|
||||
CertificateType certificateType,
|
||||
Optional<String> certificate) {
|
||||
if (certificate.isEmpty()
|
||||
|| !certificateChecker.shouldReceiveExpiringNotification(
|
||||
lastExpiringCertNotificationSentDate, certificate.get())) {
|
||||
toDateTime(lastExpiringCertNotificationSentDate), certificate.get())) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
ImmutableSet<InternetAddress> recipients = getEmailAddresses(registrar, Type.TECH);
|
||||
ImmutableSet<InternetAddress> ccs = getEmailAddresses(registrar, Type.ADMIN);
|
||||
DateTime expirationDate =
|
||||
new DateTime(certificateChecker.getCertificate(certificate.get()).getNotAfter());
|
||||
Instant expirationDate =
|
||||
certificateChecker.getCertificate(certificate.get()).getNotAfter().toInstant();
|
||||
logger.atInfo().log(
|
||||
" %s SSL certificate of registrar '%s' will expire on %s.",
|
||||
certificateType.getDisplayName(), registrar.getRegistrarName(), expirationDate);
|
||||
@@ -188,9 +191,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
* for applicable certificate.
|
||||
*/
|
||||
updateLastNotificationSentDate(
|
||||
registrar,
|
||||
clock.nowUtc().minusMinutes((int) UPDATE_TIME_OFFSET.getStandardMinutes()),
|
||||
certificateType);
|
||||
registrar, clock.now().minus(UPDATE_TIME_OFFSET), certificateType);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
@@ -203,7 +204,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
/** Updates the last notification sent date in database. */
|
||||
@VisibleForTesting
|
||||
void updateLastNotificationSentDate(
|
||||
Registrar registrar, DateTime now, CertificateType certificateType) {
|
||||
Registrar registrar, Instant now, CertificateType certificateType) {
|
||||
try {
|
||||
tm().transact(
|
||||
() -> {
|
||||
@@ -215,7 +216,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
logger.atInfo().log(
|
||||
"Updated last notification email sent date to %s for %s certificate of "
|
||||
+ "registrar %s.",
|
||||
DATE_FORMATTER.print(now),
|
||||
DATE_FORMATTER.format(now),
|
||||
certificateType.getDisplayName(),
|
||||
registrar.getRegistrarName());
|
||||
}
|
||||
@@ -225,7 +226,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
logger.atInfo().log(
|
||||
"Updated last notification email sent date to %s for %s certificate of "
|
||||
+ "registrar %s.",
|
||||
DATE_FORMATTER.print(now),
|
||||
DATE_FORMATTER.format(now),
|
||||
certificateType.getDisplayName(),
|
||||
registrar.getRegistrarName());
|
||||
}
|
||||
@@ -298,7 +299,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
@VisibleForTesting
|
||||
@SuppressWarnings("lgtm[java/dereferenced-value-may-be-null]")
|
||||
String getEmailBody(
|
||||
String registrarName, CertificateType type, DateTime expirationDate, String registrarId) {
|
||||
String registrarName, CertificateType type, Instant expirationDate, String registrarId) {
|
||||
checkArgumentNotNull(expirationDate, "Expiration date cannot be null");
|
||||
checkArgumentNotNull(type, "Certificate type cannot be null");
|
||||
checkArgumentNotNull(registrarId, "Registrar Id cannot be null");
|
||||
@@ -306,7 +307,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
expirationWarningEmailBodyText,
|
||||
registrarName,
|
||||
type.getDisplayName(),
|
||||
DATE_FORMATTER.print(expirationDate),
|
||||
DATE_FORMATTER.format(expirationDate),
|
||||
registrarId);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
// Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.batch;
|
||||
|
||||
import static google.registry.model.common.Cursor.CursorType.REMOTE_CACHE_DOMAIN_SYNC;
|
||||
import static google.registry.model.common.Cursor.CursorType.REMOTE_CACHE_HOST_SYNC;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
import static google.registry.util.DateTimeUtils.START_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;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.cache.SimplifiedJedisClient;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.common.Cursor;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.model.tld.Tlds;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Action(
|
||||
service = Action.Service.BACKEND,
|
||||
path = SyncRemoteCacheAction.PATH,
|
||||
method = POST,
|
||||
auth = Auth.AUTH_ADMIN)
|
||||
public class SyncRemoteCacheAction implements Runnable {
|
||||
|
||||
public static final String PATH = "/_dr/task/syncRemoteCache";
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final String LOCK_NAME = "syncRemoteCacheAction";
|
||||
private static final int BATCH_SIZE = 10000;
|
||||
|
||||
private final LockHandler lockHandler;
|
||||
private final Response response;
|
||||
private final Optional<SimplifiedJedisClient> jedisClient;
|
||||
|
||||
@Inject
|
||||
public SyncRemoteCacheAction(
|
||||
LockHandler lockHandler, Response response, Optional<SimplifiedJedisClient> jedisClient) {
|
||||
this.lockHandler = lockHandler;
|
||||
this.response = response;
|
||||
this.jedisClient = jedisClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
response.setContentType(MediaType.PLAIN_TEXT_UTF_8);
|
||||
if (jedisClient.isEmpty()) {
|
||||
response.setStatus(SC_NO_CONTENT);
|
||||
response.setPayload("No Jedis/Valkey configuration found");
|
||||
return;
|
||||
}
|
||||
Callable<Void> runner =
|
||||
() -> {
|
||||
try {
|
||||
runLocked();
|
||||
response.setStatus(SC_OK);
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log("Errored out during execution.");
|
||||
response.setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||
response.setPayload(String.format("Errored out with cause: %s", e));
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
if (!lockHandler.executeWithLocks(runner, null, Duration.ofHours(1), LOCK_NAME)) {
|
||||
// Send a 200-series status code to prevent this conflicting action from retrying.
|
||||
response.setStatus(SC_NO_CONTENT);
|
||||
response.setPayload("Could not acquire lock; already running?");
|
||||
}
|
||||
}
|
||||
|
||||
private void runLocked() {
|
||||
// Note: the transaction ordering means that cursors in our database are updated only if all the
|
||||
// operations for the entity type succeeded. There is no downside to processing the same objects
|
||||
// multiple times if, for some reason, saving the cursor to the DB fails.
|
||||
int syncedDomains = tm().transact(this::syncDomains);
|
||||
int syncedHosts = tm().transact(this::syncHosts);
|
||||
String message = String.format("Synced %d domains and %d hosts.", syncedDomains, syncedHosts);
|
||||
logger.atInfo().log(message);
|
||||
response.setPayload(message);
|
||||
}
|
||||
|
||||
private int syncDomains() {
|
||||
Instant domainCursorTime = getPreviousCursorTime(REMOTE_CACHE_DOMAIN_SYNC);
|
||||
ImmutableSet<String> realTlds = Tlds.getTldsOfType(Tld.TldType.REAL);
|
||||
List<Domain> domains =
|
||||
tm().query(
|
||||
"FROM Domain WHERE updateTimestamp.lastUpdateTime > :cursorTime AND tld IN"
|
||||
+ " :realTlds ORDER BY updateTimestamp ASC",
|
||||
Domain.class)
|
||||
.setParameter("cursorTime", domainCursorTime)
|
||||
.setParameter("realTlds", realTlds)
|
||||
.setMaxResults(BATCH_SIZE)
|
||||
.getResultList();
|
||||
if (domains.isEmpty()) {
|
||||
logger.atInfo().log("No domains to process");
|
||||
return 0;
|
||||
}
|
||||
logger.atInfo().log("Processing %d domains", domains.size());
|
||||
processResources(Domain.class, domains, Domain::getDomainName);
|
||||
setNewCursorTime(domains, REMOTE_CACHE_DOMAIN_SYNC);
|
||||
return domains.size();
|
||||
}
|
||||
|
||||
private int syncHosts() {
|
||||
Instant hostCursorTime = getPreviousCursorTime(REMOTE_CACHE_HOST_SYNC);
|
||||
List<Host> hosts =
|
||||
tm().query(
|
||||
"FROM Host WHERE updateTimestamp.lastUpdateTime > :cursorTime ORDER BY"
|
||||
+ " updateTimestamp ASC",
|
||||
Host.class)
|
||||
.setParameter("cursorTime", hostCursorTime)
|
||||
.setMaxResults(BATCH_SIZE)
|
||||
.getResultList();
|
||||
if (hosts.isEmpty()) {
|
||||
logger.atInfo().log("No hosts to process");
|
||||
return 0;
|
||||
}
|
||||
logger.atInfo().log("Processing %d hosts", hosts.size());
|
||||
processResources(Host.class, hosts, Host::getRepoId);
|
||||
setNewCursorTime(hosts, REMOTE_CACHE_HOST_SYNC);
|
||||
return hosts.size();
|
||||
}
|
||||
|
||||
private <T extends EppResource> void processResources(
|
||||
Class<T> clazz, List<T> resources, Function<T, String> getKeyFunction) {
|
||||
ImmutableList.Builder<String> toDeleteBuilder = new ImmutableList.Builder<>();
|
||||
ImmutableList.Builder<SimplifiedJedisClient.JedisResource<T>> toSaveBuilder =
|
||||
new ImmutableList.Builder<>();
|
||||
|
||||
for (T resource : resources) {
|
||||
String key = getKeyFunction.apply(resource);
|
||||
if (resource.getDeletionTime().isAfter(tm().getTxTime())) {
|
||||
toSaveBuilder.add(new SimplifiedJedisClient.JedisResource<>(key, resource));
|
||||
} else {
|
||||
toDeleteBuilder.add(key);
|
||||
}
|
||||
}
|
||||
ImmutableList<String> toDelete = toDeleteBuilder.build();
|
||||
ImmutableList<SimplifiedJedisClient.JedisResource<T>> toSave = toSaveBuilder.build();
|
||||
|
||||
jedisClient.get().deleteAll(clazz, toDelete);
|
||||
logger.atInfo().log("Invalidated %d from the remote cache", toDelete.size());
|
||||
jedisClient.get().setAll(toSave);
|
||||
logger.atInfo().log("Set %d in the remote cache", toSave.size());
|
||||
}
|
||||
|
||||
private Instant getPreviousCursorTime(Cursor.CursorType cursorType) {
|
||||
return tm().loadByKeyIfPresent(Cursor.createGlobalVKey(cursorType))
|
||||
.map(Cursor::getCursorTime)
|
||||
.orElse(START_INSTANT);
|
||||
}
|
||||
|
||||
private void setNewCursorTime(
|
||||
List<? extends EppResource> resources, Cursor.CursorType cursorType) {
|
||||
Instant lastUpdateTime = Iterables.getLast(resources).getUpdateTimestamp().getTimestamp();
|
||||
tm().put(Cursor.createGlobal(cursorType, lastUpdateTime));
|
||||
logger.atInfo().log("Set new %s cursor time to %s", cursorType, lastUpdateTime);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.beam;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.util.DateTimeUtils.LOWERCASE_TIMESTAMP_FORMATTER;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -61,7 +62,7 @@ public class BeamUtils {
|
||||
// with a letter and ending with a letter or number. So we replace the "T" and "Z" in ISO 8601
|
||||
// with lowercase letters.
|
||||
String jobName =
|
||||
String.format("%s-%s", prefix, clock.nowUtc().toString("yyyy-MM-dd't'HH-mm-ss'z'"));
|
||||
String.format("%s-%s", prefix, LOWERCASE_TIMESTAMP_FORMATTER.format(clock.now()));
|
||||
checkArgument(
|
||||
Pattern.compile("^[a-z][-a-z0-9]*[a-z0-9]*").matcher(jobName).matches(),
|
||||
"The job name %s is illegal, it consists of only characters [-a-z0-9], "
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.beam.billing;
|
||||
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -22,7 +23,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -70,7 +70,7 @@ public record BillingEvent(
|
||||
String flags) {
|
||||
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss 'UTC'").withZone(ZoneOffset.UTC);
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss 'UTC'").withZone(UTC);
|
||||
|
||||
private static final Pattern SYNTHETIC_REGEX = Pattern.compile("SYNTHETIC", Pattern.LITERAL);
|
||||
|
||||
@@ -164,13 +164,10 @@ public record BillingEvent(
|
||||
/** Returns the grouping key for this {@code BillingEvent}, to generate the overall invoice. */
|
||||
InvoiceGroupingKey getInvoiceGroupingKey() {
|
||||
return new InvoiceGroupingKey(
|
||||
ZonedDateTime.ofInstant(billingTime(), ZoneOffset.UTC)
|
||||
.toLocalDate()
|
||||
.withDayOfMonth(1)
|
||||
.toString(),
|
||||
ZonedDateTime.ofInstant(billingTime(), UTC).toLocalDate().withDayOfMonth(1).toString(),
|
||||
years() == 0
|
||||
? ""
|
||||
: ZonedDateTime.ofInstant(billingTime(), ZoneOffset.UTC)
|
||||
: ZonedDateTime.ofInstant(billingTime(), UTC)
|
||||
.toLocalDate()
|
||||
.withDayOfMonth(1)
|
||||
.plusYears(years())
|
||||
|
||||
@@ -55,7 +55,6 @@ import google.registry.util.Clock;
|
||||
import google.registry.util.SystemClock;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.io.Serializable;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -312,8 +311,7 @@ public class ExpandBillingRecurrencesPipeline implements Serializable {
|
||||
for (Instant eventTime : eventTimesToExpand) {
|
||||
recurrenceLastExpansionTime = latestOf(recurrenceLastExpansionTime, eventTime);
|
||||
oneTimesToExpandCounter.inc();
|
||||
Instant billingTime =
|
||||
eventTime.plus(Duration.ofMillis(tld.getAutoRenewGracePeriodLength().getMillis()));
|
||||
Instant billingTime = eventTime.plusMillis(tld.getAutoRenewGracePeriodLength().getMillis());
|
||||
// Note that the DomainHistory is created as of transaction time, as opposed to event time.
|
||||
// This might be counterintuitive because other DomainHistories are created at the time
|
||||
// mutation events occur, such as in DomainDeleteFlow or DomainRenewFlow. Therefore, it is
|
||||
@@ -447,7 +445,7 @@ public class ExpandBillingRecurrencesPipeline implements Serializable {
|
||||
Cursor.createGlobalVKey(RECURRING_BILLING))
|
||||
.orElse(
|
||||
Cursor.createGlobal(RECURRING_BILLING, START_INSTANT))
|
||||
.getCursorTimeInstant();
|
||||
.getCursorTime();
|
||||
if (!currentCursorTime.equals(startTime)) {
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.beam.common;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.persistence.transaction.CriteriaQueryBuilder;
|
||||
import java.io.Serializable;
|
||||
import org.apache.beam.sdk.Pipeline;
|
||||
import org.apache.beam.sdk.PipelineResult;
|
||||
import org.apache.beam.sdk.coders.StringUtf8Coder;
|
||||
import org.apache.beam.sdk.options.PipelineOptionsFactory;
|
||||
import org.apache.beam.sdk.transforms.Count;
|
||||
import org.apache.beam.sdk.transforms.DoFn;
|
||||
import org.apache.beam.sdk.transforms.ParDo;
|
||||
|
||||
/**
|
||||
* For smoke test in the build/deployment process.
|
||||
*
|
||||
* <p>There two coverage gaps in unit tests for BEAM pipelines:
|
||||
*
|
||||
* <ul>
|
||||
* <li>The compatibility of the JVM and SDK in the pipeline image
|
||||
* <li>The JPA setup, which is performed by the {@link RegistryPipelineWorkerInitializer}
|
||||
* </ul>
|
||||
*
|
||||
* <p>This classes defines a pipeline that performs one quick database query. The pipeline is
|
||||
* expected to complete quickly, and the build or deployment process may launch it on GCP and wait
|
||||
* for its completion to be certain that all aspects are tested for Nomulus pipelines.
|
||||
*/
|
||||
public class SmokeTestPipeline implements Serializable {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
public static void main(String[] args) {
|
||||
PipelineOptionsFactory.register(RegistryPipelineOptions.class);
|
||||
RegistryPipelineOptions options =
|
||||
PipelineOptionsFactory.fromArgs(args).withValidation().as(RegistryPipelineOptions.class);
|
||||
runPipeline(options);
|
||||
}
|
||||
|
||||
static PipelineResult runPipeline(RegistryPipelineOptions options) {
|
||||
Pipeline pipeline = Pipeline.create(options);
|
||||
pipeline
|
||||
.apply(
|
||||
"Read Tlds",
|
||||
RegistryJpaIO.read(() -> CriteriaQueryBuilder.create(Tld.class).build(), Tld::getTldStr)
|
||||
.withCoder(StringUtf8Coder.of()))
|
||||
.apply("Count Tlds", Count.globally())
|
||||
.apply(
|
||||
"Verify Count",
|
||||
ParDo.of(
|
||||
new DoFn<Long, Void>() {
|
||||
@DoFn.ProcessElement
|
||||
public void processElement(@Element Long count) {
|
||||
logger.atInfo().log("Tld count: %s", count);
|
||||
verify(count > 0, "Expecting 1 or more, got %s.", count);
|
||||
}
|
||||
}));
|
||||
|
||||
return pipeline.run();
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,8 @@ import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.security.Security;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.apache.beam.sdk.options.PipelineOptions;
|
||||
import org.apache.beam.sdk.transforms.DoFn;
|
||||
@@ -66,8 +68,6 @@ import org.apache.beam.sdk.values.PCollection;
|
||||
import org.apache.beam.sdk.values.PDone;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
public class RdeIO {
|
||||
|
||||
@@ -163,7 +163,7 @@ public class RdeIO {
|
||||
// Determine some basic things about the deposit.
|
||||
final RdeMode mode = key.mode();
|
||||
final String tld = key.tld();
|
||||
final DateTime watermark = key.watermark();
|
||||
final Instant watermark = key.watermark();
|
||||
final int revision =
|
||||
Optional.ofNullable(key.revision())
|
||||
.orElseGet(() -> RdeRevision.getNextRevision(tld, watermark, mode));
|
||||
@@ -259,7 +259,7 @@ public class RdeIO {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private static final long serialVersionUID = 5822176227753327224L;
|
||||
private static final Duration ENQUEUE_DELAY = Duration.standardMinutes(1);
|
||||
private static final Duration ENQUEUE_DELAY = Duration.ofMinutes(1);
|
||||
|
||||
private final CloudTasksUtils cloudTasksUtils;
|
||||
|
||||
@@ -276,9 +276,9 @@ public class RdeIO {
|
||||
Tld tld = Tld.get(key.tld());
|
||||
Optional<Cursor> cursor =
|
||||
tm().loadByKeyIfPresent(Cursor.createScopedVKey(key.cursor(), tld));
|
||||
DateTime position = getCursorTimeOrStartOfTime(cursor);
|
||||
Instant position = getCursorTimeOrStartOfTime(cursor);
|
||||
checkState(key.interval() != null, "Interval must be present");
|
||||
DateTime newPosition = key.watermark().plus(key.interval());
|
||||
Instant newPosition = key.watermark().plus(key.interval());
|
||||
if (!position.isBefore(newPosition)) {
|
||||
logger.atWarning().log("Cursor has already been rolled forward.");
|
||||
return;
|
||||
|
||||
@@ -27,7 +27,6 @@ import static google.registry.beam.rde.RdePipeline.TupleTags.REVISION_ID;
|
||||
import static google.registry.beam.rde.RdePipeline.TupleTags.SUPERORDINATE_DOMAINS;
|
||||
import static google.registry.model.reporting.HistoryEntryDao.RESOURCE_TYPES_TO_HISTORY_TYPES;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static google.registry.util.SafeSerializationUtils.safeDeserializeCollection;
|
||||
import static google.registry.util.SafeSerializationUtils.serializeCollection;
|
||||
import static google.registry.util.SerializeUtils.decodeBase64;
|
||||
@@ -72,6 +71,7 @@ import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import org.apache.beam.sdk.Pipeline;
|
||||
import org.apache.beam.sdk.PipelineResult;
|
||||
import org.apache.beam.sdk.coders.KvCoder;
|
||||
@@ -97,7 +97,6 @@ import org.apache.beam.sdk.values.PCollectionTuple;
|
||||
import org.apache.beam.sdk.values.TupleTag;
|
||||
import org.apache.beam.sdk.values.TupleTagList;
|
||||
import org.apache.beam.sdk.values.TypeDescriptor;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Definition of a Dataflow Flex template, which generates RDE/BRDA deposits.
|
||||
@@ -171,7 +170,7 @@ public class RdePipeline implements Serializable {
|
||||
private final transient RdePipelineOptions options;
|
||||
private final ValidationMode mode;
|
||||
private final ImmutableSet<PendingDeposit> pendingDeposits;
|
||||
private final DateTime watermark;
|
||||
private final Instant watermark;
|
||||
private final String rdeBucket;
|
||||
private final byte[] stagingKeyBytes;
|
||||
private final GcsUtils gcsUtils;
|
||||
@@ -190,7 +189,7 @@ public class RdePipeline implements Serializable {
|
||||
this.options = options;
|
||||
this.mode = ValidationMode.valueOf(options.getValidationMode());
|
||||
this.pendingDeposits = decodePendingDeposits(options.getPendings());
|
||||
ImmutableSet<DateTime> potentialWatermarks =
|
||||
ImmutableSet<Instant> potentialWatermarks =
|
||||
pendingDeposits.stream()
|
||||
.map(PendingDeposit::watermark)
|
||||
.distinct()
|
||||
@@ -324,7 +323,7 @@ public class RdePipeline implements Serializable {
|
||||
? "AND resource.tld IN " + "(SELECT id FROM Tld WHERE tldType = 'REAL')"
|
||||
: ""))
|
||||
.replace("%entity%", historyClass.getSimpleName()),
|
||||
ImmutableMap.of("watermark", toInstant(watermark)),
|
||||
ImmutableMap.of("watermark", watermark),
|
||||
Object[].class,
|
||||
row -> KV.of((String) row[0], (long) row[1]))
|
||||
.withCoder(KvCoder.of(StringUtf8Coder.of(), VarLongCoder.of())));
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.beam.resave;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static org.apache.beam.sdk.values.TypeDescriptors.integers;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -102,7 +103,7 @@ public class ResaveAllEppResourcesPipeline implements Serializable {
|
||||
* transfers, grace periods).
|
||||
*
|
||||
* <p>The logic of what might have changed is paraphrased from {@link
|
||||
* DomainBase#cloneProjectedAtTime(DateTime)}.
|
||||
* DomainBase#cloneProjectedAtTime(Instant)}.
|
||||
*/
|
||||
private void fastResaveDomains(Pipeline pipeline) {
|
||||
Read<String, String> repoIdRead =
|
||||
@@ -164,7 +165,7 @@ public class ResaveAllEppResourcesPipeline implements Serializable {
|
||||
.collect(toImmutableList());
|
||||
ImmutableList<EppResource> mappedResources =
|
||||
tm().loadByKeys(keys).values().stream()
|
||||
.map(r -> r.cloneProjectedAtTime(now))
|
||||
.map(r -> r.cloneProjectedAtTime(toInstant(now)))
|
||||
.collect(toImmutableList());
|
||||
tm().putAll(mappedResources);
|
||||
});
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.beam.spec11;
|
||||
|
||||
import static google.registry.util.DateTimeUtils.toJodaInstant;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.apache.http.HttpStatus.SC_OK;
|
||||
|
||||
@@ -22,7 +23,6 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.io.CharStreams;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -132,9 +132,7 @@ public class SafeBrowsingTransforms {
|
||||
if (!domainNameInfoBuffer.isEmpty()) {
|
||||
ImmutableSet<KV<DomainNameInfo, ThreatMatch>> results = evaluateAndFlush();
|
||||
results.forEach(
|
||||
(kv) ->
|
||||
context.output(
|
||||
kv, DateTimeUtils.toJodaInstant(clock.now()), GlobalWindow.INSTANCE));
|
||||
(kv) -> context.output(kv, toJodaInstant(clock.now()), GlobalWindow.INSTANCE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,19 +64,19 @@ import google.registry.util.SqlTemplate;
|
||||
import google.registry.util.SystemSleeper;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Class encapsulating parameters and state for accessing the Bigquery API. */
|
||||
public class BigqueryConnection implements AutoCloseable {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final Duration MIN_POLL_INTERVAL = Duration.millis(500);
|
||||
private static final Duration MIN_POLL_INTERVAL = Duration.ofMillis(500);
|
||||
|
||||
@NonFinalForTesting
|
||||
private static Sleeper sleeper = new SystemSleeper();
|
||||
@@ -88,7 +88,7 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
private static final String TEMP_DATASET_NAME = "__temp__";
|
||||
|
||||
/** Default time to live for temporary tables. */
|
||||
private static final Duration TEMP_TABLE_TTL = Duration.standardHours(24);
|
||||
private static final Duration TEMP_TABLE_TTL = Duration.ofHours(24);
|
||||
|
||||
/** Bigquery client instance wrapped by this class. */
|
||||
private final Bigquery bigquery;
|
||||
@@ -109,7 +109,7 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
private boolean overwrite = false;
|
||||
|
||||
/** Duration to wait between polls for job status. */
|
||||
private Duration pollInterval = Duration.millis(1000);
|
||||
private Duration pollInterval = Duration.ofSeconds(1);
|
||||
|
||||
BigqueryConnection(Bigquery bigquery, Clock clock) {
|
||||
this.bigquery = bigquery;
|
||||
@@ -146,9 +146,9 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
|
||||
public Builder setPollInterval(Duration pollInterval) {
|
||||
checkArgument(
|
||||
!pollInterval.isShorterThan(MIN_POLL_INTERVAL),
|
||||
pollInterval.compareTo(MIN_POLL_INTERVAL) >= 0,
|
||||
"poll interval must be at least %s ms",
|
||||
MIN_POLL_INTERVAL.getMillis());
|
||||
MIN_POLL_INTERVAL.toMillis());
|
||||
instance.pollInterval = pollInterval;
|
||||
return this;
|
||||
}
|
||||
@@ -225,7 +225,7 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
}
|
||||
|
||||
public Builder timeToLive(Duration duration) {
|
||||
this.table.setExpirationTime(clock.nowUtc().plus(duration).getMillis());
|
||||
this.table.setExpirationTime(clock.now().plus(duration).toEpochMilli());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,16 @@
|
||||
|
||||
package google.registry.bigquery;
|
||||
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
import static java.time.temporal.ChronoUnit.MICROS;
|
||||
|
||||
import com.google.api.services.bigquery.model.JobReference;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.SignStyle;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.DateTimeFormatterBuilder;
|
||||
import org.joda.time.format.DateTimeParser;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
/** Utilities related to Bigquery. */
|
||||
public class BigqueryUtils {
|
||||
@@ -67,47 +70,56 @@ public class BigqueryUtils {
|
||||
*
|
||||
* <p>The general format definition is "YYYY-MM-DD HH:MM:SS.SSS[ ZZ]", where the fractional
|
||||
* seconds portion can have 0-6 decimal places (although we restrict it to 0-3 here since Joda
|
||||
* DateTime only supports up to millisecond precision) and the zone if not specified defaults to
|
||||
* Instant only supports up to millisecond precision) and the zone if not specified defaults to
|
||||
* UTC.
|
||||
*
|
||||
* <p>Although we expect a zone specification of "UTC" when parsing, we don't emit it when
|
||||
* printing because in some cases BigQuery does not allow any time zone specification (instead it
|
||||
* assumes UTC for whatever input you provide) for input timestamp strings (see b/16380363).
|
||||
*
|
||||
* @see <a href="https://cloud.google.com/bigquery/data-types#timestamp-type">
|
||||
* BigQuery Data Types - TIMESTAMP</a>
|
||||
* @see <a href="https://cloud.google.com/bigquery/data-types#timestamp-type">BigQuery Data Types
|
||||
* - TIMESTAMP</a>
|
||||
*/
|
||||
public static final DateTimeFormatter BIGQUERY_TIMESTAMP_FORMAT = new DateTimeFormatterBuilder()
|
||||
.append(ISODateTimeFormat.date())
|
||||
.appendLiteral(' ')
|
||||
.append(
|
||||
// For printing, always print out the milliseconds.
|
||||
ISODateTimeFormat.hourMinuteSecondMillis().getPrinter(),
|
||||
// For parsing, we need a series of parsers to correctly handle the milliseconds.
|
||||
new DateTimeParser[] {
|
||||
// Try to parse the time with milliseconds first, which requires at least one
|
||||
// fractional second digit, and if that fails try to parse without milliseconds.
|
||||
ISODateTimeFormat.hourMinuteSecondMillis().getParser(),
|
||||
ISODateTimeFormat.hourMinuteSecond().getParser()})
|
||||
// Print UTC as the empty string since BigQuery's TIMESTAMP() function does not accept any
|
||||
// time zone specification, but require "UTC" on parsing. Since we force this formatter to
|
||||
// always use UTC below, the other arguments do not matter. If b/16380363 ever gets resolved
|
||||
// this could be simplified to appendLiteral(" UTC").
|
||||
.appendTimeZoneOffset("", " UTC", false, 1, 1)
|
||||
.toFormatter()
|
||||
.withZoneUTC();
|
||||
private static final DateTimeFormatter BIGQUERY_TIMESTAMP_PARSER =
|
||||
new DateTimeFormatterBuilder()
|
||||
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.NOT_NEGATIVE)
|
||||
.appendLiteral('-')
|
||||
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
|
||||
.appendLiteral('-')
|
||||
.appendValue(ChronoField.DAY_OF_MONTH, 2)
|
||||
.appendLiteral(' ')
|
||||
.appendPattern("HH:mm:ss")
|
||||
.optionalStart()
|
||||
.appendFraction(ChronoField.MILLI_OF_SECOND, 0, 3, true)
|
||||
.optionalEnd()
|
||||
.appendLiteral(" UTC")
|
||||
.toFormatter()
|
||||
.withZone(UTC);
|
||||
|
||||
private static final DateTimeFormatter BIGQUERY_TIMESTAMP_PRINTER =
|
||||
new DateTimeFormatterBuilder()
|
||||
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.NOT_NEGATIVE)
|
||||
.appendLiteral('-')
|
||||
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
|
||||
.appendLiteral('-')
|
||||
.appendValue(ChronoField.DAY_OF_MONTH, 2)
|
||||
.appendLiteral(' ')
|
||||
.appendPattern("HH:mm:ss")
|
||||
.appendFraction(ChronoField.MILLI_OF_SECOND, 3, 3, true)
|
||||
.toFormatter()
|
||||
.withZone(UTC);
|
||||
|
||||
/**
|
||||
* Returns the human-readable string version of the given DateTime, suitable for conversion
|
||||
* within BigQuery from a string literal into a BigQuery timestamp type.
|
||||
* Returns the human-readable string version of the given Instant, suitable for conversion within
|
||||
* BigQuery from a string literal into a BigQuery timestamp type.
|
||||
*/
|
||||
public static String toBigqueryTimestampString(DateTime dateTime) {
|
||||
return BIGQUERY_TIMESTAMP_FORMAT.print(dateTime);
|
||||
public static String toBigqueryTimestampString(Instant dateTime) {
|
||||
return BIGQUERY_TIMESTAMP_PRINTER.format(dateTime);
|
||||
}
|
||||
|
||||
/** Returns the DateTime for a given human-readable string-formatted BigQuery timestamp. */
|
||||
public static DateTime fromBigqueryTimestampString(String timestampString) {
|
||||
return BIGQUERY_TIMESTAMP_FORMAT.parseDateTime(timestampString);
|
||||
/** Returns the Instant for a given human-readable string-formatted BigQuery timestamp. */
|
||||
public static Instant fromBigqueryTimestampString(String timestampString) {
|
||||
return BIGQUERY_TIMESTAMP_PARSER.parse(timestampString, Instant::from);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,15 +135,16 @@ public class BigqueryUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link DateTime} into a numeric string that BigQuery understands as a timestamp:
|
||||
* the decimal number of seconds since the epoch, precise up to microseconds.
|
||||
* Converts a time into a numeric string that BigQuery understands as a timestamp: the decimal
|
||||
* number of seconds since the epoch, precise up to microseconds.
|
||||
*
|
||||
* <p>Note that since {@code DateTime} only stores milliseconds, the last 3 digits will be zero.
|
||||
* <p>Note that while {@code Instant} supports nanosecond precision, BigQuery only supports
|
||||
* microsecond precision, so the sub-microsecond precision is truncated.
|
||||
*
|
||||
* @see <a href="https://developers.google.com/bigquery/timestamp">Data Types</a>
|
||||
*/
|
||||
public static String toBigqueryTimestamp(DateTime dateTime) {
|
||||
return toBigqueryTimestamp(dateTime.getMillis(), TimeUnit.MILLISECONDS);
|
||||
public static String toBigqueryTimestamp(Instant dateTime) {
|
||||
return toBigqueryTimestamp(MICROS.between(Instant.EPOCH, dateTime), TimeUnit.MICROSECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,7 +116,7 @@ public class BsaDownloadAction implements Runnable {
|
||||
|
||||
Void runWithinLock() {
|
||||
// Cannot enroll new TLDs after download starts. This may change if b/309175410 is fixed.
|
||||
if (!Tlds.hasActiveBsaEnrollment(clock.nowUtc())) {
|
||||
if (!Tlds.hasActiveBsaEnrollment(clock.now())) {
|
||||
logger.atInfo().log("No TLDs enrolled with BSA. Quitting.");
|
||||
return null;
|
||||
}
|
||||
@@ -179,9 +179,7 @@ public class BsaDownloadAction implements Runnable {
|
||||
gcsClient.writeUnblockableDomains(
|
||||
schedule.jobName(),
|
||||
batches
|
||||
.map(
|
||||
batch ->
|
||||
applyLabelDiff(batch, lazyIdnChecker.get(), schedule, clock.nowUtc()))
|
||||
.map(batch -> applyLabelDiff(batch, lazyIdnChecker.get(), schedule, clock.now()))
|
||||
.flatMap(ImmutableList::stream));
|
||||
}
|
||||
schedule.updateJobStage(DownloadStage.REPORT_START_OF_ORDER_PROCESSING);
|
||||
|
||||
@@ -17,8 +17,8 @@ package google.registry.bsa;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.Callable;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Helper for guarding all BSA related work with a common lock. */
|
||||
public class BsaLock {
|
||||
|
||||
@@ -67,7 +67,7 @@ public class BsaRefreshAction implements Runnable {
|
||||
GcsClient gcsClient,
|
||||
BsaReportSender bsaReportSender,
|
||||
@Config("bsaTxnBatchSize") int transactionBatchSize,
|
||||
@Config("domainCreateTxnCommitTimeLag") org.joda.time.Duration domainCreateTxnCommitTimeLag,
|
||||
@Config("domainCreateTxnCommitTimeLag") Duration domainCreateTxnCommitTimeLag,
|
||||
BsaEmailSender emailSender,
|
||||
BsaLock bsaLock,
|
||||
Clock clock,
|
||||
@@ -76,7 +76,7 @@ public class BsaRefreshAction implements Runnable {
|
||||
this.gcsClient = gcsClient;
|
||||
this.bsaReportSender = bsaReportSender;
|
||||
this.transactionBatchSize = transactionBatchSize;
|
||||
this.domainCreateTxnCommitTimeLag = Duration.ofMillis(domainCreateTxnCommitTimeLag.getMillis());
|
||||
this.domainCreateTxnCommitTimeLag = domainCreateTxnCommitTimeLag;
|
||||
this.emailSender = emailSender;
|
||||
this.bsaLock = bsaLock;
|
||||
this.clock = clock;
|
||||
|
||||
@@ -88,14 +88,14 @@ public class BsaValidateAction implements Runnable {
|
||||
IdnChecker idnChecker,
|
||||
BsaEmailSender emailSender,
|
||||
@Config("bsaTxnBatchSize") int transactionBatchSize,
|
||||
@Config("bsaValidationMaxStaleness") org.joda.time.Duration maxStaleness,
|
||||
@Config("bsaValidationMaxStaleness") Duration maxStaleness,
|
||||
Clock clock,
|
||||
Response response) {
|
||||
this.gcsClient = gcsClient;
|
||||
this.idnChecker = idnChecker;
|
||||
this.emailSender = emailSender;
|
||||
this.transactionBatchSize = transactionBatchSize;
|
||||
this.maxStaleness = Duration.ofMillis(maxStaleness.getMillis());
|
||||
this.maxStaleness = maxStaleness;
|
||||
this.clock = clock;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import google.registry.tldconfig.idn.IdnLabelValidator;
|
||||
import google.registry.tldconfig.idn.IdnTableEnum;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* Checks labels' validity wrt Idns in TLDs enrolled with BSA.
|
||||
@@ -45,7 +45,7 @@ public class IdnChecker {
|
||||
|
||||
@Inject
|
||||
IdnChecker(Clock clock) {
|
||||
this.idnToTlds = getIdnToTldMap(clock.nowUtc());
|
||||
this.idnToTlds = getIdnToTldMap(clock.now());
|
||||
allTlds = idnToTlds.values().stream().flatMap(ImmutableSet::stream).collect(toImmutableSet());
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class IdnChecker {
|
||||
return Sets.difference(allTlds, getSupportingTlds(idnTables)).immutableCopy();
|
||||
}
|
||||
|
||||
private static ImmutableMap<IdnTableEnum, ImmutableSet<Tld>> getIdnToTldMap(DateTime now) {
|
||||
private static ImmutableMap<IdnTableEnum, ImmutableSet<Tld>> getIdnToTldMap(Instant now) {
|
||||
var idnToTldMap = new ImmutableMultimap.Builder<IdnTableEnum, Tld>();
|
||||
Tlds.getTldEntitiesOfType(TldType.REAL).stream()
|
||||
.filter(tld -> isEnrolledWithBsa(tld, now))
|
||||
|
||||
@@ -20,7 +20,6 @@ import static google.registry.bsa.BsaStringUtils.DOMAIN_JOINER;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.isReserved;
|
||||
import static google.registry.model.tld.Tlds.findTldForName;
|
||||
import static google.registry.model.tld.label.ReservedList.loadReservedLists;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
@@ -35,7 +34,6 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Utility for looking up reserved domain names.
|
||||
@@ -47,15 +45,6 @@ public final class ReservedDomainsUtils {
|
||||
|
||||
private ReservedDomainsUtils() {}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getAllReservedNames(Instant)}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InlineMeSuggester")
|
||||
public static Stream<String> getAllReservedNames(DateTime now) {
|
||||
return getAllReservedNames(toInstant(now));
|
||||
}
|
||||
|
||||
public static Stream<String> getAllReservedNames(Instant now) {
|
||||
return Tlds.getTldEntitiesOfType(TldType.REAL).stream()
|
||||
.filter(tld -> Tld.isEnrolledWithBsa(tld, now))
|
||||
@@ -74,15 +63,6 @@ public final class ReservedDomainsUtils {
|
||||
.collect(toImmutableSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getAllReservedDomainsInTld(Tld, Instant)}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InlineMeSuggester")
|
||||
static ImmutableSet<String> getAllReservedDomainsInTld(Tld tld, DateTime now) {
|
||||
return getAllReservedDomainsInTld(tld, toInstant(now));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@code domain} is a reserved name that can be registered right now (e.g.,
|
||||
* during sunrise or with allocation token), therefore unblockable.
|
||||
@@ -95,13 +75,4 @@ public final class ReservedDomainsUtils {
|
||||
InternetDomainName.from(domain),
|
||||
Objects.equals(tld.getTldState(now), TldState.START_DATE_SUNRISE));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #isReservedDomain(String, Instant)}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InlineMeSuggester")
|
||||
public static boolean isReservedDomain(String domain, DateTime now) {
|
||||
return isReservedDomain(domain, toInstant(now));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,12 +31,12 @@ import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import org.joda.time.Duration;
|
||||
import org.joda.time.Instant;
|
||||
|
||||
/**
|
||||
* A credential for accessing the BSA API.
|
||||
@@ -104,7 +104,7 @@ public class BsaCredential {
|
||||
}
|
||||
|
||||
private void ensureAuthTokenValid() throws IOException, GeneralSecurityException {
|
||||
Instant now = Instant.ofEpochMilli(clock.nowUtc().getMillis());
|
||||
Instant now = clock.now();
|
||||
if (authToken != null && lastRefreshTime.plus(authTokenExpiry).isAfter(now)) {
|
||||
logger.atInfo().log("AuthToken still valid, reusing.");
|
||||
return;
|
||||
|
||||
@@ -17,7 +17,7 @@ package google.registry.bsa.persistence;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static google.registry.bsa.DownloadStage.DONE;
|
||||
import static google.registry.bsa.DownloadStage.DOWNLOAD_BLOCK_LISTS;
|
||||
import static google.registry.util.DateTimeUtils.ISO_8601_FORMATTER;
|
||||
import static google.registry.util.DateTimeUtils.formatInstant;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Objects;
|
||||
@@ -84,7 +84,7 @@ class BsaDownload {
|
||||
*/
|
||||
String getJobName() {
|
||||
// Return a value based on job start time, which is unique.
|
||||
return ISO_8601_FORMATTER.format(getCreationTime()).toLowerCase(Locale.ROOT).replace(":", "");
|
||||
return formatInstant(getCreationTime()).toLowerCase(Locale.ROOT).replace(":", "");
|
||||
}
|
||||
|
||||
boolean isDone() {
|
||||
|
||||
@@ -20,7 +20,6 @@ import static google.registry.bsa.DownloadStage.DONE;
|
||||
import static google.registry.bsa.DownloadStage.NOP;
|
||||
import static google.registry.bsa.persistence.RefreshScheduler.fetchMostRecentRefresh;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static org.joda.time.Duration.standardSeconds;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -28,9 +27,9 @@ import google.registry.bsa.persistence.DownloadSchedule.CompletedJob;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* Assigns work for each cron invocation of the BSA Download job.
|
||||
@@ -57,7 +56,7 @@ import org.joda.time.Duration;
|
||||
public final class DownloadScheduler {
|
||||
|
||||
/** Allows a new download to proceed if the cron job fires a little early due to NTP drift. */
|
||||
private static final Duration CRON_JITTER = standardSeconds(5);
|
||||
private static final Duration CRON_JITTER = Duration.ofSeconds(5);
|
||||
|
||||
private final Duration downloadInterval;
|
||||
private final Duration maxNopInterval;
|
||||
@@ -117,8 +116,8 @@ public final class DownloadScheduler {
|
||||
private boolean isTimeAgain(BsaDownload mostRecent, Duration interval) {
|
||||
return mostRecent
|
||||
.getCreationTime()
|
||||
.plus(java.time.Duration.ofMillis(interval.getMillis()))
|
||||
.minus(java.time.Duration.ofMillis(CRON_JITTER.getMillis()))
|
||||
.plusMillis(interval.toMillis())
|
||||
.minusMillis(CRON_JITTER.toMillis())
|
||||
.isBefore(clock.now());
|
||||
}
|
||||
|
||||
|
||||
@@ -37,9 +37,9 @@ import google.registry.bsa.api.UnblockableDomain.Reason;
|
||||
import google.registry.model.ForeignKeyUtils;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.tld.Tld;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Applies the BSA label diffs from the latest BSA download. */
|
||||
public final class LabelDiffUpdates {
|
||||
@@ -60,7 +60,7 @@ public final class LabelDiffUpdates {
|
||||
ImmutableList<BlockLabel> labels,
|
||||
IdnChecker idnChecker,
|
||||
DownloadSchedule schedule,
|
||||
DateTime now) {
|
||||
Instant now) {
|
||||
ImmutableList.Builder<UnblockableDomain> nonBlockedDomains = new ImmutableList.Builder<>();
|
||||
ImmutableMap<LabelType, ImmutableList<BlockLabel>> labelsByType =
|
||||
ImmutableMap.copyOf(
|
||||
@@ -134,7 +134,7 @@ public final class LabelDiffUpdates {
|
||||
}
|
||||
|
||||
static ImmutableList<UnblockableDomain> tallyUnblockableDomainsForNewLabels(
|
||||
ImmutableList<BlockLabel> labels, IdnChecker idnChecker, DateTime now) {
|
||||
ImmutableList<BlockLabel> labels, IdnChecker idnChecker, Instant now) {
|
||||
ImmutableList.Builder<UnblockableDomain> nonBlockedDomains = new ImmutableList.Builder<>();
|
||||
|
||||
for (BlockLabel label : labels) {
|
||||
|
||||
@@ -85,25 +85,29 @@ public final class CacheModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public static DomainCache provideDomainCache(Optional<UnifiedJedis> jedis, Clock clock) {
|
||||
if (jedis.isEmpty()) {
|
||||
return domainName ->
|
||||
ForeignKeyUtils.loadResourceByCache(Domain.class, domainName, clock.now());
|
||||
}
|
||||
SimplifiedJedisClient<Domain> jedisClient =
|
||||
SimplifiedJedisClient.create(Domain.class, jedis.get());
|
||||
return new MultilayerDomainCache(jedisClient, clock);
|
||||
public static Optional<SimplifiedJedisClient> provideJedisClient(Optional<UnifiedJedis> jedis) {
|
||||
return jedis.map(SimplifiedJedisClient::new);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public static HostCache provideHostCache(Optional<UnifiedJedis> jedis) {
|
||||
if (jedis.isEmpty()) {
|
||||
public static DomainCache provideDomainCache(
|
||||
Optional<SimplifiedJedisClient> domainJedisClient, Clock clock) {
|
||||
if (domainJedisClient.isEmpty()) {
|
||||
return domainName ->
|
||||
ForeignKeyUtils.loadResourceByCache(Domain.class, domainName, clock.now());
|
||||
}
|
||||
return new MultilayerDomainCache(domainJedisClient.get(), clock);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public static HostCache provideHostCache(Optional<SimplifiedJedisClient> hostJedisClient) {
|
||||
if (hostJedisClient.isEmpty()) {
|
||||
return repoId ->
|
||||
Optional.ofNullable(EppResource.loadByCache(VKey.create(Host.class, repoId)));
|
||||
}
|
||||
SimplifiedJedisClient<Host> jedisClient = SimplifiedJedisClient.create(Host.class, jedis.get());
|
||||
return new MultilayerHostCache(jedisClient);
|
||||
return new MultilayerHostCache(hostJedisClient.get());
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.cache;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.ForeignKeyUtils;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.util.Clock;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
@@ -31,14 +32,14 @@ public class MultilayerDomainCache extends MultilayerEppResourceCache<Domain>
|
||||
|
||||
private final Clock clock;
|
||||
|
||||
public MultilayerDomainCache(SimplifiedJedisClient<Domain> jedisClient, Clock clock) {
|
||||
public MultilayerDomainCache(SimplifiedJedisClient jedisClient, Clock clock) {
|
||||
super(jedisClient);
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Domain> loadByDomainName(String domainName) {
|
||||
return loadFromCaches(domainName);
|
||||
return loadFromCaches(Domain.class, domainName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,11 +53,11 @@ public class MultilayerDomainCache extends MultilayerEppResourceCache<Domain>
|
||||
Instant now = clock.now();
|
||||
return possibleDomain
|
||||
.filter(domain -> now.isBefore(domain.getDeletionTime()))
|
||||
.map(domain -> domain.cloneProjectedAtInstant(now));
|
||||
.map(domain -> domain.cloneProjectedAtTime(now));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getJedisPrefix() {
|
||||
return "Domain__";
|
||||
protected boolean shouldPersistToRemoteCache(Domain domain) {
|
||||
return Tld.get(domain.getTld()).getTldType().equals(Tld.TldType.REAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,17 +35,19 @@ public abstract class MultilayerEppResourceCache<V extends EppResource> {
|
||||
.maximumSize(RegistryConfig.getEppResourceMaxCachedEntries())
|
||||
.build();
|
||||
|
||||
private final SimplifiedJedisClient<V> jedisClient;
|
||||
private final SimplifiedJedisClient jedisClient;
|
||||
|
||||
protected MultilayerEppResourceCache(SimplifiedJedisClient<V> jedisClient) {
|
||||
protected MultilayerEppResourceCache(SimplifiedJedisClient jedisClient) {
|
||||
this.jedisClient = jedisClient;
|
||||
}
|
||||
|
||||
protected abstract Optional<V> loadFromDatabase(String key);
|
||||
|
||||
protected abstract String getJedisPrefix();
|
||||
protected boolean shouldPersistToRemoteCache(V value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Optional<V> loadFromCaches(String key) {
|
||||
protected Optional<V> loadFromCaches(Class<V> clazz, String key) {
|
||||
// hopefully the resource is in the local cache
|
||||
Optional<V> possibleValue = Optional.ofNullable(localCache.getIfPresent(key));
|
||||
if (possibleValue.isPresent()) {
|
||||
@@ -53,8 +55,7 @@ public abstract class MultilayerEppResourceCache<V extends EppResource> {
|
||||
}
|
||||
|
||||
// if not, try the remote cache
|
||||
String jedisKey = getJedisPrefix() + key;
|
||||
possibleValue = jedisClient.get(jedisKey);
|
||||
possibleValue = jedisClient.get(clazz, key);
|
||||
if (possibleValue.isPresent()) {
|
||||
localCache.put(key, possibleValue.get());
|
||||
return possibleValue;
|
||||
@@ -65,7 +66,9 @@ public abstract class MultilayerEppResourceCache<V extends EppResource> {
|
||||
.map(
|
||||
v -> {
|
||||
// Optional has no direct "peek" functionality to fill the caches
|
||||
jedisClient.set(jedisKey, v);
|
||||
if (shouldPersistToRemoteCache(v)) {
|
||||
jedisClient.set(new SimplifiedJedisClient.JedisResource<>(key, v));
|
||||
}
|
||||
localCache.put(key, v);
|
||||
return v;
|
||||
});
|
||||
|
||||
@@ -27,13 +27,13 @@ import java.util.Optional;
|
||||
*/
|
||||
public class MultilayerHostCache extends MultilayerEppResourceCache<Host> implements HostCache {
|
||||
|
||||
public MultilayerHostCache(SimplifiedJedisClient<Host> jedisClient) {
|
||||
public MultilayerHostCache(SimplifiedJedisClient jedisClient) {
|
||||
super(jedisClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Host> loadByRepoId(String repoId) {
|
||||
return loadFromCaches(repoId);
|
||||
return loadFromCaches(Host.class, repoId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -41,9 +41,4 @@ public class MultilayerHostCache extends MultilayerEppResourceCache<Host> implem
|
||||
return replicaTm()
|
||||
.transact(() -> replicaTm().loadByKeyIfPresent(VKey.create(Host.class, repoId)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getJedisPrefix() {
|
||||
return "Host__";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,26 @@
|
||||
|
||||
package google.registry.cache;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.host.Host;
|
||||
import io.protostuff.LinkedBuffer;
|
||||
import io.protostuff.ProtostuffIOUtil;
|
||||
import io.protostuff.Schema;
|
||||
import io.protostuff.runtime.RuntimeSchema;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
import redis.clients.jedis.AbstractPipeline;
|
||||
import redis.clients.jedis.UnifiedJedis;
|
||||
import redis.clients.jedis.params.SetParams;
|
||||
|
||||
/**
|
||||
* A {@link UnifiedJedis} client that handles serialization/deserialization.
|
||||
@@ -33,37 +43,88 @@ import redis.clients.jedis.UnifiedJedis;
|
||||
* <p>{@link UnifiedJedis} pairs key-value types, so we need the key to be serialized to a byte
|
||||
* array as well.
|
||||
*/
|
||||
public class SimplifiedJedisClient<V extends EppResource> {
|
||||
public class SimplifiedJedisClient {
|
||||
|
||||
public record JedisResource<V extends EppResource>(String key, V value) {}
|
||||
|
||||
private static final ImmutableMap<Class<? extends EppResource>, String> TYPE_PREFIXES =
|
||||
ImmutableMap.of(
|
||||
Domain.class, "d_",
|
||||
Host.class, "h_");
|
||||
|
||||
private static final ImmutableMap<Class<? extends EppResource>, Schema<? extends EppResource>>
|
||||
VALUE_SCHEMAS =
|
||||
ImmutableMap.of(
|
||||
Domain.class, RuntimeSchema.getSchema(Domain.class),
|
||||
Host.class, RuntimeSchema.getSchema(Host.class));
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final int BATCH_SIZE = 500;
|
||||
|
||||
private final Schema<V> valueSchema;
|
||||
private final UnifiedJedis jedis;
|
||||
|
||||
public static <V extends EppResource> SimplifiedJedisClient<V> create(
|
||||
Class<V> valueClass, UnifiedJedis jedis) {
|
||||
Schema<V> valueSchema = RuntimeSchema.getSchema(valueClass);
|
||||
return new SimplifiedJedisClient<>(valueSchema, jedis);
|
||||
}
|
||||
|
||||
private SimplifiedJedisClient(Schema<V> valueSchema, UnifiedJedis jedis) {
|
||||
this.valueSchema = valueSchema;
|
||||
SimplifiedJedisClient(UnifiedJedis jedis) {
|
||||
this.jedis = jedis;
|
||||
}
|
||||
|
||||
/** Gets the value from the remote cache. Returns null if it does not exist. */
|
||||
public Optional<V> get(String key) {
|
||||
public <V extends EppResource> Optional<V> get(Class<V> clazz, String key) {
|
||||
checkNotNull(key, "Key cannot be null");
|
||||
byte[] data = jedis.get(key.getBytes(StandardCharsets.UTF_8));
|
||||
return Optional.ofNullable(data).map(this::deserialize);
|
||||
byte[] data = jedis.get(convertKey(clazz, key));
|
||||
return Optional.ofNullable(data).map(d -> deserialize(clazz, d));
|
||||
}
|
||||
|
||||
/** Sets the value in the remote cache. */
|
||||
public void set(String key, V value) {
|
||||
checkNotNull(key, "Key cannot be null");
|
||||
checkNotNull(value, "Value cannot be null");
|
||||
jedis.set(key.getBytes(StandardCharsets.UTF_8), serialize(value));
|
||||
public <V extends EppResource> void set(JedisResource<V> resource) {
|
||||
checkNotNull(resource.key, "Key cannot be null");
|
||||
checkNotNull(resource.value, "Value cannot be null");
|
||||
jedis.set(
|
||||
convertKey(resource.value.getClass(), resource.key),
|
||||
serialize(resource.value),
|
||||
new SetParams().pxAt(resource.value.getDeletionTime().toEpochMilli()));
|
||||
}
|
||||
|
||||
private byte[] serialize(V value) {
|
||||
/** Sets multiple values in the remote cache using a Jedis {@link AbstractPipeline}. */
|
||||
public <V extends EppResource> void setAll(ImmutableCollection<JedisResource<V>> resources) {
|
||||
logger.atInfo().log("Processing %d resources", resources.size());
|
||||
for (Iterable<JedisResource<V>> batch : Iterables.partition(resources, BATCH_SIZE)) {
|
||||
try (AbstractPipeline pipeline = jedis.pipelined()) {
|
||||
batch.forEach(
|
||||
resource ->
|
||||
pipeline.set(
|
||||
convertKey(resource.value.getClass(), resource.key),
|
||||
serialize(resource.value),
|
||||
new SetParams().pxAt(resource.value.getDeletionTime().toEpochMilli())));
|
||||
pipeline.sync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all values associated with the given keys in Valkey.
|
||||
*
|
||||
* <p>If any given key does not exist, it does nothing.
|
||||
*
|
||||
* <p>Note: we use {@code unlink} here instead of {@code del} so that the actual deletion can
|
||||
* happen in the background whenever the server wants. The keys are removed from the namespace
|
||||
* immediately, and we don't need the memory to be reclaimed this instant.
|
||||
*
|
||||
* <p>This could also be accomplished by using {@link #setAll(ImmutableCollection)} with
|
||||
* expiration times that are in the past, but this is clearer.
|
||||
*/
|
||||
public void deleteAll(Class<?> valueType, ImmutableCollection<String> keys) {
|
||||
// we use a reasonably small batch size to avoid overwhelming the network
|
||||
for (Iterable<String> batch : Iterables.partition(keys, BATCH_SIZE)) {
|
||||
byte[][] keysToUnlink =
|
||||
Streams.stream(batch).map(key -> convertKey(valueType, key)).toArray(byte[][]::new);
|
||||
jedis.unlink(keysToUnlink);
|
||||
}
|
||||
}
|
||||
|
||||
private <V extends EppResource> byte[] serialize(V value) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Schema<V> valueSchema = (Schema<V>) getValueSchema(value.getClass());
|
||||
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
|
||||
try {
|
||||
return ProtostuffIOUtil.toByteArray(value, valueSchema, buffer);
|
||||
@@ -72,9 +133,22 @@ public class SimplifiedJedisClient<V extends EppResource> {
|
||||
}
|
||||
}
|
||||
|
||||
private V deserialize(byte[] data) {
|
||||
private <V extends EppResource> V deserialize(Class<V> clazz, byte[] data) {
|
||||
// We use protobufs because other deserializers don't play nicely with immutable collections
|
||||
Schema<V> valueSchema = getValueSchema(clazz);
|
||||
V value = valueSchema.newMessage();
|
||||
ProtostuffIOUtil.mergeFrom(data, value, valueSchema);
|
||||
return value;
|
||||
}
|
||||
|
||||
private byte[] convertKey(Class<?> clazz, String key) {
|
||||
checkArgument(TYPE_PREFIXES.containsKey(clazz), "Unknown class type %s", clazz);
|
||||
return (TYPE_PREFIXES.get(clazz) + key).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <V extends EppResource> Schema<V> getValueSchema(Class<V> clazz) {
|
||||
checkArgument(VALUE_SCHEMAS.containsKey(clazz), "Unknown class type %s", clazz);
|
||||
return (Schema<V>) VALUE_SCHEMAS.get(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("databaseRetention")
|
||||
public static Duration provideDatabaseRetention() {
|
||||
public static java.time.Duration provideDatabaseRetention() {
|
||||
return getDatabaseRetention();
|
||||
}
|
||||
|
||||
@@ -281,8 +281,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("brdaInterval")
|
||||
public static Duration provideBrdaInterval() {
|
||||
return Duration.standardDays(7);
|
||||
public static java.time.Duration provideBrdaInterval() {
|
||||
return java.time.Duration.ofDays(7);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,8 +315,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("publishDnsUpdatesLockDuration")
|
||||
public static Duration providePublishDnsUpdatesLockDuration() {
|
||||
return Duration.standardMinutes(3);
|
||||
public static java.time.Duration providePublishDnsUpdatesLockDuration() {
|
||||
return java.time.Duration.ofMinutes(3);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,8 +343,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("readDnsRefreshRequestsActionRuntime")
|
||||
public static Duration provideReadDnsRefreshRequestsRuntime() {
|
||||
return Duration.standardSeconds(45);
|
||||
public static java.time.Duration provideReadDnsRefreshRequestsRuntime() {
|
||||
return java.time.Duration.ofSeconds(45);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -354,8 +354,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("dnsDefaultATtl")
|
||||
public static Duration provideDnsDefaultATtl() {
|
||||
return Duration.standardHours(1);
|
||||
public static java.time.Duration provideDnsDefaultATtl() {
|
||||
return java.time.Duration.ofHours(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,8 +365,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("dnsDefaultNsTtl")
|
||||
public static Duration provideDnsDefaultNsTtl() {
|
||||
return Duration.standardHours(3);
|
||||
public static java.time.Duration provideDnsDefaultNsTtl() {
|
||||
return java.time.Duration.ofHours(3);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -376,8 +376,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("dnsDefaultDsTtl")
|
||||
public static Duration provideDnsDefaultDsTtl() {
|
||||
return Duration.standardHours(1);
|
||||
public static java.time.Duration provideDnsDefaultDsTtl() {
|
||||
return java.time.Duration.ofHours(1);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -757,8 +757,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("rdeInterval")
|
||||
public static Duration provideRdeInterval() {
|
||||
return Duration.standardDays(1);
|
||||
public static java.time.Duration provideRdeInterval() {
|
||||
return java.time.Duration.ofDays(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -768,8 +768,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("rdeReportLockTimeout")
|
||||
public static Duration provideRdeReportLockTimeout() {
|
||||
return Duration.standardMinutes(1);
|
||||
public static java.time.Duration provideRdeReportLockTimeout() {
|
||||
return java.time.Duration.ofMinutes(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -792,8 +792,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("rdeUploadLockTimeout")
|
||||
public static Duration provideRdeUploadLockTimeout() {
|
||||
return Duration.standardMinutes(30);
|
||||
public static java.time.Duration provideRdeUploadLockTimeout() {
|
||||
return java.time.Duration.ofMinutes(30);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -805,8 +805,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("rdeUploadSftpCooldown")
|
||||
public static Duration provideRdeUploadSftpCooldown() {
|
||||
return Duration.standardHours(2);
|
||||
public static java.time.Duration provideRdeUploadSftpCooldown() {
|
||||
return java.time.Duration.ofHours(2);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -841,8 +841,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("sheetLockTimeout")
|
||||
public static Duration provideSheetLockTimeout() {
|
||||
return Duration.standardHours(1);
|
||||
public static java.time.Duration provideSheetLockTimeout() {
|
||||
return java.time.Duration.ofHours(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -865,8 +865,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("emailThrottleDuration")
|
||||
public static Duration provideEmailThrottleSeconds(RegistryConfigSettings config) {
|
||||
return Duration.standardSeconds(config.misc.emailThrottleSeconds);
|
||||
public static java.time.Duration provideEmailThrottleSeconds(RegistryConfigSettings config) {
|
||||
return java.time.Duration.ofSeconds(config.misc.emailThrottleSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -946,8 +946,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("sshTimeout")
|
||||
public static Duration provideSshTimeout() {
|
||||
return Duration.standardSeconds(30);
|
||||
public static java.time.Duration provideSshTimeout() {
|
||||
return java.time.Duration.ofSeconds(30);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -957,8 +957,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("transactionCooldown")
|
||||
public static Duration provideTransactionCooldown() {
|
||||
return Duration.standardMinutes(5);
|
||||
public static java.time.Duration provideTransactionCooldown() {
|
||||
return java.time.Duration.ofMinutes(5);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1327,15 +1327,15 @@ public final class RegistryConfig {
|
||||
|
||||
@Provides
|
||||
@Config("bsaLockLeaseExpiry")
|
||||
public static Duration provideBsaLockLeaseExpiry(RegistryConfigSettings config) {
|
||||
return Duration.standardMinutes(config.bsa.bsaLockLeaseExpiryMinutes);
|
||||
public static java.time.Duration provideBsaLockLeaseExpiry(RegistryConfigSettings config) {
|
||||
return java.time.Duration.ofMinutes(config.bsa.bsaLockLeaseExpiryMinutes);
|
||||
}
|
||||
|
||||
/** Returns the desired interval between successive BSA downloads. */
|
||||
@Provides
|
||||
@Config("bsaDownloadInterval")
|
||||
public static Duration provideBsaDownloadInterval(RegistryConfigSettings config) {
|
||||
return Duration.standardMinutes(config.bsa.bsaDownloadIntervalMinutes);
|
||||
public static java.time.Duration provideBsaDownloadInterval(RegistryConfigSettings config) {
|
||||
return java.time.Duration.ofMinutes(config.bsa.bsaDownloadIntervalMinutes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1344,8 +1344,8 @@ public final class RegistryConfig {
|
||||
*/
|
||||
@Provides
|
||||
@Config("bsaMaxNopInterval")
|
||||
public static Duration provideBsaMaxNopInterval(RegistryConfigSettings config) {
|
||||
return Duration.standardHours(config.bsa.bsaMaxNopIntervalHours);
|
||||
public static java.time.Duration provideBsaMaxNopInterval(RegistryConfigSettings config) {
|
||||
return java.time.Duration.ofHours(config.bsa.bsaMaxNopIntervalHours);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -1356,14 +1356,16 @@ public final class RegistryConfig {
|
||||
|
||||
@Provides
|
||||
@Config("domainCreateTxnCommitTimeLag")
|
||||
public static Duration provideDomainCreateTxnCommitTimeLag(RegistryConfigSettings config) {
|
||||
return Duration.standardSeconds(config.bsa.domainCreateTxnCommitTimeLagSeconds);
|
||||
public static java.time.Duration provideDomainCreateTxnCommitTimeLag(
|
||||
RegistryConfigSettings config) {
|
||||
return java.time.Duration.ofSeconds(config.bsa.domainCreateTxnCommitTimeLagSeconds);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("bsaValidationMaxStaleness")
|
||||
public static Duration provideBsaValidationMaxStaleness(RegistryConfigSettings config) {
|
||||
return Duration.standardSeconds(config.bsa.bsaValidationMaxStalenessSeconds);
|
||||
public static java.time.Duration provideBsaValidationMaxStaleness(
|
||||
RegistryConfigSettings config) {
|
||||
return java.time.Duration.ofSeconds(config.bsa.bsaValidationMaxStalenessSeconds);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -1374,8 +1376,8 @@ public final class RegistryConfig {
|
||||
|
||||
@Provides
|
||||
@Config("bsaAuthTokenExpiry")
|
||||
public static Duration provideBsaAuthTokenExpiry(RegistryConfigSettings config) {
|
||||
return Duration.standardSeconds(config.bsa.authTokenExpirySeconds);
|
||||
public static java.time.Duration provideBsaAuthTokenExpiry(RegistryConfigSettings config) {
|
||||
return java.time.Duration.ofSeconds(config.bsa.authTokenExpirySeconds);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -1488,8 +1490,8 @@ public final class RegistryConfig {
|
||||
*
|
||||
* @see google.registry.tools.server.GenerateZoneFilesAction
|
||||
*/
|
||||
public static Duration getDatabaseRetention() {
|
||||
return Duration.standardDays(30);
|
||||
public static java.time.Duration getDatabaseRetention() {
|
||||
return java.time.Duration.ofDays(30);
|
||||
}
|
||||
|
||||
public static boolean areServersLocal() {
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.google.monitoring.metrics.LabelDescriptor;
|
||||
import com.google.monitoring.metrics.MetricRegistryImpl;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import jakarta.inject.Inject;
|
||||
import org.joda.time.Duration;
|
||||
import java.time.Duration;
|
||||
|
||||
/** DNS instrumentation. */
|
||||
// TODO(b/67947699):Once load testing is done, revisit these to rename them and delete the ones that
|
||||
@@ -239,15 +239,15 @@ public class DnsMetrics {
|
||||
int batchSize = numberOfDomains + numberOfHosts;
|
||||
|
||||
processingTimePerCommitDist.record(
|
||||
processingDuration.getMillis(), tld, status.name(), dnsWriter);
|
||||
processingDuration.toMillis(), tld, status.name(), dnsWriter);
|
||||
processingTimePerItemDist.record(
|
||||
processingDuration.getMillis(), batchSize, tld, status.name(), dnsWriter);
|
||||
processingDuration.toMillis(), batchSize, tld, status.name(), dnsWriter);
|
||||
|
||||
if (batchSize > 0) {
|
||||
normalizedProcessingTimePerCommitDist.record(
|
||||
processingDuration.getMillis() / (double) batchSize, tld, status.name(), dnsWriter);
|
||||
processingDuration.toMillis() / (double) batchSize, tld, status.name(), dnsWriter);
|
||||
normalizedProcessingTimePerItemDist.record(
|
||||
processingDuration.getMillis() / (double) batchSize,
|
||||
processingDuration.toMillis() / (double) batchSize,
|
||||
batchSize,
|
||||
tld,
|
||||
status.name(),
|
||||
@@ -267,7 +267,7 @@ public class DnsMetrics {
|
||||
Duration timeSinceUpdateRequest,
|
||||
Duration timeSinceActionEnqueued) {
|
||||
updateRequestLatency.record(
|
||||
timeSinceUpdateRequest.getMillis(), numberOfItems, tld, status.name(), dnsWriter);
|
||||
publishQueueDelay.record(timeSinceActionEnqueued.getMillis(), tld, status.name(), dnsWriter);
|
||||
timeSinceUpdateRequest.toMillis(), numberOfItems, tld, status.name(), dnsWriter);
|
||||
publishQueueDelay.record(timeSinceActionEnqueued.toMillis(), tld, status.name(), dnsWriter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ import google.registry.dns.writer.DnsWriterZone;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.RequestParameters;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Dagger module for the dns package. */
|
||||
@Module
|
||||
@@ -68,15 +68,15 @@ public abstract class DnsModule {
|
||||
|
||||
@Provides
|
||||
@Parameter(PARAM_PUBLISH_TASK_ENQUEUED)
|
||||
static DateTime provideCreateTime(HttpServletRequest req) {
|
||||
return DateTime.parse(extractRequiredParameter(req, PARAM_PUBLISH_TASK_ENQUEUED));
|
||||
static Instant provideCreateTime(HttpServletRequest req) {
|
||||
return Instant.parse(extractRequiredParameter(req, PARAM_PUBLISH_TASK_ENQUEUED));
|
||||
}
|
||||
|
||||
// TODO: Retire the old header after DNS pull queue migration.
|
||||
@Provides
|
||||
@Parameter(PARAM_REFRESH_REQUEST_TIME)
|
||||
static DateTime provideItemsCreateTime(HttpServletRequest req) {
|
||||
return DateTime.parse(
|
||||
static Instant provideItemsCreateTime(HttpServletRequest req) {
|
||||
return Instant.parse(
|
||||
extractOptionalParameter(req, "itemsCreated")
|
||||
.orElse(extractRequiredParameter(req, PARAM_REFRESH_REQUEST_TIME)));
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.dns;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.persistence.PersistenceModule.TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.toJavaDuration;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -24,10 +25,10 @@ import com.google.common.net.InternetDomainName;
|
||||
import google.registry.model.common.DnsRefreshRequest;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.model.tld.Tlds;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Utility class to handle DNS refresh requests. */
|
||||
public final class DnsUtils {
|
||||
@@ -42,13 +43,13 @@ public final class DnsUtils {
|
||||
// Throws an IllegalArgumentException if the name is not under a managed TLD -- we only update
|
||||
// DNS for names that are under our management.
|
||||
String tld = Tlds.findTldForNameOrThrow(InternetDomainName.from(name)).toString();
|
||||
tm().insert(new DnsRefreshRequest(type, name, tld, tm().getTransactionTime().plus(delay)));
|
||||
tm().insert(new DnsRefreshRequest(type, name, tld, tm().getTxTime().plus(delay)));
|
||||
}
|
||||
|
||||
private static void requestDnsRefresh(
|
||||
ImmutableCollection<String> names, TargetType type, Duration delay) {
|
||||
tm().assertInTransaction();
|
||||
DateTime requestTime = tm().getTransactionTime().plus(delay);
|
||||
Instant requestTime = tm().getTxTime().plus(delay);
|
||||
tm().insertAll(
|
||||
names.stream()
|
||||
.map(
|
||||
@@ -103,7 +104,7 @@ public final class DnsUtils {
|
||||
return tm().transact(
|
||||
TRANSACTION_REPEATABLE_READ,
|
||||
() -> {
|
||||
DateTime transactionTime = tm().getTransactionTime();
|
||||
Instant transactionTime = tm().getTxTime();
|
||||
ImmutableList<DnsRefreshRequest> requests =
|
||||
tm().query(
|
||||
"FROM DnsRefreshRequest WHERE tld = :tld "
|
||||
@@ -150,10 +151,10 @@ public final class DnsUtils {
|
||||
if (tldName.isPresent()) {
|
||||
Tld tld = Tld.get(tldName.get().toString());
|
||||
if (tld.getDnsAPlusAaaaTtl().isPresent()) {
|
||||
dnsAPlusAaaaTtl = tld.getDnsAPlusAaaaTtl().get();
|
||||
dnsAPlusAaaaTtl = toJavaDuration(tld.getDnsAPlusAaaaTtl().get());
|
||||
}
|
||||
}
|
||||
return dnsAPlusAaaaTtl.getStandardSeconds();
|
||||
return dnsAPlusAaaaTtl.toSeconds();
|
||||
}
|
||||
|
||||
/** The possible values of the {@code DNS_TARGET_TYPE_PARAM} parameter. */
|
||||
|
||||
@@ -63,11 +63,11 @@ import google.registry.util.DomainNameUtils;
|
||||
import google.registry.util.EmailMessage;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Task that sends domain and host updates to the DNS server. */
|
||||
@Action(
|
||||
@@ -100,8 +100,8 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
*/
|
||||
private final String dnsWriter;
|
||||
|
||||
private final DateTime enqueuedTime;
|
||||
private final DateTime itemsCreateTime;
|
||||
private final Instant enqueuedTime;
|
||||
private final Instant itemsCreateTime;
|
||||
private final int lockIndex;
|
||||
private final int numPublishLocks;
|
||||
private final Set<String> domains;
|
||||
@@ -121,8 +121,8 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
@Inject
|
||||
public PublishDnsUpdatesAction(
|
||||
@Parameter(PARAM_DNS_WRITER) String dnsWriter,
|
||||
@Parameter(PARAM_PUBLISH_TASK_ENQUEUED) DateTime enqueuedTime,
|
||||
@Parameter(PARAM_REFRESH_REQUEST_TIME) DateTime itemsCreateTime,
|
||||
@Parameter(PARAM_PUBLISH_TASK_ENQUEUED) Instant enqueuedTime,
|
||||
@Parameter(PARAM_REFRESH_REQUEST_TIME) Instant itemsCreateTime,
|
||||
@Parameter(PARAM_LOCK_INDEX) int lockIndex,
|
||||
@Parameter(PARAM_NUM_PUBLISH_LOCKS) int numPublishLocks,
|
||||
@Parameter(PARAM_DOMAINS) Set<String> domains,
|
||||
@@ -167,15 +167,15 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
}
|
||||
|
||||
private void recordActionResult(ActionStatus status) {
|
||||
DateTime now = clock.nowUtc();
|
||||
Instant now = clock.now();
|
||||
|
||||
dnsMetrics.recordActionResult(
|
||||
tld,
|
||||
dnsWriter,
|
||||
status,
|
||||
nullToEmpty(domains).size() + nullToEmpty(hosts).size(),
|
||||
new Duration(itemsCreateTime, now),
|
||||
new Duration(enqueuedTime, now));
|
||||
Duration.between(itemsCreateTime, now),
|
||||
Duration.between(enqueuedTime, now));
|
||||
logger.atInfo().log(
|
||||
"publishDnsWriter latency statistics: TLD: %s, dnsWriter: %s, actionStatus: %s, "
|
||||
+ "numItems: %d, timeSinceCreation: %s, timeInQueue: %s.",
|
||||
@@ -183,8 +183,8 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
dnsWriter,
|
||||
status,
|
||||
nullToEmpty(domains).size() + nullToEmpty(hosts).size(),
|
||||
new Duration(itemsCreateTime, now),
|
||||
new Duration(enqueuedTime, now));
|
||||
Duration.between(itemsCreateTime, now),
|
||||
Duration.between(enqueuedTime, now));
|
||||
}
|
||||
|
||||
/** Runs the task. */
|
||||
@@ -237,7 +237,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
.ifPresent(
|
||||
dn -> {
|
||||
Optional<Domain> domain =
|
||||
ForeignKeyUtils.loadResource(Domain.class, dn, clock.nowUtc());
|
||||
ForeignKeyUtils.loadResource(Domain.class, dn, clock.now());
|
||||
if (domain.isPresent()) {
|
||||
notifyWithEmailAboutDnsUpdateFailure(
|
||||
domain.get().getCurrentSponsorRegistrarId(), dn, false);
|
||||
@@ -250,8 +250,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
.findFirst()
|
||||
.ifPresent(
|
||||
hn -> {
|
||||
Optional<Host> host =
|
||||
ForeignKeyUtils.loadResource(Host.class, hn, clock.nowUtc());
|
||||
Optional<Host> host = ForeignKeyUtils.loadResource(Host.class, hn, clock.now());
|
||||
if (host.isPresent()) {
|
||||
notifyWithEmailAboutDnsUpdateFailure(
|
||||
host.get().getPersistedCurrentSponsorRegistrarId(), hn, true);
|
||||
@@ -336,7 +335,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
.put(PARAM_DNS_WRITER, dnsWriter)
|
||||
.put(PARAM_LOCK_INDEX, Integer.toString(lockIndex))
|
||||
.put(PARAM_NUM_PUBLISH_LOCKS, Integer.toString(numPublishLocks))
|
||||
.put(PARAM_PUBLISH_TASK_ENQUEUED, clock.nowUtc().toString())
|
||||
.put(PARAM_PUBLISH_TASK_ENQUEUED, clock.now().toString())
|
||||
.put(PARAM_REFRESH_REQUEST_TIME, itemsCreateTime.toString())
|
||||
.put(PARAM_DOMAINS, Joiner.on(",").join(domains))
|
||||
.put(PARAM_HOSTS, Joiner.on(",").join(hosts))
|
||||
@@ -374,7 +373,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
|
||||
/** Steps through the domain and host refreshes contained in the parameters and processes them. */
|
||||
private void processBatch() {
|
||||
DateTime timeAtStart = clock.nowUtc();
|
||||
Instant timeAtStart = clock.now();
|
||||
|
||||
DnsWriter writer = dnsWriterProxy.getByClassNameForTld(dnsWriter, tld);
|
||||
|
||||
@@ -426,7 +425,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
|
||||
actionStatus = ActionStatus.SUCCESS;
|
||||
} finally {
|
||||
recordActionResult(actionStatus);
|
||||
Duration duration = new Duration(timeAtStart, clock.nowUtc());
|
||||
Duration duration = Duration.between(timeAtStart, clock.now());
|
||||
dnsMetrics.recordCommit(
|
||||
tld, dnsWriter, commitStatus, duration, domainsPublished, hostsPublished);
|
||||
logger.atInfo().log(
|
||||
|
||||
@@ -28,7 +28,7 @@ import static google.registry.dns.DnsUtils.deleteRequests;
|
||||
import static google.registry.dns.DnsUtils.readAndUpdateRequestsWithLatestProcessTime;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
import static google.registry.request.RequestParameters.PARAM_TLD;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
import static google.registry.util.DomainNameUtils.getSecondLevelDomain;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
@@ -49,10 +49,10 @@ import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* Action for fanning out DNS refresh tasks by TLD, using data taken from {@link DnsRefreshRequest}
|
||||
@@ -104,11 +104,11 @@ public final class ReadDnsRefreshRequestsAction implements Runnable {
|
||||
logger.atInfo().log("The queue updated is paused for TLD: %s.", tld);
|
||||
return;
|
||||
}
|
||||
DateTime requestedEndTime = clock.nowUtc().plus(requestedMaximumDuration);
|
||||
Instant requestedEndTime = clock.now().plus(requestedMaximumDuration);
|
||||
// See getLockIndex(), requests are evenly distributed to [1, numDnsPublishLocks], so each
|
||||
// bucket would be roughly the size of tldUpdateBatchSize.
|
||||
int processBatchSize = tldUpdateBatchSize * Tld.get(tld).getNumDnsPublishLocks();
|
||||
while (requestedEndTime.isAfter(clock.nowUtc())) {
|
||||
while (requestedEndTime.isAfter(clock.now())) {
|
||||
ImmutableList<DnsRefreshRequest> requests =
|
||||
readAndUpdateRequestsWithLatestProcessTime(
|
||||
tld, requestedMaximumDuration, processBatchSize);
|
||||
@@ -165,7 +165,7 @@ public final class ReadDnsRefreshRequestsAction implements Runnable {
|
||||
void enqueueUpdates(int lockIndex, int numPublishLocks, Collection<DnsRefreshRequest> requests) {
|
||||
ImmutableList.Builder<String> domainsBuilder = new ImmutableList.Builder<>();
|
||||
ImmutableList.Builder<String> hostsBuilder = new ImmutableList.Builder<>();
|
||||
DateTime earliestRequestTime = END_OF_TIME;
|
||||
Instant earliestRequestTime = END_INSTANT;
|
||||
for (DnsRefreshRequest request : requests) {
|
||||
if (request.getRequestTime().isBefore(earliestRequestTime)) {
|
||||
earliestRequestTime = request.getRequestTime();
|
||||
@@ -189,7 +189,7 @@ public final class ReadDnsRefreshRequestsAction implements Runnable {
|
||||
.put(PARAM_DNS_WRITER, dnsWriter)
|
||||
.put(PARAM_LOCK_INDEX, Integer.toString(lockIndex))
|
||||
.put(PARAM_NUM_PUBLISH_LOCKS, Integer.toString(numPublishLocks))
|
||||
.put(PARAM_PUBLISH_TASK_ENQUEUED, clock.nowUtc().toString())
|
||||
.put(PARAM_PUBLISH_TASK_ENQUEUED, clock.now().toString())
|
||||
.put(PARAM_REFRESH_REQUEST_TIME, earliestRequestTime.toString())
|
||||
.put(PARAM_DOMAINS, Joiner.on(',').join(domains))
|
||||
.put(PARAM_HOSTS, Joiner.on(',').join(hosts))
|
||||
|
||||
@@ -78,7 +78,7 @@ public final class RefreshDnsAction implements Runnable {
|
||||
|
||||
private <T extends EppResource & ForeignKeyedEppResource>
|
||||
T loadAndVerifyExistence(Class<T> clazz, String foreignKey) {
|
||||
return ForeignKeyUtils.loadResource(clazz, foreignKey, clock.nowUtc())
|
||||
return ForeignKeyUtils.loadResource(clazz, foreignKey, clock.now())
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new NotFoundException(
|
||||
|
||||
@@ -30,7 +30,7 @@ import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import jakarta.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
import java.time.Instant;
|
||||
|
||||
@Action(
|
||||
service = Action.Service.BACKEND,
|
||||
@@ -56,7 +56,7 @@ public class RefreshDnsOnHostRenameAction implements Runnable {
|
||||
public void run() {
|
||||
tm().transact(
|
||||
() -> {
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Instant now = tm().getTxTime();
|
||||
Host host = tm().loadByKeyIfPresent(hostKey).orElse(null);
|
||||
boolean hostValid = true;
|
||||
String failureMessage = null;
|
||||
|
||||
@@ -44,6 +44,7 @@ import google.registry.model.tld.Tld;
|
||||
import google.registry.model.tld.Tlds;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.Concurrent;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import google.registry.util.Retrier;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
@@ -51,6 +52,7 @@ import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.AbstractMap.SimpleImmutableEntry;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -59,7 +61,6 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* {@link DnsWriter} implementation that talks to Google Cloud DNS.
|
||||
@@ -123,8 +124,7 @@ public class CloudDnsWriter extends BaseDnsWriter {
|
||||
String absoluteDomainName = getAbsoluteHostName(domainName);
|
||||
|
||||
// Load the target domain. Note that it can be absent if this domain was just deleted.
|
||||
Optional<Domain> domain =
|
||||
ForeignKeyUtils.loadResource(Domain.class, domainName, clock.nowUtc());
|
||||
Optional<Domain> domain = ForeignKeyUtils.loadResource(Domain.class, domainName, clock.now());
|
||||
|
||||
// Return early if no DNS records should be published.
|
||||
// desiredRecordsBuilder is populated with an empty set to indicate that all existing records
|
||||
@@ -148,7 +148,12 @@ public class CloudDnsWriter extends BaseDnsWriter {
|
||||
domainRecords.add(
|
||||
new ResourceRecordSet()
|
||||
.setName(absoluteDomainName)
|
||||
.setTtl((int) tld.getDnsDsTtl().orElse(defaultDsTtl).getStandardSeconds())
|
||||
.setTtl(
|
||||
(int)
|
||||
tld.getDnsDsTtl()
|
||||
.map(DateTimeUtils::toJavaDuration)
|
||||
.orElse(defaultDsTtl)
|
||||
.toSeconds())
|
||||
.setType("DS")
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setRrdatas(ImmutableList.copyOf(dsRrData)));
|
||||
@@ -171,7 +176,12 @@ public class CloudDnsWriter extends BaseDnsWriter {
|
||||
domainRecords.add(
|
||||
new ResourceRecordSet()
|
||||
.setName(absoluteDomainName)
|
||||
.setTtl((int) tld.getDnsNsTtl().orElse(defaultNsTtl).getStandardSeconds())
|
||||
.setTtl(
|
||||
(int)
|
||||
tld.getDnsNsTtl()
|
||||
.map(DateTimeUtils::toJavaDuration)
|
||||
.orElse(defaultNsTtl)
|
||||
.toSeconds())
|
||||
.setType("NS")
|
||||
.setKind("dns#resourceRecordSet")
|
||||
.setRrdatas(ImmutableList.copyOf(nsRrData)));
|
||||
@@ -190,7 +200,7 @@ public class CloudDnsWriter extends BaseDnsWriter {
|
||||
// Load the target host. Note that it can be absent if this host was just deleted.
|
||||
// desiredRecords is populated with an empty set to indicate that all existing records
|
||||
// should be deleted.
|
||||
Optional<Host> host = ForeignKeyUtils.loadResource(Host.class, hostName, clock.nowUtc());
|
||||
Optional<Host> host = ForeignKeyUtils.loadResource(Host.class, hostName, clock.now());
|
||||
|
||||
// Return early if the host is deleted.
|
||||
if (host.isEmpty()) {
|
||||
|
||||
@@ -28,8 +28,8 @@ import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Duration;
|
||||
import javax.net.SocketFactory;
|
||||
import org.joda.time.Duration;
|
||||
import org.xbill.DNS.Message;
|
||||
import org.xbill.DNS.Opcode;
|
||||
|
||||
@@ -76,7 +76,7 @@ public class DnsMessageTransport {
|
||||
@Config("dnsUpdateTimeout") Duration updateTimeout) {
|
||||
this.factory = factory;
|
||||
this.updateHost = updateHost;
|
||||
this.updateTimeout = Ints.checkedCast(updateTimeout.getMillis());
|
||||
this.updateTimeout = Ints.checkedCast(updateTimeout.toMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@ package google.registry.dns.writer.dnsupdate;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import org.joda.time.Duration;
|
||||
import java.time.Duration;
|
||||
|
||||
/** Dagger module that provides DNS configuration settings. */
|
||||
@Module
|
||||
@@ -39,6 +39,6 @@ public class DnsUpdateConfigModule {
|
||||
@Provides
|
||||
@Config("dnsUpdateTimeout")
|
||||
public static Duration provideDnsUpdateTimeout() {
|
||||
return Duration.standardSeconds(30);
|
||||
return Duration.ofSeconds(30);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,13 +34,14 @@ import google.registry.model.host.Host;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.model.tld.Tlds;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Duration;
|
||||
import org.xbill.DNS.AAAARecord;
|
||||
import org.xbill.DNS.ARecord;
|
||||
import org.xbill.DNS.DClass;
|
||||
@@ -130,7 +131,7 @@ public class DnsUpdateWriter extends BaseDnsWriter {
|
||||
*/
|
||||
private void publishDomain(String domainName, String requestingHostName) {
|
||||
Optional<Domain> domainOptional =
|
||||
ForeignKeyUtils.loadResource(Domain.class, domainName, clock.nowUtc());
|
||||
ForeignKeyUtils.loadResource(Domain.class, domainName, clock.now());
|
||||
update.delete(toAbsoluteName(domainName), Type.ANY);
|
||||
// If the domain is now deleted, then don't update DNS for it.
|
||||
if (domainOptional.isPresent()) {
|
||||
@@ -194,7 +195,10 @@ public class DnsUpdateWriter extends BaseDnsWriter {
|
||||
new DSRecord(
|
||||
toAbsoluteName(domain.getDomainName()),
|
||||
DClass.IN,
|
||||
tld.getDnsDsTtl().orElse(dnsDefaultDsTtl).getStandardSeconds(),
|
||||
tld.getDnsDsTtl()
|
||||
.map(DateTimeUtils::toJavaDuration)
|
||||
.orElse(dnsDefaultDsTtl)
|
||||
.toSeconds(),
|
||||
signerData.getKeyTag(),
|
||||
signerData.getAlgorithm(),
|
||||
signerData.getDigestType(),
|
||||
@@ -219,7 +223,7 @@ public class DnsUpdateWriter extends BaseDnsWriter {
|
||||
private void addInBailiwickNameServerSet(Domain domain, Update update) {
|
||||
for (String hostName :
|
||||
intersection(domain.loadNameserverHostNames(), domain.getSubordinateHosts())) {
|
||||
Optional<Host> host = ForeignKeyUtils.loadResource(Host.class, hostName, clock.nowUtc());
|
||||
Optional<Host> host = ForeignKeyUtils.loadResource(Host.class, hostName, clock.now());
|
||||
checkState(host.isPresent(), "Host %s cannot be loaded", hostName);
|
||||
update.add(makeAddressSet(host.get()));
|
||||
update.add(makeV6AddressSet(host.get()));
|
||||
@@ -234,7 +238,10 @@ public class DnsUpdateWriter extends BaseDnsWriter {
|
||||
new NSRecord(
|
||||
toAbsoluteName(domain.getDomainName()),
|
||||
DClass.IN,
|
||||
tld.getDnsNsTtl().orElse(dnsDefaultNsTtl).getStandardSeconds(),
|
||||
tld.getDnsNsTtl()
|
||||
.map(DateTimeUtils::toJavaDuration)
|
||||
.orElse(dnsDefaultNsTtl)
|
||||
.toSeconds(),
|
||||
toAbsoluteName(hostName));
|
||||
nameServerSet.addRR(record);
|
||||
}
|
||||
|
||||
@@ -47,8 +47,6 @@ import java.time.Instant;
|
||||
import java.util.List;
|
||||
import org.hibernate.query.NativeQuery;
|
||||
import org.hibernate.query.TupleTransformer;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
/**
|
||||
* An action that exports the list of active domains on all real TLDs to Google Drive and GCS.
|
||||
@@ -175,8 +173,7 @@ public class ExportDomainListsAction implements Runnable {
|
||||
@Override
|
||||
public String transformTuple(Object[] domainResult, String[] strings) {
|
||||
String domainName = (String) domainResult[0];
|
||||
Instant deletionInstant = (Instant) domainResult[1];
|
||||
DateTime deletionTime = new DateTime(deletionInstant.toEpochMilli(), DateTimeZone.UTC);
|
||||
Instant deletionTime = (Instant) domainResult[1];
|
||||
String[] domainStatuses = (String[]) domainResult[2];
|
||||
String gracePeriodType = (String) domainResult[3];
|
||||
boolean inPendingDelete =
|
||||
|
||||
@@ -25,7 +25,8 @@ import static google.registry.model.registrar.RegistrarPoc.Type.MARKETING;
|
||||
import static google.registry.model.registrar.RegistrarPoc.Type.TECH;
|
||||
import static google.registry.model.registrar.RegistrarPoc.Type.WHOIS;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.isAtOrAfter;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -37,13 +38,12 @@ import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarAddress;
|
||||
import google.registry.model.registrar.RegistrarPoc;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Class for synchronizing all {@link Registrar} objects to a Google Spreadsheet.
|
||||
@@ -63,9 +63,9 @@ class SyncRegistrarsSheet {
|
||||
boolean wereRegistrarsModified() {
|
||||
Optional<Cursor> cursor =
|
||||
tm().transact(() -> tm().loadByKeyIfPresent(Cursor.createGlobalVKey(SYNC_REGISTRAR_SHEET)));
|
||||
DateTime lastUpdateTime = cursor.isEmpty() ? START_OF_TIME : cursor.get().getCursorTime();
|
||||
Instant lastUpdateTime = cursor.isEmpty() ? START_INSTANT : cursor.get().getCursorTime();
|
||||
for (Registrar registrar : Registrar.loadAllCached()) {
|
||||
if (DateTimeUtils.isAtOrAfter(registrar.getLastUpdateTime(), lastUpdateTime)) {
|
||||
if (isAtOrAfter(registrar.getLastUpdateTime(), lastUpdateTime)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ class SyncRegistrarsSheet {
|
||||
|
||||
/** Performs the synchronization operation. */
|
||||
void run(String spreadsheetId) throws IOException {
|
||||
final DateTime executionTime = clock.nowUtc();
|
||||
Instant executionTime = clock.now();
|
||||
sheetSynchronizer.synchronize(
|
||||
spreadsheetId,
|
||||
new Ordering<Registrar>() {
|
||||
|
||||
@@ -30,10 +30,10 @@ import google.registry.request.auth.Auth;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* Action for synchronizing the registrars spreadsheet.
|
||||
|
||||
@@ -35,7 +35,6 @@ import static google.registry.monitoring.whitebox.CheckApiMetric.Tier.STANDARD;
|
||||
import static google.registry.persistence.PersistenceModule.TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
|
||||
import static google.registry.pricing.PricingEngineProxy.isDomainPremium;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static google.registry.util.DomainNameUtils.canonicalizeHostname;
|
||||
import static org.json.simple.JSONValue.toJSONString;
|
||||
|
||||
@@ -61,9 +60,9 @@ import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An action that returns availability and premium checks as JSON.
|
||||
@@ -131,7 +130,7 @@ public class CheckApiAction implements Runnable {
|
||||
// Throws an EppException with a reasonable error message which will be sent back to caller.
|
||||
validateDomainNameWithIdnTables(domainName);
|
||||
|
||||
DateTime now = replicaTm().getTransactionTime();
|
||||
Instant now = replicaTm().getTxTime();
|
||||
Tld tld = Tld.get(domainName.parent().toString());
|
||||
try {
|
||||
verifyNotInPredelegation(tld, now);
|
||||
@@ -166,7 +165,7 @@ public class CheckApiAction implements Runnable {
|
||||
metricBuilder.status(SUCCESS).availability(availability);
|
||||
responseBuilder.put("status", "success").put("available", availability.equals(AVAILABLE));
|
||||
|
||||
boolean isPremium = isDomainPremium(domainString, toInstant(now));
|
||||
boolean isPremium = isDomainPremium(domainString, now);
|
||||
metricBuilder.tier(isPremium ? PREMIUM : STANDARD);
|
||||
responseBuilder.put("tier", isPremium ? "premium" : "standard");
|
||||
if (!AVAILABLE.equals(availability)) {
|
||||
@@ -183,7 +182,7 @@ public class CheckApiAction implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkExists(String domainString, DateTime now) {
|
||||
private boolean checkExists(String domainString, Instant now) {
|
||||
return ForeignKeyUtils.loadKeyByCache(Domain.class, domainString, now).isPresent();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ 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;
|
||||
@@ -50,7 +49,6 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Static utility functions for resource flows. */
|
||||
public final class ResourceFlowUtils {
|
||||
@@ -66,8 +64,7 @@ public final class ResourceFlowUtils {
|
||||
}
|
||||
|
||||
/** Check if there are domains linked to the host to be deleted. Throws an exception if so. */
|
||||
public static void checkLinkedDomains(final String targetId, final DateTime now)
|
||||
throws EppException {
|
||||
public static void checkLinkedDomains(final String targetId, Instant now) throws EppException {
|
||||
VKey<Host> key =
|
||||
ForeignKeyUtils.loadKey(Host.class, targetId, now)
|
||||
.orElseThrow(() -> new ResourceDoesNotExistException(Host.class, targetId));
|
||||
@@ -89,11 +86,6 @@ public final class ResourceFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static <R extends EppResource & ForeignKeyedEppResource> R loadAndVerifyExistence(
|
||||
Class<R> clazz, String targetId, DateTime now) throws ResourceDoesNotExistException {
|
||||
return loadAndVerifyExistence(clazz, targetId, toInstant(now));
|
||||
}
|
||||
|
||||
public static <R extends EppResource & ForeignKeyedEppResource> R loadAndVerifyExistence(
|
||||
Class<R> clazz, String targetId, Instant now) throws ResourceDoesNotExistException {
|
||||
return verifyExistence(clazz, targetId, ForeignKeyUtils.loadResource(clazz, targetId, now));
|
||||
@@ -105,7 +97,7 @@ public final class ResourceFlowUtils {
|
||||
}
|
||||
|
||||
public static <R extends EppResource> void verifyResourceDoesNotExist(
|
||||
Class<R> clazz, String targetId, DateTime now, String registrarId) throws EppException {
|
||||
Class<R> clazz, String targetId, Instant now, String registrarId) throws EppException {
|
||||
Optional<R> resource = ForeignKeyUtils.loadResource(clazz, targetId, now);
|
||||
if (resource.isPresent()) {
|
||||
// These are similar exceptions, but we can track them internally as log-based metrics.
|
||||
|
||||
@@ -25,7 +25,7 @@ import google.registry.flows.domain.DomainCheckFlow;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.CheckData.DomainCheck;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import org.joda.time.DateTime;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* A no-op base class for {@link DomainCheckFlow} custom logic.
|
||||
@@ -75,7 +75,7 @@ public class DomainCheckFlowCustomLogic extends BaseFlowCustomLogic {
|
||||
* but can be overridden in v>=0.12 of the fee extension.
|
||||
*/
|
||||
public record AfterValidationParameters(
|
||||
ImmutableMap<String, InternetDomainName> domainNames, DateTime asOfDate) {
|
||||
ImmutableMap<String, InternetDomainName> domainNames, Instant asOfDate) {
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoBuilder_DomainCheckFlowCustomLogic_AfterValidationParameters_Builder();
|
||||
@@ -87,7 +87,7 @@ public class DomainCheckFlowCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
Builder setDomainNames(ImmutableMap<String, InternetDomainName> domainNames);
|
||||
|
||||
Builder setAsOfDate(DateTime asOfDate);
|
||||
Builder setAsOfDate(Instant asOfDate);
|
||||
|
||||
AfterValidationParameters build();
|
||||
}
|
||||
@@ -102,7 +102,7 @@ public class DomainCheckFlowCustomLogic extends BaseFlowCustomLogic {
|
||||
public record BeforeResponseParameters(
|
||||
ImmutableList<DomainCheck> domainChecks,
|
||||
ImmutableList<? extends ResponseExtension> responseExtensions,
|
||||
DateTime asOfDate) {
|
||||
Instant asOfDate) {
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoBuilder_DomainCheckFlowCustomLogic_BeforeResponseParameters_Builder();
|
||||
@@ -116,7 +116,7 @@ public class DomainCheckFlowCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
Builder setResponseExtensions(ImmutableList<? extends ResponseExtension> responseExtensions);
|
||||
|
||||
Builder setAsOfDate(DateTime asOfDate);
|
||||
Builder setAsOfDate(Instant asOfDate);
|
||||
|
||||
BeforeResponseParameters build();
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ import google.registry.flows.domain.DomainPricingLogic;
|
||||
import google.registry.flows.domain.FeesAndCredits;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.tld.Tld;
|
||||
import java.time.Instant;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A no-op base class to customize {@link DomainPricingLogic}.
|
||||
@@ -79,7 +79,7 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
||||
FeesAndCredits feesAndCredits,
|
||||
Tld tld,
|
||||
InternetDomainName domainName,
|
||||
DateTime asOfDate,
|
||||
Instant asOfDate,
|
||||
int years) {
|
||||
|
||||
public static Builder newBuilder() {
|
||||
@@ -96,7 +96,7 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
Builder setDomainName(InternetDomainName domainName);
|
||||
|
||||
Builder setAsOfDate(DateTime asOfDate);
|
||||
Builder setAsOfDate(Instant asOfDate);
|
||||
|
||||
Builder setYears(int years);
|
||||
|
||||
@@ -109,7 +109,7 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
||||
FeesAndCredits feesAndCredits,
|
||||
Tld tld,
|
||||
InternetDomainName domainName,
|
||||
DateTime asOfDate,
|
||||
Instant asOfDate,
|
||||
int years) {
|
||||
|
||||
public static Builder newBuilder() {
|
||||
@@ -126,7 +126,7 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
Builder setDomainName(InternetDomainName domainName);
|
||||
|
||||
Builder setAsOfDate(DateTime asOfDate);
|
||||
Builder setAsOfDate(Instant asOfDate);
|
||||
|
||||
Builder setYears(int years);
|
||||
|
||||
@@ -136,7 +136,7 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
/** A record to encapsulate parameters for a call to {@link #customizeRestorePrice} . */
|
||||
public record RestorePriceParameters(
|
||||
FeesAndCredits feesAndCredits, Tld tld, InternetDomainName domainName, DateTime asOfDate) {
|
||||
FeesAndCredits feesAndCredits, Tld tld, InternetDomainName domainName, Instant asOfDate) {
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoBuilder_DomainPricingCustomLogic_RestorePriceParameters_Builder();
|
||||
@@ -152,7 +152,7 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
Builder setDomainName(InternetDomainName domainName);
|
||||
|
||||
Builder setAsOfDate(DateTime asOfDate);
|
||||
Builder setAsOfDate(Instant asOfDate);
|
||||
|
||||
RestorePriceParameters build();
|
||||
}
|
||||
@@ -160,7 +160,7 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
/** A record to encapsulate parameters for a call to {@link #customizeTransferPrice} . */
|
||||
public record TransferPriceParameters(
|
||||
FeesAndCredits feesAndCredits, Tld tld, InternetDomainName domainName, DateTime asOfDate) {
|
||||
FeesAndCredits feesAndCredits, Tld tld, InternetDomainName domainName, Instant asOfDate) {
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoBuilder_DomainPricingCustomLogic_TransferPriceParameters_Builder();
|
||||
@@ -176,7 +176,7 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
Builder setDomainName(InternetDomainName domainName);
|
||||
|
||||
Builder setAsOfDate(DateTime asOfDate);
|
||||
Builder setAsOfDate(Instant asOfDate);
|
||||
|
||||
TransferPriceParameters build();
|
||||
}
|
||||
@@ -184,7 +184,7 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
/** A record to encapsulate parameters for a call to {@link #customizeUpdatePrice} . */
|
||||
public record UpdatePriceParameters(
|
||||
FeesAndCredits feesAndCredits, Tld tld, InternetDomainName domainName, DateTime asOfDate) {
|
||||
FeesAndCredits feesAndCredits, Tld tld, InternetDomainName domainName, Instant asOfDate) {
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoBuilder_DomainPricingCustomLogic_UpdatePriceParameters_Builder();
|
||||
@@ -200,7 +200,7 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
Builder setDomainName(InternetDomainName domainName);
|
||||
|
||||
Builder setAsOfDate(DateTime asOfDate);
|
||||
Builder setAsOfDate(Instant asOfDate);
|
||||
|
||||
UpdatePriceParameters build();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseData;
|
||||
import google.registry.model.eppoutput.EppResponse.ResponseExtension;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import org.joda.time.DateTime;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* A no-op base class for {@link DomainRenewFlow} custom logic.
|
||||
@@ -80,7 +80,7 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
|
||||
}
|
||||
|
||||
/** A class to encapsulate parameters for a call to {@link #afterValidation}. */
|
||||
public record AfterValidationParameters(Domain existingDomain, int years, DateTime now) {
|
||||
public record AfterValidationParameters(Domain existingDomain, int years, Instant now) {
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoBuilder_DomainRenewFlowCustomLogic_AfterValidationParameters_Builder();
|
||||
@@ -94,7 +94,7 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
Builder setYears(int years);
|
||||
|
||||
Builder setNow(DateTime now);
|
||||
Builder setNow(Instant now);
|
||||
|
||||
AfterValidationParameters build();
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
|
||||
HistoryEntry historyEntry,
|
||||
EntityChanges entityChanges,
|
||||
int years,
|
||||
DateTime now) {
|
||||
Instant now) {
|
||||
|
||||
public static Builder newBuilder() {
|
||||
return new AutoBuilder_DomainRenewFlowCustomLogic_BeforeSaveParameters_Builder();
|
||||
@@ -133,7 +133,7 @@ public class DomainRenewFlowCustomLogic extends BaseFlowCustomLogic {
|
||||
|
||||
Builder setYears(int years);
|
||||
|
||||
Builder setNow(DateTime now);
|
||||
Builder setNow(Instant now);
|
||||
|
||||
BeforeSaveParameters build();
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ import google.registry.model.tld.label.ReservationType;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@@ -89,7 +90,6 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that checks whether a domain can be provisioned.
|
||||
@@ -156,7 +156,7 @@ public final class DomainCheckFlow implements TransactionalFlow {
|
||||
extensionManager.validate();
|
||||
ImmutableList<String> domainNames = ((Check) resourceCommand).getTargetIds();
|
||||
verifyTargetIdCount(domainNames, maxChecks);
|
||||
DateTime now = clock.nowUtc();
|
||||
Instant now = clock.now();
|
||||
ImmutableMap.Builder<String, InternetDomainName> parsedDomainsBuilder =
|
||||
new ImmutableMap.Builder<>();
|
||||
// Only check that the registrar has access to a TLD the first time it is encountered
|
||||
@@ -225,7 +225,7 @@ public final class DomainCheckFlow implements TransactionalFlow {
|
||||
ImmutableSet<InternetDomainName> bsaBlockedDomainNames,
|
||||
ImmutableMap<String, TldState> tldStates,
|
||||
ImmutableMap<String, InternetDomainName> parsedDomains,
|
||||
DateTime now)
|
||||
Instant now)
|
||||
throws EppException {
|
||||
InternetDomainName idn = parsedDomains.get(domainName);
|
||||
Optional<AllocationToken> token;
|
||||
@@ -286,7 +286,7 @@ public final class DomainCheckFlow implements TransactionalFlow {
|
||||
ImmutableMap<String, InternetDomainName> domainNames,
|
||||
ImmutableMap<String, VKey<Domain>> existingDomains,
|
||||
ImmutableSet<String> availableDomains,
|
||||
DateTime now)
|
||||
Instant now)
|
||||
throws EppException {
|
||||
Optional<FeeCheckCommandExtension> feeCheckOpt =
|
||||
eppInput.getSingleExtension(FeeCheckCommandExtension.class);
|
||||
@@ -480,7 +480,7 @@ public final class DomainCheckFlow implements TransactionalFlow {
|
||||
}
|
||||
|
||||
static ImmutableSet<InternetDomainName> getBsaBlockedDomains(
|
||||
ImmutableCollection<InternetDomainName> parsedDomains, DateTime now) {
|
||||
ImmutableCollection<InternetDomainName> parsedDomains, Instant now) {
|
||||
Map<String, ImmutableList<InternetDomainName>> labelToDomainNames =
|
||||
parsedDomains.stream()
|
||||
.filter(
|
||||
|
||||
@@ -49,10 +49,10 @@ import google.registry.model.tld.Tld;
|
||||
import google.registry.model.tmch.ClaimsListDao;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that checks whether domain labels are trademarked.
|
||||
@@ -103,7 +103,7 @@ public final class DomainClaimsCheckFlow implements TransactionalFlow {
|
||||
checkAllowedAccessToTld(registrarId, tldStr);
|
||||
checkHasBillingAccount(registrarId, tldStr);
|
||||
Tld tld = Tld.get(tldStr);
|
||||
DateTime now = clock.nowUtc();
|
||||
Instant now = clock.now();
|
||||
verifyNotInPredelegation(tld, now);
|
||||
verifyClaimsPeriodNotEnded(tld, now);
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ import google.registry.model.tmch.ClaimsList;
|
||||
import google.registry.model.tmch.ClaimsListDao;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
@@ -236,7 +237,7 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
verifyRegistrarIsActive(registrarId);
|
||||
extensionManager.validate();
|
||||
verifyDomainDoesNotExist();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Instant now = tm().getTxTime();
|
||||
DomainCommand.Create command = cloneAndLinkReferences((Create) resourceCommand, now);
|
||||
Period period = command.getPeriod();
|
||||
verifyUnitIsYears(period);
|
||||
@@ -314,7 +315,7 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
// at this point so that we can verify it before the "after validation" extension point.
|
||||
signedMarkId =
|
||||
tmchUtils
|
||||
.verifySignedMarks(launchCreate.get().getSignedMarks(), domainLabel, toInstant(now))
|
||||
.verifySignedMarks(launchCreate.get().getSignedMarks(), domainLabel, now)
|
||||
.getId();
|
||||
}
|
||||
verifyNotBlockedByBsa(domainName, tld, now, allocationToken);
|
||||
@@ -328,11 +329,11 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
eppInput.getSingleExtension(FeeCreateCommandExtension.class);
|
||||
FeesAndCredits feesAndCredits =
|
||||
pricingLogic.getCreatePrice(
|
||||
tld, targetId, toInstant(now), years, isAnchorTenant, isSunriseCreate, allocationToken);
|
||||
tld, targetId, now, years, isAnchorTenant, isSunriseCreate, allocationToken);
|
||||
validateFeeChallenge(feeCreate, feesAndCredits, defaultTokenUsed);
|
||||
Optional<SecDnsCreateExtension> secDnsCreate =
|
||||
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
|
||||
DateTime registrationExpirationTime = plusYears(now, years);
|
||||
Instant registrationExpirationTime = plusYears(now, years);
|
||||
String repoId = createDomainRepoId(tm().allocateId(), tld.getTldStr());
|
||||
long historyRevisionId = tm().allocateId();
|
||||
HistoryEntryId domainHistoryId = new HistoryEntryId(repoId, historyRevisionId);
|
||||
@@ -435,21 +436,13 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
FeesAndCredits responseFeesAndCredits =
|
||||
shouldShowDefaultPrice
|
||||
? pricingLogic.getCreatePrice(
|
||||
tld,
|
||||
targetId,
|
||||
toInstant(now),
|
||||
years,
|
||||
isAnchorTenant,
|
||||
isSunriseCreate,
|
||||
Optional.empty())
|
||||
tld, targetId, now, years, isAnchorTenant, isSunriseCreate, Optional.empty())
|
||||
: feesAndCredits;
|
||||
|
||||
BeforeResponseReturnData responseData =
|
||||
flowCustomLogic.beforeResponse(
|
||||
BeforeResponseParameters.newBuilder()
|
||||
.setResData(
|
||||
DomainCreateData.create(
|
||||
targetId, toInstant(now), toInstant(registrationExpirationTime)))
|
||||
.setResData(DomainCreateData.create(targetId, now, registrationExpirationTime))
|
||||
.setResponseExtensions(createResponseExtensions(feeCreate, responseFeesAndCredits))
|
||||
.build());
|
||||
return responseBuilder
|
||||
@@ -501,7 +494,7 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
private void verifyIsGaOrSpecialCase(
|
||||
Tld tld,
|
||||
ClaimsList claimsList,
|
||||
DateTime now,
|
||||
Instant now,
|
||||
String domainLabel,
|
||||
Optional<AllocationToken> allocationToken,
|
||||
boolean isAnchorTenant,
|
||||
@@ -565,14 +558,14 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
}
|
||||
|
||||
private DomainHistory buildDomainHistory(
|
||||
Domain domain, Tld tld, DateTime now, Period period, Duration addGracePeriod) {
|
||||
Domain domain, Tld tld, Instant now, Period period, Duration addGracePeriod) {
|
||||
// We ignore prober transactions
|
||||
if (tld.getTldType() == TldType.REAL) {
|
||||
historyBuilder.setDomainTransactionRecords(
|
||||
ImmutableSet.of(
|
||||
DomainTransactionRecord.create(
|
||||
tld.getTldStr(),
|
||||
toInstant(now.plus(addGracePeriod)),
|
||||
now.plusMillis(addGracePeriod.getMillis()),
|
||||
TransactionReportField.netAddsFieldFromYears(period.getValue()),
|
||||
1)));
|
||||
}
|
||||
@@ -588,7 +581,7 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
FeesAndCredits feesAndCredits,
|
||||
HistoryEntryId domainHistoryId,
|
||||
Optional<AllocationToken> allocationToken,
|
||||
DateTime now) {
|
||||
Instant now) {
|
||||
ImmutableSet.Builder<Flag> flagsBuilder = new ImmutableSet.Builder<>();
|
||||
// Sunrise and anchor tenancy are orthogonal tags and thus both can be present together.
|
||||
if (isSunriseCreate) {
|
||||
@@ -607,14 +600,14 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
.setRegistrarId(registrarId)
|
||||
.setPeriodYears(years)
|
||||
.setCost(feesAndCredits.getCreateCost())
|
||||
.setEventTime(toInstant(now))
|
||||
.setEventTime(now)
|
||||
.setAllocationToken(allocationToken.map(AllocationToken::createVKey).orElse(null))
|
||||
.setBillingTime(
|
||||
toInstant(
|
||||
now.plus(
|
||||
isAnchorTenant
|
||||
now.plusMillis(
|
||||
(isAnchorTenant
|
||||
? tld.getAnchorTenantAddGracePeriodLength()
|
||||
: tld.getAddGracePeriodLength())))
|
||||
: tld.getAddGracePeriodLength())
|
||||
.getMillis()))
|
||||
.setFlags(flagsBuilder.build())
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.build();
|
||||
@@ -622,7 +615,7 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
|
||||
private BillingRecurrence createAutorenewBillingEvent(
|
||||
HistoryEntryId domainHistoryId,
|
||||
DateTime registrationExpirationTime,
|
||||
Instant registrationExpirationTime,
|
||||
boolean isAnchorTenant,
|
||||
Optional<AllocationToken> allocationToken) {
|
||||
// Non-standard renewal behaviors can occur for anchor tenants (always NONPREMIUM pricing) or if
|
||||
@@ -639,7 +632,7 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId(targetId)
|
||||
.setRegistrarId(registrarId)
|
||||
.setEventTime(toInstant(registrationExpirationTime))
|
||||
.setEventTime(registrationExpirationTime)
|
||||
.setRecurrenceEndTime(END_INSTANT)
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.setRenewalPriceBehavior(renewalPriceBehavior)
|
||||
@@ -648,11 +641,11 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
}
|
||||
|
||||
private Autorenew createAutorenewPollMessage(
|
||||
HistoryEntryId domainHistoryId, DateTime registrationExpirationTime) {
|
||||
HistoryEntryId domainHistoryId, Instant registrationExpirationTime) {
|
||||
return new PollMessage.Autorenew.Builder()
|
||||
.setTargetId(targetId)
|
||||
.setRegistrarId(registrarId)
|
||||
.setEventTime(toInstant(registrationExpirationTime))
|
||||
.setEventTime(registrationExpirationTime)
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.build();
|
||||
@@ -662,7 +655,7 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
Optional<DateTime> previousDeletionTime =
|
||||
domainDeletionTimeCache.getDeletionTimeForDomain(targetId);
|
||||
if (previousDeletionTime.isPresent()
|
||||
&& !tm().getTransactionTime().isAfter(previousDeletionTime.get())) {
|
||||
&& !tm().getTxTime().isAfter(toInstant(previousDeletionTime.get()))) {
|
||||
throw new ResourceCreateContentionException(targetId);
|
||||
}
|
||||
}
|
||||
@@ -683,10 +676,10 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
}
|
||||
|
||||
private static PollMessage.OneTime createNameCollisionOneTimePollMessage(
|
||||
String domainName, HistoryEntry historyEntry, String registrarId, DateTime now) {
|
||||
String domainName, HistoryEntry historyEntry, String registrarId, Instant now) {
|
||||
return new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId(registrarId)
|
||||
.setEventTime(toInstant(now))
|
||||
.setEventTime(now)
|
||||
.setMsg(COLLISION_MESSAGE) // Remind the registrar of the name collision policy.
|
||||
.setResponseData(
|
||||
ImmutableList.of(
|
||||
|
||||
@@ -42,6 +42,7 @@ import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static google.registry.util.CollectionUtils.union;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -100,6 +101,7 @@ import google.registry.model.tld.Tld;
|
||||
import google.registry.model.tld.Tld.TldType;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -147,7 +149,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
flowCustomLogic.beforeValidation();
|
||||
validateRegistrarIsLoggedIn(registrarId);
|
||||
extensionManager.validate();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Instant now = tm().getTxTime();
|
||||
// Loads the target resource if it exists
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
Tld tld = Tld.get(existingDomain.getTld());
|
||||
@@ -163,7 +165,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
} else {
|
||||
builder = existingDomain.asBuilder();
|
||||
}
|
||||
builder.setLastEppUpdateTime(toInstant(now)).setLastEppUpdateRegistrarId(registrarId);
|
||||
builder.setLastEppUpdateTime(now).setLastEppUpdateRegistrarId(registrarId);
|
||||
Duration redemptionGracePeriodLength = tld.getRedemptionGracePeriodLength();
|
||||
Duration pendingDeleteLength = tld.getPendingDeleteLength();
|
||||
Optional<DomainDeleteSuperuserExtension> domainDeleteSuperuserExtension =
|
||||
@@ -186,15 +188,15 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
: redemptionGracePeriodLength.plus(pendingDeleteLength);
|
||||
HistoryEntryId domainHistoryId = createHistoryEntryId(existingDomain);
|
||||
historyBuilder.setRevisionId(domainHistoryId.getRevisionId());
|
||||
DateTime deletionTime = now.plus(durationUntilDelete);
|
||||
Instant deletionTime = now.plusMillis(durationUntilDelete.getMillis());
|
||||
if (durationUntilDelete.equals(Duration.ZERO)) {
|
||||
builder.setDeletionTime(toInstant(now)).setStatusValues(null);
|
||||
builder.setDeletionTime(now).setStatusValues(null);
|
||||
} else {
|
||||
DateTime redemptionTime = now.plus(redemptionGracePeriodLength);
|
||||
Instant redemptionTime = now.plusMillis(redemptionGracePeriodLength.getMillis());
|
||||
asyncTaskEnqueuer.enqueueAsyncResave(
|
||||
existingDomain.createVKey(), now, ImmutableSortedSet.of(redemptionTime, deletionTime));
|
||||
builder
|
||||
.setDeletionTime(toInstant(deletionTime))
|
||||
.setDeletionTime(deletionTime)
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
|
||||
// Clear out all old grace periods and add REDEMPTION, which does not include a key to a
|
||||
// billing event because there isn't one for a domain delete.
|
||||
@@ -203,7 +205,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
GracePeriod.createWithoutBillingEvent(
|
||||
GracePeriodStatus.REDEMPTION,
|
||||
existingDomain.getRepoId(),
|
||||
toInstant(redemptionTime),
|
||||
redemptionTime,
|
||||
registrarId)));
|
||||
// Note: The expiration time is unchanged, so if it's before the new deletion time, there will
|
||||
// be a "phantom autorenew" where the expiration time advances. No poll message will be
|
||||
@@ -238,22 +240,22 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
}
|
||||
|
||||
// Cancel any grace periods that were still active, and set the expiration time accordingly.
|
||||
DateTime newExpirationTime = existingDomain.getRegistrationExpirationDateTime();
|
||||
Instant newExpirationTime = existingDomain.getRegistrationExpirationTime();
|
||||
for (GracePeriod gracePeriod : existingDomain.getGracePeriods()) {
|
||||
// No cancellation is written if the grace period was not for a billable event.
|
||||
if (gracePeriod.hasBillingEvent()) {
|
||||
entitiesToInsert.add(
|
||||
BillingCancellation.forGracePeriod(
|
||||
gracePeriod, toInstant(now), domainHistoryId, targetId));
|
||||
BillingCancellation.forGracePeriod(gracePeriod, now, domainHistoryId, targetId));
|
||||
if (gracePeriod.getBillingEvent() != null) {
|
||||
// Take the amount of registration time being refunded off the expiration time.
|
||||
// This can be either add grace periods or renew grace periods.
|
||||
BillingEvent billingEvent = tm().loadByKey(gracePeriod.getBillingEvent());
|
||||
newExpirationTime = newExpirationTime.minusYears(billingEvent.getPeriodYears());
|
||||
newExpirationTime =
|
||||
newExpirationTime.atZone(UTC).minusYears(billingEvent.getPeriodYears()).toInstant();
|
||||
} else if (gracePeriod.getBillingRecurrence() != null) {
|
||||
// Take 1 year off the registration if in the autorenew grace period (no need to load the
|
||||
// recurrence billing event; all autorenews are for 1 year).
|
||||
newExpirationTime = newExpirationTime.minusYears(1);
|
||||
newExpirationTime = newExpirationTime.atZone(UTC).minusYears(1).toInstant();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,7 +294,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
flowCustomLogic.beforeResponse(
|
||||
BeforeResponseParameters.newBuilder()
|
||||
.setResultCode(
|
||||
newDomain.getDeletionTime().isAfter(toInstant(now))
|
||||
newDomain.getDeletionTime().isAfter(now)
|
||||
? SUCCESS_WITH_ACTION_PENDING
|
||||
: SUCCESS)
|
||||
.setResponseExtensions(
|
||||
@@ -305,7 +307,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
.build();
|
||||
}
|
||||
|
||||
private void verifyDeleteAllowed(Domain existingDomain, Tld tld, DateTime now)
|
||||
private void verifyDeleteAllowed(Domain existingDomain, Tld tld, Instant now)
|
||||
throws EppException {
|
||||
verifyOptionalAuthInfo(authInfo, existingDomain);
|
||||
verifyNoDisallowedStatuses(existingDomain, ImmutableSet.of(StatusValue.PENDING_DELETE));
|
||||
@@ -321,11 +323,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
}
|
||||
|
||||
private DomainHistory buildDomainHistory(
|
||||
Domain domain,
|
||||
Tld tld,
|
||||
DateTime now,
|
||||
Duration durationUntilDelete,
|
||||
boolean inAddGracePeriod) {
|
||||
Domain domain, Tld tld, Instant now, Duration durationUntilDelete, boolean inAddGracePeriod) {
|
||||
// We ignore prober transactions
|
||||
if (tld.getTldType() == TldType.REAL) {
|
||||
Duration maxGracePeriod =
|
||||
@@ -345,7 +343,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
cancelledRecords,
|
||||
DomainTransactionRecord.create(
|
||||
domain.getTld(),
|
||||
toInstant(now.plus(durationUntilDelete)),
|
||||
now.plusMillis(durationUntilDelete.getMillis()),
|
||||
inAddGracePeriod
|
||||
? TransactionReportField.DELETED_DOMAINS_GRACE
|
||||
: TransactionReportField.DELETED_DOMAINS_NOGRACE,
|
||||
@@ -355,7 +353,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
}
|
||||
|
||||
private PollMessage.OneTime createDeletePollMessage(
|
||||
Domain existingDomain, HistoryEntryId domainHistoryId, DateTime deletionTime) {
|
||||
Domain existingDomain, HistoryEntryId domainHistoryId, Instant deletionTime) {
|
||||
Optional<MetadataExtension> metadataExtension =
|
||||
eppInput.getSingleExtension(MetadataExtension.class);
|
||||
boolean hasMetadataMessage =
|
||||
@@ -379,10 +377,10 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
}
|
||||
|
||||
private PollMessage.OneTime createImmediateDeletePollMessage(
|
||||
Domain existingDomain, HistoryEntryId domainHistoryId, DateTime now, DateTime deletionTime) {
|
||||
Domain existingDomain, HistoryEntryId domainHistoryId, Instant now, Instant deletionTime) {
|
||||
return new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId(existingDomain.getPersistedCurrentSponsorRegistrarId())
|
||||
.setEventTime(toInstant(now))
|
||||
.setEventTime(now)
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.setMsg(
|
||||
String.format(
|
||||
@@ -397,7 +395,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
|
||||
@Nullable
|
||||
private ImmutableList<FeeTransformResponseExtension> getResponseExtensions(
|
||||
BillingRecurrence billingRecurrence, Domain existingDomain, DateTime now) {
|
||||
BillingRecurrence billingRecurrence, Domain existingDomain, Instant now) {
|
||||
FeeTransformResponseExtension.Builder feeResponseBuilder = getDeleteResponseBuilder();
|
||||
if (feeResponseBuilder == null) {
|
||||
return ImmutableList.of();
|
||||
@@ -419,14 +417,11 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
}
|
||||
|
||||
private Money getGracePeriodCost(
|
||||
BillingRecurrence billingRecurrence, GracePeriod gracePeriod, DateTime now) {
|
||||
BillingRecurrence billingRecurrence, GracePeriod gracePeriod, Instant now) {
|
||||
if (gracePeriod.getType() == GracePeriodStatus.AUTO_RENEW) {
|
||||
// If we updated the autorenew billing event, reuse it.
|
||||
DateTime autoRenewTime =
|
||||
toDateTime(
|
||||
billingRecurrence
|
||||
.getRecurrenceTimeOfYear()
|
||||
.getLastInstanceBeforeOrAt(toInstant(now)));
|
||||
toDateTime(billingRecurrence.getRecurrenceTimeOfYear().getLastInstanceBeforeOrAt(now));
|
||||
return getDomainRenewCost(targetId, toInstant(autoRenewTime), 1);
|
||||
}
|
||||
return tm().loadByKey(checkNotNull(gracePeriod.getBillingEvent())).getCost();
|
||||
|
||||
@@ -42,9 +42,9 @@ import static google.registry.pricing.PricingEngineProxy.isDomainPremium;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.isAtOrAfter;
|
||||
import static google.registry.util.DateTimeUtils.plusYears;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static google.registry.util.DateTimeUtils.minusDays;
|
||||
import static google.registry.util.DomainNameUtils.ACE_PREFIX;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
@@ -133,7 +133,6 @@ import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.xbill.DNS.DNSSEC.Algorithm;
|
||||
|
||||
@@ -253,7 +252,7 @@ public class DomainFlowUtils {
|
||||
public static void verifyNotBlockedByBsa(
|
||||
InternetDomainName domainName,
|
||||
Tld tld,
|
||||
DateTime now,
|
||||
Instant now,
|
||||
Optional<AllocationToken> allocationToken)
|
||||
throws DomainLabelBlockedByBsaException {
|
||||
if (!isRegisterBsaCreate(domainName, allocationToken)
|
||||
@@ -262,7 +261,7 @@ public class DomainFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isBlockedByBsa(String domainLabel, Tld tld, DateTime now) {
|
||||
public static boolean isBlockedByBsa(String domainLabel, Tld tld, Instant now) {
|
||||
return isEnrolledWithBsa(tld, now) && isLabelBlocked(domainLabel);
|
||||
}
|
||||
|
||||
@@ -458,7 +457,7 @@ public class DomainFlowUtils {
|
||||
|
||||
/** Verifies that a launch extension's specified phase matches the specified tld's phase. */
|
||||
static void verifyLaunchPhaseMatchesRegistryPhase(
|
||||
Tld tld, LaunchExtension launchExtension, DateTime now) throws EppException {
|
||||
Tld tld, LaunchExtension launchExtension, Instant now) throws EppException {
|
||||
if (!LAUNCH_PHASE_TO_TLD_STATES.containsKey(launchExtension.getPhase())
|
||||
|| !LAUNCH_PHASE_TO_TLD_STATES
|
||||
.get(launchExtension.getPhase())
|
||||
@@ -474,8 +473,8 @@ public class DomainFlowUtils {
|
||||
* this registrar.
|
||||
*/
|
||||
static void verifyPremiumNameIsNotBlocked(
|
||||
String domainName, DateTime priceTime, String registrarId) throws EppException {
|
||||
if (isDomainPremium(domainName, toInstant(priceTime))) {
|
||||
String domainName, Instant priceTime, String registrarId) throws EppException {
|
||||
if (isDomainPremium(domainName, priceTime)) {
|
||||
if (Registrar.loadByRegistrarIdCached(registrarId).get().getBlockPremiumNames()) {
|
||||
throw new PremiumNameBlockedException();
|
||||
}
|
||||
@@ -486,7 +485,7 @@ public class DomainFlowUtils {
|
||||
* Helper to call {@link CreateOrUpdate#cloneAndLinkReferences} and convert exceptions to
|
||||
* EppExceptions, since this is needed in several places.
|
||||
*/
|
||||
static <T extends CreateOrUpdate<T>> T cloneAndLinkReferences(T command, DateTime now)
|
||||
static <T extends CreateOrUpdate<T>> T cloneAndLinkReferences(T command, Instant now)
|
||||
throws EppException {
|
||||
try {
|
||||
return command.cloneAndLinkReferences(now);
|
||||
@@ -532,7 +531,7 @@ public class DomainFlowUtils {
|
||||
public static BillingRecurrence updateAutorenewRecurrenceEndTime(
|
||||
Domain domain,
|
||||
BillingRecurrence existingBillingRecurrence,
|
||||
DateTime newEndTime,
|
||||
Instant newEndTime,
|
||||
@Nullable HistoryEntryId historyId) {
|
||||
Optional<Autorenew> autorenewPollMessage =
|
||||
tm().loadByKeyIfPresent(domain.getAutorenewPollMessage());
|
||||
@@ -560,14 +559,14 @@ public class DomainFlowUtils {
|
||||
|
||||
// If the resultant autorenew poll message would have no poll messages to deliver, then just
|
||||
// delete it. Otherwise, save it with the new end time.
|
||||
if (isAtOrAfter(updatedAutorenewPollMessage.getEventTime(), toInstant(newEndTime))) {
|
||||
if (isAtOrAfter(updatedAutorenewPollMessage.getEventTime(), newEndTime)) {
|
||||
autorenewPollMessage.ifPresent(autorenew -> tm().delete(autorenew));
|
||||
} else {
|
||||
tm().put(updatedAutorenewPollMessage);
|
||||
}
|
||||
|
||||
BillingRecurrence newBillingRecurrence =
|
||||
existingBillingRecurrence.asBuilder().setRecurrenceEndTime(toInstant(newEndTime)).build();
|
||||
existingBillingRecurrence.asBuilder().setRecurrenceEndTime(newEndTime).build();
|
||||
tm().update(newBillingRecurrence);
|
||||
return newBillingRecurrence;
|
||||
}
|
||||
@@ -582,13 +581,13 @@ public class DomainFlowUtils {
|
||||
InternetDomainName domainName,
|
||||
Optional<Domain> domain,
|
||||
@Nullable CurrencyUnit topLevelCurrency,
|
||||
DateTime currentDate,
|
||||
Instant currentDate,
|
||||
DomainPricingLogic pricingLogic,
|
||||
Optional<AllocationToken> allocationToken,
|
||||
boolean isAvailable,
|
||||
@Nullable BillingRecurrence billingRecurrence)
|
||||
throws EppException {
|
||||
Instant now = toInstant(currentDate);
|
||||
Instant now = currentDate;
|
||||
// Use the custom effective date specified in the fee check request, if there is one.
|
||||
if (feeRequest.getEffectiveDate().isPresent()) {
|
||||
now = feeRequest.getEffectiveDate().get();
|
||||
@@ -847,9 +846,9 @@ public class DomainFlowUtils {
|
||||
*
|
||||
* @throws ExceedsMaxRegistrationYearsException if the new registration period is too long
|
||||
*/
|
||||
public static void validateRegistrationPeriod(DateTime now, DateTime newExpirationTime)
|
||||
public static void validateRegistrationPeriod(Instant now, Instant newExpirationTime)
|
||||
throws EppException {
|
||||
if (plusYears(now, MAX_REGISTRATION_YEARS).isBefore(newExpirationTime)) {
|
||||
if (now.atZone(UTC).plusYears(MAX_REGISTRATION_YEARS).toInstant().isBefore(newExpirationTime)) {
|
||||
throw new ExceedsMaxRegistrationYearsException();
|
||||
}
|
||||
}
|
||||
@@ -935,7 +934,7 @@ public class DomainFlowUtils {
|
||||
}
|
||||
|
||||
/** Check that the registry phase is not predelegation, during which some flows are forbidden. */
|
||||
public static void verifyNotInPredelegation(Tld registry, DateTime now)
|
||||
public static void verifyNotInPredelegation(Tld registry, Instant now)
|
||||
throws BadCommandForRegistryPhaseException {
|
||||
if (registry.getTldState(now) == PREDELEGATION) {
|
||||
throw new BadCommandForRegistryPhaseException();
|
||||
@@ -970,7 +969,7 @@ public class DomainFlowUtils {
|
||||
|
||||
/** Validate the notice from a launch create extension, allowing null as a valid notice. */
|
||||
static void validateLaunchCreateNotice(
|
||||
@Nullable LaunchNotice notice, String domainLabel, boolean isSuperuser, DateTime now)
|
||||
@Nullable LaunchNotice notice, String domainLabel, boolean isSuperuser, Instant now)
|
||||
throws EppException {
|
||||
if (notice == null) {
|
||||
return;
|
||||
@@ -984,7 +983,7 @@ public class DomainFlowUtils {
|
||||
throw new ExpiredClaimException();
|
||||
}
|
||||
// An acceptance within the past 48 hours is mandated by the TMCH Functional Spec.
|
||||
if (notice.getAcceptedTime().isBefore(now.minusHours(48))) {
|
||||
if (notice.getAcceptedTime().isBefore(minusDays(now, 2))) {
|
||||
throw new AcceptedTooLongAgoException();
|
||||
}
|
||||
}
|
||||
@@ -998,8 +997,8 @@ public class DomainFlowUtils {
|
||||
}
|
||||
|
||||
/** Check that the claims period hasn't ended. */
|
||||
static void verifyClaimsPeriodNotEnded(Tld tld, DateTime now) throws ClaimsPeriodEndedException {
|
||||
if (isAtOrAfter(now, tld.getClaimsPeriodEnd())) {
|
||||
static void verifyClaimsPeriodNotEnded(Tld tld, Instant now) throws ClaimsPeriodEndedException {
|
||||
if (!now.isBefore(tld.getClaimsPeriodEnd())) {
|
||||
throw new ClaimsPeriodEndedException(tld.getTldStr());
|
||||
}
|
||||
}
|
||||
@@ -1066,7 +1065,7 @@ public class DomainFlowUtils {
|
||||
*/
|
||||
public static ImmutableSet<DomainTransactionRecord> createCancelingRecords(
|
||||
Domain domain,
|
||||
final DateTime now,
|
||||
Instant now,
|
||||
Duration maxSearchPeriod,
|
||||
final ImmutableSet<TransactionReportField> cancelableFields) {
|
||||
|
||||
@@ -1081,7 +1080,7 @@ public class DomainFlowUtils {
|
||||
for (DomainTransactionRecord record :
|
||||
historyEntry.getDomainTransactionRecords()) {
|
||||
if (cancelableFields.contains(record.getReportField())
|
||||
&& record.getReportingTime().isAfter(toInstant(now))) {
|
||||
&& record.getReportingTime().isAfter(now)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1110,12 +1109,12 @@ public class DomainFlowUtils {
|
||||
}
|
||||
|
||||
private static List<DomainHistory> findRecentHistoryEntries(
|
||||
Domain domain, DateTime now, Duration maxSearchPeriod) {
|
||||
Domain domain, Instant now, Duration maxSearchPeriod) {
|
||||
return tm().query(
|
||||
"FROM DomainHistory WHERE modificationTime >= :beginning AND repoId = "
|
||||
+ ":repoId ORDER BY modificationTime ASC",
|
||||
DomainHistory.class)
|
||||
.setParameter("beginning", toInstant(now.minus(maxSearchPeriod)))
|
||||
.setParameter("beginning", now.minusMillis(maxSearchPeriod.getMillis()))
|
||||
.setParameter("repoId", domain.getRepoId())
|
||||
.getResultList();
|
||||
}
|
||||
|
||||
@@ -56,8 +56,8 @@ import google.registry.persistence.IsolationLevel;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that returns information about a domain.
|
||||
@@ -105,7 +105,7 @@ public final class DomainInfoFlow implements MutatingFlow {
|
||||
flowCustomLogic.beforeValidation();
|
||||
validateRegistrarIsLoggedIn(registrarId);
|
||||
extensionManager.validate();
|
||||
DateTime now = clock.nowUtc();
|
||||
Instant now = clock.now();
|
||||
Domain domain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
verifyOptionalAuthInfo(authInfo, domain);
|
||||
flowCustomLogic.afterValidation(
|
||||
@@ -124,7 +124,7 @@ public final class DomainInfoFlow implements MutatingFlow {
|
||||
.setCreationTime(domain.getCreationTime())
|
||||
.setLastEppUpdateTime(domain.getLastEppUpdateTime())
|
||||
.setRegistrationExpirationTime(domain.getRegistrationExpirationTime())
|
||||
.setLastTransferTime(domain.getLastTransferTimeInstant());
|
||||
.setLastTransferTime(domain.getLastTransferTime());
|
||||
|
||||
// If authInfo is non-null, then the caller is authorized to see the full information since we
|
||||
// will have already verified the authInfo is valid.
|
||||
@@ -149,7 +149,7 @@ public final class DomainInfoFlow implements MutatingFlow {
|
||||
.build();
|
||||
}
|
||||
|
||||
private ImmutableList<ResponseExtension> getDomainResponseExtensions(Domain domain, DateTime now)
|
||||
private ImmutableList<ResponseExtension> getDomainResponseExtensions(Domain domain, Instant now)
|
||||
throws EppException {
|
||||
ImmutableList.Builder<ResponseExtension> extensions = new ImmutableList.Builder<>();
|
||||
addSecDnsExtensionIfPresent(extensions, domain.getDsData());
|
||||
|
||||
@@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.flows.domain.DomainFlowUtils.zeroInCurrency;
|
||||
import static google.registry.flows.domain.token.AllocationTokenFlowUtils.discountTokenInvalidForPremiumName;
|
||||
import static google.registry.pricing.PricingEngineProxy.getPricesForDomainName;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||
|
||||
import com.google.common.net.InternetDomainName;
|
||||
@@ -117,7 +116,7 @@ public final class DomainPricingLogic {
|
||||
.setFeesAndCredits(feesBuilder.build())
|
||||
.setTld(tld)
|
||||
.setDomainName(InternetDomainName.from(domainName))
|
||||
.setAsOfDate(toDateTime(dateTime))
|
||||
.setAsOfDate(dateTime)
|
||||
.setYears(years)
|
||||
.build());
|
||||
}
|
||||
@@ -188,7 +187,7 @@ public final class DomainPricingLogic {
|
||||
.build())
|
||||
.setTld(tld)
|
||||
.setDomainName(InternetDomainName.from(domainName))
|
||||
.setAsOfDate(toDateTime(dateTime))
|
||||
.setAsOfDate(dateTime)
|
||||
.setYears(years)
|
||||
.build());
|
||||
}
|
||||
@@ -212,7 +211,7 @@ public final class DomainPricingLogic {
|
||||
.setFeesAndCredits(feesAndCredits.build())
|
||||
.setTld(tld)
|
||||
.setDomainName(InternetDomainName.from(domainName))
|
||||
.setAsOfDate(toDateTime(dateTime))
|
||||
.setAsOfDate(dateTime)
|
||||
.build());
|
||||
}
|
||||
|
||||
@@ -235,7 +234,7 @@ public final class DomainPricingLogic {
|
||||
.build())
|
||||
.setTld(tld)
|
||||
.setDomainName(InternetDomainName.from(domainName))
|
||||
.setAsOfDate(toDateTime(dateTime))
|
||||
.setAsOfDate(dateTime)
|
||||
.build());
|
||||
}
|
||||
|
||||
@@ -253,7 +252,7 @@ public final class DomainPricingLogic {
|
||||
.build())
|
||||
.setTld(tld)
|
||||
.setDomainName(InternetDomainName.from(domainName))
|
||||
.setAsOfDate(toDateTime(dateTime))
|
||||
.setAsOfDate(dateTime)
|
||||
.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ import static google.registry.flows.domain.token.AllocationTokenFlowUtils.maybeA
|
||||
import static google.registry.flows.domain.token.AllocationTokenFlowUtils.verifyBulkTokenAllowedOnDomain;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_RENEW;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.plusYears;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -87,9 +87,9 @@ import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.model.tld.Tld;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
@@ -164,7 +164,7 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
validateRegistrarIsLoggedIn(registrarId);
|
||||
verifyRegistrarIsActive(registrarId);
|
||||
extensionManager.validate();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Instant now = tm().getTxTime();
|
||||
Renew command = (Renew) resourceCommand;
|
||||
// Loads the target resource if it exists
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
@@ -191,8 +191,12 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
// If client passed an applicable static token this updates the domain
|
||||
existingDomain = maybeApplyBulkPricingRemovalToken(existingDomain, allocationToken);
|
||||
|
||||
DateTime newExpirationTime =
|
||||
plusYears(existingDomain.getRegistrationExpirationDateTime(), years); // Uncapped
|
||||
Instant newExpirationTime =
|
||||
existingDomain
|
||||
.getRegistrationExpirationTime()
|
||||
.atZone(UTC)
|
||||
.plusYears(years)
|
||||
.toInstant(); // Uncapped
|
||||
validateRegistrationPeriod(now, newExpirationTime);
|
||||
Optional<FeeRenewCommandExtension> feeRenew =
|
||||
eppInput.getSingleExtension(FeeRenewCommandExtension.class);
|
||||
@@ -202,7 +206,7 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
pricingLogic.getRenewPrice(
|
||||
Tld.get(existingDomain.getTld()),
|
||||
targetId,
|
||||
toInstant(now),
|
||||
now,
|
||||
years,
|
||||
existingBillingRecurrence,
|
||||
allocationToken);
|
||||
@@ -222,14 +226,14 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
// Create a new autorenew billing event and poll message starting at the new expiration time.
|
||||
BillingRecurrence newAutorenewEvent =
|
||||
newAutorenewBillingEvent(existingDomain)
|
||||
.setEventTime(toInstant(newExpirationTime))
|
||||
.setEventTime(newExpirationTime)
|
||||
.setRenewalPrice(existingBillingRecurrence.getRenewalPrice().orElse(null))
|
||||
.setRenewalPriceBehavior(existingBillingRecurrence.getRenewalPriceBehavior())
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.build();
|
||||
PollMessage.Autorenew newAutorenewPollMessage =
|
||||
newAutorenewPollMessage(existingDomain)
|
||||
.setEventTime(toInstant(newExpirationTime))
|
||||
.setEventTime(newExpirationTime)
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.build();
|
||||
// End the old autorenew billing event and poll message now. This may delete the poll message.
|
||||
@@ -238,7 +242,7 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
Domain newDomain =
|
||||
existingDomain
|
||||
.asBuilder()
|
||||
.setLastEppUpdateTime(toInstant(now))
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateRegistrarId(registrarId)
|
||||
.setRegistrationExpirationTime(newExpirationTime)
|
||||
.setAutorenewBillingEvent(newAutorenewEvent.createVKey())
|
||||
@@ -288,7 +292,7 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
}
|
||||
|
||||
private DomainHistory buildDomainHistory(
|
||||
Domain newDomain, DateTime now, Period period, Duration renewGracePeriod) {
|
||||
Domain newDomain, Instant now, Period period, Duration renewGracePeriod) {
|
||||
Optional<MetadataExtension> metadataExtensionOpt =
|
||||
eppInput.getSingleExtension(MetadataExtension.class);
|
||||
if (metadataExtensionOpt.isPresent()) {
|
||||
@@ -306,7 +310,7 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
ImmutableSet.of(
|
||||
DomainTransactionRecord.create(
|
||||
newDomain.getTld(),
|
||||
toInstant(now.plus(renewGracePeriod)),
|
||||
now.plusMillis(renewGracePeriod.getMillis()),
|
||||
TransactionReportField.netRenewsFieldFromYears(period.getValue()),
|
||||
1)))
|
||||
.build();
|
||||
@@ -331,7 +335,7 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
// If the date they specify doesn't match the expiration, fail. (This is an idempotence check).
|
||||
if (!command
|
||||
.getCurrentExpirationDate()
|
||||
.equals(existingDomain.getRegistrationExpirationDateTime().toLocalDate())) {
|
||||
.equals(toDateTime(existingDomain.getRegistrationExpirationTime()).toLocalDate())) {
|
||||
throw new IncorrectCurrentExpirationDateException();
|
||||
}
|
||||
}
|
||||
@@ -342,20 +346,20 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
int years,
|
||||
HistoryEntryId domainHistoryId,
|
||||
Optional<AllocationToken> allocationToken,
|
||||
DateTime now) {
|
||||
Instant now) {
|
||||
return new BillingEvent.Builder()
|
||||
.setReason(Reason.RENEW)
|
||||
.setTargetId(targetId)
|
||||
.setRegistrarId(registrarId)
|
||||
.setPeriodYears(years)
|
||||
.setCost(renewCost)
|
||||
.setEventTime(toInstant(now))
|
||||
.setEventTime(now)
|
||||
.setAllocationToken(
|
||||
allocationToken
|
||||
.filter(t -> AllocationToken.TokenBehavior.DEFAULT.equals(t.getTokenBehavior()))
|
||||
.map(AllocationToken::createVKey)
|
||||
.orElse(null))
|
||||
.setBillingTime(toInstant(now.plus(Tld.get(tld).getRenewGracePeriodLength())))
|
||||
.setBillingTime(now.plusMillis(Tld.get(tld).getRenewGracePeriodLength().getMillis()))
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyRegistrarIsActi
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_RESTORE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -70,9 +70,9 @@ import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.model.tld.Tld;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that requests that a domain in the redemption grace period be restored.
|
||||
@@ -137,12 +137,11 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
|
||||
verifyRegistrarIsActive(registrarId);
|
||||
extensionManager.validate();
|
||||
Update command = (Update) resourceCommand;
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Instant now = tm().getTxTime();
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
boolean isExpired = existingDomain.getRegistrationExpirationDateTime().isBefore(now);
|
||||
boolean isExpired = existingDomain.getRegistrationExpirationTime().isBefore(now);
|
||||
FeesAndCredits feesAndCredits =
|
||||
pricingLogic.getRestorePrice(
|
||||
Tld.get(existingDomain.getTld()), targetId, toInstant(now), isExpired);
|
||||
pricingLogic.getRestorePrice(Tld.get(existingDomain.getTld()), targetId, now, isExpired);
|
||||
Optional<FeeUpdateCommandExtension> feeUpdate =
|
||||
eppInput.getSingleExtension(FeeUpdateCommandExtension.class);
|
||||
verifyRestoreAllowed(command, existingDomain, feeUpdate, feesAndCredits, now);
|
||||
@@ -150,8 +149,12 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
|
||||
historyBuilder.setRevisionId(domainHistoryId.getRevisionId());
|
||||
ImmutableSet.Builder<ImmutableObject> entitiesToInsert = new ImmutableSet.Builder<>();
|
||||
|
||||
DateTime newExpirationTime =
|
||||
existingDomain.getRegistrationExpirationDateTime().plusYears(isExpired ? 1 : 0);
|
||||
Instant newExpirationTime =
|
||||
existingDomain
|
||||
.getRegistrationExpirationTime()
|
||||
.atZone(UTC)
|
||||
.plusYears(isExpired ? 1 : 0)
|
||||
.toInstant();
|
||||
// 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) {
|
||||
@@ -164,14 +167,14 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
|
||||
|
||||
BillingRecurrence autorenewEvent =
|
||||
newAutorenewBillingEvent(existingDomain)
|
||||
.setEventTime(toInstant(newExpirationTime))
|
||||
.setEventTime(newExpirationTime)
|
||||
.setRecurrenceEndTime(END_INSTANT)
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.build();
|
||||
entitiesToInsert.add(autorenewEvent);
|
||||
PollMessage.Autorenew autorenewPollMessage =
|
||||
newAutorenewPollMessage(existingDomain)
|
||||
.setEventTime(toInstant(newExpirationTime))
|
||||
.setEventTime(newExpirationTime)
|
||||
.setAutorenewEndTime(END_INSTANT)
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.build();
|
||||
@@ -197,17 +200,14 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
|
||||
.build();
|
||||
}
|
||||
|
||||
private DomainHistory buildDomainHistory(Domain newDomain, DateTime now) {
|
||||
private DomainHistory buildDomainHistory(Domain newDomain, Instant now) {
|
||||
return historyBuilder
|
||||
.setType(DOMAIN_RESTORE)
|
||||
.setDomain(newDomain)
|
||||
.setDomainTransactionRecords(
|
||||
ImmutableSet.of(
|
||||
DomainTransactionRecord.create(
|
||||
newDomain.getTld(),
|
||||
toInstant(now),
|
||||
TransactionReportField.RESTORED_DOMAINS,
|
||||
1)))
|
||||
newDomain.getTld(), now, TransactionReportField.RESTORED_DOMAINS, 1)))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
|
||||
Domain existingDomain,
|
||||
Optional<FeeUpdateCommandExtension> feeUpdate,
|
||||
FeesAndCredits feesAndCredits,
|
||||
DateTime now)
|
||||
Instant now)
|
||||
throws EppException {
|
||||
verifyOptionalAuthInfo(authInfo, existingDomain);
|
||||
if (!isSuperuser) {
|
||||
@@ -239,10 +239,10 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
|
||||
|
||||
private static Domain performRestore(
|
||||
Domain existingDomain,
|
||||
DateTime newExpirationTime,
|
||||
Instant newExpirationTime,
|
||||
BillingRecurrence autorenewEvent,
|
||||
PollMessage.Autorenew autorenewPollMessage,
|
||||
DateTime now,
|
||||
Instant now,
|
||||
String registrarId) {
|
||||
return existingDomain
|
||||
.asBuilder()
|
||||
@@ -256,28 +256,28 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
|
||||
// Clear the autorenew end time so if it had expired but is now explicitly being restored,
|
||||
// it won't immediately be deleted again.
|
||||
.setAutorenewEndTime(Optional.empty())
|
||||
.setLastEppUpdateTime(toInstant(now))
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateRegistrarId(registrarId)
|
||||
.build();
|
||||
}
|
||||
|
||||
private BillingEvent createRenewBillingEvent(
|
||||
HistoryEntryId domainHistoryId, Money renewCost, DateTime now) {
|
||||
HistoryEntryId domainHistoryId, Money renewCost, Instant now) {
|
||||
return prepareBillingEvent(domainHistoryId, renewCost, now).setReason(Reason.RENEW).build();
|
||||
}
|
||||
|
||||
private BillingEvent createRestoreBillingEvent(
|
||||
HistoryEntryId domainHistoryId, Money restoreCost, DateTime now) {
|
||||
HistoryEntryId domainHistoryId, Money restoreCost, Instant now) {
|
||||
return prepareBillingEvent(domainHistoryId, restoreCost, now).setReason(Reason.RESTORE).build();
|
||||
}
|
||||
|
||||
private BillingEvent.Builder prepareBillingEvent(
|
||||
HistoryEntryId domainHistoryId, Money cost, DateTime now) {
|
||||
HistoryEntryId domainHistoryId, Money cost, Instant now) {
|
||||
return new BillingEvent.Builder()
|
||||
.setTargetId(targetId)
|
||||
.setRegistrarId(registrarId)
|
||||
.setEventTime(toInstant(now))
|
||||
.setBillingTime(toInstant(now))
|
||||
.setEventTime(now)
|
||||
.setBillingTime(now)
|
||||
.setPeriodYears(1)
|
||||
.setCost(cost)
|
||||
.setDomainHistoryId(domainHistoryId);
|
||||
|
||||
@@ -33,8 +33,6 @@ 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_INSTANT;
|
||||
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;
|
||||
@@ -70,9 +68,9 @@ import google.registry.model.tld.Tld;
|
||||
import google.registry.model.transfer.DomainTransferData;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that approves a pending transfer on a domain.
|
||||
@@ -127,7 +125,7 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
extensionManager.register(MetadataExtension.class, AllocationTokenExtension.class);
|
||||
validateRegistrarIsLoggedIn(registrarId);
|
||||
extensionManager.validate();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Instant now = tm().getTxTime();
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
AllocationTokenFlowUtils.loadAllocationTokenFromExtension(
|
||||
registrarId, targetId, now, eppInput.getSingleExtension(AllocationTokenExtension.class));
|
||||
@@ -169,9 +167,9 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
// billing event should not be passed in.
|
||||
hasBulkToken ? null : existingBillingRecurrence)
|
||||
.getRenewCost())
|
||||
.setEventTime(toInstant(now))
|
||||
.setEventTime(now)
|
||||
.setBillingTime(
|
||||
toInstant(now.plus(Tld.get(tldStr).getTransferGracePeriodLength())))
|
||||
now.plusMillis(Tld.get(tldStr).getTransferGracePeriodLength().getMillis()))
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.build());
|
||||
|
||||
@@ -188,18 +186,15 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
// still needs to be charged for the auto-renew.
|
||||
if (billingEvent.isPresent()) {
|
||||
entitiesToInsert.add(
|
||||
BillingCancellation.forGracePeriod(
|
||||
autorenewGrace, toInstant(now), domainHistoryId, targetId));
|
||||
BillingCancellation.forGracePeriod(autorenewGrace, now, domainHistoryId, targetId));
|
||||
}
|
||||
}
|
||||
// Close the old autorenew event and poll message at the transfer time (aka now). This may end
|
||||
// up deleting the poll message.
|
||||
updateAutorenewRecurrenceEndTime(
|
||||
existingDomain, existingBillingRecurrence, now, domainHistoryId);
|
||||
DateTime newExpirationTime =
|
||||
toDateTime(
|
||||
computeExDateForApprovalTime(
|
||||
existingDomain, toInstant(now), transferData.getTransferPeriod()));
|
||||
Instant newExpirationTime =
|
||||
computeExDateForApprovalTime(existingDomain, now, transferData.getTransferPeriod());
|
||||
// Create a new autorenew event starting at the expiration time.
|
||||
BillingRecurrence autorenewEvent =
|
||||
new BillingRecurrence.Builder()
|
||||
@@ -207,7 +202,7 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId(targetId)
|
||||
.setRegistrarId(gainingRegistrarId)
|
||||
.setEventTime(toInstant(newExpirationTime))
|
||||
.setEventTime(newExpirationTime)
|
||||
.setRenewalPriceBehavior(
|
||||
hasBulkToken
|
||||
? RenewalPriceBehavior.DEFAULT
|
||||
@@ -221,7 +216,7 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setTargetId(targetId)
|
||||
.setRegistrarId(gainingRegistrarId)
|
||||
.setEventTime(toInstant(newExpirationTime))
|
||||
.setEventTime(newExpirationTime)
|
||||
.setAutorenewEndTime(END_INSTANT)
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
@@ -238,7 +233,7 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
partiallyApprovedDomain
|
||||
.getTransferData()
|
||||
.asBuilder()
|
||||
.setTransferredRegistrationExpirationTime(toInstant(newExpirationTime))
|
||||
.setTransferredRegistrationExpirationTime(newExpirationTime)
|
||||
.build())
|
||||
.setRegistrationExpirationTime(newExpirationTime)
|
||||
.setAutorenewBillingEvent(autorenewEvent.createVKey())
|
||||
@@ -252,7 +247,7 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
GracePeriod.forBillingEvent(
|
||||
GracePeriodStatus.TRANSFER, existingDomain.getRepoId(), event)))
|
||||
.orElseGet(ImmutableSet::of))
|
||||
.setLastEppUpdateTime(toInstant(now))
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateRegistrarId(registrarId)
|
||||
// Even if the existing domain had a bulk token, that bulk token should be removed
|
||||
// on transfer
|
||||
@@ -276,14 +271,12 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
return responseBuilder
|
||||
.setResData(
|
||||
createTransferResponse(
|
||||
targetId,
|
||||
newDomain.getTransferData(),
|
||||
newDomain.getRegistrationExpirationDateTime()))
|
||||
targetId, newDomain.getTransferData(), newDomain.getRegistrationExpirationTime()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private DomainHistory buildDomainHistory(
|
||||
Domain newDomain, Tld tld, DateTime now, String gainingRegistrarId) {
|
||||
Domain newDomain, Tld tld, Instant now, String gainingRegistrarId) {
|
||||
ImmutableSet<DomainTransactionRecord> cancelingRecords =
|
||||
createCancelingRecords(
|
||||
newDomain,
|
||||
@@ -299,7 +292,7 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
cancelingRecords,
|
||||
DomainTransactionRecord.create(
|
||||
newDomain.getTld(),
|
||||
toInstant(now.plus(tld.getTransferGracePeriodLength())),
|
||||
now.plusMillis(tld.getTransferGracePeriodLength().getMillis()),
|
||||
TRANSFER_SUCCESSFUL,
|
||||
1)))
|
||||
.build();
|
||||
|
||||
@@ -29,7 +29,7 @@ import static google.registry.model.ResourceTransferUtils.denyPendingTransfer;
|
||||
import static google.registry.model.reporting.DomainTransactionRecord.TransactionReportField.TRANSFER_SUCCESSFUL;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_CANCEL;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.EppException;
|
||||
@@ -51,8 +51,8 @@ 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;
|
||||
|
||||
/**
|
||||
* An EPP flow that cancels a pending transfer on a domain.
|
||||
@@ -92,7 +92,7 @@ public final class DomainTransferCancelFlow 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);
|
||||
verifyOptionalAuthInfo(authInfo, existingDomain);
|
||||
verifyHasPendingTransfer(existingDomain);
|
||||
@@ -120,7 +120,7 @@ public final class DomainTransferCancelFlow implements MutatingFlow {
|
||||
BillingRecurrence existingBillingRecurrence =
|
||||
tm().loadByKey(existingDomain.getAutorenewBillingEvent());
|
||||
updateAutorenewRecurrenceEndTime(
|
||||
existingDomain, existingBillingRecurrence, END_OF_TIME, domainHistory.getHistoryEntryId());
|
||||
existingDomain, existingBillingRecurrence, END_INSTANT, domainHistory.getHistoryEntryId());
|
||||
// Delete the billing event and poll messages that were written in case the transfer would have
|
||||
// been implicitly server approved.
|
||||
tm().delete(existingDomain.getTransferData().getServerApproveEntities());
|
||||
@@ -129,7 +129,7 @@ public final class DomainTransferCancelFlow implements MutatingFlow {
|
||||
.build();
|
||||
}
|
||||
|
||||
private DomainHistory buildDomainHistory(Domain newDomain, Tld tld, DateTime now) {
|
||||
private DomainHistory buildDomainHistory(Domain newDomain, Tld tld, Instant now) {
|
||||
ImmutableSet<DomainTransactionRecord> cancelingRecords =
|
||||
createCancelingRecords(
|
||||
newDomain,
|
||||
|
||||
@@ -19,8 +19,6 @@ import static google.registry.flows.ResourceFlowUtils.computeExDateForApprovalTi
|
||||
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;
|
||||
@@ -38,8 +36,8 @@ import google.registry.model.transfer.DomainTransferData;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that queries a pending transfer on a domain.
|
||||
@@ -72,7 +70,7 @@ public final class DomainTransferQueryFlow implements TransactionalFlow {
|
||||
public EppResponse run() throws EppException {
|
||||
validateRegistrarIsLoggedIn(registrarId);
|
||||
extensionManager.validate(); // There are no legal extensions for this flow.
|
||||
DateTime now = clock.nowUtc();
|
||||
Instant now = clock.now();
|
||||
Domain domain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
verifyOptionalAuthInfo(authInfo, domain);
|
||||
// Most of the fields on the transfer response are required, so there's no way to return valid
|
||||
@@ -88,14 +86,12 @@ public final class DomainTransferQueryFlow implements TransactionalFlow {
|
||||
&& !registrarId.equals(transferData.getLosingRegistrarId())) {
|
||||
throw new NotAuthorizedToViewTransferException();
|
||||
}
|
||||
DateTime newExpirationTime = null;
|
||||
Instant newExpirationTime = null;
|
||||
if (transferData.getTransferStatus().isApproved()) {
|
||||
newExpirationTime = toDateTime(transferData.getTransferredRegistrationExpirationTime());
|
||||
newExpirationTime = transferData.getTransferredRegistrationExpirationTime();
|
||||
} else if (transferData.getTransferStatus().equals(TransferStatus.PENDING)) {
|
||||
newExpirationTime =
|
||||
toDateTime(
|
||||
computeExDateForApprovalTime(
|
||||
domain, toInstant(now), domain.getTransferData().getTransferPeriod()));
|
||||
computeExDateForApprovalTime(domain, now, domain.getTransferData().getTransferPeriod());
|
||||
}
|
||||
return responseBuilder
|
||||
.setResData(createTransferResponse(targetId, transferData, newExpirationTime))
|
||||
|
||||
@@ -31,9 +31,8 @@ import static google.registry.model.reporting.DomainTransactionRecord.Transactio
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REJECT;
|
||||
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.END_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.EppException;
|
||||
@@ -57,7 +56,6 @@ import google.registry.model.transfer.TransferStatus;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that rejects a pending transfer on a domain.
|
||||
@@ -112,18 +110,18 @@ public final class DomainTransferRejectFlow implements MutatingFlow {
|
||||
Domain newDomain =
|
||||
denyPendingTransfer(
|
||||
existingDomain, TransferStatus.CLIENT_REJECTED, toDateTime(now), registrarId);
|
||||
DomainHistory domainHistory = buildDomainHistory(newDomain, tld, toDateTime(now));
|
||||
DomainHistory domainHistory = buildDomainHistory(newDomain, tld, now);
|
||||
tm().update(newDomain);
|
||||
tm().insertAll(
|
||||
domainHistory,
|
||||
createGainingTransferPollMessage(
|
||||
targetId, newDomain.getTransferData(), null, toDateTime(now), domainHistoryId));
|
||||
targetId, newDomain.getTransferData(), null, 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 =
|
||||
tm().loadByKey(existingDomain.getAutorenewBillingEvent());
|
||||
updateAutorenewRecurrenceEndTime(
|
||||
existingDomain, existingBillingRecurrence, END_OF_TIME, domainHistory.getHistoryEntryId());
|
||||
existingDomain, existingBillingRecurrence, END_INSTANT, domainHistory.getHistoryEntryId());
|
||||
// Delete the billing event and poll messages that were written in case the transfer would have
|
||||
// been implicitly server approved.
|
||||
tm().delete(existingDomain.getTransferData().getServerApproveEntities());
|
||||
@@ -132,7 +130,7 @@ public final class DomainTransferRejectFlow implements MutatingFlow {
|
||||
.build();
|
||||
}
|
||||
|
||||
private DomainHistory buildDomainHistory(Domain newDomain, Tld tld, DateTime now) {
|
||||
private DomainHistory buildDomainHistory(Domain newDomain, Tld tld, Instant now) {
|
||||
ImmutableSet<DomainTransactionRecord> cancelingRecords =
|
||||
createCancelingRecords(
|
||||
newDomain,
|
||||
@@ -144,8 +142,7 @@ public final class DomainTransferRejectFlow implements MutatingFlow {
|
||||
.setDomainTransactionRecords(
|
||||
union(
|
||||
cancelingRecords,
|
||||
DomainTransactionRecord.create(
|
||||
newDomain.getTld(), toInstant(now), TRANSFER_NACKED, 1)))
|
||||
DomainTransactionRecord.create(newDomain.getTld(), now, TRANSFER_NACKED, 1)))
|
||||
.setDomain(newDomain)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -35,8 +35,7 @@ import static google.registry.flows.domain.DomainTransferUtils.createTransferSer
|
||||
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static java.time.temporal.ChronoUnit.DAYS;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -84,7 +83,6 @@ import google.registry.model.transfer.TransferStatus;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that requests a transfer on a domain.
|
||||
@@ -165,7 +163,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
validateRegistrarIsLoggedIn(gainingClientId);
|
||||
verifyRegistrarIsActive(gainingClientId);
|
||||
extensionManager.validate();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Instant now = tm().getTxTime();
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
AllocationTokenFlowUtils.loadAllocationTokenFromExtension(
|
||||
gainingClientId,
|
||||
@@ -198,9 +196,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
feesAndCredits = Optional.empty();
|
||||
} else if (existingDomain.getCurrentBulkToken().isEmpty()) {
|
||||
feesAndCredits =
|
||||
Optional.of(
|
||||
pricingLogic.getTransferPrice(
|
||||
tld, targetId, toInstant(now), existingBillingRecurrence));
|
||||
Optional.of(pricingLogic.getTransferPrice(tld, targetId, now, existingBillingRecurrence));
|
||||
} else {
|
||||
// If existing domain is in a bulk pricing package, calculate the transfer price with default
|
||||
// renewal price
|
||||
@@ -208,7 +204,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
feesAndCredits =
|
||||
period.getValue() == 0
|
||||
? Optional.empty()
|
||||
: Optional.of(pricingLogic.getTransferPrice(tld, targetId, toInstant(now), null));
|
||||
: Optional.of(pricingLogic.getTransferPrice(tld, targetId, now, null));
|
||||
}
|
||||
|
||||
if (feesAndCredits.isPresent()) {
|
||||
@@ -218,13 +214,13 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
historyBuilder
|
||||
.setRevisionId(domainHistoryId.getRevisionId())
|
||||
.setOtherRegistrarId(existingDomain.getCurrentSponsorRegistrarId());
|
||||
DateTime automaticTransferTime =
|
||||
Instant automaticTransferTime =
|
||||
superuserExtension
|
||||
.map(
|
||||
domainTransferRequestSuperuserExtension ->
|
||||
now.plusDays(
|
||||
domainTransferRequestSuperuserExtension.getAutomaticTransferLength()))
|
||||
.orElseGet(() -> now.plus(tld.getAutomaticTransferLength()));
|
||||
now.plus(
|
||||
domainTransferRequestSuperuserExtension.getAutomaticTransferLength(), DAYS))
|
||||
.orElseGet(() -> now.plusMillis(tld.getAutomaticTransferLength().getMillis()));
|
||||
// If the domain will be in the auto-renew grace period at the moment of transfer, the transfer
|
||||
// will subsume the autorenew, so we don't add the normal extra year from the transfer.
|
||||
// The gaining registrar is still billed for the extra year; the losing registrar will get a
|
||||
@@ -234,10 +230,8 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
// policy documentation for transfers subsuming autorenews within the autorenew grace period.
|
||||
Domain domainAtTransferTime = existingDomain.cloneProjectedAtTime(automaticTransferTime);
|
||||
// The new expiration time if there is a server approval.
|
||||
DateTime serverApproveNewExpirationTime =
|
||||
toDateTime(
|
||||
computeExDateForApprovalTime(
|
||||
domainAtTransferTime, toInstant(automaticTransferTime), period));
|
||||
Instant serverApproveNewExpirationTime =
|
||||
computeExDateForApprovalTime(domainAtTransferTime, automaticTransferTime, period);
|
||||
// Create speculative entities in anticipation of an automatic server approval.
|
||||
ImmutableSet<TransferServerApproveEntity> serverApproveEntities =
|
||||
createTransferServerApproveEntities(
|
||||
@@ -257,12 +251,11 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
domainHistoryId.getRevisionId(),
|
||||
new DomainTransferData.Builder()
|
||||
.setTransferRequestTrid(trid)
|
||||
.setTransferRequestTime(toInstant(now))
|
||||
.setTransferRequestTime(now)
|
||||
.setGainingRegistrarId(gainingClientId)
|
||||
.setLosingRegistrarId(existingDomain.getCurrentSponsorRegistrarId())
|
||||
.setPendingTransferExpirationTime(toInstant(automaticTransferTime))
|
||||
.setTransferredRegistrationExpirationTime(
|
||||
toInstant(serverApproveNewExpirationTime)),
|
||||
.setPendingTransferExpirationTime(automaticTransferTime)
|
||||
.setTransferredRegistrationExpirationTime(serverApproveNewExpirationTime),
|
||||
serverApproveEntities,
|
||||
period);
|
||||
// Create a poll message to notify the losing registrar that a transfer was requested.
|
||||
@@ -270,7 +263,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
createLosingTransferPollMessage(
|
||||
targetId, pendingTransferData, serverApproveNewExpirationTime, domainHistoryId)
|
||||
.asBuilder()
|
||||
.setEventTime(toInstant(now))
|
||||
.setEventTime(now)
|
||||
.build();
|
||||
// End the old autorenew event and poll message at the implicit transfer time. This may delete
|
||||
// the poll message if it has no events left. Note that if the automatic transfer succeeds, then
|
||||
@@ -283,7 +276,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
.asBuilder()
|
||||
.setTransferData(pendingTransferData)
|
||||
.addStatusValue(StatusValue.PENDING_TRANSFER)
|
||||
.setLastEppUpdateTime(toInstant(now))
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateRegistrarId(gainingClientId)
|
||||
.build();
|
||||
DomainHistory domainHistory = buildDomainHistory(newDomain, tld, now, period);
|
||||
@@ -295,7 +288,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
tm().insertAll(domainHistory, requestPollMessage);
|
||||
return responseBuilder
|
||||
.setResultFromCode(SUCCESS_WITH_ACTION_PENDING)
|
||||
.setResData(createResponse(period, existingDomain, newDomain, toInstant(now)))
|
||||
.setResData(createResponse(period, existingDomain, newDomain, now))
|
||||
.setExtensions(createResponseExtensions(feesAndCredits, feeTransfer))
|
||||
.build();
|
||||
}
|
||||
@@ -303,7 +296,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
private void verifyTransferAllowed(
|
||||
Domain existingDomain,
|
||||
Period period,
|
||||
DateTime now,
|
||||
Instant now,
|
||||
Optional<DomainTransferRequestSuperuserExtension> superuserExtension)
|
||||
throws EppException {
|
||||
verifyNoDisallowedStatuses(existingDomain, ImmutableSet.of(StatusValue.PENDING_DELETE));
|
||||
@@ -366,7 +359,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
}
|
||||
}
|
||||
|
||||
private DomainHistory buildDomainHistory(Domain newDomain, Tld tld, DateTime now, Period period) {
|
||||
private DomainHistory buildDomainHistory(Domain newDomain, Tld tld, Instant now, Period period) {
|
||||
return historyBuilder
|
||||
.setType(DOMAIN_TRANSFER_REQUEST)
|
||||
.setPeriod(period)
|
||||
@@ -375,9 +368,8 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
ImmutableSet.of(
|
||||
DomainTransactionRecord.create(
|
||||
tld.getTldStr(),
|
||||
toInstant(
|
||||
now.plus(tld.getAutomaticTransferLength())
|
||||
.plus(tld.getTransferGracePeriodLength())),
|
||||
now.plusMillis(tld.getAutomaticTransferLength().getMillis())
|
||||
.plusMillis(tld.getTransferGracePeriodLength().getMillis()),
|
||||
TransactionReportField.TRANSFER_SUCCESSFUL,
|
||||
1)))
|
||||
.build();
|
||||
@@ -391,7 +383,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
Instant approveNowExtendedRegistrationTime =
|
||||
computeExDateForApprovalTime(existingDomain, now, period);
|
||||
return createTransferResponse(
|
||||
targetId, newDomain.getTransferData(), toDateTime(approveNowExtendedRegistrationTime));
|
||||
targetId, newDomain.getTransferData(), approveNowExtendedRegistrationTime);
|
||||
}
|
||||
|
||||
private static ImmutableList<FeeTransformResponseExtension> createResponseExtensions(
|
||||
|
||||
@@ -17,7 +17,6 @@ package google.registry.flows.domain;
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static com.google.common.collect.MoreCollectors.onlyElement;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -41,10 +40,10 @@ import google.registry.model.transfer.DomainTransferData.TransferServerApproveEn
|
||||
import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Utility logic for facilitating domain transfers.
|
||||
@@ -107,25 +106,25 @@ public final class DomainTransferUtils {
|
||||
* </ul>
|
||||
*/
|
||||
public static ImmutableSet<TransferServerApproveEntity> createTransferServerApproveEntities(
|
||||
DateTime automaticTransferTime,
|
||||
DateTime serverApproveNewExpirationTime,
|
||||
Instant automaticTransferTime,
|
||||
Instant serverApproveNewExpirationTime,
|
||||
HistoryEntryId domainHistoryId,
|
||||
Domain existingDomain,
|
||||
BillingRecurrence existingBillingRecurrence,
|
||||
Trid trid,
|
||||
String gainingRegistrarId,
|
||||
Optional<Money> transferCost,
|
||||
DateTime now) {
|
||||
Instant now) {
|
||||
String targetId = existingDomain.getDomainName();
|
||||
// Create a TransferData for the server-approve case to use for the speculative poll messages.
|
||||
DomainTransferData serverApproveTransferData =
|
||||
new DomainTransferData.Builder()
|
||||
.setTransferRequestTrid(trid)
|
||||
.setTransferRequestTime(toInstant(now))
|
||||
.setTransferRequestTime(now)
|
||||
.setGainingRegistrarId(gainingRegistrarId)
|
||||
.setLosingRegistrarId(existingDomain.getCurrentSponsorRegistrarId())
|
||||
.setPendingTransferExpirationTime(toInstant(automaticTransferTime))
|
||||
.setTransferredRegistrationExpirationTime(toInstant(serverApproveNewExpirationTime))
|
||||
.setPendingTransferExpirationTime(automaticTransferTime)
|
||||
.setTransferredRegistrationExpirationTime(serverApproveNewExpirationTime)
|
||||
.setTransferStatus(TransferStatus.SERVER_APPROVED)
|
||||
.build();
|
||||
Tld tld = Tld.get(existingDomain.getTld());
|
||||
@@ -180,8 +179,8 @@ public final class DomainTransferUtils {
|
||||
public static PollMessage createGainingTransferPollMessage(
|
||||
String targetId,
|
||||
DomainTransferData transferData,
|
||||
@Nullable DateTime extendedRegistrationExpirationTime,
|
||||
DateTime now,
|
||||
@Nullable Instant extendedRegistrationExpirationTime,
|
||||
Instant now,
|
||||
HistoryEntryId domainHistoryId) {
|
||||
return new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId(transferData.getGainingRegistrarId())
|
||||
@@ -203,7 +202,7 @@ public final class DomainTransferUtils {
|
||||
public static PollMessage createLosingTransferPollMessage(
|
||||
String targetId,
|
||||
DomainTransferData transferData,
|
||||
@Nullable DateTime extendedRegistrationExpirationTime,
|
||||
@Nullable Instant extendedRegistrationExpirationTime,
|
||||
HistoryEntryId domainHistoryId) {
|
||||
return new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId(transferData.getLosingRegistrarId())
|
||||
@@ -220,7 +219,7 @@ public final class DomainTransferUtils {
|
||||
static DomainTransferResponse createTransferResponse(
|
||||
String targetId,
|
||||
DomainTransferData transferData,
|
||||
@Nullable DateTime extendedRegistrationExpirationTime) {
|
||||
@Nullable Instant extendedRegistrationExpirationTime) {
|
||||
return new DomainTransferResponse.Builder()
|
||||
.setDomainName(targetId)
|
||||
.setGainingRegistrarId(transferData.getGainingRegistrarId())
|
||||
@@ -228,19 +227,19 @@ public final class DomainTransferUtils {
|
||||
.setPendingTransferExpirationTime(transferData.getPendingTransferExpirationTime())
|
||||
.setTransferRequestTime(transferData.getTransferRequestTime())
|
||||
.setTransferStatus(transferData.getTransferStatus())
|
||||
.setExtendedRegistrationExpirationTime(toInstant(extendedRegistrationExpirationTime))
|
||||
.setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static PollMessage.Autorenew createGainingClientAutorenewPollMessage(
|
||||
DateTime serverApproveNewExpirationTime,
|
||||
Instant serverApproveNewExpirationTime,
|
||||
HistoryEntryId domainHistoryId,
|
||||
String targetId,
|
||||
String gainingRegistrarId) {
|
||||
return new PollMessage.Autorenew.Builder()
|
||||
.setTargetId(targetId)
|
||||
.setRegistrarId(gainingRegistrarId)
|
||||
.setEventTime(toInstant(serverApproveNewExpirationTime))
|
||||
.setEventTime(serverApproveNewExpirationTime)
|
||||
.setAutorenewEndTime(END_INSTANT)
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
@@ -249,7 +248,7 @@ public final class DomainTransferUtils {
|
||||
|
||||
private static BillingRecurrence createGainingClientAutorenewEvent(
|
||||
BillingRecurrence existingBillingRecurrence,
|
||||
DateTime serverApproveNewExpirationTime,
|
||||
Instant serverApproveNewExpirationTime,
|
||||
HistoryEntryId domainHistoryId,
|
||||
String targetId,
|
||||
String gainingRegistrarId) {
|
||||
@@ -258,7 +257,7 @@ public final class DomainTransferUtils {
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId(targetId)
|
||||
.setRegistrarId(gainingRegistrarId)
|
||||
.setEventTime(toInstant(serverApproveNewExpirationTime))
|
||||
.setEventTime(serverApproveNewExpirationTime)
|
||||
.setRecurrenceEndTime(END_INSTANT)
|
||||
.setRenewalPriceBehavior(existingBillingRecurrence.getRenewalPriceBehavior())
|
||||
.setRenewalPrice(existingBillingRecurrence.getRenewalPrice().orElse(null))
|
||||
@@ -283,8 +282,8 @@ public final class DomainTransferUtils {
|
||||
* href="https://www.icann.org/news/advisory-2002-06-06-en">this ICANN advisory</a>.
|
||||
*/
|
||||
private static Optional<BillingCancellation> createOptionalAutorenewCancellation(
|
||||
DateTime automaticTransferTime,
|
||||
DateTime now,
|
||||
Instant automaticTransferTime,
|
||||
Instant now,
|
||||
HistoryEntryId domainHistoryId,
|
||||
String targetId,
|
||||
Domain existingDomain,
|
||||
@@ -295,17 +294,16 @@ public final class DomainTransferUtils {
|
||||
domainAtTransferTime.getGracePeriodsOfType(GracePeriodStatus.AUTO_RENEW), null);
|
||||
if (autorenewGracePeriod != null && transferCost.isPresent()) {
|
||||
return Optional.of(
|
||||
BillingCancellation.forGracePeriod(
|
||||
autorenewGracePeriod, toInstant(now), domainHistoryId, targetId)
|
||||
BillingCancellation.forGracePeriod(autorenewGracePeriod, now, domainHistoryId, targetId)
|
||||
.asBuilder()
|
||||
.setEventTime(toInstant(automaticTransferTime))
|
||||
.setEventTime(automaticTransferTime)
|
||||
.build());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static BillingEvent createTransferBillingEvent(
|
||||
DateTime automaticTransferTime,
|
||||
Instant automaticTransferTime,
|
||||
HistoryEntryId domainHistoryId,
|
||||
String targetId,
|
||||
String gainingRegistrarId,
|
||||
@@ -317,9 +315,9 @@ public final class DomainTransferUtils {
|
||||
.setRegistrarId(gainingRegistrarId)
|
||||
.setCost(transferCost)
|
||||
.setPeriodYears(1)
|
||||
.setEventTime(toInstant(automaticTransferTime))
|
||||
.setEventTime(automaticTransferTime)
|
||||
.setBillingTime(
|
||||
toInstant(automaticTransferTime.plus(registry.getTransferGracePeriodLength())))
|
||||
automaticTransferTime.plusMillis(registry.getTransferGracePeriodLength().getMillis()))
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ import static google.registry.flows.domain.DomainFlowUtils.verifyClientUpdateNot
|
||||
import static google.registry.flows.domain.DomainFlowUtils.verifyNotInPendingDelete;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_UPDATE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -85,9 +84,9 @@ import google.registry.model.poll.PollMessage;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.model.tld.Tld;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* An EPP flow that updates a domain.
|
||||
@@ -165,7 +164,7 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
flowCustomLogic.beforeValidation();
|
||||
validateRegistrarIsLoggedIn(registrarId);
|
||||
extensionManager.validate();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Instant now = tm().getTxTime();
|
||||
Update command = cloneAndLinkReferences((Update) resourceCommand, now);
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
verifyUpdateAllowed(command, existingDomain, now);
|
||||
@@ -212,7 +211,7 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
}
|
||||
|
||||
/** Fail if the object doesn't exist or was deleted. */
|
||||
private void verifyUpdateAllowed(Update command, Domain existingDomain, DateTime now)
|
||||
private void verifyUpdateAllowed(Update command, Domain existingDomain, Instant now)
|
||||
throws EppException {
|
||||
verifyOptionalAuthInfo(authInfo, existingDomain);
|
||||
AddRemove add = command.getInnerAdd();
|
||||
@@ -228,13 +227,13 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
Tld tld = Tld.get(tldStr);
|
||||
Optional<FeeUpdateCommandExtension> feeUpdate =
|
||||
eppInput.getSingleExtension(FeeUpdateCommandExtension.class);
|
||||
FeesAndCredits feesAndCredits = pricingLogic.getUpdatePrice(tld, targetId, toInstant(now));
|
||||
FeesAndCredits feesAndCredits = pricingLogic.getUpdatePrice(tld, targetId, now);
|
||||
validateFeesAckedIfPresent(feeUpdate, feesAndCredits, false);
|
||||
verifyNotInPendingDelete(add.getNameservers());
|
||||
validateNameserversAllowedOnTld(tldStr, add.getNameserverHostNames());
|
||||
}
|
||||
|
||||
private Domain performUpdate(Update command, Domain domain, DateTime now) throws EppException {
|
||||
private Domain performUpdate(Update command, Domain domain, Instant now) throws EppException {
|
||||
AddRemove add = command.getInnerAdd();
|
||||
AddRemove remove = command.getInnerRemove();
|
||||
Optional<SecDnsUpdateExtension> secDnsUpdate =
|
||||
@@ -263,7 +262,7 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
.collect(toImmutableSet()),
|
||||
secDnsUpdate.get())
|
||||
: domain.getDsData())
|
||||
.setLastEppUpdateTime(toInstant(now))
|
||||
.setLastEppUpdateTime(now)
|
||||
.setLastEppUpdateRegistrarId(registrarId)
|
||||
.addStatusValues(add.getStatusValues())
|
||||
.removeStatusValues(remove.getStatusValues())
|
||||
@@ -282,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.getRegistrationExpirationDateTime()));
|
||||
Optional.ofNullable(autorenews ? null : domain.getRegistrationExpirationTime()));
|
||||
}
|
||||
}
|
||||
return domainBuilder.build();
|
||||
@@ -305,7 +304,7 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
|
||||
/** Some status updates cost money. Bill only once no matter how many of them are changed. */
|
||||
private Optional<BillingEvent> createBillingEventForStatusUpdates(
|
||||
Domain existingDomain, Domain newDomain, DomainHistory historyEntry, DateTime now) {
|
||||
Domain existingDomain, Domain newDomain, DomainHistory historyEntry, Instant now) {
|
||||
Optional<MetadataExtension> metadataExtension =
|
||||
eppInput.getSingleExtension(MetadataExtension.class);
|
||||
if (metadataExtension.isPresent() && metadataExtension.get().getRequestedByRegistrar()) {
|
||||
@@ -319,8 +318,8 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
.setTargetId(targetId)
|
||||
.setRegistrarId(registrarId)
|
||||
.setCost(Tld.get(existingDomain.getTld()).getServerStatusChangeBillingCost())
|
||||
.setEventTime(toInstant(now))
|
||||
.setBillingTime(toInstant(now))
|
||||
.setEventTime(now)
|
||||
.setBillingTime(now)
|
||||
.setDomainHistory(historyEntry)
|
||||
.build());
|
||||
}
|
||||
@@ -331,7 +330,7 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
|
||||
/** Enqueues a poll message iff a superuser is adding/removing server statuses. */
|
||||
private Optional<PollMessage.OneTime> createPollMessageForServerStatusUpdates(
|
||||
Domain existingDomain, Domain newDomain, DomainHistory historyEntry, DateTime now) {
|
||||
Domain existingDomain, Domain newDomain, DomainHistory historyEntry, Instant now) {
|
||||
if (registrarId.equals(existingDomain.getPersistedCurrentSponsorRegistrarId())) {
|
||||
// Don't send a poll message when a superuser registrar is updating its own domain.
|
||||
return Optional.empty();
|
||||
@@ -369,7 +368,7 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
return Optional.ofNullable(
|
||||
new PollMessage.OneTime.Builder()
|
||||
.setHistoryEntry(historyEntry)
|
||||
.setEventTime(toInstant(now))
|
||||
.setEventTime(now)
|
||||
.setRegistrarId(existingDomain.getCurrentSponsorRegistrarId())
|
||||
.setMsg(msg)
|
||||
.setResponseData(
|
||||
|
||||
@@ -19,7 +19,6 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.pricing.PricingEngineProxy.isDomainPremium;
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Strings;
|
||||
@@ -43,9 +42,9 @@ import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Utility functions for dealing with {@link AllocationToken}s in domain flows. */
|
||||
public class AllocationTokenFlowUtils {
|
||||
@@ -72,7 +71,7 @@ public class AllocationTokenFlowUtils {
|
||||
public static Optional<AllocationToken> loadAllocationTokenFromExtension(
|
||||
String registrarId,
|
||||
String domainName,
|
||||
DateTime now,
|
||||
Instant now,
|
||||
Optional<AllocationTokenExtension> extension)
|
||||
throws NonexistentAllocationTokenException, AllocationTokenInvalidException {
|
||||
if (extension.isEmpty()) {
|
||||
@@ -91,7 +90,7 @@ public class AllocationTokenFlowUtils {
|
||||
*/
|
||||
public static Optional<AllocationToken> loadTokenFromExtensionOrGetDefault(
|
||||
String registrarId,
|
||||
DateTime now,
|
||||
Instant now,
|
||||
Optional<AllocationTokenExtension> extension,
|
||||
Tld tld,
|
||||
String domainName,
|
||||
@@ -166,9 +165,8 @@ public class AllocationTokenFlowUtils {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static boolean tokenIsValidAgainstDomain(
|
||||
InternetDomainName domainName, AllocationToken token, CommandName commandName, DateTime now) {
|
||||
if (discountTokenInvalidForPremiumName(
|
||||
token, isDomainPremium(domainName.toString(), toInstant(now)))) {
|
||||
InternetDomainName domainName, AllocationToken token, CommandName commandName, Instant now) {
|
||||
if (discountTokenInvalidForPremiumName(token, isDomainPremium(domainName.toString(), now))) {
|
||||
return false;
|
||||
}
|
||||
if (!token.getAllowedEppActions().isEmpty()
|
||||
@@ -194,7 +192,7 @@ public class AllocationTokenFlowUtils {
|
||||
String domainName,
|
||||
CommandName commandName,
|
||||
String registrarId,
|
||||
DateTime now,
|
||||
Instant now,
|
||||
Optional<Integer> years,
|
||||
DomainPricingLogic pricingLogic)
|
||||
throws EppException {
|
||||
@@ -234,7 +232,7 @@ public class AllocationTokenFlowUtils {
|
||||
String domainName,
|
||||
AllocationToken token,
|
||||
CommandName commandName,
|
||||
DateTime now,
|
||||
Instant now,
|
||||
Optional<Integer> years,
|
||||
DomainPricingLogic pricingLogic)
|
||||
throws EppException {
|
||||
@@ -244,13 +242,12 @@ public class AllocationTokenFlowUtils {
|
||||
case CREATE ->
|
||||
pricingLogic
|
||||
.getCreatePrice(
|
||||
tld, domainName, toInstant(now), yearsForAction, false, false, Optional.of(token))
|
||||
tld, domainName, now, yearsForAction, false, false, Optional.of(token))
|
||||
.getTotalCost()
|
||||
.getAmount();
|
||||
case RENEW ->
|
||||
pricingLogic
|
||||
.getRenewPrice(
|
||||
tld, domainName, toInstant(now), yearsForAction, null, Optional.of(token))
|
||||
.getRenewPrice(tld, domainName, now, yearsForAction, null, Optional.of(token))
|
||||
.getTotalCost()
|
||||
.getAmount();
|
||||
default -> BigDecimal.ZERO;
|
||||
@@ -259,7 +256,7 @@ public class AllocationTokenFlowUtils {
|
||||
|
||||
/** Loads a given token and validates it against the registrar, time, etc */
|
||||
private static AllocationToken loadAndValidateToken(
|
||||
String token, String registrarId, String domainName, DateTime now)
|
||||
String token, String registrarId, String domainName, Instant now)
|
||||
throws NonexistentAllocationTokenException, AllocationTokenInvalidException {
|
||||
if (Strings.isNullOrEmpty(token)) {
|
||||
// We load the token directly from the input XML. If it's null or empty we should throw
|
||||
@@ -283,7 +280,7 @@ public class AllocationTokenFlowUtils {
|
||||
}
|
||||
|
||||
private static void validateTokenEntity(
|
||||
AllocationToken token, String registrarId, String domainName, DateTime now)
|
||||
AllocationToken token, String registrarId, String domainName, Instant now)
|
||||
throws AllocationTokenInvalidException {
|
||||
if (token.isRedeemed()) {
|
||||
throw new AlreadyRedeemedAllocationTokenException();
|
||||
|
||||
@@ -62,7 +62,7 @@ public final class HostCheckFlow implements TransactionalFlow {
|
||||
ImmutableList<String> hostnames = ((Check) resourceCommand).getTargetIds();
|
||||
verifyTargetIdCount(hostnames, maxChecks);
|
||||
ImmutableSet<String> existingIds =
|
||||
ForeignKeyUtils.loadKeys(Host.class, hostnames, clock.nowUtc()).keySet();
|
||||
ForeignKeyUtils.loadKeys(Host.class, hostnames, clock.now()).keySet();
|
||||
ImmutableList.Builder<HostCheck> checks = new ImmutableList.Builder<>();
|
||||
for (String hostname : hostnames) {
|
||||
HostFlowUtils.validateHostName(hostname);
|
||||
|
||||
@@ -25,7 +25,6 @@ import static google.registry.model.EppResourceUtils.createRepoId;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.HOST_CREATE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
@@ -101,7 +100,7 @@ public final class HostCreateFlow implements MutatingFlow {
|
||||
extensionManager.validate();
|
||||
Create command = (Create) resourceCommand;
|
||||
Instant now = tm().getTxTime();
|
||||
verifyResourceDoesNotExist(Host.class, targetId, toDateTime(now), registrarId);
|
||||
verifyResourceDoesNotExist(Host.class, targetId, now, registrarId);
|
||||
// The superordinate domain of the host object if creating an in-bailiwick host, or null if
|
||||
// creating an external host. This is looked up before we actually create the Host object, so
|
||||
// we can detect error conditions earlier.
|
||||
|
||||
@@ -24,7 +24,6 @@ import static google.registry.flows.ResourceFlowUtils.verifyResourceOwnership;
|
||||
import static google.registry.flows.host.HostFlowUtils.validateHostName;
|
||||
import static google.registry.model.eppoutput.Result.Code.SUCCESS;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.EppException;
|
||||
@@ -85,7 +84,7 @@ public final class HostDeleteFlow implements MutatingFlow {
|
||||
extensionManager.validate();
|
||||
Instant now = tm().getTxTime();
|
||||
validateHostName(targetId);
|
||||
checkLinkedDomains(targetId, toDateTime(now));
|
||||
checkLinkedDomains(targetId, now);
|
||||
Host existingHost = loadAndVerifyExistence(Host.class, targetId, now);
|
||||
verifyNoDisallowedStatuses(existingHost, ImmutableSet.of(StatusValue.PENDING_DELETE));
|
||||
if (!isSuperuser) {
|
||||
@@ -94,7 +93,7 @@ public final class HostDeleteFlow implements MutatingFlow {
|
||||
// the client id, needs to be read off of it.
|
||||
EppResource owningResource =
|
||||
existingHost.isSubordinate()
|
||||
? tm().loadByKey(existingHost.getSuperordinateDomain()).cloneProjectedAtInstant(now)
|
||||
? tm().loadByKey(existingHost.getSuperordinateDomain()).cloneProjectedAtTime(now)
|
||||
: existingHost;
|
||||
verifyResourceOwnership(registrarId, owningResource);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public final class HostInfoFlow implements TransactionalFlow {
|
||||
// there is no superordinate domain, the host's own values for these fields will be correct.
|
||||
if (host.isSubordinate()) {
|
||||
Domain superordinateDomain =
|
||||
tm().loadByKey(host.getSuperordinateDomain()).cloneProjectedAtInstant(now);
|
||||
tm().loadByKey(host.getSuperordinateDomain()).cloneProjectedAtTime(now);
|
||||
hostInfoDataBuilder
|
||||
.setCurrentSponsorRegistrarId(superordinateDomain.getCurrentSponsorRegistrarId())
|
||||
.setLastTransferTime(host.computeLastTransferTime(superordinateDomain));
|
||||
|
||||
@@ -145,7 +145,7 @@ public final class HostUpdateFlow implements MutatingFlow {
|
||||
String newHostName = firstNonNull(suppliedNewHostName, oldHostName);
|
||||
Domain oldSuperordinateDomain =
|
||||
existingHost.isSubordinate()
|
||||
? tm().loadByKey(existingHost.getSuperordinateDomain()).cloneProjectedAtInstant(now)
|
||||
? tm().loadByKey(existingHost.getSuperordinateDomain()).cloneProjectedAtTime(now)
|
||||
: null;
|
||||
// Note that lookupSuperordinateDomain calls cloneProjectedAtTime on the domain for us.
|
||||
Optional<Domain> newSuperordinateDomain =
|
||||
|
||||
@@ -83,7 +83,7 @@ public final class PollAckFlow implements MutatingFlow {
|
||||
throw new InvalidMessageIdException(messageId);
|
||||
}
|
||||
|
||||
final Instant now = tm().getTxTime();
|
||||
Instant now = tm().getTxTime();
|
||||
|
||||
// Load the message to be acked. If a message is queued to be delivered in the future, we treat
|
||||
// it as if it doesn't exist yet. Same for if the message ID year isn't the same as the actual
|
||||
|
||||
@@ -63,7 +63,7 @@ public final class PollFlowUtils {
|
||||
// If the next event falls within the bounds of the end time, then just update the eventTime
|
||||
// and re-save it for future autorenew poll messages to be delivered. Otherwise, this
|
||||
// autorenew poll message has no more events to deliver and should be deleted.
|
||||
if (nextEventTime.isBefore(autorenewPollMessage.getAutorenewEndTimeInstant())) {
|
||||
if (nextEventTime.isBefore(autorenewPollMessage.getAutorenewEndTime())) {
|
||||
tm().put(autorenewPollMessage.asBuilder().setEventTime(nextEventTime).build());
|
||||
} else {
|
||||
tm().delete(autorenewPollMessage.createVKey());
|
||||
|
||||
@@ -16,12 +16,14 @@ package google.registry.model;
|
||||
import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap;
|
||||
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
|
||||
import static com.google.common.collect.Ordering.natural;
|
||||
import static google.registry.util.DateTimeUtils.ISO_8601_FORMATTER;
|
||||
import static google.registry.util.DateTimeUtils.formatInstant;
|
||||
import static google.registry.util.DateTimeUtils.parseInstant;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.KeyDeserializer;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
@@ -64,6 +66,8 @@ public class EntityYamlUtils {
|
||||
module.addSerializer(CreateAutoTimestamp.class, new CreateAutoTimestampSerializer());
|
||||
module.addDeserializer(CreateAutoTimestamp.class, new CreateAutoTimestampDeserializer());
|
||||
module.addSerializer(Duration.class, new DurationSerializer());
|
||||
module.addKeySerializer(Instant.class, new InstantKeySerializer());
|
||||
module.addKeyDeserializer(Instant.class, new InstantKeyDeserializer());
|
||||
module.addSerializer(Instant.class, new InstantSerializer());
|
||||
module.addDeserializer(Instant.class, new InstantDeserializer());
|
||||
ObjectMapper mapper =
|
||||
@@ -416,7 +420,7 @@ public class EntityYamlUtils {
|
||||
if (value.getTimestamp() == null) {
|
||||
gen.writeNull();
|
||||
} else {
|
||||
gen.writeString(ISO_8601_FORMATTER.format(value.getTimestamp()));
|
||||
gen.writeString(formatInstant(value.getTimestamp()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,6 +445,24 @@ public class EntityYamlUtils {
|
||||
}
|
||||
|
||||
/** A custom JSON serializer for {@link Instant}. */
|
||||
|
||||
/** A custom JSON key serializer for {@link Instant}. */
|
||||
public static class InstantKeySerializer extends JsonSerializer<Instant> {
|
||||
@Override
|
||||
public void serialize(Instant value, JsonGenerator gen, SerializerProvider provider)
|
||||
throws IOException {
|
||||
gen.writeFieldName(formatInstant(value));
|
||||
}
|
||||
}
|
||||
|
||||
/** A custom JSON key deserializer for {@link Instant}. */
|
||||
public static class InstantKeyDeserializer extends KeyDeserializer {
|
||||
@Override
|
||||
public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
|
||||
return parseInstant(key);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstantSerializer extends StdSerializer<Instant> {
|
||||
|
||||
public InstantSerializer() {
|
||||
@@ -450,7 +472,7 @@ public class EntityYamlUtils {
|
||||
@Override
|
||||
public void serialize(Instant value, JsonGenerator gen, SerializerProvider provider)
|
||||
throws IOException {
|
||||
gen.writeString(ISO_8601_FORMATTER.format(value));
|
||||
gen.writeString(formatInstant(value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,6 @@ import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** An EPP entity object (i.e. a domain, contact, or host). */
|
||||
@MappedSuperclass
|
||||
@@ -191,11 +190,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||
}
|
||||
|
||||
/** 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);
|
||||
public abstract EppResource cloneProjectedAtTime(Instant now);
|
||||
|
||||
/** Get the foreign key string for this resource. */
|
||||
public abstract String getForeignKey();
|
||||
|
||||
@@ -20,7 +20,6 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.isAtOrAfter;
|
||||
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -69,7 +68,7 @@ public final class EppResourceUtils {
|
||||
/** Helper to call {@link EppResource#cloneProjectedAtTime} without warnings. */
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends EppResource> T cloneProjectedAtTime(T resource, DateTime now) {
|
||||
return (T) resource.cloneProjectedAtTime(now);
|
||||
return (T) resource.cloneProjectedAtTime(toInstant(now));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -121,7 +120,7 @@ public final class EppResourceUtils {
|
||||
builder
|
||||
.removeStatusValue(StatusValue.PENDING_TRANSFER)
|
||||
.setTransferData(transferDataBuilder.build())
|
||||
.setLastTransferTime(toDateTime(transferData.getPendingTransferExpirationTime()))
|
||||
.setLastTransferTime(transferData.getPendingTransferExpirationTime())
|
||||
.setPersistedCurrentSponsorRegistrarId(transferData.getGainingRegistrarId());
|
||||
}
|
||||
|
||||
@@ -155,8 +154,7 @@ public final class EppResourceUtils {
|
||||
* @return the resource at {@code timestamp} or {@code null} if resource is deleted or not yet
|
||||
* created.
|
||||
*/
|
||||
public static <T extends EppResource> T loadAtPointInTime(
|
||||
final T resource, final Instant timestamp) {
|
||||
public static <T extends EppResource> T loadAtPointInTime(final T resource, Instant timestamp) {
|
||||
// If we're before the resource creation time, don't try to find a "most recent revision".
|
||||
if (timestamp.isBefore(resource.getCreationTime())) {
|
||||
return null;
|
||||
@@ -171,7 +169,7 @@ public final class EppResourceUtils {
|
||||
return (loadedResource == null)
|
||||
? null
|
||||
: (isActive(loadedResource, timestamp)
|
||||
? (T) loadedResource.cloneProjectedAtInstant(timestamp)
|
||||
? (T) loadedResource.cloneProjectedAtTime(timestamp)
|
||||
: null);
|
||||
}
|
||||
|
||||
@@ -190,7 +188,7 @@ public final class EppResourceUtils {
|
||||
* falling back to using the resource as-is if there are no revisions.
|
||||
*/
|
||||
private static <T extends EppResource> T loadMostRecentRevisionAtTime(
|
||||
final T resource, final Instant timestamp) {
|
||||
final T resource, Instant timestamp) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T resourceAtPointInTime =
|
||||
(T)
|
||||
|
||||
@@ -185,7 +185,7 @@ public final class ForeignKeyUtils {
|
||||
Class<E> clazz, Collection<String> 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)));
|
||||
.collect(toImmutableMap(Entry::getKey, e -> (E) e.getValue().cloneProjectedAtTime(now)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -543,6 +543,6 @@ public final class ForeignKeyUtils {
|
||||
foreignKeyToResourceCache
|
||||
.get(VKey.create(clazz, foreignKey))
|
||||
.filter(e -> now.isBefore(e.getDeletionTime()))
|
||||
.map(e -> e.cloneProjectedAtInstant(now));
|
||||
.map(e -> e.cloneProjectedAtTime(now));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ package google.registry.model;
|
||||
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static com.google.common.collect.Maps.transformValues;
|
||||
import static google.registry.util.DateTimeUtils.ISO_8601_FORMATTER;
|
||||
import static google.registry.util.DateTimeUtils.formatInstant;
|
||||
import static java.lang.annotation.ElementType.FIELD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
import static java.util.stream.Collectors.toCollection;
|
||||
@@ -143,7 +143,7 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
for (Entry<Field, Object> entry : getSignificantFields().entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof Instant instant) {
|
||||
value = ISO_8601_FORMATTER.format(instant);
|
||||
value = formatInstant(instant);
|
||||
}
|
||||
sortedFields.put(entry.getKey().getName(), value);
|
||||
}
|
||||
@@ -161,7 +161,7 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
? entry.getValue()
|
||||
: hydrate(entry.getValue());
|
||||
if (value instanceof Instant instant) {
|
||||
value = ISO_8601_FORMATTER.format(instant);
|
||||
value = formatInstant(instant);
|
||||
}
|
||||
sortedFields.put(field.getName(), value);
|
||||
}
|
||||
@@ -187,7 +187,7 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
return immutableObject.toHydratedString();
|
||||
}
|
||||
if (value instanceof Instant instant) {
|
||||
return ISO_8601_FORMATTER.format(instant);
|
||||
return formatInstant(instant);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -225,7 +225,7 @@ public abstract class ImmutableObject implements Cloneable {
|
||||
// original ImmutableObject might have been the result of a cloneEmptyToNull call).
|
||||
.collect(toList());
|
||||
} else if (o instanceof Instant instant) {
|
||||
return ISO_8601_FORMATTER.format(instant);
|
||||
return formatInstant(instant);
|
||||
} else if (o instanceof Number || o instanceof Boolean) {
|
||||
return o;
|
||||
} else {
|
||||
|
||||
@@ -21,7 +21,8 @@ import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static google.registry.model.tld.Tld.TldState.GENERAL_AVAILABILITY;
|
||||
import static google.registry.model.tld.Tld.TldState.START_DATE_SUNRISE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -45,6 +46,7 @@ import google.registry.persistence.VKey;
|
||||
import google.registry.tools.IamClient;
|
||||
import google.registry.util.CidrAddressBlock;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -107,13 +109,13 @@ public final class OteAccountBuilder {
|
||||
.setZip("55555")
|
||||
.build();
|
||||
|
||||
private static final ImmutableSortedMap<DateTime, Money> EAP_FEE_SCHEDULE =
|
||||
private static final ImmutableSortedMap<Instant, Money> EAP_FEE_SCHEDULE =
|
||||
ImmutableSortedMap.of(
|
||||
new DateTime(0),
|
||||
Instant.EPOCH,
|
||||
Money.of(CurrencyUnit.USD, 0),
|
||||
DateTime.parse("2018-03-01T00:00:00Z"),
|
||||
Instant.parse("2018-03-01T00:00:00Z"),
|
||||
Money.of(CurrencyUnit.USD, 100),
|
||||
DateTime.parse("2030-03-01T00:00:00Z"),
|
||||
Instant.parse("2030-03-01T00:00:00Z"),
|
||||
Money.of(CurrencyUnit.USD, 0));
|
||||
|
||||
/**
|
||||
@@ -233,7 +235,7 @@ public final class OteAccountBuilder {
|
||||
|
||||
/** Sets the client certificate to all the OT&E Registrars. */
|
||||
public OteAccountBuilder setCertificate(String asciiCert, DateTime now) {
|
||||
return transformRegistrars(builder -> builder.setClientCertificate(asciiCert, now));
|
||||
return transformRegistrars(builder -> builder.setClientCertificate(asciiCert, toInstant(now)));
|
||||
}
|
||||
|
||||
/** Sets the IP allowlist to all the OT&E Registrars. */
|
||||
@@ -329,7 +331,7 @@ public final class OteAccountBuilder {
|
||||
new Tld.Builder()
|
||||
.setTldStr(tldName)
|
||||
.setPremiumPricingEngine(StaticPremiumListPricingEngine.NAME)
|
||||
.setTldStateTransitions(ImmutableSortedMap.of(START_OF_TIME, initialTldState))
|
||||
.setTldStateTransitions(ImmutableSortedMap.of(START_INSTANT, initialTldState))
|
||||
.setDnsWriters(ImmutableSet.of("VoidDnsWriter"))
|
||||
.setPremiumList(premiumList.get())
|
||||
.setTldType(TldType.TEST)
|
||||
|
||||
@@ -16,7 +16,6 @@ package google.registry.model;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
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;
|
||||
@@ -161,7 +160,7 @@ public final class ResourceTransferUtils {
|
||||
checkArgument(transferStatus.isApproved(), "Not an approval transfer status");
|
||||
Domain.Builder builder = resolvePendingTransfer(domain, transferStatus, now);
|
||||
return builder
|
||||
.setLastTransferTime(toDateTime(now))
|
||||
.setLastTransferTime(now)
|
||||
.setPersistedCurrentSponsorRegistrarId(domain.getTransferData().getGainingRegistrarId())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@ package google.registry.model.common;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.UnsafeSerializable;
|
||||
@@ -35,7 +33,6 @@ import jakarta.persistence.Id;
|
||||
import jakarta.persistence.IdClass;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Shared entity for date cursors.
|
||||
@@ -103,7 +100,13 @@ public class Cursor extends UpdateAutoTimestampEntity {
|
||||
ICANN_UPLOAD_TX(true),
|
||||
|
||||
/** Cursor for tracking monthly uploads of ICANN activity reports. */
|
||||
ICANN_UPLOAD_ACTIVITY(true);
|
||||
ICANN_UPLOAD_ACTIVITY(true),
|
||||
|
||||
/** Cursor for tracking the reflection of domain changes in the remote cache. */
|
||||
REMOTE_CACHE_DOMAIN_SYNC(false),
|
||||
|
||||
/** Cursor for tracking the reflection of host changes in the remote cache. */
|
||||
REMOTE_CACHE_HOST_SYNC(false);
|
||||
|
||||
private final boolean scoped;
|
||||
|
||||
@@ -150,15 +153,6 @@ public class Cursor extends UpdateAutoTimestampEntity {
|
||||
return getUpdateTimestamp().getTimestamp();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getLastUpdateTime()}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InlineMeSuggester")
|
||||
public DateTime getLastUpdateDateTime() {
|
||||
return toDateTime(getUpdateTimestamp().getTimestamp());
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return scope;
|
||||
}
|
||||
@@ -183,30 +177,12 @@ public class Cursor extends UpdateAutoTimestampEntity {
|
||||
return create(cursorType, cursorTime, GLOBAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #createGlobal(CursorType, Instant)}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InlineMeSuggester")
|
||||
public static Cursor createGlobal(CursorType cursorType, DateTime cursorTime) {
|
||||
return createGlobal(cursorType, toInstant(cursorTime));
|
||||
}
|
||||
|
||||
/** Creates a new cursor instance with a given {@link Tld} scope. */
|
||||
public static Cursor createScoped(CursorType cursorType, Instant cursorTime, Tld scope) {
|
||||
checkNotNull(scope, "Cursor scope cannot be null");
|
||||
return create(cursorType, cursorTime, scope.getTldStr());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #createScoped(CursorType, Instant, Tld)}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InlineMeSuggester")
|
||||
public static Cursor createScoped(CursorType cursorType, DateTime cursorTime, Tld scope) {
|
||||
return createScoped(cursorType, toInstant(cursorTime), scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new cursor instance with a given TLD scope, or global if the scope is {@link
|
||||
* #GLOBAL}.
|
||||
@@ -224,29 +200,11 @@ public class Cursor extends UpdateAutoTimestampEntity {
|
||||
/**
|
||||
* Returns the current time for a given cursor, or {@code START_INSTANT} if the cursor is null.
|
||||
*/
|
||||
public static Instant getCursorTimeOrStartOfTimeInstant(Optional<Cursor> cursor) {
|
||||
return cursor.map(Cursor::getCursorTimeInstant).orElse(START_INSTANT);
|
||||
public static Instant getCursorTimeOrStartOfTime(Optional<Cursor> cursor) {
|
||||
return cursor.map(Cursor::getCursorTime).orElse(START_INSTANT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getCursorTimeOrStartOfTimeInstant(Optional)}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InlineMeSuggester")
|
||||
public static DateTime getCursorTimeOrStartOfTime(Optional<Cursor> cursor) {
|
||||
return toDateTime(getCursorTimeOrStartOfTimeInstant(cursor));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getCursorTimeInstant()}
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("InlineMeSuggester")
|
||||
public DateTime getCursorTime() {
|
||||
return toDateTime(cursorTime);
|
||||
}
|
||||
|
||||
public Instant getCursorTimeInstant() {
|
||||
public Instant getCursorTime() {
|
||||
return cursorTime;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ package google.registry.model.common;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
|
||||
import google.registry.dns.DnsUtils.TargetType;
|
||||
import google.registry.dns.PublishDnsUpdatesAction;
|
||||
@@ -31,8 +31,8 @@ import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Index;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.Instant;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@Entity
|
||||
@Table(indexes = {@Index(columnList = "requestTime"), @Index(columnList = "lastProcessTime")})
|
||||
@@ -54,10 +54,10 @@ public class DnsRefreshRequest extends ImmutableObject {
|
||||
private String tld;
|
||||
|
||||
@Column(nullable = false)
|
||||
private DateTime requestTime;
|
||||
private Instant requestTime;
|
||||
|
||||
@Column(nullable = false)
|
||||
private DateTime lastProcessTime;
|
||||
private Instant lastProcessTime;
|
||||
|
||||
public TargetType getType() {
|
||||
return type;
|
||||
@@ -71,7 +71,7 @@ public class DnsRefreshRequest extends ImmutableObject {
|
||||
return tld;
|
||||
}
|
||||
|
||||
public DateTime getRequestTime() {
|
||||
public Instant getRequestTime() {
|
||||
return requestTime;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public class DnsRefreshRequest extends ImmutableObject {
|
||||
* there are concurrent reads that all attempt to read the rows with oldest {@link #requestTime},
|
||||
* or another read that comes too early after the previous read.
|
||||
*/
|
||||
public DateTime getLastProcessTime() {
|
||||
public Instant getLastProcessTime() {
|
||||
return lastProcessTime;
|
||||
}
|
||||
|
||||
@@ -102,8 +102,8 @@ public class DnsRefreshRequest extends ImmutableObject {
|
||||
TargetType type,
|
||||
String name,
|
||||
String tld,
|
||||
DateTime requestTime,
|
||||
DateTime lastProcessTime) {
|
||||
Instant requestTime,
|
||||
Instant lastProcessTime) {
|
||||
checkNotNull(type, "Target type cannot be null");
|
||||
checkNotNull(name, "Domain/host name cannot be null");
|
||||
checkNotNull(tld, "TLD cannot be null");
|
||||
@@ -119,11 +119,11 @@ public class DnsRefreshRequest extends ImmutableObject {
|
||||
this.lastProcessTime = lastProcessTime;
|
||||
}
|
||||
|
||||
public DnsRefreshRequest(TargetType type, String name, String tld, DateTime requestTime) {
|
||||
this(null, type, name, tld, requestTime, START_OF_TIME);
|
||||
public DnsRefreshRequest(TargetType type, String name, String tld, Instant requestTime) {
|
||||
this(null, type, name, tld, requestTime, START_INSTANT);
|
||||
}
|
||||
|
||||
public DnsRefreshRequest updateProcessTime(DateTime processTime) {
|
||||
public DnsRefreshRequest updateProcessTime(Instant processTime) {
|
||||
checkArgument(
|
||||
processTime.isAfter(getRequestTime()),
|
||||
"Process time %s must be later than request time %s",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user