mirror of
https://github.com/google/nomulus
synced 2026-06-09 16:33:02 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b78d12e73f | |||
| 4a1d0609f3 | |||
| 61b121f464 | |||
| 074f78cfb3 | |||
| 7be5fe4c01 | |||
| 1876e2c3e8 | |||
| 49f14b5e1b | |||
| d2881b47dc | |||
| 9f3dfec118 | |||
| 60e84e72d7 | |||
| aedfdd47f1 |
@@ -31,7 +31,7 @@ jobs:
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
java-version: '25'
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Engineering Standards for Gemini CLI
|
||||
|
||||
This document outlines foundational mandates, architectural patterns, and project-specific conventions to ensure high-quality, idiomatic, and consistent code from the first iteration.
|
||||
|
||||
## Core Mandates
|
||||
|
||||
### 1. Rigorous Import Management
|
||||
- **Addition:** When adding new symbols, ensure the corresponding import is added.
|
||||
- **Removal:** When removing the last usage of a class or symbol from a file (e.g., removing a `@Inject Clock clock;` field), **immediately remove the associated import**. Do not wait for a build failure to identify unused imports.
|
||||
- **Checkstyle:** Proactively fix common checkstyle errors (line length > 100, formatting, unused imports) during the initial code write. Do not wait for CI/build failures to address these, as iterative fixes are inefficient.
|
||||
- **Verification:** Before finalizing any change, scan the imports section for redundancy.
|
||||
|
||||
### 2. Time and Precision Handling (java.time Migration)
|
||||
- **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:**
|
||||
- Avoid direct calls to `Instant.now()`, `DateTime.now()`, `ZonedDateTime.now()`, or `System.currentTimeMillis()`.
|
||||
- Inject `google.registry.util.Clock` (production) or `google.registry.testing.FakeClock` (tests).
|
||||
- Use `clock.nowDate()` to get a `ZonedDateTime` in UTC.
|
||||
- **Beam Pipelines:**
|
||||
- Ensure `Clock` is serializable (it is by default in this project) when used in Beam `DoFn`s.
|
||||
- Pass the `Clock` through the constructor or via Dagger provider methods in the pipeline module.
|
||||
- **Command-Line Tools:**
|
||||
- Use `@Inject Clock clock;` in `Command` implementations.
|
||||
- The `clock` field should be **package-private** (no access modifier) to allow manual initialization in corresponding test classes.
|
||||
- In test classes (e.g., `UpdateDomainCommandTest`), manually set `command.clock = fakeClock;` in the `@BeforeEach` method.
|
||||
- Base test classes like `EppToolCommandTestCase` should handle this assignment for their generic command types where applicable.
|
||||
|
||||
### 3. Dependency Injection (Dagger)
|
||||
- **Concrete Types:** Dagger `inject` methods must use explicit concrete types. Generic `inject(Command)` methods will not work.
|
||||
- **Test Components:** Use `TestRegistryToolComponent` for command-line tool tests to bridge the gap between `main` and `nonprod/test` source sets.
|
||||
|
||||
### 4. Database Consistency
|
||||
- **JPA Converters:** Be aware that JPA converters (like `DateTimeConverter`) may perform truncation or transformation. Ensure application-level logic matches these transformations to avoid "dirty" state or unexpected diffs.
|
||||
- **Transaction Management:**
|
||||
- **Top-Level:** Define database transactions (`tm().transact(...)`) at the highest possible level in the call chain (e.g., in an Action, a Command, or a Flow). This ensures all operations are atomic and handled by the retry logic.
|
||||
- **DAO Methods:** Avoid declaring transactions inside low-level DAO methods. Use `tm().assertInTransaction()` to ensure that these methods are only called within a valid transactional context.
|
||||
- **Utility/Cache Methods:** Use `tm().reTransact(...)` for utility methods or Caffeine cache loaders that might be invoked from both transactional and non-transactional paths.
|
||||
- `reTransact` will join an existing transaction if one is present (acting as a no-op) or start a new one if not.
|
||||
- This is particularly useful for in-memory caches where the loader must be able to fetch data regardless of whether the caller is currently in a transaction.
|
||||
- **Transactional Time:** Ensure code that relies on `tm().getTransactionTime()` is executed within a transaction context.
|
||||
|
||||
### 5. Testing Best Practices
|
||||
- **FakeClock and Sleeper:** Use `FakeClock` and `Sleeper` for any logic involving timeouts, delays, or expiration.
|
||||
- **Empirical Reproduction:** Before fixing a bug, always create a test case that reproduces the failure.
|
||||
- **Base Classes:** Leverage `CommandTestCase`, `EppToolCommandTestCase`, etc., to reduce boilerplate and ensure consistent setup (e.g., clock initialization).
|
||||
|
||||
### 6. Project Dependencies
|
||||
- **Common Module:** When using `Clock` or other core utilities in a new or separate module (like `load-testing`), ensure `implementation project(':common')` is added to the module's `build.gradle`.
|
||||
|
||||
## Performance and Efficiency
|
||||
- **Turn Minimization:** Aim for "perfect" code in the first iteration. Iterative fixes for checkstyle or compilation errors consume significant context and time.
|
||||
- **Context Management:** Use sub-agents for batch refactoring or high-volume output tasks to keep the main session history lean and efficient.
|
||||
+7
-1
@@ -200,6 +200,7 @@ allprojects {
|
||||
"--add-exports",
|
||||
"jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED"]
|
||||
options.forkOptions.jvmArgs = ["-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED",
|
||||
"-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
|
||||
@@ -359,6 +360,8 @@ subprojects {
|
||||
// There are at least two instances, one in core/build.gradle, one in
|
||||
// release/stage_beam_pipeline.sh
|
||||
java {
|
||||
// TODO(b/457758757): change to V_25 once Java in all environments are
|
||||
// upgraded.
|
||||
sourceCompatibility = JavaVersion.VERSION_21
|
||||
targetCompatibility = JavaVersion.VERSION_21
|
||||
}
|
||||
@@ -533,7 +536,10 @@ task javadoc(type: Javadoc) {
|
||||
// In a lot of places we don't write @return so suppress warnings about that.
|
||||
// We don't report HTML lint errors because XJB-generated POJO files have
|
||||
// incorrect tags (like dangling </p> without the corresponding open tag.
|
||||
options.addBooleanOption('Xdoclint:all,-missing,-html', true)
|
||||
// Starting in Java 25, references to primitives and arrays are forbidden.
|
||||
// The JAXB-generated classes have array references, and we suppress the
|
||||
// error with '-reference'.
|
||||
options.addBooleanOption('Xdoclint:all,-missing,-html,-reference', true)
|
||||
options.addBooleanOption("-allow-script-in-comments",true)
|
||||
options.tags = ["type:a:Generic Type",
|
||||
"error:a:Expected Error",
|
||||
|
||||
+16
-19
@@ -1,41 +1,38 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
aopalliance:aopalliance:1.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.github.ben-manes.caffeine:caffeine:3.0.5=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.github.ben-manes.caffeine:caffeine:3.2.3=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.auto.service:auto-service-annotations:1.0.1=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.auto.value:auto-value-annotations:1.11.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.auto.value:auto-value-annotations:1.9=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.auto:auto-common:1.2.1=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,deploy_jar,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
com.google.errorprone:error_prone_annotation:2.23.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.23.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.auto:auto-common:1.2.2=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.code.findbugs:jsr305:3.0.2=checkstyle,compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.errorprone:error_prone_annotation:2.48.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.36.0=checkstyle
|
||||
com.google.errorprone:error_prone_annotations:2.43.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.errorprone:error_prone_check_api:2.23.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.23.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_type_annotations:2.23.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.48.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_check_api:2.48.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.48.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.flogger:flogger:0.9=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:failureaccess:1.0.1=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.googlejavaformat:google-java-format:1.34.1=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.2=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:failureaccess:1.0.3=checkstyle
|
||||
com.google.guava:guava-parent:32.1.1-jre=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:guava:32.1.1-jre=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.3=annotationProcessor,checkstyle,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:guava:33.4.3-android=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.guava:guava:33.4.8-jre=checkstyle
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=checkstyle,compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.inject:guice:5.1.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:guava:33.5.0-jre=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,compileClasspath,deploy_jar,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
com.google.j2objc:j2objc-annotations:3.0.0=checkstyle,compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.google.protobuf:protobuf-java:3.19.6=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.j2objc:j2objc-annotations:3.1=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.protobuf:protobuf-java:4.33.2=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
com.google.truth:truth:1.4.5=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
com.puppycrawl.tools:checkstyle:10.24.0=checkstyle
|
||||
commons-beanutils:commons-beanutils:1.10.1=checkstyle
|
||||
commons-codec:commons-codec:1.15=checkstyle
|
||||
commons-collections:commons-collections:3.2.2=checkstyle
|
||||
info.picocli:picocli:4.7.7=checkstyle
|
||||
io.github.eisop:dataflow-errorprone:3.34.0-eisop1=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.16=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
jakarta.inject:jakarta.inject-api:2.0.1=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
@@ -57,7 +54,7 @@ org.apache.maven.doxia:doxia-module-xdoc:1.12.0=checkstyle
|
||||
org.apache.maven.doxia:doxia-sink-api:1.12.0=checkstyle
|
||||
org.apache.xbean:xbean-reflect:3.7=checkstyle
|
||||
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath
|
||||
org.checkerframework:checker-qual:3.33.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.19.0=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.43.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.checkerframework:checker-qual:3.49.3=checkstyle
|
||||
org.codehaus.plexus:plexus-classworlds:2.6.0=checkstyle
|
||||
@@ -70,7 +67,7 @@ org.jacoco:org.jacoco.ant:0.8.14=jacocoAnt
|
||||
org.jacoco:org.jacoco.core:0.8.14=jacocoAnt
|
||||
org.jacoco:org.jacoco.report:0.8.14=jacocoAnt
|
||||
org.javassist:javassist:3.28.0-GA=checkstyle
|
||||
org.jspecify:jspecify:1.0.0=checkstyle,compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.jspecify:jspecify:1.0.0=annotationProcessor,checkstyle,compileClasspath,deploy_jar,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
@@ -82,7 +79,7 @@ org.ow2.asm:asm-commons:9.9=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.9=jacocoAnt
|
||||
org.ow2.asm:asm:9.8=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath,testing,testingCompileClasspath
|
||||
org.ow2.asm:asm:9.9=jacocoAnt
|
||||
org.pcollections:pcollections:3.1.4=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.pcollections:pcollections:4.0.1=annotationProcessor,testAnnotationProcessor,testingAnnotationProcessor
|
||||
org.reflections:reflections:0.10.2=checkstyle
|
||||
org.xmlresolver:xmlresolver:5.2.2=checkstyle
|
||||
empty=shadow,testingCompile,testingRuntime,testingRuntimeClasspath
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
package google.registry.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -30,5 +33,14 @@ import org.joda.time.DateTime;
|
||||
public interface Clock extends Serializable {
|
||||
|
||||
/** Returns current time in UTC timezone. */
|
||||
@Deprecated
|
||||
DateTime nowUtc();
|
||||
|
||||
/** Returns current Instant (which is always in UTC). */
|
||||
Instant now();
|
||||
|
||||
/** Returns the current time as a {@link ZonedDateTime} in UTC. */
|
||||
default ZonedDateTime nowDate() {
|
||||
return ZonedDateTime.ofInstant(now(), ZoneOffset.UTC);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Ordering;
|
||||
import java.sql.Date;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -28,7 +31,10 @@ import org.joda.time.LocalDate;
|
||||
public abstract class DateTimeUtils {
|
||||
|
||||
/** The start of the epoch, in a convenient constant. */
|
||||
public static final DateTime START_OF_TIME = new DateTime(0, DateTimeZone.UTC);
|
||||
@Deprecated public static final DateTime START_OF_TIME = new DateTime(0, DateTimeZone.UTC);
|
||||
|
||||
/** The start of the UNIX epoch (which is defined in UTC), in a convenient constant. */
|
||||
public static final Instant START_INSTANT = Instant.ofEpochMilli(0);
|
||||
|
||||
/**
|
||||
* A date in the far future that we can treat as infinity.
|
||||
@@ -37,19 +43,40 @@ public abstract class DateTimeUtils {
|
||||
* but Java uses milliseconds, so this is the largest representable date that will survive a
|
||||
* round-trip through the database.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final DateTime END_OF_TIME = new DateTime(Long.MAX_VALUE / 1000, DateTimeZone.UTC);
|
||||
|
||||
/**
|
||||
* An instant in the far future that we can treat as infinity.
|
||||
*
|
||||
* <p>This value is (2^63-1)/1000 rounded down. Postgres can store dates as 64 bit microseconds,
|
||||
* but Java uses milliseconds, so this is the largest representable date that will survive a
|
||||
* round-trip through the database.
|
||||
*/
|
||||
public static final Instant END_INSTANT = Instant.ofEpochMilli(Long.MAX_VALUE / 1000);
|
||||
|
||||
/** Returns the earliest of a number of given {@link DateTime} instances. */
|
||||
public static DateTime earliestOf(DateTime first, DateTime... rest) {
|
||||
return earliestDateTimeOf(Lists.asList(first, rest));
|
||||
}
|
||||
|
||||
/** Returns the earliest of a number of given {@link Instant} instances. */
|
||||
public static Instant earliestOf(Instant first, Instant... rest) {
|
||||
return earliestOf(Lists.asList(first, rest));
|
||||
}
|
||||
|
||||
/** Returns the earliest element in a {@link DateTime} iterable. */
|
||||
public static DateTime earliestOf(Iterable<DateTime> dates) {
|
||||
public static DateTime earliestDateTimeOf(Iterable<DateTime> dates) {
|
||||
checkArgument(!Iterables.isEmpty(dates));
|
||||
return Ordering.<DateTime>natural().min(dates);
|
||||
}
|
||||
|
||||
/** Returns the earliest element in a {@link Instant} iterable. */
|
||||
public static Instant earliestOf(Iterable<Instant> instants) {
|
||||
checkArgument(!Iterables.isEmpty(instants));
|
||||
return Ordering.<Instant>natural().min(instants);
|
||||
}
|
||||
|
||||
/** Returns the latest of a number of given {@link DateTime} instances. */
|
||||
public static DateTime latestOf(DateTime first, DateTime... rest) {
|
||||
return latestOf(Lists.asList(first, rest));
|
||||
@@ -66,29 +93,63 @@ public abstract class DateTimeUtils {
|
||||
return !timeToCheck.isAfter(timeToCompareTo);
|
||||
}
|
||||
|
||||
/** Returns whether the first {@link Instant} is equal to or earlier than the second. */
|
||||
public static boolean isBeforeOrAt(Instant timeToCheck, Instant timeToCompareTo) {
|
||||
return !timeToCheck.isAfter(timeToCompareTo);
|
||||
}
|
||||
|
||||
/** Returns whether the first {@link DateTime} is equal to or later than the second. */
|
||||
public static boolean isAtOrAfter(DateTime timeToCheck, DateTime timeToCompareTo) {
|
||||
return !timeToCheck.isBefore(timeToCompareTo);
|
||||
}
|
||||
|
||||
/** Returns whether the first {@link Instant} is equal to or later than the second. */
|
||||
public static boolean isAtOrAfter(Instant timeToCheck, Instant timeToCompareTo) {
|
||||
return !timeToCheck.isBefore(timeToCompareTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds years to a date, in the {@code Duration} sense of semantic years. Use this instead of
|
||||
* {@link DateTime#plusYears} to ensure that we never end up on February 29.
|
||||
*/
|
||||
@Deprecated
|
||||
public static DateTime leapSafeAddYears(DateTime now, int years) {
|
||||
checkArgument(years >= 0);
|
||||
return years == 0 ? now : now.plusYears(1).plusYears(years - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds years to a date, in the {@code Duration} sense of semantic years. Use this instead of
|
||||
* {@link java.time.ZonedDateTime#plusYears} to ensure that we never end up on February 29.
|
||||
*/
|
||||
public static Instant leapSafeAddYears(Instant now, long years) {
|
||||
checkArgument(years >= 0);
|
||||
return (years == 0)
|
||||
? now
|
||||
: now.atZone(ZoneOffset.UTC).plusYears(1).plusYears(years - 1).toInstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts years from a date, in the {@code Duration} sense of semantic years. Use this instead
|
||||
* of {@link DateTime#minusYears} to ensure that we never end up on February 29.
|
||||
*/
|
||||
@Deprecated
|
||||
public static DateTime leapSafeSubtractYears(DateTime now, int years) {
|
||||
checkArgument(years >= 0);
|
||||
return years == 0 ? now : now.minusYears(1).minusYears(years - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts years from a date, in the {@code Duration} sense of semantic years. Use this instead
|
||||
* of {@link java.time.ZonedDateTime#minusYears} to ensure that we never end up on February 29.
|
||||
*/
|
||||
public static Instant leapSafeSubtractYears(Instant now, int years) {
|
||||
checkArgument(years >= 0);
|
||||
return (years == 0)
|
||||
? now
|
||||
: now.atZone(ZoneOffset.UTC).minusYears(1).minusYears(years - 1).toInstant();
|
||||
}
|
||||
|
||||
public static Date toSqlDate(LocalDate localDate) {
|
||||
return new Date(localDate.toDateTimeAtStartOfDay().getMillis());
|
||||
}
|
||||
@@ -96,4 +157,34 @@ public abstract class DateTimeUtils {
|
||||
public static LocalDate toLocalDate(Date date) {
|
||||
return new LocalDate(date.getTime(), DateTimeZone.UTC);
|
||||
}
|
||||
|
||||
/** Convert a joda {@link DateTime} to a java.time {@link Instant}, null-safe. */
|
||||
@Nullable
|
||||
public static Instant toInstant(@Nullable DateTime dateTime) {
|
||||
return (dateTime == null) ? null : Instant.ofEpochMilli(dateTime.getMillis());
|
||||
}
|
||||
|
||||
/** Convert a java.time {@link Instant} to a joda {@link DateTime}, null-safe. */
|
||||
@Nullable
|
||||
public static DateTime toDateTime(@Nullable Instant instant) {
|
||||
return (instant == null) ? null : new DateTime(instant.toEpochMilli(), DateTimeZone.UTC);
|
||||
}
|
||||
|
||||
/** Convert a java.time {@link java.time.Instant} to a joda {@link org.joda.time.Instant}. */
|
||||
@Nullable
|
||||
public static org.joda.time.Instant toJodaInstant(@Nullable java.time.Instant instant) {
|
||||
return (instant == null) ? null : org.joda.time.Instant.ofEpochMilli(instant.toEpochMilli());
|
||||
}
|
||||
|
||||
public static Instant plusYears(Instant instant, int years) {
|
||||
return instant.atZone(ZoneOffset.UTC).plusYears(years).toInstant();
|
||||
}
|
||||
|
||||
public static Instant plusDays(Instant instant, int days) {
|
||||
return instant.atZone(ZoneOffset.UTC).plusDays(days).toInstant();
|
||||
}
|
||||
|
||||
public static Instant minusDays(Instant instant, int days) {
|
||||
return instant.atZone(ZoneOffset.UTC).minusDays(days).toInstant();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.util;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -34,4 +35,13 @@ public class SystemClock implements Clock {
|
||||
public DateTime nowUtc() {
|
||||
return DateTime.now(UTC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant now() {
|
||||
// Truncate to milliseconds to match the precision of Joda DateTime and our database schema
|
||||
// (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(java.time.temporal.ChronoUnit.MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.joda.time.Duration.millis;
|
||||
|
||||
import google.registry.util.Clock;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -54,6 +55,11 @@ public final class FakeClock implements Clock {
|
||||
return new DateTime(currentTimeMillis.addAndGet(autoIncrementStepMs), UTC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant now() {
|
||||
return Instant.ofEpochMilli(currentTimeMillis.addAndGet(autoIncrementStepMs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the increment applied to the clock whenever it is queried. The increment is zero by
|
||||
* default: the clock is left unchanged when queried.
|
||||
|
||||
@@ -1,34 +1,31 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
aopalliance:aopalliance:1.0=annotationProcessor,testAnnotationProcessor
|
||||
com.github.ben-manes.caffeine:caffeine:3.0.5=annotationProcessor,testAnnotationProcessor
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.auto.service:auto-service-annotations:1.0.1=annotationProcessor,testAnnotationProcessor
|
||||
com.google.auto.value:auto-value-annotations:1.9=annotationProcessor,testAnnotationProcessor
|
||||
com.google.auto:auto-common:1.2.1=annotationProcessor,testAnnotationProcessor
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotation:2.23.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.23.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.auto:auto-common:1.2.2=annotationProcessor,testAnnotationProcessor
|
||||
com.google.code.findbugs:jsr305:3.0.2=checkstyle
|
||||
com.google.errorprone:error_prone_annotation:2.48.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.36.0=checkstyle
|
||||
com.google.errorprone:error_prone_check_api:2.23.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.23.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_type_annotations:2.23.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.1=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.3=checkstyle
|
||||
com.google.guava:guava-parent:32.1.1-jre=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:guava:32.1.1-jre=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.48.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_check_api:2.48.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.48.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.googlejavaformat:google-java-format:1.34.1=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.3=annotationProcessor,checkstyle,testAnnotationProcessor
|
||||
com.google.guava:guava:33.4.8-jre=checkstyle
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=checkstyle
|
||||
com.google.inject:guice:5.1.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:guava:33.5.0-jre=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,testAnnotationProcessor
|
||||
com.google.j2objc:j2objc-annotations:3.0.0=checkstyle
|
||||
com.google.protobuf:protobuf-java:3.19.6=annotationProcessor,testAnnotationProcessor
|
||||
com.google.j2objc:j2objc-annotations:3.1=annotationProcessor,testAnnotationProcessor
|
||||
com.google.protobuf:protobuf-java:4.33.2=annotationProcessor,testAnnotationProcessor
|
||||
com.puppycrawl.tools:checkstyle:10.24.0=checkstyle
|
||||
commons-beanutils:commons-beanutils:1.10.1=checkstyle
|
||||
commons-codec:commons-codec:1.15=checkstyle
|
||||
commons-collections:commons-collections:3.2.2=checkstyle
|
||||
info.picocli:picocli:4.7.7=checkstyle
|
||||
io.github.eisop:dataflow-errorprone:3.34.0-eisop1=annotationProcessor,testAnnotationProcessor
|
||||
io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,testAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,testAnnotationProcessor
|
||||
javax.inject:javax.inject:1=annotationProcessor,testAnnotationProcessor
|
||||
net.sf.saxon:Saxon-HE:12.5=checkstyle
|
||||
@@ -45,7 +42,7 @@ org.apache.maven.doxia:doxia-logging-api:1.12.0=checkstyle
|
||||
org.apache.maven.doxia:doxia-module-xdoc:1.12.0=checkstyle
|
||||
org.apache.maven.doxia:doxia-sink-api:1.12.0=checkstyle
|
||||
org.apache.xbean:xbean-reflect:3.7=checkstyle
|
||||
org.checkerframework:checker-qual:3.33.0=annotationProcessor,testAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.19.0=annotationProcessor,testAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.49.3=checkstyle
|
||||
org.codehaus.plexus:plexus-classworlds:2.6.0=checkstyle
|
||||
org.codehaus.plexus:plexus-component-annotations:2.1.0=checkstyle
|
||||
@@ -56,11 +53,11 @@ org.jacoco:org.jacoco.ant:0.8.14=jacocoAnt
|
||||
org.jacoco:org.jacoco.core:0.8.14=jacocoAnt
|
||||
org.jacoco:org.jacoco.report:0.8.14=jacocoAnt
|
||||
org.javassist:javassist:3.28.0-GA=checkstyle
|
||||
org.jspecify:jspecify:1.0.0=checkstyle
|
||||
org.jspecify:jspecify:1.0.0=annotationProcessor,checkstyle,testAnnotationProcessor
|
||||
org.ow2.asm:asm-commons:9.9=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.9=jacocoAnt
|
||||
org.ow2.asm:asm:9.9=jacocoAnt
|
||||
org.pcollections:pcollections:3.1.4=annotationProcessor,testAnnotationProcessor
|
||||
org.pcollections:pcollections:4.0.1=annotationProcessor,testAnnotationProcessor
|
||||
org.reflections:reflections:0.10.2=checkstyle
|
||||
org.xmlresolver:xmlresolver:5.2.2=checkstyle
|
||||
empty=compileClasspath,deploy_jar,runtimeClasspath,shadow,testCompileClasspath,testRuntimeClasspath
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
FROM eclipse-temurin:21
|
||||
FROM eclipse-temurin:25
|
||||
ADD build/libs/nomulus.jar /nomulus.jar
|
||||
ENTRYPOINT ["java", "-jar", "/nomulus.jar"]
|
||||
|
||||
+4
-6
@@ -74,11 +74,7 @@ sourceSets {
|
||||
nonprod {
|
||||
java {
|
||||
compileClasspath += main.output
|
||||
|
||||
// Add the DB runtime classpath to nonprod so we can load the flyway
|
||||
// scripts.
|
||||
runtimeClasspath += main.output +
|
||||
rootProject.project(":db").sourceSets.main.runtimeClasspath
|
||||
runtimeClasspath += main.output
|
||||
}
|
||||
}
|
||||
test {
|
||||
@@ -102,6 +98,7 @@ configurations {
|
||||
devtool
|
||||
|
||||
nonprodImplementation.extendsFrom implementation
|
||||
nonprodRuntimeOnly.extendsFrom runtimeOnly
|
||||
|
||||
testImplementation.extendsFrom nonprodImplementation
|
||||
|
||||
@@ -259,6 +256,7 @@ dependencies {
|
||||
implementation project(':util')
|
||||
// Import NomulusPostreSql from ':db' for implementation but exclude dependencies.
|
||||
implementation project(path: ':db', configuration: 'implementationApi')
|
||||
nonprodRuntimeOnly project(':db')
|
||||
testRuntimeOnly project(':db')
|
||||
|
||||
annotationProcessor deps['com.google.auto.service:auto-service']
|
||||
@@ -593,7 +591,7 @@ if (environment == 'alpha') {
|
||||
gs://${gcpProject}-deploy/live/beam/${metaDataBaseName} \
|
||||
--image-gcr-path ${imageName}:live \
|
||||
--sdk-language JAVA \
|
||||
--flex-template-base-image gcr.io/dataflow-templates-base/java21-template-launcher-base:latest \
|
||||
--flex-template-base-image gcr.io/dataflow-templates-base/java25-template-launcher-base:latest \
|
||||
--metadata-file ${projectDir}/src/main/resources/${metaData} \
|
||||
--jar ${uberJarName} \
|
||||
--env FLEX_TEMPLATE_JAVA_MAIN_CLASS=${mainClass} \
|
||||
|
||||
+38
-36
@@ -1,7 +1,7 @@
|
||||
# This is a Gradle generated file for dependency locking.
|
||||
# Manual edits can break the build and are not advised.
|
||||
# This file is expected to be part of source control.
|
||||
aopalliance:aopalliance:1.0=annotationProcessor,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
aopalliance:aopalliance:1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
args4j:args4j:2.33=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.charleskorn.kaml:kaml:0.20.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.21=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -100,8 +100,10 @@ com.google.apis:google-api-services-admin-directory:directory_v1-rev20260227-2.0
|
||||
com.google.apis:google-api-services-bigquery:v2-rev20240815-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20240310-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dataflow:v1b3-rev20260213-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dns:v1-rev20260219-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20260322-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dns:v1-rev20260219-2.0.0=deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dns:v1-rev20260402-2.0.0=compileClasspath,nonprodCompileClasspath,nonprodRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20260322-2.0.0=deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20260405-2.0.0=compileClasspath,nonprodCompileClasspath,nonprodRuntimeClasspath
|
||||
com.google.apis:google-api-services-gmail:v1-rev20260112-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-groupssettings:v1-rev20220614-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-healthcare:v1-rev20240130-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -122,7 +124,7 @@ com.google.auto.value:auto-value-annotations:1.11.0=compileClasspath,deploy_jar,
|
||||
com.google.auto.value:auto-value-annotations:1.9=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.auto.value:auto-value:1.11.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auto.value:auto-value:1.11.1=annotationProcessor,testAnnotationProcessor
|
||||
com.google.auto:auto-common:1.2.1=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.auto:auto-common:1.2.2=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.cloud.bigdataoss:gcsio:2.2.16=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.bigdataoss:util:2.2.16=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.bigtable:bigtable-client-core-config:1.28.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -132,7 +134,7 @@ com.google.cloud.opentelemetry:detector-resources-support:0.33.0=deploy_jar,nonp
|
||||
com.google.cloud.opentelemetry:exporter-metrics:0.33.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.opentelemetry:shared-resourcemapping:0.33.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.28.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.28.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.28.2=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigquerystorage:3.9.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.cloud:google-cloud-bigquerystorage:3.9.2=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigtable:2.43.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
@@ -158,7 +160,7 @@ com.google.cloud:grpc-gcp:1.6.1=compileClasspath,deploy_jar,nonprodCompileClassp
|
||||
com.google.cloud:libraries-bom:26.48.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:proto-google-cloud-firestore-bundle-v1:3.25.1=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.cloud:proto-google-cloud-firestore-bundle-v1:3.26.5=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.gson:gson:2.10.1=soy
|
||||
com.google.code.gson:gson:2.12.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.common.html.types:types:1.0.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -166,14 +168,12 @@ com.google.dagger:dagger-compiler:2.59.2=annotationProcessor,testAnnotationProce
|
||||
com.google.dagger:dagger-spi:2.59.2=annotationProcessor,testAnnotationProcessor
|
||||
com.google.dagger:dagger:2.59.2=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.devtools.ksp:symbol-processing-api:2.2.20-2.0.3=annotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotation:2.23.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotation:2.48.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.20.0=soy
|
||||
com.google.errorprone:error_prone_annotations:2.23.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.36.0=checkstyle
|
||||
com.google.errorprone:error_prone_annotations:2.48.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.errorprone:error_prone_check_api:2.23.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.23.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_type_annotations:2.23.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.48.0=annotationProcessor,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.errorprone:error_prone_check_api:2.48.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.48.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.escapevelocity:escapevelocity:1.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.flatbuffers:flatbuffers-java:23.5.26=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.flogger:flogger-system-backend:0.7.4=soy
|
||||
@@ -182,18 +182,16 @@ com.google.flogger:flogger:0.7.4=soy
|
||||
com.google.flogger:flogger:0.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.flogger:google-extensions:0.7.4=soy
|
||||
com.google.flogger:google-extensions:0.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.googlejavaformat:google-java-format:1.33.0=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.1=nonprodAnnotationProcessor,soy
|
||||
com.google.guava:failureaccess:1.0.2=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.3=checkstyle,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:guava-parent:32.1.1-jre=nonprodAnnotationProcessor,soy
|
||||
com.google.googlejavaformat:google-java-format:1.34.1=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:failureaccess:1.0.1=soy
|
||||
com.google.guava:failureaccess:1.0.3=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:guava-parent:32.1.1-jre=soy
|
||||
com.google.guava:guava-testlib:33.3.0-jre=testRuntimeClasspath
|
||||
com.google.guava:guava-testlib:33.5.0-jre=testCompileClasspath
|
||||
com.google.guava:guava:32.1.1-jre=nonprodAnnotationProcessor,soy
|
||||
com.google.guava:guava:33.0.0-jre=annotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:guava:32.1.1-jre=soy
|
||||
com.google.guava:guava:33.4.8-jre=checkstyle
|
||||
com.google.guava:guava:33.5.0-jre=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:guava:33.5.0-jre=annotationProcessor,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.gwt:gwt-user:2.10.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-apache-v2:2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-appengine:1.46.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -202,10 +200,9 @@ com.google.http-client:google-http-client-jackson2:1.46.3=compileClasspath,deplo
|
||||
com.google.http-client:google-http-client-protobuf:1.44.2=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.http-client:google-http-client-protobuf:1.45.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client:2.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.inject:guice:5.1.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.inject:guice:7.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.j2objc:j2objc-annotations:3.0.0=checkstyle
|
||||
com.google.j2objc:j2objc-annotations:3.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.j2objc:j2objc-annotations:3.1=annotationProcessor,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.jsinterop:jsinterop-annotations:1.0.1=soy
|
||||
com.google.jsinterop:jsinterop-annotations:2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.monitoring-client:contrib:1.0.7=testCompileClasspath,testRuntimeClasspath
|
||||
@@ -220,8 +217,8 @@ com.google.oauth-client:google-oauth-client-servlet:1.39.0=compileClasspath,nonp
|
||||
com.google.oauth-client:google-oauth-client:1.39.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java-util:4.33.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.protobuf:protobuf-java-util:4.34.1=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java:3.19.6=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.protobuf:protobuf-java:3.21.7=soy
|
||||
com.google.protobuf:protobuf-java:4.33.2=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.protobuf:protobuf-java:4.34.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.re2j:re2j:1.7=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.template:soy:2024-02-26=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -274,7 +271,7 @@ guru.nidi:graphviz-java:0.18.1=testRuntimeClasspath
|
||||
info.picocli:picocli:4.7.7=checkstyle
|
||||
io.apicurio:apicurio-registry-protobuf-schema-utilities:3.0.0.M2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.github.classgraph:classgraph:4.8.162=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.github.eisop:dataflow-errorprone:3.34.0-eisop1=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.16=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-alts:1.70.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -454,8 +451,8 @@ org.bouncycastle:bcprov-jdk18on:1.83=compileClasspath,deploy_jar,nonprodCompileC
|
||||
org.bouncycastle:bcutil-jdk18on:1.83=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.checkerframework:checker-compat-qual:2.5.3=annotationProcessor,compileClasspath,nonprodCompileClasspath,soy,testAnnotationProcessor,testCompileClasspath
|
||||
org.checkerframework:checker-compat-qual:2.5.6=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.checkerframework:checker-qual:3.33.0=nonprodAnnotationProcessor,soy
|
||||
org.checkerframework:checker-qual:3.41.0=annotationProcessor,testAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.19.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.33.0=soy
|
||||
org.checkerframework:checker-qual:3.49.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
org.checkerframework:checker-qual:3.49.3=checkstyle
|
||||
org.checkerframework:checker-qual:3.52.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -480,8 +477,8 @@ org.eclipse.jetty:jetty-server:12.1.7=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-session:12.1.7=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-util:12.1.7=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-xml:12.1.7=testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:12.2.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:12.2.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:12.3.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:12.3.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:codemodel:4.0.7=jaxb
|
||||
org.glassfish.jaxb:jaxb-core:4.0.6=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:jaxb-core:4.0.7=jaxb
|
||||
@@ -532,7 +529,7 @@ org.joda:joda-money:2.0.3=compileClasspath,deploy_jar,nonprodCompileClasspath,no
|
||||
org.json:json:20230618=soy
|
||||
org.json:json:20240303=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jsoup:jsoup:1.22.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jspecify:jspecify:1.0.0=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
org.jspecify:jspecify:1.0.0=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
org.junit-pioneer:junit-pioneer:2.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
@@ -564,7 +561,7 @@ org.ow2.asm:asm:9.5=soy
|
||||
org.ow2.asm:asm:9.7.1=compileClasspath,nonprodCompileClasspath
|
||||
org.ow2.asm:asm:9.8=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:9.9=jacocoAnt
|
||||
org.pcollections:pcollections:3.1.4=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
org.pcollections:pcollections:4.0.1=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
org.postgresql:postgresql:42.7.10=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.reflections:reflections:0.10.2=checkstyle
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -606,12 +603,17 @@ tools.jackson.core:jackson-core:3.1.0=compileClasspath,deploy_jar,nonprodCompile
|
||||
tools.jackson.core:jackson-databind:3.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
tools.jackson:jackson-bom:3.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-api:17.1.7=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-diagram:17.8.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-operations:17.8.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-postgresql:17.8.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-text:17.8.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-diagram:17.10.0=compileClasspath,nonprodCompileClasspath,nonprodRuntimeClasspath
|
||||
us.fatehi:schemacrawler-diagram:17.9.0=deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-operations:17.10.0=compileClasspath,nonprodCompileClasspath,nonprodRuntimeClasspath
|
||||
us.fatehi:schemacrawler-operations:17.9.0=deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-postgresql:17.10.0=compileClasspath,nonprodCompileClasspath,nonprodRuntimeClasspath
|
||||
us.fatehi:schemacrawler-postgresql:17.9.0=deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-text:17.10.0=compileClasspath,nonprodCompileClasspath,nonprodRuntimeClasspath
|
||||
us.fatehi:schemacrawler-text:17.9.0=deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-tools:17.1.7=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-utility:17.1.7=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler:17.8.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler:17.10.0=compileClasspath,nonprodCompileClasspath,nonprodRuntimeClasspath
|
||||
us.fatehi:schemacrawler:17.9.0=deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
xerces:xmlParserAPIs:2.6.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
empty=devtool,shadow
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.batch;
|
||||
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
||||
import static google.registry.flows.FlowUtils.marshalWithLenientRetry;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_NO_CONTENT;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
@@ -39,7 +40,6 @@ import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import java.util.Optional;
|
||||
@@ -212,7 +212,7 @@ public class BulkDomainTransferAction implements Runnable {
|
||||
|
||||
private boolean shouldSkipDomain(String domainName) {
|
||||
Optional<Domain> maybeDomain =
|
||||
ForeignKeyUtils.loadResource(Domain.class, domainName, tm().getTransactionTime());
|
||||
ForeignKeyUtils.loadResource(Domain.class, domainName, tm().getTxTime());
|
||||
if (maybeDomain.isEmpty()) {
|
||||
logger.atWarning().log("Domain '%s' was already deleted", domainName);
|
||||
missingDomains++;
|
||||
@@ -232,7 +232,7 @@ public class BulkDomainTransferAction implements Runnable {
|
||||
return true;
|
||||
}
|
||||
if (domain.getStatusValues().contains(StatusValue.PENDING_DELETE)
|
||||
|| !domain.getDeletionTime().equals(DateTimeUtils.END_OF_TIME)) {
|
||||
|| !domain.getDeletionTime().equals(END_INSTANT)) {
|
||||
logger.atWarning().log("Domain '%s' is in PENDING_DELETE", domainName);
|
||||
pendingDelete++;
|
||||
return true;
|
||||
|
||||
@@ -18,6 +18,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
||||
import static google.registry.flows.FlowUtils.marshalWithLenientRetry;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.ResourceUtils.readResourceUtf8;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
@@ -177,7 +178,7 @@ public class DeleteExpiredDomainsAction implements Runnable {
|
||||
"Failed to delete domain %s because of its autorenew end time: %s.",
|
||||
transDomain.getDomainName(), transDomain.getAutorenewEndTime());
|
||||
return Optional.empty();
|
||||
} else if (domain.getDeletionTime().isBefore(END_OF_TIME)) {
|
||||
} else if (domain.getDeletionTime().isBefore(END_INSTANT)) {
|
||||
logger.atSevere().log(
|
||||
"Failed to delete domain %s because it was already deleted on %s.",
|
||||
transDomain.getDomainName(), transDomain.getDeletionTime());
|
||||
|
||||
@@ -28,7 +28,6 @@ import static google.registry.request.RequestParameters.PARAM_BATCH_SIZE;
|
||||
import static google.registry.request.RequestParameters.PARAM_DRY_RUN;
|
||||
import static google.registry.request.RequestParameters.PARAM_TLDS;
|
||||
import static google.registry.util.RegistryEnvironment.PRODUCTION;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -44,6 +43,7 @@ import google.registry.model.tld.Tld.TldType;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
@@ -111,16 +111,20 @@ public class DeleteProberDataAction implements Runnable {
|
||||
|
||||
String registryAdminRegistrarId;
|
||||
|
||||
private final Clock clock;
|
||||
|
||||
@Inject
|
||||
DeleteProberDataAction(
|
||||
@Parameter(PARAM_DRY_RUN) boolean isDryRun,
|
||||
@Parameter(PARAM_TLDS) ImmutableSet<String> tlds,
|
||||
@Parameter(PARAM_BATCH_SIZE) Optional<Integer> batchSize,
|
||||
@Config("registryAdminClientId") String registryAdminRegistrarId) {
|
||||
@Config("registryAdminClientId") String registryAdminRegistrarId,
|
||||
Clock clock) {
|
||||
this.isDryRun = isDryRun;
|
||||
this.tlds = tlds;
|
||||
this.batchSize = batchSize.orElse(DEFAULT_BATCH_SIZE);
|
||||
this.registryAdminRegistrarId = registryAdminRegistrarId;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -145,7 +149,7 @@ public class DeleteProberDataAction implements Runnable {
|
||||
AtomicInteger softDeletedDomains = new AtomicInteger();
|
||||
AtomicInteger hardDeletedDomains = new AtomicInteger();
|
||||
AtomicReference<ImmutableList<Domain>> domainsBatch = new AtomicReference<>();
|
||||
DateTime startTime = DateTime.now(UTC);
|
||||
DateTime startTime = clock.nowUtc();
|
||||
do {
|
||||
tm().transact(
|
||||
TRANSACTION_REPEATABLE_READ,
|
||||
@@ -164,7 +168,7 @@ public class DeleteProberDataAction implements Runnable {
|
||||
hardDeletedDomains.get(), batchSize);
|
||||
|
||||
// Automatically kill the job if it is running for over 20 hours
|
||||
} while (DateTime.now(UTC).isBefore(startTime.plusHours(20))
|
||||
} while (clock.nowUtc().isBefore(startTime.plusHours(20))
|
||||
&& domainsBatch.get().size() == batchSize);
|
||||
logger.atInfo().log(
|
||||
"%s %d domains.",
|
||||
|
||||
@@ -188,7 +188,7 @@ public class RelockDomainAction implements Runnable {
|
||||
"Domain %s has a pending delete.",
|
||||
domainName);
|
||||
checkArgument(
|
||||
!DateTimeUtils.isAtOrAfter(tm().getTransactionTime(), domain.getDeletionTime()),
|
||||
!DateTimeUtils.isAtOrAfter(tm().getTxTime(), domain.getDeletionTime()),
|
||||
"Domain %s has been deleted.",
|
||||
domainName);
|
||||
checkArgument(
|
||||
|
||||
+6
-3
@@ -19,7 +19,6 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
import static org.apache.http.HttpStatus.SC_INTERNAL_SERVER_ERROR;
|
||||
import static org.apache.http.HttpStatus.SC_OK;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -37,6 +36,7 @@ import google.registry.model.registrar.RegistrarPoc.Type;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.EmailMessage;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
@@ -73,6 +73,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
private final GmailClient gmailClient;
|
||||
private final String expirationWarningEmailSubjectText;
|
||||
private final Response response;
|
||||
private final Clock clock;
|
||||
|
||||
@Inject
|
||||
public SendExpiringCertificateNotificationEmailAction(
|
||||
@@ -80,12 +81,14 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
@Config("expirationWarningEmailSubjectText") String expirationWarningEmailSubjectText,
|
||||
GmailClient gmailClient,
|
||||
CertificateChecker certificateChecker,
|
||||
Response response) {
|
||||
Response response,
|
||||
Clock clock) {
|
||||
this.certificateChecker = certificateChecker;
|
||||
this.expirationWarningEmailSubjectText = expirationWarningEmailSubjectText;
|
||||
this.gmailClient = gmailClient;
|
||||
this.expirationWarningEmailBodyText = expirationWarningEmailBodyText;
|
||||
this.response = response;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -186,7 +189,7 @@ public class SendExpiringCertificateNotificationEmailAction implements Runnable
|
||||
*/
|
||||
updateLastNotificationSentDate(
|
||||
registrar,
|
||||
DateTime.now(UTC).minusMinutes((int) UPDATE_TIME_OFFSET.getStandardMinutes()),
|
||||
clock.nowUtc().minusMinutes((int) UPDATE_TIME_OFFSET.getStandardMinutes()),
|
||||
certificateType);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@ import static google.registry.util.CollectionUtils.union;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.earliestOf;
|
||||
import static google.registry.util.DateTimeUtils.latestOf;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static org.apache.beam.sdk.values.TypeDescriptors.voids;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -372,7 +373,7 @@ public class ExpandBillingRecurrencesPipeline implements Serializable {
|
||||
// during ARGP).
|
||||
//
|
||||
// See: DomainFlowUtils#createCancellingRecords
|
||||
domain.getDeletionTime().isBefore(billingTime)
|
||||
domain.getDeletionTime().isBefore(toInstant(billingTime))
|
||||
? ImmutableSet.of()
|
||||
: ImmutableSet.of(
|
||||
DomainTransactionRecord.create(
|
||||
|
||||
@@ -21,6 +21,8 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
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;
|
||||
@@ -40,7 +42,6 @@ import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.joda.time.Instant;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -74,6 +75,8 @@ public class SafeBrowsingTransforms {
|
||||
/** Provides the SafeBrowsing API key at runtime. */
|
||||
private final String apiKey;
|
||||
|
||||
private final Clock clock;
|
||||
|
||||
/**
|
||||
* Maps a domain name's {@code domainName} to its corresponding {@link DomainNameInfo} to
|
||||
* facilitate batching SafeBrowsing API requests.
|
||||
@@ -101,9 +104,10 @@ public class SafeBrowsingTransforms {
|
||||
* HttpClients#createDefault()}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
EvaluateSafeBrowsingFn(String apiKey, Retrier retrier) {
|
||||
EvaluateSafeBrowsingFn(String apiKey, Retrier retrier, Clock clock) {
|
||||
this.apiKey = apiKey;
|
||||
this.retrier = retrier;
|
||||
this.clock = clock;
|
||||
closeableHttpClientSupplier = (Supplier & Serializable) HttpClients::createDefault;
|
||||
}
|
||||
|
||||
@@ -115,9 +119,10 @@ public class SafeBrowsingTransforms {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
EvaluateSafeBrowsingFn(
|
||||
String apiKey, Retrier retrier, Supplier<CloseableHttpClient> clientSupplier) {
|
||||
String apiKey, Retrier retrier, Clock clock, Supplier<CloseableHttpClient> clientSupplier) {
|
||||
this.apiKey = apiKey;
|
||||
this.retrier = retrier;
|
||||
this.clock = clock;
|
||||
closeableHttpClientSupplier = clientSupplier;
|
||||
}
|
||||
|
||||
@@ -126,7 +131,10 @@ public class SafeBrowsingTransforms {
|
||||
public void finishBundle(FinishBundleContext context) {
|
||||
if (!domainNameInfoBuffer.isEmpty()) {
|
||||
ImmutableSet<KV<DomainNameInfo, ThreatMatch>> results = evaluateAndFlush();
|
||||
results.forEach((kv) -> context.output(kv, Instant.now(), GlobalWindow.INSTANCE));
|
||||
results.forEach(
|
||||
(kv) ->
|
||||
context.output(
|
||||
kv, DateTimeUtils.toJodaInstant(clock.now()), GlobalWindow.INSTANCE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import google.registry.model.reporting.Spec11ThreatMatch;
|
||||
import google.registry.model.reporting.Spec11ThreatMatch.ThreatType;
|
||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.UtilsModule;
|
||||
import jakarta.inject.Singleton;
|
||||
@@ -263,8 +264,9 @@ public class Spec11Pipeline implements Serializable {
|
||||
}
|
||||
|
||||
@Provides
|
||||
EvaluateSafeBrowsingFn provideSafeBrowsingFn(Spec11PipelineOptions options, Retrier retrier) {
|
||||
return new EvaluateSafeBrowsingFn(options.getSafeBrowsingApiKey(), retrier);
|
||||
EvaluateSafeBrowsingFn provideSafeBrowsingFn(
|
||||
Spec11PipelineOptions options, Retrier retrier, Clock clock) {
|
||||
return new EvaluateSafeBrowsingFn(options.getSafeBrowsingApiKey(), retrier, clock);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -24,7 +24,6 @@ import static com.google.common.util.concurrent.Futures.transformAsync;
|
||||
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
|
||||
import static google.registry.bigquery.BigqueryUtils.toJobReferenceString;
|
||||
import static google.registry.config.RegistryConfig.getProjectId;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
|
||||
import com.google.api.client.http.AbstractInputStreamContent;
|
||||
@@ -58,6 +57,7 @@ import com.google.common.util.concurrent.MoreExecutors;
|
||||
import google.registry.bigquery.BigqueryUtils.DestinationFormat;
|
||||
import google.registry.bigquery.BigqueryUtils.TableType;
|
||||
import google.registry.bigquery.BigqueryUtils.WriteDisposition;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.NonFinalForTesting;
|
||||
import google.registry.util.Sleeper;
|
||||
import google.registry.util.SqlTemplate;
|
||||
@@ -69,7 +69,6 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** Class encapsulating parameters and state for accessing the Bigquery API. */
|
||||
@@ -94,6 +93,9 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
/** Bigquery client instance wrapped by this class. */
|
||||
private final Bigquery bigquery;
|
||||
|
||||
/** Clock instance for this connection. */
|
||||
private final Clock clock;
|
||||
|
||||
/** Executor service for bigquery jobs. */
|
||||
private ListeningExecutorService service;
|
||||
|
||||
@@ -109,8 +111,9 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
/** Duration to wait between polls for job status. */
|
||||
private Duration pollInterval = Duration.millis(1000);
|
||||
|
||||
BigqueryConnection(Bigquery bigquery) {
|
||||
BigqueryConnection(Bigquery bigquery, Clock clock) {
|
||||
this.bigquery = bigquery;
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
/** Builder for a {@link BigqueryConnection}, since the latter is immutable once created. */
|
||||
@@ -118,8 +121,8 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
private BigqueryConnection instance;
|
||||
|
||||
@Inject
|
||||
Builder(Bigquery bigquery) {
|
||||
instance = new BigqueryConnection(bigquery);
|
||||
Builder(Bigquery bigquery, Clock clock) {
|
||||
instance = new BigqueryConnection(bigquery, clock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,6 +198,11 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
private final TableReference tableRef = new TableReference();
|
||||
private TableType type = TableType.TABLE;
|
||||
private WriteDisposition writeDisposition = WriteDisposition.WRITE_EMPTY;
|
||||
private final Clock clock;
|
||||
|
||||
public Builder(Clock clock) {
|
||||
this.clock = clock;
|
||||
}
|
||||
|
||||
public Builder datasetId(String datasetId) {
|
||||
tableRef.setDatasetId(datasetId);
|
||||
@@ -217,7 +225,7 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
}
|
||||
|
||||
public Builder timeToLive(Duration duration) {
|
||||
this.table.setExpirationTime(DateTime.now(UTC).plus(duration).getMillis());
|
||||
this.table.setExpirationTime(clock.nowUtc().plus(duration).getMillis());
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -302,7 +310,7 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
|
||||
/** Returns a partially built DestinationTable with the default dataset and overwrite behavior. */
|
||||
public DestinationTable.Builder buildDestinationTable(String tableName) {
|
||||
return new DestinationTable.Builder()
|
||||
return new DestinationTable.Builder(clock)
|
||||
.datasetId(datasetId)
|
||||
.type(TableType.TABLE)
|
||||
.name(tableName)
|
||||
@@ -314,7 +322,7 @@ public class BigqueryConnection implements AutoCloseable {
|
||||
* temporary table dataset, with the default TTL and overwrite behavior.
|
||||
*/
|
||||
public DestinationTable.Builder buildTemporaryTable() {
|
||||
return new DestinationTable.Builder()
|
||||
return new DestinationTable.Builder(clock)
|
||||
.datasetId(TEMP_DATASET_NAME)
|
||||
.type(TableType.TABLE)
|
||||
.name(getRandomTableName())
|
||||
|
||||
@@ -988,6 +988,19 @@ public final class RegistryConfig {
|
||||
return 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to include optional RDAP history results in domain responses.
|
||||
*
|
||||
* <p>The RDAP Response Profile (Feb 2024) section 2.3 specifies that while registration and
|
||||
* expiration events are required, other types are optional. In an effort to reduce database
|
||||
* load, we (by default) omit the optional events.
|
||||
*/
|
||||
@Provides
|
||||
@Config("rdapIncludeOptionalHistoryResults")
|
||||
public static boolean provideRdapIncludeOptionalHistoryResults() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum QPS for the Google Cloud Monitoring V3 (aka Stackdriver) API. The QPS limit can be
|
||||
* adjusted by contacting Cloud Support.
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.flows;
|
||||
|
||||
import static com.google.common.collect.Sets.intersection;
|
||||
import static google.registry.model.EppResourceUtils.isLinked;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -44,6 +45,7 @@ import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -89,6 +91,11 @@ public final class ResourceFlowUtils {
|
||||
|
||||
public static <R 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));
|
||||
}
|
||||
|
||||
@@ -197,8 +204,8 @@ public final class ResourceFlowUtils {
|
||||
*
|
||||
* @param domain is the domain already projected at approvalTime
|
||||
*/
|
||||
public static DateTime computeExDateForApprovalTime(
|
||||
DomainBase domain, DateTime approvalTime, Period period) {
|
||||
public static Instant computeExDateForApprovalTime(
|
||||
DomainBase domain, Instant approvalTime, Period period) {
|
||||
boolean inAutoRenew = domain.getGracePeriodStatuses().contains(GracePeriodStatus.AUTO_RENEW);
|
||||
// inAutoRenew is set to false if the period is zero because a zero-period transfer should not
|
||||
// subsume an autorenew.
|
||||
|
||||
@@ -236,7 +236,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
}
|
||||
|
||||
// Cancel any grace periods that were still active, and set the expiration time accordingly.
|
||||
DateTime newExpirationTime = existingDomain.getRegistrationExpirationTime();
|
||||
DateTime newExpirationTime = existingDomain.getRegistrationExpirationDateTime();
|
||||
for (GracePeriod gracePeriod : existingDomain.getGracePeriods()) {
|
||||
// No cancellation is written if the grace period was not for a billable event.
|
||||
if (gracePeriod.hasBillingEvent()) {
|
||||
@@ -289,7 +289,7 @@ public final class DomainDeleteFlow implements MutatingFlow, SqlStatementLogging
|
||||
flowCustomLogic.beforeResponse(
|
||||
BeforeResponseParameters.newBuilder()
|
||||
.setResultCode(
|
||||
newDomain.getDeletionTime().isAfter(now)
|
||||
newDomain.getDeletionDateTime().isAfter(now)
|
||||
? SUCCESS_WITH_ACTION_PENDING
|
||||
: SUCCESS)
|
||||
.setResponseExtensions(
|
||||
|
||||
@@ -503,7 +503,7 @@ public class DomainFlowUtils {
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId(domain.getDomainName())
|
||||
.setRegistrarId(domain.getCurrentSponsorRegistrarId())
|
||||
.setEventTime(domain.getRegistrationExpirationTime());
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -514,7 +514,7 @@ public class DomainFlowUtils {
|
||||
return new Autorenew.Builder()
|
||||
.setTargetId(domain.getDomainName())
|
||||
.setRegistrarId(domain.getCurrentSponsorRegistrarId())
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setMsg("Domain was auto-renewed.");
|
||||
}
|
||||
|
||||
@@ -658,7 +658,7 @@ public class DomainFlowUtils {
|
||||
// process, don't count as expired for the purposes of requiring an added year of renewal on
|
||||
// restore because they can't be restored in the first place.
|
||||
boolean isExpired =
|
||||
domain.isPresent() && domain.get().getRegistrationExpirationTime().isBefore(now);
|
||||
domain.isPresent() && domain.get().getRegistrationExpirationDateTime().isBefore(now);
|
||||
fees = pricingLogic.getRestorePrice(tld, domainNameString, now, isExpired).getFees();
|
||||
}
|
||||
case TRANSFER -> {
|
||||
|
||||
@@ -122,8 +122,8 @@ public final class DomainInfoFlow implements MutatingFlow {
|
||||
.setNameservers(
|
||||
hostsRequest.requestDelegated() ? domain.loadNameserverHostNames() : null)
|
||||
.setCreationTime(domain.getCreationTime())
|
||||
.setLastEppUpdateTime(domain.getLastEppUpdateTime())
|
||||
.setRegistrationExpirationTime(domain.getRegistrationExpirationTime())
|
||||
.setLastEppUpdateTime(domain.getLastEppUpdateDateTime())
|
||||
.setRegistrationExpirationTime(domain.getRegistrationExpirationDateTime())
|
||||
.setLastTransferTime(domain.getLastTransferTime());
|
||||
|
||||
// If authInfo is non-null, then the caller is authorized to see the full information since we
|
||||
|
||||
@@ -191,7 +191,7 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
existingDomain = maybeApplyBulkPricingRemovalToken(existingDomain, allocationToken);
|
||||
|
||||
DateTime newExpirationTime =
|
||||
leapSafeAddYears(existingDomain.getRegistrationExpirationTime(), years); // Uncapped
|
||||
leapSafeAddYears(existingDomain.getRegistrationExpirationDateTime(), years); // Uncapped
|
||||
validateRegistrationPeriod(now, newExpirationTime);
|
||||
Optional<FeeRenewCommandExtension> feeRenew =
|
||||
eppInput.getSingleExtension(FeeRenewCommandExtension.class);
|
||||
@@ -328,8 +328,9 @@ public final class DomainRenewFlow implements MutatingFlow {
|
||||
// We only allow __REMOVE_BULK_PRICING__ token on bulk pricing domains for now
|
||||
verifyBulkTokenAllowedOnDomain(existingDomain, allocationToken);
|
||||
// If the date they specify doesn't match the expiration, fail. (This is an idempotence check).
|
||||
if (!command.getCurrentExpirationDate().equals(
|
||||
existingDomain.getRegistrationExpirationTime().toLocalDate())) {
|
||||
if (!command
|
||||
.getCurrentExpirationDate()
|
||||
.equals(existingDomain.getRegistrationExpirationDateTime().toLocalDate())) {
|
||||
throw new IncorrectCurrentExpirationDateException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
|
||||
Update command = (Update) resourceCommand;
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
boolean isExpired = existingDomain.getRegistrationExpirationTime().isBefore(now);
|
||||
boolean isExpired = existingDomain.getRegistrationExpirationDateTime().isBefore(now);
|
||||
FeesAndCredits feesAndCredits =
|
||||
pricingLogic.getRestorePrice(Tld.get(existingDomain.getTld()), targetId, now, isExpired);
|
||||
Optional<FeeUpdateCommandExtension> feeUpdate =
|
||||
@@ -149,7 +149,7 @@ public final class DomainRestoreRequestFlow implements MutatingFlow {
|
||||
ImmutableSet.Builder<ImmutableObject> entitiesToInsert = new ImmutableSet.Builder<>();
|
||||
|
||||
DateTime newExpirationTime =
|
||||
existingDomain.getRegistrationExpirationTime().plusYears(isExpired ? 1 : 0);
|
||||
existingDomain.getRegistrationExpirationDateTime().plusYears(isExpired ? 1 : 0);
|
||||
// Restore the expiration time on the deleted domain, except if that's already passed, then add
|
||||
// a year and bill for it immediately, with no grace period.
|
||||
if (isExpired) {
|
||||
|
||||
@@ -33,6 +33,8 @@ import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.CollectionUtils.union;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -193,7 +195,9 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
updateAutorenewRecurrenceEndTime(
|
||||
existingDomain, existingBillingRecurrence, now, domainHistoryId);
|
||||
DateTime newExpirationTime =
|
||||
computeExDateForApprovalTime(existingDomain, now, transferData.getTransferPeriod());
|
||||
toDateTime(
|
||||
computeExDateForApprovalTime(
|
||||
existingDomain, toInstant(now), transferData.getTransferPeriod()));
|
||||
// Create a new autorenew event starting at the expiration time.
|
||||
BillingRecurrence autorenewEvent =
|
||||
new BillingRecurrence.Builder()
|
||||
@@ -268,8 +272,11 @@ public final class DomainTransferApproveFlow implements MutatingFlow {
|
||||
// been implicitly server approved.
|
||||
tm().delete(existingDomain.getTransferData().getServerApproveEntities());
|
||||
return responseBuilder
|
||||
.setResData(createTransferResponse(
|
||||
targetId, newDomain.getTransferData(), newDomain.getRegistrationExpirationTime()))
|
||||
.setResData(
|
||||
createTransferResponse(
|
||||
targetId,
|
||||
newDomain.getTransferData(),
|
||||
newDomain.getRegistrationExpirationDateTime()))
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,15 +15,17 @@
|
||||
package google.registry.flows.domain;
|
||||
|
||||
import static google.registry.flows.FlowUtils.validateRegistrarIsLoggedIn;
|
||||
import static google.registry.flows.ResourceFlowUtils.computeExDateForApprovalTime;
|
||||
import static google.registry.flows.ResourceFlowUtils.loadAndVerifyExistence;
|
||||
import static google.registry.flows.ResourceFlowUtils.verifyOptionalAuthInfo;
|
||||
import static google.registry.flows.domain.DomainTransferUtils.createTransferResponse;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.ExtensionManager;
|
||||
import google.registry.flows.FlowModule.RegistrarId;
|
||||
import google.registry.flows.FlowModule.TargetId;
|
||||
import google.registry.flows.ResourceFlowUtils;
|
||||
import google.registry.flows.TransactionalFlow;
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.flows.exceptions.NoTransferHistoryToQueryException;
|
||||
@@ -88,11 +90,12 @@ public final class DomainTransferQueryFlow implements TransactionalFlow {
|
||||
}
|
||||
DateTime newExpirationTime = null;
|
||||
if (transferData.getTransferStatus().isApproved()) {
|
||||
newExpirationTime = transferData.getTransferredRegistrationExpirationTime();
|
||||
newExpirationTime = transferData.getTransferredRegistrationExpirationDateTime();
|
||||
} else if (transferData.getTransferStatus().equals(TransferStatus.PENDING)) {
|
||||
newExpirationTime =
|
||||
ResourceFlowUtils.computeExDateForApprovalTime(
|
||||
domain, now, domain.getTransferData().getTransferPeriod());
|
||||
toDateTime(
|
||||
computeExDateForApprovalTime(
|
||||
domain, toInstant(now), domain.getTransferData().getTransferPeriod()));
|
||||
}
|
||||
return responseBuilder
|
||||
.setResData(createTransferResponse(targetId, transferData, newExpirationTime))
|
||||
|
||||
@@ -32,6 +32,7 @@ import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.CollectionUtils.union;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.EppException;
|
||||
@@ -53,6 +54,7 @@ import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -92,7 +94,7 @@ public final class DomainTransferRejectFlow implements MutatingFlow {
|
||||
extensionManager.register(MetadataExtension.class);
|
||||
validateRegistrarIsLoggedIn(registrarId);
|
||||
extensionManager.validate();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Instant now = tm().getTxTime();
|
||||
Domain existingDomain = loadAndVerifyExistence(Domain.class, targetId, now);
|
||||
Tld tld = Tld.get(existingDomain.getTld());
|
||||
HistoryEntryId domainHistoryId = createHistoryEntryId(existingDomain);
|
||||
@@ -107,13 +109,14 @@ public final class DomainTransferRejectFlow implements MutatingFlow {
|
||||
checkAllowedAccessToTld(registrarId, existingDomain.getTld());
|
||||
}
|
||||
Domain newDomain =
|
||||
denyPendingTransfer(existingDomain, TransferStatus.CLIENT_REJECTED, now, registrarId);
|
||||
DomainHistory domainHistory = buildDomainHistory(newDomain, tld, now);
|
||||
denyPendingTransfer(
|
||||
existingDomain, TransferStatus.CLIENT_REJECTED, toDateTime(now), registrarId);
|
||||
DomainHistory domainHistory = buildDomainHistory(newDomain, tld, toDateTime(now));
|
||||
tm().update(newDomain);
|
||||
tm().insertAll(
|
||||
domainHistory,
|
||||
createGainingTransferPollMessage(
|
||||
targetId, newDomain.getTransferData(), null, now, domainHistoryId));
|
||||
targetId, newDomain.getTransferData(), null, toDateTime(now), domainHistoryId));
|
||||
// Reopen the autorenew event and poll message that we closed for the implicit transfer. This
|
||||
// may end up recreating the poll message if it was deleted upon the transfer request.
|
||||
BillingRecurrence existingBillingRecurrence =
|
||||
|
||||
@@ -35,6 +35,8 @@ import static google.registry.flows.domain.DomainTransferUtils.createTransferSer
|
||||
import static google.registry.model.eppoutput.Result.Code.SUCCESS_WITH_ACTION_PENDING;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -80,6 +82,7 @@ import google.registry.model.transfer.DomainTransferData.TransferServerApproveEn
|
||||
import google.registry.model.transfer.TransferResponse.DomainTransferResponse;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@@ -230,7 +233,9 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
Domain domainAtTransferTime = existingDomain.cloneProjectedAtTime(automaticTransferTime);
|
||||
// The new expiration time if there is a server approval.
|
||||
DateTime serverApproveNewExpirationTime =
|
||||
computeExDateForApprovalTime(domainAtTransferTime, automaticTransferTime, period);
|
||||
toDateTime(
|
||||
computeExDateForApprovalTime(
|
||||
domainAtTransferTime, toInstant(automaticTransferTime), period));
|
||||
// Create speculative entities in anticipation of an automatic server approval.
|
||||
ImmutableSet<TransferServerApproveEntity> serverApproveEntities =
|
||||
createTransferServerApproveEntities(
|
||||
@@ -287,7 +292,7 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
tm().insertAll(domainHistory, requestPollMessage);
|
||||
return responseBuilder
|
||||
.setResultFromCode(SUCCESS_WITH_ACTION_PENDING)
|
||||
.setResData(createResponse(period, existingDomain, newDomain, now))
|
||||
.setResData(createResponse(period, existingDomain, newDomain, toInstant(now)))
|
||||
.setExtensions(createResponseExtensions(feesAndCredits, feeTransfer))
|
||||
.build();
|
||||
}
|
||||
@@ -375,14 +380,14 @@ public final class DomainTransferRequestFlow implements MutatingFlow {
|
||||
}
|
||||
|
||||
private DomainTransferResponse createResponse(
|
||||
Period period, Domain existingDomain, Domain newDomain, DateTime now) {
|
||||
Period period, Domain existingDomain, Domain newDomain, Instant now) {
|
||||
// If the registration were approved this instant, this is what the new expiration would be,
|
||||
// because we cap at 10 years from the moment of approval. This is different from the server
|
||||
// approval new expiration time, which is capped at 10 years from the server approve time.
|
||||
DateTime approveNowExtendedRegistrationTime =
|
||||
Instant approveNowExtendedRegistrationTime =
|
||||
computeExDateForApprovalTime(existingDomain, now, period);
|
||||
return createTransferResponse(
|
||||
targetId, newDomain.getTransferData(), approveNowExtendedRegistrationTime);
|
||||
targetId, newDomain.getTransferData(), toDateTime(approveNowExtendedRegistrationTime));
|
||||
}
|
||||
|
||||
private static ImmutableList<FeeTransformResponseExtension> createResponseExtensions(
|
||||
|
||||
@@ -184,7 +184,7 @@ public final class DomainTransferUtils {
|
||||
HistoryEntryId domainHistoryId) {
|
||||
return new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId(transferData.getGainingRegistrarId())
|
||||
.setEventTime(transferData.getPendingTransferExpirationTime())
|
||||
.setEventTime(transferData.getPendingTransferExpirationDateTime())
|
||||
.setMsg(transferData.getTransferStatus().getMessage())
|
||||
.setResponseData(
|
||||
ImmutableList.of(
|
||||
@@ -206,7 +206,7 @@ public final class DomainTransferUtils {
|
||||
HistoryEntryId domainHistoryId) {
|
||||
return new PollMessage.OneTime.Builder()
|
||||
.setRegistrarId(transferData.getLosingRegistrarId())
|
||||
.setEventTime(transferData.getPendingTransferExpirationTime())
|
||||
.setEventTime(transferData.getPendingTransferExpirationDateTime())
|
||||
.setMsg(transferData.getTransferStatus().getMessage())
|
||||
.setResponseData(
|
||||
ImmutableList.of(
|
||||
@@ -224,7 +224,7 @@ public final class DomainTransferUtils {
|
||||
.setDomainName(targetId)
|
||||
.setGainingRegistrarId(transferData.getGainingRegistrarId())
|
||||
.setLosingRegistrarId(transferData.getLosingRegistrarId())
|
||||
.setPendingTransferExpirationTime(transferData.getPendingTransferExpirationTime())
|
||||
.setPendingTransferExpirationTime(transferData.getPendingTransferExpirationDateTime())
|
||||
.setTransferRequestTime(transferData.getTransferRequestTime())
|
||||
.setTransferStatus(transferData.getTransferStatus())
|
||||
.setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime)
|
||||
|
||||
@@ -281,7 +281,7 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
if (superuserExt.get().getAutorenews().isPresent()) {
|
||||
boolean autorenews = superuserExt.get().getAutorenews().get();
|
||||
domainBuilder.setAutorenewEndTime(
|
||||
Optional.ofNullable(autorenews ? null : domain.getRegistrationExpirationTime()));
|
||||
Optional.ofNullable(autorenews ? null : domain.getRegistrationExpirationDateTime()));
|
||||
}
|
||||
}
|
||||
return domainBuilder.build();
|
||||
|
||||
@@ -99,7 +99,7 @@ public final class HostInfoFlow implements TransactionalFlow {
|
||||
.setCreationRegistrarId(host.getCreationRegistrarId())
|
||||
.setCreationTime(host.getCreationTime())
|
||||
.setLastEppUpdateRegistrarId(host.getLastEppUpdateRegistrarId())
|
||||
.setLastEppUpdateTime(host.getLastEppUpdateTime())
|
||||
.setLastEppUpdateTime(host.getLastEppUpdateDateTime())
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.keyring;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
@@ -21,7 +22,6 @@ import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.api.Keyring;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyring;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
|
||||
/** Dagger module for {@link Keyring} */
|
||||
@Module
|
||||
@@ -38,9 +38,10 @@ public abstract class KeyringModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("cloudSqlReplicaInstanceConnectionName")
|
||||
public static Optional<String> provideCloudSqlReplicaInstanceConnectionName(Keyring keyring) {
|
||||
return Optional.ofNullable(keyring.getSqlReplicaConnectionName());
|
||||
@Config("cloudSqlReplicaInstanceConnectionNames")
|
||||
public static ImmutableList<String> provideCloudSqlReplicaInstanceConnectionNames(
|
||||
Keyring keyring) {
|
||||
return ImmutableList.copyOf(keyring.getSqlReplicaConnectionNames());
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.keyring.api;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||
@@ -151,9 +152,17 @@ public interface Keyring extends AutoCloseable {
|
||||
/** Returns the Cloud SQL connection name of the primary database instance. */
|
||||
String getSqlPrimaryConnectionName();
|
||||
|
||||
/** Returns the Cloud SQL connection name of the replica database instance. */
|
||||
/**
|
||||
* Returns the Cloud SQL connection name of the replica database instance.
|
||||
*
|
||||
* <p>Note: It is likely a better idea to use multiple replicas and {@link
|
||||
* #getSqlReplicaConnectionNames()} instead.
|
||||
*/
|
||||
String getSqlReplicaConnectionName();
|
||||
|
||||
/** Returns the Cloud SQL connection names of the replica database instances. */
|
||||
ImmutableList<String> getSqlReplicaConnectionNames();
|
||||
|
||||
// Don't throw so try-with-resources works better.
|
||||
@Override
|
||||
void close();
|
||||
|
||||
@@ -17,6 +17,8 @@ package google.registry.keyring.secretmanager;
|
||||
import static com.google.common.base.CaseFormat.LOWER_HYPHEN;
|
||||
import static com.google.common.base.CaseFormat.UPPER_UNDERSCORE;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.keyring.api.KeySerializer;
|
||||
import google.registry.keyring.api.Keyring;
|
||||
import google.registry.keyring.api.KeyringException;
|
||||
@@ -66,7 +68,8 @@ public class SecretManagerKeyring implements Keyring {
|
||||
RDE_SSH_CLIENT_PUBLIC_STRING,
|
||||
SAFE_BROWSING_API_KEY,
|
||||
SQL_PRIMARY_CONN_NAME,
|
||||
SQL_REPLICA_CONN_NAME;
|
||||
SQL_REPLICA_CONN_NAME,
|
||||
SQL_REPLICA_CONN_NAMES;
|
||||
|
||||
String getLabel() {
|
||||
return UPPER_UNDERSCORE.to(LOWER_HYPHEN, name());
|
||||
@@ -157,7 +160,25 @@ public class SecretManagerKeyring implements Keyring {
|
||||
|
||||
@Override
|
||||
public String getSqlReplicaConnectionName() {
|
||||
return getString(StringKeyLabel.SQL_REPLICA_CONN_NAME);
|
||||
try {
|
||||
return getString(StringKeyLabel.SQL_REPLICA_CONN_NAME);
|
||||
} catch (KeyringException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableList<String> getSqlReplicaConnectionNames() {
|
||||
try {
|
||||
String names = getString(StringKeyLabel.SQL_REPLICA_CONN_NAMES);
|
||||
return ImmutableList.copyOf(
|
||||
Splitter.on('\n').trimResults().omitEmptyStrings().splitToList(names));
|
||||
} catch (KeyringException e) {
|
||||
String replicaConnectionName = getSqlReplicaConnectionName();
|
||||
return replicaConnectionName == null
|
||||
? ImmutableList.of()
|
||||
: ImmutableList.of(replicaConnectionName);
|
||||
}
|
||||
}
|
||||
|
||||
/** No persistent resources are maintained for this Keyring implementation. */
|
||||
|
||||
+5
@@ -34,6 +34,7 @@ import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringK
|
||||
import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringKeyLabel.SAFE_BROWSING_API_KEY;
|
||||
import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringKeyLabel.SQL_PRIMARY_CONN_NAME;
|
||||
import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringKeyLabel.SQL_REPLICA_CONN_NAME;
|
||||
import static google.registry.keyring.secretmanager.SecretManagerKeyring.StringKeyLabel.SQL_REPLICA_CONN_NAMES;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
@@ -134,6 +135,10 @@ public final class SecretManagerKeyringUpdater {
|
||||
return setString(name, SQL_REPLICA_CONN_NAME);
|
||||
}
|
||||
|
||||
public SecretManagerKeyringUpdater setSqlReplicaConnectionNames(String names) {
|
||||
return setString(names, SQL_REPLICA_CONN_NAMES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the secrets in the Secret Manager.
|
||||
*
|
||||
|
||||
@@ -25,6 +25,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
@@ -45,6 +46,7 @@ import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import jakarta.persistence.Transient;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -163,10 +165,15 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||
return creationRegistrarId;
|
||||
}
|
||||
|
||||
public DateTime getLastEppUpdateTime() {
|
||||
@Deprecated
|
||||
public DateTime getLastEppUpdateDateTime() {
|
||||
return lastEppUpdateTime;
|
||||
}
|
||||
|
||||
public Instant getLastEppUpdateTime() {
|
||||
return toInstant(lastEppUpdateTime);
|
||||
}
|
||||
|
||||
public String getLastEppUpdateRegistrarId() {
|
||||
return lastEppUpdateRegistrarId;
|
||||
}
|
||||
@@ -185,13 +192,22 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||
return nullToEmptyImmutableCopy(statuses);
|
||||
}
|
||||
|
||||
public DateTime getDeletionTime() {
|
||||
@Deprecated
|
||||
public DateTime getDeletionDateTime() {
|
||||
return deletionTime;
|
||||
}
|
||||
|
||||
public Instant getDeletionTime() {
|
||||
return toInstant(deletionTime);
|
||||
}
|
||||
|
||||
/** Return a clone of the resource with timed status values modified using the given time. */
|
||||
@Deprecated
|
||||
public abstract EppResource cloneProjectedAtTime(DateTime now);
|
||||
|
||||
/** Return a clone of the resource with timed status values modified using the given time. */
|
||||
public abstract EppResource cloneProjectedAtInstant(Instant now);
|
||||
|
||||
/** Get the foreign key string for this resource. */
|
||||
public abstract String getForeignKey();
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import google.registry.model.transfer.DomainTransferData;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.persistence.VKey;
|
||||
import jakarta.persistence.Query;
|
||||
import java.time.Instant;
|
||||
import java.util.Comparator;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -83,7 +84,7 @@ public final class EppResourceUtils {
|
||||
* exclusive, which happily maps to the behavior of Interval.
|
||||
*/
|
||||
private static Interval getLifetime(EppResource resource) {
|
||||
return new Interval(resource.getCreationTime(), resource.getDeletionTime());
|
||||
return new Interval(resource.getCreationTime(), resource.getDeletionDateTime());
|
||||
}
|
||||
|
||||
public static boolean isActive(EppResource resource, DateTime time) {
|
||||
@@ -108,7 +109,7 @@ public final class EppResourceUtils {
|
||||
builder
|
||||
.removeStatusValue(StatusValue.PENDING_TRANSFER)
|
||||
.setTransferData(transferDataBuilder.build())
|
||||
.setLastTransferTime(transferData.getPendingTransferExpirationTime())
|
||||
.setLastTransferTime(transferData.getPendingTransferExpirationDateTime())
|
||||
.setPersistedCurrentSponsorRegistrarId(transferData.getGainingRegistrarId());
|
||||
}
|
||||
|
||||
@@ -120,10 +121,10 @@ public final class EppResourceUtils {
|
||||
* </ul>
|
||||
*/
|
||||
public static void projectResourceOntoBuilderAtTime(
|
||||
DomainBase domain, DomainBase.Builder<?, ?> builder, DateTime now) {
|
||||
DomainBase domain, DomainBase.Builder<?, ?> builder, Instant now) {
|
||||
DomainTransferData transferData = domain.getTransferData();
|
||||
// If there's a pending transfer that has expired, process it.
|
||||
DateTime expirationTime = transferData.getPendingTransferExpirationTime();
|
||||
Instant expirationTime = transferData.getPendingTransferExpirationTime();
|
||||
if (TransferStatus.PENDING.equals(transferData.getTransferStatus())
|
||||
&& isBeforeOrAt(expirationTime, now)) {
|
||||
setAutomaticTransferSuccessProperties(builder, transferData);
|
||||
|
||||
@@ -35,6 +35,7 @@ import google.registry.persistence.VKey;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.util.NonFinalForTesting;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -81,6 +82,7 @@ public final class ForeignKeyUtils {
|
||||
* <p>Returns null if no resource with this foreign key was ever created or if the most recently
|
||||
* created resource was deleted before time "now".
|
||||
*/
|
||||
@Deprecated
|
||||
public static <E extends EppResource> Optional<E> loadResource(
|
||||
Class<E> clazz, String foreignKey, DateTime now) {
|
||||
// Note: no need to project to "now" because loadResources already does
|
||||
@@ -88,6 +90,19 @@ public final class ForeignKeyUtils {
|
||||
loadResources(clazz, ImmutableList.of(foreignKey), now).get(foreignKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an {@link EppResource} from the database by foreign key.
|
||||
*
|
||||
* <p>Returns null if no resource with this foreign key was ever created or if the most recently
|
||||
* created resource was deleted before time "now".
|
||||
*/
|
||||
public static <E extends EppResource> Optional<E> loadResource(
|
||||
Class<E> clazz, String foreignKey, Instant now) {
|
||||
// Note: no need to project to "now" because loadResources already does
|
||||
return Optional.ofNullable(
|
||||
loadResources(clazz, ImmutableList.of(foreignKey), now).get(foreignKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a map of {@link String} foreign keys to {@link VKey}s to {@link EppResource} that are
|
||||
* active at or after the specified moment in time.
|
||||
@@ -110,13 +125,29 @@ public final class ForeignKeyUtils {
|
||||
* or has been soft-deleted.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public static <E extends EppResource> ImmutableMap<String, E> loadResources(
|
||||
Class<E> clazz, Collection<String> foreignKeys, DateTime now) {
|
||||
return loadMostRecentResourceObjects(clazz, foreignKeys, false).entrySet().stream()
|
||||
.filter(e -> now.isBefore(e.getValue().getDeletionTime()))
|
||||
.filter(e -> now.isBefore(e.getValue().getDeletionDateTime()))
|
||||
.collect(toImmutableMap(Entry::getKey, e -> (E) e.getValue().cloneProjectedAtTime(now)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a map of {@link String} foreign keys to the {@link EppResource} that are active at or
|
||||
* after the specified moment in time.
|
||||
*
|
||||
* <p>The returned map will omit any foreign keys for which the {@link EppResource} doesn't exist
|
||||
* or has been soft-deleted.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E extends EppResource> ImmutableMap<String, E> loadResources(
|
||||
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)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to load {@link VKey}s to all the most recent {@link EppResource}s for the given
|
||||
* foreign keys, regardless of whether they have been soft-deleted.
|
||||
@@ -397,7 +428,7 @@ public final class ForeignKeyUtils {
|
||||
return (Optional<E>)
|
||||
foreignKeyToResourceCache
|
||||
.get(VKey.create(clazz, foreignKey))
|
||||
.filter(e -> now.isBefore(e.getDeletionTime()))
|
||||
.filter(e -> now.isBefore(e.getDeletionDateTime()))
|
||||
.map(e -> e.cloneProjectedAtTime(now));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,11 +50,11 @@ public final class ResourceTransferUtils {
|
||||
.setDomainName(domain.getForeignKey())
|
||||
.setExtendedRegistrationExpirationTime(
|
||||
ADD_EXDATE_STATUSES.contains(transferData.getTransferStatus())
|
||||
? transferData.getTransferredRegistrationExpirationTime()
|
||||
? transferData.getTransferredRegistrationExpirationDateTime()
|
||||
: null)
|
||||
.setGainingRegistrarId(transferData.getGainingRegistrarId())
|
||||
.setLosingRegistrarId(transferData.getLosingRegistrarId())
|
||||
.setPendingTransferExpirationTime(transferData.getPendingTransferExpirationTime())
|
||||
.setPendingTransferExpirationTime(transferData.getPendingTransferExpirationDateTime())
|
||||
.setTransferRequestTime(transferData.getTransferRequestTime())
|
||||
.setTransferStatus(transferData.getTransferStatus())
|
||||
.build();
|
||||
|
||||
@@ -104,7 +104,7 @@ public class BillingCancellation extends BillingBase {
|
||||
.setRegistrarId(gracePeriod.getRegistrarId())
|
||||
.setEventTime(eventTime)
|
||||
// The charge being cancelled will take place at the grace period's expiration time.
|
||||
.setBillingTime(gracePeriod.getExpirationTime())
|
||||
.setBillingTime(gracePeriod.getExpirationDateTime())
|
||||
.setDomainHistoryId(domainHistoryId);
|
||||
// Set the grace period's billing event using the appropriate Cancellation builder method.
|
||||
if (gracePeriod.getBillingEvent() != null) {
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package google.registry.model.domain;
|
||||
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.EppResource.ForeignKeyedEppResource;
|
||||
import google.registry.model.annotations.ExternalMessagingName;
|
||||
@@ -37,6 +39,7 @@ import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.JoinTable;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.time.Instant;
|
||||
import java.util.Set;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -153,6 +156,11 @@ public class Domain extends DomainBase implements ForeignKeyedEppResource {
|
||||
|
||||
@Override
|
||||
public Domain cloneProjectedAtTime(final DateTime now) {
|
||||
return cloneDomainProjectedAtTime(this, toInstant(now));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Domain cloneProjectedAtInstant(final Instant now) {
|
||||
return cloneDomainProjectedAtTime(this, now);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,9 +32,14 @@ import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.earliestOf;
|
||||
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
|
||||
import static google.registry.util.DateTimeUtils.leapSafeAddYears;
|
||||
import static google.registry.util.DateTimeUtils.plusYears;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static google.registry.util.DomainNameUtils.canonicalizeHostname;
|
||||
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
import static java.time.ZoneOffset.UTC;
|
||||
import static java.time.temporal.ChronoUnit.YEARS;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
@@ -79,13 +84,13 @@ import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import jakarta.persistence.Transient;
|
||||
import java.time.Instant;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import org.hibernate.collection.spi.PersistentSet;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Interval;
|
||||
|
||||
/**
|
||||
* A persistable domain resource including mutable and non-mutable fields.
|
||||
@@ -285,10 +290,15 @@ public class DomainBase extends EppResource {
|
||||
return nullToEmptyImmutableCopy(subordinateHosts);
|
||||
}
|
||||
|
||||
public DateTime getRegistrationExpirationTime() {
|
||||
@Deprecated
|
||||
public DateTime getRegistrationExpirationDateTime() {
|
||||
return registrationExpirationTime;
|
||||
}
|
||||
|
||||
public Instant getRegistrationExpirationTime() {
|
||||
return toInstant(registrationExpirationTime);
|
||||
}
|
||||
|
||||
public VKey<OneTime> getDeletePollMessage() {
|
||||
return deletePollMessage;
|
||||
}
|
||||
@@ -436,6 +446,11 @@ public class DomainBase extends EppResource {
|
||||
|
||||
@Override
|
||||
public DomainBase cloneProjectedAtTime(final DateTime now) {
|
||||
return cloneDomainProjectedAtTime(this, toInstant(now));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainBase cloneProjectedAtInstant(final Instant now) {
|
||||
return cloneDomainProjectedAtTime(this, now);
|
||||
}
|
||||
|
||||
@@ -444,9 +459,9 @@ public class DomainBase extends EppResource {
|
||||
* parallels the logic in {@code DomainTransferApproveFlow} which handles explicit client
|
||||
* approvals.
|
||||
*/
|
||||
static <T extends DomainBase> T cloneDomainProjectedAtTime(T domain, DateTime now) {
|
||||
static <T extends DomainBase> T cloneDomainProjectedAtTime(T domain, Instant now) {
|
||||
DomainTransferData transferData = domain.getTransferData();
|
||||
DateTime transferExpirationTime = transferData.getPendingTransferExpirationTime();
|
||||
Instant transferExpirationTime = transferData.getPendingTransferExpirationTime();
|
||||
|
||||
// If there's a pending transfer that has expired, handle it.
|
||||
if (TransferStatus.PENDING.equals(transferData.getTransferStatus())
|
||||
@@ -459,7 +474,7 @@ public class DomainBase extends EppResource {
|
||||
T domainAtTransferTime =
|
||||
cloneDomainProjectedAtTime(domain, transferExpirationTime.minusMillis(1));
|
||||
|
||||
DateTime expirationDate = transferData.getTransferredRegistrationExpirationTime();
|
||||
Instant expirationDate = transferData.getTransferredRegistrationExpirationTime();
|
||||
if (expirationDate == null) {
|
||||
// Extend the registration by the correct number of years from the expiration time
|
||||
// that was current on the domain right before the transfer, capped at 10 years from
|
||||
@@ -478,7 +493,7 @@ public class DomainBase extends EppResource {
|
||||
Builder builder =
|
||||
domainAtTransferTime
|
||||
.asBuilder()
|
||||
.setRegistrationExpirationTime(expirationDate)
|
||||
.setRegistrationExpirationTime(toDateTime(expirationDate))
|
||||
// Set the speculatively-written new autorenew events as the domain's autorenew
|
||||
// events.
|
||||
.setAutorenewBillingEvent(transferData.getServerApproveAutorenewEvent())
|
||||
@@ -492,8 +507,8 @@ public class DomainBase extends EppResource {
|
||||
GracePeriod.create(
|
||||
GracePeriodStatus.TRANSFER,
|
||||
domain.getRepoId(),
|
||||
transferExpirationTime.plus(
|
||||
Tld.get(domain.getTld()).getTransferGracePeriodLength()),
|
||||
toDateTime(transferExpirationTime)
|
||||
.plus(Tld.get(domain.getTld()).getTransferGracePeriodLength()),
|
||||
transferData.getGainingRegistrarId(),
|
||||
transferData.getServerApproveBillingEvent())));
|
||||
} else {
|
||||
@@ -503,32 +518,33 @@ public class DomainBase extends EppResource {
|
||||
// Set all remaining transfer properties.
|
||||
setAutomaticTransferSuccessProperties(builder, transferData);
|
||||
builder
|
||||
.setLastEppUpdateTime(transferExpirationTime)
|
||||
.setLastEppUpdateTime(toDateTime(transferExpirationTime))
|
||||
.setLastEppUpdateRegistrarId(transferData.getGainingRegistrarId());
|
||||
// Finish projecting to now.
|
||||
return (T) builder.build().cloneProjectedAtTime(now);
|
||||
return (T) builder.build().cloneProjectedAtInstant(now);
|
||||
}
|
||||
|
||||
Optional<DateTime> newLastEppUpdateTime = Optional.empty();
|
||||
Optional<Instant> newLastEppUpdateTime = Optional.empty();
|
||||
|
||||
// There is no transfer. Do any necessary autorenews for active domains.
|
||||
|
||||
Builder builder = domain.asBuilder();
|
||||
if (isBeforeOrAt(domain.getRegistrationExpirationTime(), now)
|
||||
&& END_OF_TIME.equals(domain.getDeletionTime())) {
|
||||
&& END_OF_TIME.equals(domain.getDeletionDateTime())) {
|
||||
// Autorenew by the number of years between the old expiration time and now.
|
||||
DateTime lastAutorenewTime =
|
||||
Instant lastAutorenewTime =
|
||||
leapSafeAddYears(
|
||||
domain.getRegistrationExpirationTime(),
|
||||
new Interval(domain.getRegistrationExpirationTime(), now).toPeriod().getYears());
|
||||
DateTime newExpirationTime = lastAutorenewTime.plusYears(1);
|
||||
YEARS.between(domain.getRegistrationExpirationTime().atZone(UTC), now.atZone(UTC)));
|
||||
Instant newExpirationTime = plusYears(lastAutorenewTime, 1);
|
||||
builder
|
||||
.setRegistrationExpirationTime(newExpirationTime)
|
||||
.setRegistrationExpirationTime(toDateTime(newExpirationTime))
|
||||
.addGracePeriod(
|
||||
GracePeriod.createForRecurrence(
|
||||
GracePeriodStatus.AUTO_RENEW,
|
||||
domain.getRepoId(),
|
||||
lastAutorenewTime.plus(Tld.get(domain.getTld()).getAutoRenewGracePeriodLength()),
|
||||
toDateTime(lastAutorenewTime)
|
||||
.plus(Tld.get(domain.getTld()).getAutoRenewGracePeriodLength()),
|
||||
domain.getCurrentSponsorRegistrarId(),
|
||||
domain.getAutorenewBillingEvent()));
|
||||
newLastEppUpdateTime = Optional.of(lastAutorenewTime);
|
||||
@@ -551,10 +567,10 @@ public class DomainBase extends EppResource {
|
||||
// id, so we have to do the comparison instead of having one variable just storing the most
|
||||
// recent time.
|
||||
if (newLastEppUpdateTime.isPresent()) {
|
||||
if (domain.getLastEppUpdateTime() == null
|
||||
if (domain.getLastEppUpdateDateTime() == null
|
||||
|| newLastEppUpdateTime.get().isAfter(domain.getLastEppUpdateTime())) {
|
||||
builder
|
||||
.setLastEppUpdateTime(newLastEppUpdateTime.get())
|
||||
.setLastEppUpdateTime(toDateTime(newLastEppUpdateTime.get()))
|
||||
.setLastEppUpdateRegistrarId(domain.getCurrentSponsorRegistrarId());
|
||||
}
|
||||
}
|
||||
@@ -567,8 +583,8 @@ public class DomainBase extends EppResource {
|
||||
}
|
||||
|
||||
/** Return what the expiration time would be if the given number of years were added to it. */
|
||||
public static DateTime extendRegistrationWithCap(
|
||||
DateTime now, DateTime currentExpirationTime, @Nullable Integer extendedRegistrationYears) {
|
||||
public static Instant extendRegistrationWithCap(
|
||||
Instant now, Instant currentExpirationTime, @Nullable Integer extendedRegistrationYears) {
|
||||
// We must cap registration at the max years (aka 10), even if that truncates the last year.
|
||||
return earliestOf(
|
||||
leapSafeAddYears(
|
||||
@@ -826,16 +842,16 @@ public class DomainBase extends EppResource {
|
||||
.setDomainName(domainBase.getDomainName())
|
||||
.setDeletePollMessage(domainBase.getDeletePollMessage())
|
||||
.setDsData(domainBase.getDsData())
|
||||
.setDeletionTime(domainBase.getDeletionTime())
|
||||
.setDeletionTime(domainBase.getDeletionDateTime())
|
||||
.setGracePeriods(domainBase.getGracePeriods())
|
||||
.setIdnTableName(domainBase.getIdnTableName())
|
||||
.setLastTransferTime(domainBase.getLastTransferTime())
|
||||
.setLaunchNotice(domainBase.getLaunchNotice())
|
||||
.setLastEppUpdateRegistrarId(domainBase.getLastEppUpdateRegistrarId())
|
||||
.setLastEppUpdateTime(domainBase.getLastEppUpdateTime())
|
||||
.setLastEppUpdateTime(domainBase.getLastEppUpdateDateTime())
|
||||
.setNameservers(domainBase.getNameservers())
|
||||
.setPersistedCurrentSponsorRegistrarId(domainBase.getPersistedCurrentSponsorRegistrarId())
|
||||
.setRegistrationExpirationTime(domainBase.getRegistrationExpirationTime())
|
||||
.setRegistrationExpirationTime(domainBase.getRegistrationExpirationDateTime())
|
||||
.setRepoId(domainBase.getRepoId())
|
||||
.setSmdId(domainBase.getSmdId())
|
||||
.setSubordinateHosts(domainBase.getSubordinateHosts())
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package google.registry.model.domain;
|
||||
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.UnsafeSerializable;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
@@ -30,6 +32,7 @@ import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import jakarta.persistence.Transient;
|
||||
import java.time.Instant;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Base class containing common fields and methods for {@link GracePeriod}. */
|
||||
@@ -90,10 +93,15 @@ public class GracePeriodBase extends ImmutableObject implements UnsafeSerializab
|
||||
return domainRepoId;
|
||||
}
|
||||
|
||||
public DateTime getExpirationTime() {
|
||||
@Deprecated
|
||||
public DateTime getExpirationDateTime() {
|
||||
return expirationTime;
|
||||
}
|
||||
|
||||
public Instant getExpirationTime() {
|
||||
return toInstant(expirationTime);
|
||||
}
|
||||
|
||||
public String getRegistrarId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
package google.registry.model.eppcommon;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -28,7 +27,6 @@ import google.registry.model.domain.fee06.FeeInfoResponseExtensionV06;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import google.registry.xml.ValidationMode;
|
||||
import google.registry.xml.XmlException;
|
||||
import google.registry.xml.XmlTransformer;
|
||||
@@ -71,13 +69,9 @@ public class EppXmlTransformer {
|
||||
private static final XmlTransformer OUTPUT_TRANSFORMER =
|
||||
new XmlTransformer(getSchemas(), EppOutput.class);
|
||||
|
||||
// TODO(b/159033801): remove method and inline ALL_SCHEMA.
|
||||
@VisibleForTesting
|
||||
public static ImmutableList<String> getSchemas() {
|
||||
if (RegistryEnvironment.get().equals(RegistryEnvironment.PRODUCTION)) {
|
||||
return ALL_SCHEMAS.stream()
|
||||
.filter(s -> !NON_PROD_SCHEMAS.contains(s))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
return ALL_SCHEMAS;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import java.net.InetAddress;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -132,6 +133,11 @@ public class HostBase extends EppResource {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EppResource cloneProjectedAtInstant(Instant now) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<? extends HostBase, ?> asBuilder() {
|
||||
return new Builder<>(clone(this));
|
||||
@@ -232,13 +238,13 @@ public class HostBase extends EppResource {
|
||||
public B copyFrom(HostBase hostBase) {
|
||||
return setCreationRegistrarId(hostBase.getCreationRegistrarId())
|
||||
.setCreationTime(hostBase.getCreationTime())
|
||||
.setDeletionTime(hostBase.getDeletionTime())
|
||||
.setDeletionTime(hostBase.getDeletionDateTime())
|
||||
.setHostName(hostBase.getHostName())
|
||||
.setInetAddresses(hostBase.getInetAddresses())
|
||||
.setLastTransferTime(hostBase.getLastTransferTime())
|
||||
.setLastSuperordinateChange(hostBase.getLastSuperordinateChange())
|
||||
.setLastEppUpdateRegistrarId(hostBase.getLastEppUpdateRegistrarId())
|
||||
.setLastEppUpdateTime(hostBase.getLastEppUpdateTime())
|
||||
.setLastEppUpdateTime(hostBase.getLastEppUpdateDateTime())
|
||||
.setPersistedCurrentSponsorRegistrarId(hostBase.getPersistedCurrentSponsorRegistrarId())
|
||||
.setRepoId(hostBase.getRepoId())
|
||||
.setSuperordinateDomain(hostBase.getSuperordinateDomain())
|
||||
|
||||
@@ -437,7 +437,7 @@ public abstract class PollMessage extends ImmutableObject
|
||||
.setTransferStatus(transferResponse.getTransferStatus())
|
||||
.setTransferRequestTime(transferResponse.getTransferRequestTime())
|
||||
.setPendingTransferExpirationTime(
|
||||
transferResponse.getPendingTransferExpirationTime())
|
||||
transferResponse.getPendingTransferExpirationDateTime())
|
||||
.setExtendedRegistrationExpirationTime(extendedRegistrationExpirationTime)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -129,34 +129,31 @@ public final class PremiumListDao {
|
||||
|
||||
public static PremiumList save(String name, CurrencyUnit currencyUnit, List<String> inputData) {
|
||||
checkArgument(!inputData.isEmpty(), "New premium list data cannot be empty");
|
||||
return save(PremiumListUtils.parseToPremiumList(name, currencyUnit, inputData));
|
||||
tm().assertInTransaction();
|
||||
return save(
|
||||
PremiumListUtils.parseToPremiumList(
|
||||
name, currencyUnit, inputData, tm().getTransactionTime()));
|
||||
}
|
||||
|
||||
/** Saves the given premium list (and its premium list entries) to Cloud SQL. */
|
||||
public static PremiumList save(PremiumList premiumListToPersist) {
|
||||
PremiumList persisted =
|
||||
tm().transact(
|
||||
() -> {
|
||||
// Make a new copy in each attempt to insert. See javadoc of the insert method for
|
||||
// more information.
|
||||
PremiumList premiumList = premiumListToPersist.asBuilder().build();
|
||||
tm().insert(premiumList);
|
||||
tm().getEntityManager().flush(); // This populates the revisionId.
|
||||
long revisionId = premiumList.getRevisionId();
|
||||
tm().assertInTransaction();
|
||||
// Make a new copy in each attempt to insert. See javadoc of the insert method for
|
||||
// more information.
|
||||
PremiumList premiumList = premiumListToPersist.asBuilder().build();
|
||||
tm().insert(premiumList);
|
||||
tm().getEntityManager().flush(); // This populates the revisionId.
|
||||
long revisionId = premiumList.getRevisionId();
|
||||
|
||||
if (!isNullOrEmpty(premiumList.getLabelsToPrices())) {
|
||||
ImmutableSet.Builder<PremiumEntry> entries = new ImmutableSet.Builder<>();
|
||||
premiumList
|
||||
.getLabelsToPrices()
|
||||
.forEach(
|
||||
(key, value) ->
|
||||
entries.add(PremiumEntry.create(revisionId, value, key)));
|
||||
tm().insertAll(entries.build());
|
||||
}
|
||||
return premiumList;
|
||||
});
|
||||
premiumListCache.invalidate(persisted.getName());
|
||||
return persisted;
|
||||
if (!isNullOrEmpty(premiumList.getLabelsToPrices())) {
|
||||
ImmutableSet.Builder<PremiumEntry> entries = new ImmutableSet.Builder<>();
|
||||
premiumList
|
||||
.getLabelsToPrices()
|
||||
.forEach((key, value) -> entries.add(PremiumEntry.create(revisionId, value, key)));
|
||||
tm().insertAll(entries.build());
|
||||
}
|
||||
premiumListCache.invalidate(premiumList.getName());
|
||||
return premiumList;
|
||||
}
|
||||
|
||||
public static void delete(PremiumList premiumList) {
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
package google.registry.model.tld.label;
|
||||
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import google.registry.model.tld.label.PremiumList.PremiumEntry;
|
||||
@@ -29,12 +27,12 @@ import org.joda.time.DateTime;
|
||||
public class PremiumListUtils {
|
||||
|
||||
public static PremiumList parseToPremiumList(
|
||||
String name, CurrencyUnit currencyUnit, List<String> inputData) {
|
||||
String name, CurrencyUnit currencyUnit, List<String> inputData, DateTime creationTime) {
|
||||
PremiumList partialPremiumList =
|
||||
new PremiumList.Builder()
|
||||
.setName(name)
|
||||
.setCurrency(currencyUnit)
|
||||
.setCreationTimestamp(DateTime.now(UTC))
|
||||
.setCreationTimestamp(creationTime)
|
||||
.build();
|
||||
ImmutableMap<String, PremiumEntry> prices = partialPremiumList.parse(inputData);
|
||||
Map<String, BigDecimal> priceAmounts = Maps.transformValues(prices, PremiumEntry::getValue);
|
||||
|
||||
@@ -24,10 +24,10 @@ import static google.registry.model.tld.label.ReservationType.FULLY_BLOCKED;
|
||||
import static google.registry.persistence.transaction.QueryComposer.Comparator.EQ;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
@@ -47,7 +47,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A list of reserved domain labels that are blocked from being registered for various reasons.
|
||||
@@ -234,7 +233,7 @@ public final class ReservedList
|
||||
*/
|
||||
private static ImmutableSet<ReservedListEntry> getReservedListEntries(
|
||||
String label, String tldStr) {
|
||||
DateTime startTime = DateTime.now(UTC);
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
Tld tld = Tld.get(checkNotNull(tldStr, "tld must not be null"));
|
||||
ImmutableSet.Builder<ReservedListEntry> entriesBuilder = new ImmutableSet.Builder<>();
|
||||
ImmutableSet.Builder<MetricsReservedListMatch> metricMatchesBuilder =
|
||||
@@ -251,9 +250,7 @@ public final class ReservedList
|
||||
}
|
||||
ImmutableSet<ReservedListEntry> entries = entriesBuilder.build();
|
||||
DomainLabelMetrics.recordReservedListCheckOutcome(
|
||||
tldStr,
|
||||
metricMatchesBuilder.build(),
|
||||
DateTime.now(UTC).getMillis() - startTime.getMillis());
|
||||
tldStr, metricMatchesBuilder.build(), stopwatch.elapsed().toMillis());
|
||||
return entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
package google.registry.model.transfer;
|
||||
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import google.registry.model.Buildable.GenericBuilder;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.UnsafeSerializable;
|
||||
@@ -23,6 +25,7 @@ import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import jakarta.xml.bind.annotation.XmlElement;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import java.time.Instant;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Fields common to {@link DomainTransferData} and {@link TransferResponse}. */
|
||||
@@ -73,10 +76,15 @@ public abstract class BaseTransferObject extends ImmutableObject implements Unsa
|
||||
return losingClientId;
|
||||
}
|
||||
|
||||
public DateTime getPendingTransferExpirationTime() {
|
||||
@Deprecated
|
||||
public DateTime getPendingTransferExpirationDateTime() {
|
||||
return pendingTransferExpirationTime;
|
||||
}
|
||||
|
||||
public Instant getPendingTransferExpirationTime() {
|
||||
return toInstant(pendingTransferExpirationTime);
|
||||
}
|
||||
|
||||
/** Base class for builders of {@link BaseTransferObject} subclasses. */
|
||||
public abstract static class Builder<T extends BaseTransferObject, B extends Builder<?, ?>>
|
||||
extends GenericBuilder<T, B> {
|
||||
|
||||
@@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||
import static google.registry.util.CollectionUtils.nullToEmpty;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -41,6 +42,7 @@ import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Convert;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Embedded;
|
||||
import java.time.Instant;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
@@ -168,10 +170,16 @@ public class DomainTransferData extends BaseTransferObject implements Buildable
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DateTime getTransferredRegistrationExpirationTime() {
|
||||
@Deprecated
|
||||
public DateTime getTransferredRegistrationExpirationDateTime() {
|
||||
return transferredRegistrationExpirationTime;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Instant getTransferredRegistrationExpirationTime() {
|
||||
return toInstant(transferredRegistrationExpirationTime);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public VKey<BillingEvent> getServerApproveBillingEvent() {
|
||||
return serverApproveBillingEvent;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.config.RegistryConfig.getHibernateConnectionIsolation;
|
||||
import static google.registry.config.RegistryConfig.getHibernateHikariConnectionTimeout;
|
||||
import static google.registry.config.RegistryConfig.getHibernateHikariIdleTimeout;
|
||||
@@ -28,6 +29,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
|
||||
import com.google.auth.oauth2.GoogleCredentials;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import dagger.BindsOptionalOf;
|
||||
@@ -36,6 +38,7 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.persistence.transaction.CloudSqlCredentialSupplier;
|
||||
import google.registry.persistence.transaction.DelegatingReplicaJpaTransactionManager;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.persistence.transaction.JpaTransactionManagerImpl;
|
||||
import google.registry.persistence.transaction.TransactionManager;
|
||||
@@ -59,6 +62,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
import org.hibernate.cfg.Environment;
|
||||
@@ -264,16 +268,13 @@ public abstract class PersistenceModule {
|
||||
static JpaTransactionManager provideReadOnlyReplicaJpaTm(
|
||||
SqlCredentialStore credentialStore,
|
||||
@PartialCloudSqlConfigs ImmutableMap<String, String> cloudSqlConfigs,
|
||||
@Config("cloudSqlReplicaInstanceConnectionName")
|
||||
Optional<String> replicaInstanceConnectionName,
|
||||
Clock clock) {
|
||||
@Config("cloudSqlReplicaInstanceConnectionNames")
|
||||
ImmutableList<String> replicaInstanceConnectionNames,
|
||||
Clock clock,
|
||||
Random random) {
|
||||
HashMap<String, String> overrides = Maps.newHashMap(cloudSqlConfigs);
|
||||
setSqlCredential(credentialStore, new RobotUser(RobotId.NOMULUS), overrides);
|
||||
replicaInstanceConnectionName.ifPresent(
|
||||
name -> overrides.put(HIKARI_DS_CLOUD_SQL_INSTANCE, name));
|
||||
overrides.put(
|
||||
Environment.ISOLATION, TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ.name());
|
||||
return new JpaTransactionManagerImpl(create(overrides), clock, true);
|
||||
return createReplicaJpaTm(overrides, replicaInstanceConnectionNames, clock, random);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -281,15 +282,34 @@ public abstract class PersistenceModule {
|
||||
@BeamReadOnlyReplicaJpaTm
|
||||
static JpaTransactionManager provideBeamReadOnlyReplicaJpaTm(
|
||||
@BeamPipelineCloudSqlConfigs ImmutableMap<String, String> beamCloudSqlConfigs,
|
||||
@Config("cloudSqlReplicaInstanceConnectionName")
|
||||
Optional<String> replicaInstanceConnectionName,
|
||||
Clock clock) {
|
||||
@Config("cloudSqlReplicaInstanceConnectionNames")
|
||||
ImmutableList<String> replicaInstanceConnectionNames,
|
||||
Clock clock,
|
||||
Random random) {
|
||||
HashMap<String, String> overrides = Maps.newHashMap(beamCloudSqlConfigs);
|
||||
replicaInstanceConnectionName.ifPresent(
|
||||
name -> overrides.put(HIKARI_DS_CLOUD_SQL_INSTANCE, name));
|
||||
overrides.put(
|
||||
return createReplicaJpaTm(overrides, replicaInstanceConnectionNames, clock, random);
|
||||
}
|
||||
|
||||
private static JpaTransactionManager createReplicaJpaTm(
|
||||
Map<String, String> baseOverrides,
|
||||
ImmutableList<String> replicaInstanceConnectionNames,
|
||||
Clock clock,
|
||||
Random random) {
|
||||
baseOverrides.put(
|
||||
Environment.ISOLATION, TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ.name());
|
||||
return new JpaTransactionManagerImpl(create(overrides), clock, true);
|
||||
if (replicaInstanceConnectionNames.isEmpty()) {
|
||||
return new JpaTransactionManagerImpl(create(baseOverrides), clock, true);
|
||||
}
|
||||
ImmutableList<JpaTransactionManager> replicas =
|
||||
replicaInstanceConnectionNames.stream()
|
||||
.map(
|
||||
name -> {
|
||||
HashMap<String, String> overrides = Maps.newHashMap(baseOverrides);
|
||||
overrides.put(HIKARI_DS_CLOUD_SQL_INSTANCE, name);
|
||||
return new JpaTransactionManagerImpl(create(overrides), clock, true);
|
||||
})
|
||||
.collect(toImmutableList());
|
||||
return new DelegatingReplicaJpaTransactionManager(replicas, random);
|
||||
}
|
||||
|
||||
/** Constructs the {@link EntityManagerFactory} instance. */
|
||||
|
||||
+361
@@ -0,0 +1,361 @@
|
||||
// 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.persistence.transaction;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||
import google.registry.persistence.VKey;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.Query;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.metamodel.Metamodel;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* A {@link JpaTransactionManager} that load-balances across multiple read-only replicas.
|
||||
*
|
||||
* <p>For each top-level transaction, one replica is chosen and used for the duration of the
|
||||
* transaction. For non-transactional methods, a replica is chosen for each call.
|
||||
*/
|
||||
public class DelegatingReplicaJpaTransactionManager implements JpaTransactionManager {
|
||||
|
||||
private final ImmutableList<JpaTransactionManager> replicas;
|
||||
private final Random random;
|
||||
private static final AtomicLong nextId = new AtomicLong(1);
|
||||
|
||||
private static final ThreadLocal<JpaTransactionManager> activeReplica = new ThreadLocal<>();
|
||||
|
||||
public DelegatingReplicaJpaTransactionManager(
|
||||
ImmutableList<JpaTransactionManager> replicas, Random random) {
|
||||
checkArgument(!replicas.isEmpty(), "At least one replica must be provided");
|
||||
this.replicas = replicas;
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
private JpaTransactionManager getReplica() {
|
||||
JpaTransactionManager replica = activeReplica.get();
|
||||
if (replica != null) {
|
||||
return replica;
|
||||
}
|
||||
return getRandomReplica();
|
||||
}
|
||||
|
||||
private <T> T runMaybeAssigningReplica(Function<JpaTransactionManager, T> work) {
|
||||
JpaTransactionManager existing = activeReplica.get();
|
||||
if (existing != null) {
|
||||
return work.apply(existing);
|
||||
}
|
||||
JpaTransactionManager replica = getRandomReplica();
|
||||
activeReplica.set(replica);
|
||||
try {
|
||||
return work.apply(replica);
|
||||
} finally {
|
||||
activeReplica.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private JpaTransactionManager getRandomReplica() {
|
||||
return replicas.get(random.nextInt(replicas.size()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inTransaction() {
|
||||
var replica = activeReplica.get();
|
||||
return replica != null && replica.inTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertInTransaction() {
|
||||
JpaTransactionManager replica = activeReplica.get();
|
||||
if (replica == null) {
|
||||
throw new IllegalStateException("Not in a transaction");
|
||||
}
|
||||
replica.assertInTransaction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long allocateId() {
|
||||
return nextId.getAndIncrement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transact(Callable<T> work) {
|
||||
return transact(null, work, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transact(TransactionIsolationLevel isolationLevel, Callable<T> work) {
|
||||
return transact(isolationLevel, work, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transactNoRetry(Callable<T> work) {
|
||||
return transactNoRetry(null, work, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transactNoRetry(TransactionIsolationLevel isolationLevel, Callable<T> work) {
|
||||
return transactNoRetry(isolationLevel, work, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T reTransact(Callable<T> work) {
|
||||
return runMaybeAssigningReplica(replica -> replica.reTransact(work));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transact(ThrowingRunnable work) {
|
||||
transact(
|
||||
() -> {
|
||||
work.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transact(TransactionIsolationLevel isolationLevel, ThrowingRunnable work) {
|
||||
transact(
|
||||
isolationLevel,
|
||||
() -> {
|
||||
work.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reTransact(ThrowingRunnable work) {
|
||||
reTransact(
|
||||
() -> {
|
||||
work.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime getTransactionTime() {
|
||||
return getReplica().getTransactionTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getTxTime() {
|
||||
return getReplica().getTxTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(Object entity) {
|
||||
getReplica().insert(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAll(ImmutableCollection<?> entities) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertAll(ImmutableObject... entities) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(Object entity) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(ImmutableObject... entities) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(ImmutableCollection<?> entities) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Object entity) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAll(ImmutableCollection<?> entities) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAll(ImmutableObject... entities) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(Object entity) {
|
||||
return getReplica().exists(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean exists(VKey<T> key) {
|
||||
return getReplica().exists(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> loadByKeyIfPresent(VKey<T> key) {
|
||||
return getReplica().loadByKeyIfPresent(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ImmutableMap<VKey<? extends T>, T> loadByKeysIfPresent(
|
||||
Iterable<? extends VKey<? extends T>> keys) {
|
||||
return getReplica().loadByKeysIfPresent(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ImmutableList<T> loadByEntitiesIfPresent(Iterable<T> entities) {
|
||||
return getReplica().loadByEntitiesIfPresent(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T loadByKey(VKey<T> key) {
|
||||
return getReplica().loadByKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ImmutableMap<VKey<? extends T>, T> loadByKeys(
|
||||
Iterable<? extends VKey<? extends T>> keys) {
|
||||
return getReplica().loadByKeys(keys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T loadByEntity(T entity) {
|
||||
return getReplica().loadByEntity(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ImmutableList<T> loadByEntities(Iterable<T> entities) {
|
||||
return getReplica().loadByEntities(entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ImmutableList<T> loadAllOf(Class<T> clazz) {
|
||||
return getReplica().loadAllOf(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Stream<T> loadAllOfStream(Class<T> clazz) {
|
||||
return getReplica().loadAllOfStream(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> loadSingleton(Class<T> clazz) {
|
||||
return getReplica().loadSingleton(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(VKey<?> key) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Iterable<? extends VKey<?>> keys) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T delete(T entity) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> QueryComposer<T> createQueryComposer(Class<T> entity) {
|
||||
return getReplica().createQueryComposer(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityManager getStandaloneEntityManager() {
|
||||
return getReplica().getStandaloneEntityManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Metamodel getMetaModel() {
|
||||
return getReplica().getMetaModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityManager getEntityManager() {
|
||||
return getReplica().getEntityManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TypedQuery<T> query(String sqlString, Class<T> resultClass) {
|
||||
return getReplica().query(sqlString, resultClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TypedQuery<T> criteriaQuery(CriteriaQuery<T> criteriaQuery) {
|
||||
return getReplica().criteriaQuery(criteriaQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query query(String sqlString) {
|
||||
return getReplica().query(sqlString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void assertDelete(VKey<T> key) {
|
||||
throw new UnsupportedOperationException("This is a replica database");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void teardown() {
|
||||
for (JpaTransactionManager replica : replicas) {
|
||||
replica.teardown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionIsolationLevel getDefaultTransactionIsolationLevel() {
|
||||
return replicas.get(0).getDefaultTransactionIsolationLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionIsolationLevel getCurrentTransactionIsolationLevel() {
|
||||
return getReplica().getCurrentTransactionIsolationLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transact(
|
||||
TransactionIsolationLevel isolationLevel, Callable<T> work, boolean logSqlStatements) {
|
||||
return runMaybeAssigningReplica(
|
||||
replica -> replica.transact(isolationLevel, work, logSqlStatements));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T transactNoRetry(
|
||||
TransactionIsolationLevel isolationLevel, Callable<T> work, boolean logSqlStatements) {
|
||||
return runMaybeAssigningReplica(
|
||||
replica -> replica.transactNoRetry(isolationLevel, work, logSqlStatements));
|
||||
}
|
||||
}
|
||||
+9
-2
@@ -21,6 +21,7 @@ import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.config.RegistryConfig.getHibernateAllowNestedTransactions;
|
||||
import static google.registry.persistence.transaction.DatabaseException.throwIfSqlException;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
import static java.util.AbstractMap.SimpleEntry;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
@@ -61,6 +62,7 @@ import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Instant;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@@ -340,6 +342,11 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
|
||||
@Override
|
||||
public DateTime getTransactionTime() {
|
||||
return toDateTime(getTxTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getTxTime() {
|
||||
assertInTransaction();
|
||||
TransactionInfo txnInfo = transactionInfo.get();
|
||||
if (txnInfo.transactionTime == null) {
|
||||
@@ -746,7 +753,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
private static class TransactionInfo {
|
||||
EntityManager entityManager;
|
||||
boolean inTransaction = false;
|
||||
DateTime transactionTime;
|
||||
Instant transactionTime;
|
||||
Supplier<Long> idProvider;
|
||||
|
||||
// The set of entity objects that have been either persisted (via insert()) or merged (via
|
||||
@@ -759,7 +766,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
private void start(Clock clock, Supplier<Long> idProvider) {
|
||||
checkArgumentNotNull(clock);
|
||||
inTransaction = true;
|
||||
transactionTime = clock.nowUtc();
|
||||
transactionTime = clock.now();
|
||||
this.idProvider = idProvider;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.time.Instant;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -49,7 +50,7 @@ public interface TransactionManager {
|
||||
void assertInTransaction();
|
||||
|
||||
/**
|
||||
* Returns a {@link long} value that can be used as {@code id} by a JPA model entity.
|
||||
* Returns a {@code long} value that can be used as {@code id} by a JPA model entity.
|
||||
*
|
||||
* <p>The returned value must be project-wide unique when transacting on the primary database
|
||||
* instance, but only needs to be unique within a JVM instance when transacting on the replica
|
||||
@@ -129,8 +130,12 @@ public interface TransactionManager {
|
||||
void reTransact(ThrowingRunnable work);
|
||||
|
||||
/** Returns the time associated with the start of this particular transaction attempt. */
|
||||
@Deprecated
|
||||
DateTime getTransactionTime();
|
||||
|
||||
/** Returns the Instant associated with the start of this particular transaction attempt. */
|
||||
Instant getTxTime();
|
||||
|
||||
/** Persists a new entity in the database, throws exception if the entity already exists. */
|
||||
void insert(Object entity);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.rdap;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;
|
||||
import static google.registry.request.Actions.getPathForAction;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static google.registry.util.DomainNameUtils.canonicalizeHostname;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
@@ -241,7 +242,7 @@ public abstract class RdapActionBase implements Runnable {
|
||||
* is authorized to do so.
|
||||
*/
|
||||
boolean isAuthorized(EppResource eppResource) {
|
||||
return getRequestTime().isBefore(eppResource.getDeletionTime())
|
||||
return toInstant(getRequestTime()).isBefore(eppResource.getDeletionTime())
|
||||
|| (shouldIncludeDeleted()
|
||||
&& rdapAuthorization.isAuthorizedForRegistrar(
|
||||
eppResource.getPersistedCurrentSponsorRegistrarId()));
|
||||
|
||||
@@ -20,6 +20,8 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.model.EppResourceUtils.isLinked;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
@@ -47,6 +49,7 @@ import google.registry.model.registrar.RegistrarAddress;
|
||||
import google.registry.model.registrar.RegistrarPoc;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.HistoryEntryDao;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.rdap.RdapDataStructures.Event;
|
||||
import google.registry.rdap.RdapDataStructures.EventAction;
|
||||
import google.registry.rdap.RdapDataStructures.Link;
|
||||
@@ -113,6 +116,10 @@ public class RdapJsonFormatter {
|
||||
@Nullable
|
||||
String rdapTosStaticUrl;
|
||||
|
||||
@Inject
|
||||
@Config("rdapIncludeOptionalHistoryResults")
|
||||
boolean rdapIncludeOptionalHistoryResults;
|
||||
|
||||
@Inject @RequestServerName String serverName;
|
||||
@Inject RdapAuthorization rdapAuthorization;
|
||||
@Inject Clock clock;
|
||||
@@ -317,7 +324,7 @@ public class RdapJsonFormatter {
|
||||
.build(),
|
||||
Event.builder()
|
||||
.setEventAction(EventAction.EXPIRATION)
|
||||
.setEventDate(domain.getRegistrationExpirationTime())
|
||||
.setEventDate(domain.getRegistrationExpirationDateTime())
|
||||
.build(),
|
||||
// RDAP response profile section 1.5:
|
||||
// The topmost object in the RDAP response MUST contain an event of "eventAction" type
|
||||
@@ -327,9 +334,27 @@ public class RdapJsonFormatter {
|
||||
.setEventAction(EventAction.LAST_UPDATE_OF_RDAP_DATABASE)
|
||||
.setEventDate(getRequestTime())
|
||||
.build());
|
||||
// RDAP Response Profile section 2.3.2.2:
|
||||
// "The event of eventAction type last changed MUST be omitted if the domain has not been
|
||||
// updated since it was created." While it is possible for the domain to be changed out of band
|
||||
// (i.e. without updating lastEppUpdateTime), that can only happen for domains that have already
|
||||
// been modified in some way. As a result, we can ignore those cases here.
|
||||
if (domain.getLastEppUpdateTime() != null
|
||||
&& domain.getLastEppUpdateTime().isAfter(toInstant(domain.getCreationTime()))) {
|
||||
// Creates an RDAP event object as defined by RFC 9083
|
||||
builder
|
||||
.eventsBuilder()
|
||||
.add(
|
||||
Event.builder()
|
||||
.setEventAction(EventAction.LAST_CHANGED)
|
||||
.setEventDate(toDateTime(domain.getLastEppUpdateTime()))
|
||||
.build());
|
||||
}
|
||||
// RDAP Response Profile section 2.3.2 discusses optional events. We add some of those
|
||||
// here. We also add a few others we find interesting.
|
||||
builder.eventsBuilder().addAll(makeOptionalEvents(domain));
|
||||
if (rdapIncludeOptionalHistoryResults) {
|
||||
builder.eventsBuilder().addAll(makeOptionalEvents(domain));
|
||||
}
|
||||
// RDAP Response Profile section 2.4.1:
|
||||
// The domain object in the RDAP response MUST contain an entity with the Registrar role.
|
||||
//
|
||||
@@ -352,27 +377,36 @@ public class RdapJsonFormatter {
|
||||
}
|
||||
// RDAP Response Profile 2.6.1: must have at least one status member
|
||||
// makeStatusValueList should in theory always contain one of either "active" or "inactive".
|
||||
// RDAP Response Profile 2.6.3, must have a notice about statuses. That is in {@link
|
||||
// RdapIcannStandardInformation#domainBoilerplateNotices}, not here.
|
||||
Set<EppEnum> allStatusValues =
|
||||
Sets.union(domain.getStatusValues(), domain.getGracePeriodStatuses());
|
||||
ImmutableSet<RdapStatus> status =
|
||||
makeStatusValueList(
|
||||
allStatusValues,
|
||||
false, // isRedacted
|
||||
domain.getDeletionTime().isBefore(getRequestTime()));
|
||||
domain.getDeletionDateTime().isBefore(getRequestTime()));
|
||||
builder.statusBuilder().addAll(status);
|
||||
if (status.isEmpty()) {
|
||||
logger.atWarning().log(
|
||||
"Domain %s (ROID %s) doesn't have any status.",
|
||||
domain.getDomainName(), domain.getRepoId());
|
||||
}
|
||||
// RDAP Response Profile 2.6.3, must have a notice about statuses. That is in {@link
|
||||
// RdapIcannStandardInformation#domainBoilerplateNotices}
|
||||
|
||||
// We're just trying to load the hosts by cache here, but the generics and casting require
|
||||
// a lot of boilerplate to make the compiler happy
|
||||
Iterable<VKey<? extends EppResource>> nameservers =
|
||||
ImmutableSet.copyOf(domain.getNameservers());
|
||||
ImmutableSet<Host> loadedHosts =
|
||||
replicaTm()
|
||||
.transact(
|
||||
() ->
|
||||
ImmutableSet.copyOf(replicaTm().loadByKeys(domain.getNameservers()).values()));
|
||||
() -> {
|
||||
ImmutableSet.Builder<Host> hostBuilder = new ImmutableSet.Builder<>();
|
||||
for (EppResource host : EppResource.loadByCacheIfEnabled(nameservers).values()) {
|
||||
hostBuilder.add((Host) host);
|
||||
}
|
||||
return hostBuilder.build();
|
||||
});
|
||||
|
||||
// Add the nameservers to the data; the load was kicked off above for efficiency.
|
||||
// RDAP Response Profile 2.8: we MUST have the nameservers
|
||||
@@ -425,8 +459,7 @@ public class RdapJsonFormatter {
|
||||
&& replicaTm()
|
||||
.transact(
|
||||
() ->
|
||||
replicaTm()
|
||||
.loadByKey(host.getSuperordinateDomain())
|
||||
EppResource.loadByCache(host.getSuperordinateDomain())
|
||||
.cloneProjectedAtTime(getRequestTime())
|
||||
.getStatusValues()
|
||||
.contains(StatusValue.PENDING_TRANSFER))) {
|
||||
@@ -438,7 +471,7 @@ public class RdapJsonFormatter {
|
||||
makeStatusValueList(
|
||||
statuses.build(),
|
||||
false, // isRedacted
|
||||
host.getDeletionTime().isBefore(getRequestTime())));
|
||||
host.getDeletionDateTime().isBefore(getRequestTime())));
|
||||
}
|
||||
|
||||
// For query responses - we MUST have all the ip addresses: RDAP Response Profile 4.2.
|
||||
@@ -747,12 +780,9 @@ public class RdapJsonFormatter {
|
||||
* that we don't need to load HistoryEntries for "summary" responses).
|
||||
*/
|
||||
private ImmutableList<Event> makeOptionalEvents(EppResource resource) {
|
||||
ImmutableList.Builder<Event> eventsBuilder = new ImmutableList.Builder<>();
|
||||
ImmutableMap<EventAction, HistoryTimeAndRegistrar> lastHistoryOfType =
|
||||
getLastHistoryByType(resource);
|
||||
ImmutableList.Builder<Event> eventsBuilder = new ImmutableList.Builder<>();
|
||||
DateTime creationTime = resource.getCreationTime();
|
||||
DateTime lastChangeTime =
|
||||
resource.getLastEppUpdateTime() == null ? creationTime : resource.getLastEppUpdateTime();
|
||||
// The order of the elements is stable - it's the order in which the enum elements are defined
|
||||
// in EventAction
|
||||
for (EventAction rdapEventAction : EventAction.values()) {
|
||||
@@ -761,34 +791,11 @@ public class RdapJsonFormatter {
|
||||
if (historyTimeAndRegistrar == null) {
|
||||
continue;
|
||||
}
|
||||
DateTime modificationTime = historyTimeAndRegistrar.modificationTime();
|
||||
// We will ignore all events that happened before the "creation time", since these events are
|
||||
// from a "previous incarnation of the domain" (for a domain that was owned by someone,
|
||||
// deleted, and then bought by someone else)
|
||||
if (modificationTime.isBefore(creationTime)) {
|
||||
continue;
|
||||
}
|
||||
eventsBuilder.add(
|
||||
Event.builder()
|
||||
.setEventAction(rdapEventAction)
|
||||
.setEventActor(historyTimeAndRegistrar.registrarId())
|
||||
.setEventDate(modificationTime)
|
||||
.build());
|
||||
// The last change time might not be the lastEppUpdateTime, since some changes happen without
|
||||
// any EPP update (for example, by the passage of time).
|
||||
if (modificationTime.isAfter(lastChangeTime) && modificationTime.isBefore(getRequestTime())) {
|
||||
lastChangeTime = modificationTime;
|
||||
}
|
||||
}
|
||||
// RDAP Response Profile section 2.3.2.2:
|
||||
// The event of eventAction type last changed MUST be omitted if the domain name has not been
|
||||
// updated since it was created
|
||||
if (lastChangeTime.isAfter(creationTime)) {
|
||||
// Creates an RDAP event object as defined by RFC 9083
|
||||
eventsBuilder.add(
|
||||
Event.builder()
|
||||
.setEventAction(EventAction.LAST_CHANGED)
|
||||
.setEventDate(lastChangeTime)
|
||||
.setEventDate(historyTimeAndRegistrar.modificationTime())
|
||||
.build());
|
||||
}
|
||||
return eventsBuilder.build();
|
||||
|
||||
@@ -94,13 +94,13 @@ final class DomainToXjcConverter {
|
||||
// identifying the end (expiration) of the domain name object's
|
||||
// registration period. This element MUST be present if the domain
|
||||
// name has been allocated.
|
||||
bean.setExDate(model.getRegistrationExpirationTime());
|
||||
bean.setExDate(model.getRegistrationExpirationDateTime());
|
||||
|
||||
// o An OPTIONAL <upDate> element that contains the date and time of
|
||||
// the most recent domain-name-object modification. This element
|
||||
// MUST NOT be present if the domain name object has never been
|
||||
// modified.
|
||||
bean.setUpDate(model.getLastEppUpdateTime());
|
||||
bean.setUpDate(model.getLastEppUpdateDateTime());
|
||||
|
||||
// o An OPTIONAL <upRr> element that contains the identifier of the
|
||||
// registrar that last updated the domain name object. This element
|
||||
@@ -228,8 +228,8 @@ final class DomainToXjcConverter {
|
||||
bean.setReRr(RdeUtils.makeXjcRdeRrType(model.getGainingRegistrarId()));
|
||||
bean.setAcRr(RdeUtils.makeXjcRdeRrType(model.getLosingRegistrarId()));
|
||||
bean.setReDate(model.getTransferRequestTime());
|
||||
bean.setAcDate(model.getPendingTransferExpirationTime());
|
||||
bean.setExDate(model.getTransferredRegistrationExpirationTime());
|
||||
bean.setAcDate(model.getPendingTransferExpirationDateTime());
|
||||
bean.setExDate(model.getTransferredRegistrationExpirationDateTime());
|
||||
return bean;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ final class HostToXjcConverter {
|
||||
bean.setName(model.getHostName());
|
||||
bean.setRoid(model.getRepoId());
|
||||
bean.setCrDate(model.getCreationTime());
|
||||
bean.setUpDate(model.getLastEppUpdateTime());
|
||||
bean.setUpDate(model.getLastEppUpdateDateTime());
|
||||
bean.setCrRr(RdeAdapter.convertRr(model.getCreationRegistrarId(), null));
|
||||
bean.setUpRr(RdeAdapter.convertRr(model.getLastEppUpdateRegistrarId(), null));
|
||||
bean.setCrRr(RdeAdapter.convertRr(model.getCreationRegistrarId(), null));
|
||||
|
||||
@@ -19,7 +19,6 @@ import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static google.registry.model.tld.Tlds.findTldForNameOrThrow;
|
||||
import static google.registry.pricing.PricingEngineProxy.getDomainCreateCost;
|
||||
import static google.registry.util.StringGenerator.DEFAULT_PASSWORD_LENGTH;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
@@ -30,7 +29,6 @@ import google.registry.util.StringGenerator;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** A command to create a new anchor tenant domain. */
|
||||
@Parameters(separators = " =", commandDescription = "Provision a domain for an anchor tenant.")
|
||||
@@ -86,7 +84,7 @@ final class CreateAnchorTenantCommand extends MutatingEppToolCommand {
|
||||
|
||||
Money cost = null;
|
||||
if (fee) {
|
||||
cost = getDomainCreateCost(domainName, DateTime.now(UTC), DEFAULT_ANCHOR_TENANT_PERIOD_YEARS);
|
||||
cost = getDomainCreateCost(domainName, clock.nowUtc(), DEFAULT_ANCHOR_TENANT_PERIOD_YEARS);
|
||||
}
|
||||
|
||||
setSoyTemplate(CreateAnchorTenantSoyInfo.getInstance(),
|
||||
|
||||
@@ -17,7 +17,6 @@ package google.registry.tools;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||
import static google.registry.pricing.PricingEngineProxy.getPricesForDomainName;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
@@ -28,7 +27,6 @@ import google.registry.util.StringGenerator;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** A command to create a new domain via EPP. */
|
||||
@Parameters(separators = " =", commandDescription = "Create a new domain via EPP.")
|
||||
@@ -64,7 +62,7 @@ final class CreateDomainCommand extends CreateOrUpdateDomainCommand {
|
||||
for (String domain : domains) {
|
||||
String currency = null;
|
||||
String cost = null;
|
||||
DomainPrices prices = getPricesForDomainName(domain, DateTime.now(UTC));
|
||||
DomainPrices prices = getPricesForDomainName(domain, clock.nowUtc());
|
||||
|
||||
// Check if the domain is premium and set the fee on the create command if so.
|
||||
if (prices.isPremium()) {
|
||||
|
||||
@@ -14,10 +14,14 @@
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.tld.label.PremiumListDao;
|
||||
import google.registry.tools.params.PathParameter;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -29,6 +33,8 @@ import org.joda.money.CurrencyUnit;
|
||||
*/
|
||||
abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand {
|
||||
|
||||
@Inject Clock clock;
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
protected List<String> inputData;
|
||||
protected CurrencyUnit currency;
|
||||
@@ -54,7 +60,7 @@ abstract class CreateOrUpdatePremiumListCommand extends ConfirmingCommand {
|
||||
String.format("Saved premium list %s with %d entries.", name, inputData.size());
|
||||
try {
|
||||
logger.atInfo().log("Saving premium list for TLD %s.", name);
|
||||
PremiumListDao.save(name, currency, inputData);
|
||||
tm().transact(() -> PremiumListDao.save(name, currency, inputData));
|
||||
logger.atInfo().log(message);
|
||||
} catch (Throwable e) {
|
||||
message = "Unexpected error saving premium list from nomulus tool command.";
|
||||
|
||||
@@ -21,7 +21,6 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.util.RegistrarUtils.normalizeRegistrarName;
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.google.common.base.Ascii;
|
||||
@@ -37,6 +36,7 @@ import google.registry.tools.params.OptionalStringParameter;
|
||||
import google.registry.tools.params.PathParameter.InputFile;
|
||||
import google.registry.tools.params.StringListParameter;
|
||||
import google.registry.util.CidrAddressBlock;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -56,6 +56,8 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
|
||||
|
||||
@Inject CertificateChecker certificateChecker;
|
||||
|
||||
@Inject Clock clock;
|
||||
|
||||
@Parameter(description = "Client identifier of the registrar account", required = true)
|
||||
List<String> mainParameters;
|
||||
|
||||
@@ -272,7 +274,7 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
|
||||
@Override
|
||||
protected final void init() throws Exception {
|
||||
initRegistrarCommand();
|
||||
DateTime now = DateTime.now(UTC);
|
||||
DateTime now = clock.nowUtc();
|
||||
for (String clientId : mainParameters) {
|
||||
Registrar oldRegistrar = getOldRegistrar(clientId);
|
||||
Registrar.Builder builder =
|
||||
|
||||
@@ -19,6 +19,8 @@ import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.tld.label.ReservedList;
|
||||
import google.registry.model.tld.label.ReservedListDao;
|
||||
import google.registry.tools.params.PathParameter;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -29,6 +31,8 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public abstract class CreateOrUpdateReservedListCommand extends ConfirmingCommand {
|
||||
|
||||
@Inject Clock clock;
|
||||
|
||||
static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.tld.Tlds.assertTldExists;
|
||||
import static google.registry.util.ListNamingUtils.convertFilePathToName;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
@@ -51,7 +50,7 @@ final class CreateReservedListCommand extends CreateOrUpdateReservedListCommand
|
||||
if (!override) {
|
||||
validateListName(name);
|
||||
}
|
||||
DateTime now = DateTime.now(UTC);
|
||||
DateTime now = clock.nowUtc();
|
||||
List<String> allLines = Files.readAllLines(input, UTF_8);
|
||||
reservedList =
|
||||
new ReservedList.Builder()
|
||||
|
||||
@@ -38,6 +38,8 @@ import com.google.template.soy.data.SoyRecord;
|
||||
import com.google.template.soy.parseinfo.SoyFileInfo;
|
||||
import com.google.template.soy.parseinfo.SoyTemplateInfo;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
@@ -49,6 +51,8 @@ import java.util.Objects;
|
||||
/** A command to execute an epp command. */
|
||||
abstract class EppToolCommand extends ConfirmingCommand implements CommandWithConnection {
|
||||
|
||||
@Inject Clock clock;
|
||||
|
||||
@Parameter(
|
||||
names = {"-u", "--superuser"},
|
||||
description = "Run in superuser mode")
|
||||
|
||||
@@ -56,8 +56,7 @@ final class GenerateDnsReportCommand implements Command {
|
||||
validateWith = PathParameter.OutputFile.class)
|
||||
private Path output = Paths.get("/dev/stdout");
|
||||
|
||||
@Inject
|
||||
Clock clock;
|
||||
@Inject Clock clock;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
@@ -81,7 +80,7 @@ final class GenerateDnsReportCommand implements Command {
|
||||
.list());
|
||||
for (Domain domain : domains) {
|
||||
// Skip deleted domains and domains that don't get published to DNS.
|
||||
if (isBeforeOrAt(domain.getDeletionTime(), now) || !domain.shouldPublishToDns()) {
|
||||
if (isBeforeOrAt(domain.getDeletionDateTime(), now) || !domain.shouldPublishToDns()) {
|
||||
continue;
|
||||
}
|
||||
write(domain);
|
||||
@@ -90,7 +89,7 @@ final class GenerateDnsReportCommand implements Command {
|
||||
Iterable<Host> nameservers = tm().transact(() -> tm().loadAllOf(Host.class));
|
||||
for (Host nameserver : nameservers) {
|
||||
// Skip deleted hosts and external hosts.
|
||||
if (isBeforeOrAt(nameserver.getDeletionTime(), now)
|
||||
if (isBeforeOrAt(nameserver.getDeletionDateTime(), now)
|
||||
|| nameserver.getInetAddresses().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package google.registry.tools;
|
||||
|
||||
import static google.registry.model.tld.Tlds.assertTldsExist;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.joda.time.Duration.standardMinutes;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
@@ -23,6 +22,8 @@ import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.tools.params.DateParameter;
|
||||
import google.registry.tools.server.GenerateZoneFilesAction;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -40,10 +41,13 @@ final class GenerateZoneFilesCommand implements CommandWithConnection {
|
||||
// Default to latest midnight that's at least 2 minutes ago.
|
||||
@Parameter(
|
||||
names = "--export_date",
|
||||
description = "The date to generate the file for (defaults to today, or yesterday if run "
|
||||
+ "before 00:02).",
|
||||
description =
|
||||
"The date to generate the file for (defaults to today, or yesterday if run "
|
||||
+ "before 00:02).",
|
||||
validateWith = DateParameter.class)
|
||||
private DateTime exportDate = DateTime.now(UTC).minus(standardMinutes(2)).withTimeAtStartOfDay();
|
||||
private DateTime exportDate;
|
||||
|
||||
@Inject Clock clock;
|
||||
|
||||
private ServiceConnection connection;
|
||||
|
||||
@@ -54,6 +58,9 @@ final class GenerateZoneFilesCommand implements CommandWithConnection {
|
||||
|
||||
@Override
|
||||
public void run() throws IOException {
|
||||
if (exportDate == null) {
|
||||
exportDate = clock.nowUtc().minus(standardMinutes(2)).withTimeAtStartOfDay();
|
||||
}
|
||||
assertTldsExist(mainParameters);
|
||||
ImmutableMap<String, Object> params = ImmutableMap.of(
|
||||
"tlds", mainParameters,
|
||||
|
||||
@@ -17,7 +17,6 @@ package google.registry.tools;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
@@ -26,7 +25,9 @@ import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.HistoryEntryDao;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.tools.CommandUtilities.ResourceType;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.xml.XmlTransformer;
|
||||
import jakarta.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Command to show history entries. */
|
||||
@@ -35,6 +36,8 @@ import org.joda.time.DateTime;
|
||||
commandDescription = "Show history entries that occurred in a given time range")
|
||||
final class GetHistoryEntriesCommand implements Command {
|
||||
|
||||
@Inject Clock clock;
|
||||
|
||||
@Parameter(
|
||||
names = {"-a", "--after"},
|
||||
description = "Only show history entries that occurred at or after this time")
|
||||
@@ -58,7 +61,7 @@ final class GetHistoryEntriesCommand implements Command {
|
||||
checkArgument(
|
||||
type != null && uniqueId != null,
|
||||
"If either of 'type' or 'id' are set then both must be");
|
||||
VKey<? extends EppResource> parentKey = type.getKey(uniqueId, DateTime.now(UTC));
|
||||
VKey<? extends EppResource> parentKey = type.getKey(uniqueId, clock.nowUtc());
|
||||
historyEntries = HistoryEntryDao.loadHistoryObjectsForResource(parentKey, after, before);
|
||||
} else {
|
||||
historyEntries = HistoryEntryDao.loadAllHistoryObjects(after, before);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import google.registry.keyring.api.KeySerializer;
|
||||
@@ -95,6 +96,10 @@ final class GetKeyringSecretCommand implements Command {
|
||||
out.write(KeySerializer.serializeString(keyring.getSqlPrimaryConnectionName()));
|
||||
case SQL_REPLICA_CONN_NAME ->
|
||||
out.write(KeySerializer.serializeString(keyring.getSqlReplicaConnectionName()));
|
||||
case SQL_REPLICA_CONN_NAMES ->
|
||||
out.write(
|
||||
KeySerializer.serializeString(
|
||||
String.join("\n", keyring.getSqlReplicaConnectionNames())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ import com.google.template.soy.data.SoyMapData;
|
||||
import google.registry.flows.ResourceFlowUtils;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.tools.soy.DomainRenewSoyInfo;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.List;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
@@ -63,9 +61,6 @@ final class RenewDomainCommand extends MutatingEppToolCommand {
|
||||
arity = 1)
|
||||
Boolean requestedByRegistrar;
|
||||
|
||||
@Inject
|
||||
Clock clock;
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormat.forPattern("YYYY-MM-dd");
|
||||
|
||||
@Override
|
||||
@@ -81,7 +76,7 @@ final class RenewDomainCommand extends MutatingEppToolCommand {
|
||||
SoyMapData soyMapData =
|
||||
new SoyMapData(
|
||||
"domainName", domain.getDomainName(),
|
||||
"expirationDate", domain.getRegistrationExpirationTime().toString(DATE_FORMATTER),
|
||||
"expirationDate", domain.getRegistrationExpirationDateTime().toString(DATE_FORMATTER),
|
||||
"period", String.valueOf(period));
|
||||
|
||||
if (requestedByRegistrar != null) {
|
||||
|
||||
@@ -37,8 +37,6 @@ import google.registry.model.host.Host;
|
||||
import google.registry.tools.params.NameserversParameter;
|
||||
import google.registry.tools.soy.DomainRenewSoyInfo;
|
||||
import google.registry.tools.soy.UniformRapidSuspensionSoyInfo;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.xml.bind.annotation.adapters.HexBinaryAdapter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
@@ -122,8 +120,6 @@ final class UniformRapidSuspensionCommand extends MutatingEppToolCommand {
|
||||
/** Set of status values to remove. */
|
||||
ImmutableSet<String> removeStatuses;
|
||||
|
||||
@Inject Clock clock;
|
||||
|
||||
@Override
|
||||
protected void initMutatingEppToolCommand()
|
||||
throws ResourceFlowUtils.ResourceDoesNotExistException {
|
||||
@@ -163,7 +159,7 @@ final class UniformRapidSuspensionCommand extends MutatingEppToolCommand {
|
||||
domain.getDomainName(),
|
||||
"expirationDate",
|
||||
domain
|
||||
.getRegistrationExpirationTime()
|
||||
.getRegistrationExpirationDateTime()
|
||||
.toString(DateTimeFormat.forPattern("YYYY-MM-dd")),
|
||||
// period is the number of years to renew the registration for
|
||||
"period",
|
||||
|
||||
@@ -99,8 +99,9 @@ class UnrenewDomainCommand extends ConfirmingCommand {
|
||||
domainsWithDisallowedStatusesBuilder.putAll(
|
||||
domainName, Sets.intersection(domain.get().getStatusValues(), DISALLOWED_STATUSES));
|
||||
if (isBeforeOrAt(
|
||||
leapSafeSubtractYears(domain.get().getRegistrationExpirationTime(), period), now)) {
|
||||
domainsExpiringTooSoonBuilder.put(domainName, domain.get().getRegistrationExpirationTime());
|
||||
leapSafeSubtractYears(domain.get().getRegistrationExpirationDateTime(), period), now)) {
|
||||
domainsExpiringTooSoonBuilder.put(
|
||||
domainName, domain.get().getRegistrationExpirationDateTime());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +144,7 @@ class UnrenewDomainCommand extends ConfirmingCommand {
|
||||
DateTime now = clock.nowUtc();
|
||||
for (String domainName : mainParameters) {
|
||||
Domain domain = ForeignKeyUtils.loadResource(Domain.class, domainName, now).get();
|
||||
DateTime previousTime = domain.getRegistrationExpirationTime();
|
||||
DateTime previousTime = domain.getRegistrationExpirationDateTime();
|
||||
DateTime newTime = leapSafeSubtractYears(previousTime, period);
|
||||
resultBuilder.append(
|
||||
String.format(
|
||||
@@ -179,12 +180,12 @@ class UnrenewDomainCommand extends ConfirmingCommand {
|
||||
"Domain %s has prohibited status values",
|
||||
domainName);
|
||||
checkState(
|
||||
leapSafeSubtractYears(domain.getRegistrationExpirationTime(), period).isAfter(now),
|
||||
leapSafeSubtractYears(domain.getRegistrationExpirationDateTime(), period).isAfter(now),
|
||||
"Domain %s expires too soon",
|
||||
domainName);
|
||||
|
||||
DateTime newExpirationTime =
|
||||
leapSafeSubtractYears(domain.getRegistrationExpirationTime(), period);
|
||||
leapSafeSubtractYears(domain.getRegistrationExpirationDateTime(), period);
|
||||
DomainHistory domainHistory =
|
||||
new DomainHistory.Builder()
|
||||
.setDomain(domain)
|
||||
|
||||
@@ -33,8 +33,6 @@ import google.registry.model.domain.GracePeriodBase;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.tools.params.NameserversParameter;
|
||||
import google.registry.tools.soy.DomainUpdateSoyInfo;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -49,8 +47,6 @@ final class UpdateDomainCommand extends CreateOrUpdateDomainCommand {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@Inject Clock clock;
|
||||
|
||||
@Parameter(names = "--statuses", description = "Comma-separated list of statuses to set.")
|
||||
private List<String> statuses = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -100,6 +100,8 @@ final class UpdateKeyringSecretCommand implements Command {
|
||||
secretManagerKeyringUpdater.setSqlPrimaryConnectionName(deserializeString(input));
|
||||
case SQL_REPLICA_CONN_NAME ->
|
||||
secretManagerKeyringUpdater.setSqlReplicaConnectionName(deserializeString(input));
|
||||
case SQL_REPLICA_CONN_NAMES ->
|
||||
secretManagerKeyringUpdater.setSqlReplicaConnectionNames(deserializeString(input));
|
||||
}
|
||||
|
||||
secretManagerKeyringUpdater.update();
|
||||
|
||||
@@ -62,7 +62,8 @@ class UpdatePremiumListCommand extends CreateOrUpdatePremiumListCommand {
|
||||
inputData = Files.readAllLines(inputFile, UTF_8);
|
||||
checkArgument(!inputData.isEmpty(), "New premium list data cannot be empty");
|
||||
currency = existingList.getCurrency();
|
||||
PremiumList updatedPremiumList = PremiumListUtils.parseToPremiumList(name, currency, inputData);
|
||||
PremiumList updatedPremiumList =
|
||||
PremiumListUtils.parseToPremiumList(name, currency, inputData, clock.nowUtc());
|
||||
if (!existingList
|
||||
.getLabelsToPrices()
|
||||
.entrySet()
|
||||
|
||||
@@ -16,7 +16,9 @@ package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.toDateTime;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
@@ -31,6 +33,7 @@ import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -161,7 +164,7 @@ public class UpdateRecurrenceCommand extends ConfirmingCommand {
|
||||
|
||||
private ImmutableMap<Domain, BillingRecurrence> loadDomainsAndRecurrences() {
|
||||
ImmutableMap.Builder<Domain, BillingRecurrence> result = new ImmutableMap.Builder<>();
|
||||
DateTime now = tm().getTransactionTime();
|
||||
Instant now = tm().getTxTime();
|
||||
for (String domainName : mainParameters) {
|
||||
Domain domain =
|
||||
ForeignKeyUtils.loadResource(Domain.class, domainName, now)
|
||||
@@ -171,7 +174,7 @@ public class UpdateRecurrenceCommand extends ConfirmingCommand {
|
||||
String.format(
|
||||
"Domain %s does not exist or has been deleted", domainName)));
|
||||
checkArgument(
|
||||
domain.getDeletionTime().equals(END_OF_TIME),
|
||||
domain.getDeletionTime().equals(END_INSTANT),
|
||||
"Domain %s has already had a deletion time set",
|
||||
domainName);
|
||||
checkArgument(
|
||||
@@ -184,7 +187,7 @@ public class UpdateRecurrenceCommand extends ConfirmingCommand {
|
||||
domainAutorenewEndTime.ifPresent(
|
||||
endTime ->
|
||||
checkArgument(
|
||||
endTime.isAfter(now),
|
||||
endTime.isAfter(toDateTime(now)),
|
||||
"Domain %s autorenew ended prior to now at %s",
|
||||
domainName,
|
||||
endTime));
|
||||
|
||||
@@ -38,5 +38,6 @@ public enum KeyringKeyName {
|
||||
RDE_STAGING_PUBLIC_KEY,
|
||||
SAFE_BROWSING_API_KEY,
|
||||
SQL_PRIMARY_CONN_NAME,
|
||||
SQL_REPLICA_CONN_NAME
|
||||
SQL_REPLICA_CONN_NAME,
|
||||
SQL_REPLICA_CONN_NAMES
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package google.registry.ui.server.console;
|
||||
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.request.Action.Method.GET;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
@@ -35,7 +34,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
@Action(
|
||||
service = Service.CONSOLE,
|
||||
@@ -86,7 +84,7 @@ public class ConsoleDumDownloadAction extends ConsoleApiAction {
|
||||
.setHeader("Cache-Control", "max-age=86400"); // 86400 seconds = 1 day
|
||||
consoleApiParams
|
||||
.response()
|
||||
.setDateHeader("Expires", DateTime.now(UTC).withTimeAtStartOfDay().plusDays(1));
|
||||
.setDateHeader("Expires", clock.nowUtc().withTimeAtStartOfDay().plusDays(1));
|
||||
|
||||
try (var writer = consoleApiParams.response().getWriter()) {
|
||||
CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT);
|
||||
|
||||
@@ -24,6 +24,7 @@ import static google.registry.testing.DatabaseHelper.loadByEntity;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.plusDays;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.flows.DaggerEppTestComponent;
|
||||
@@ -117,7 +118,7 @@ class DeleteExpiredDomainsActionTest {
|
||||
assertThat(loadByEntity(notYetExpiredDomain)).isEqualTo(notYetExpiredDomain);
|
||||
Domain reloadedExpiredDomain = loadByEntity(pendingExpirationDomain);
|
||||
assertThat(reloadedExpiredDomain.getStatusValues()).contains(PENDING_DELETE);
|
||||
assertThat(reloadedExpiredDomain.getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35));
|
||||
assertThat(reloadedExpiredDomain.getDeletionTime()).isEqualTo(plusDays(clock.now(), 35));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -26,7 +26,7 @@ import static google.registry.testing.DatabaseHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistDomainAsDeleted;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static google.registry.util.DateTimeUtils.END_INSTANT;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@@ -45,8 +45,10 @@ import google.registry.model.tld.Tld.TldType;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.SystemPropertyExtension;
|
||||
import google.registry.util.RegistryEnvironment;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import org.joda.money.Money;
|
||||
@@ -61,9 +63,11 @@ class DeleteProberDataActionTest {
|
||||
|
||||
private static final DateTime DELETION_TIME = DateTime.parse("2010-01-01T00:00:00.000Z");
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.now(UTC));
|
||||
|
||||
@RegisterExtension
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
|
||||
|
||||
@RegisterExtension
|
||||
final SystemPropertyExtension systemPropertyExtension = new SystemPropertyExtension();
|
||||
@@ -93,7 +97,9 @@ class DeleteProberDataActionTest {
|
||||
}
|
||||
|
||||
private void resetAction() {
|
||||
action = new DeleteProberDataAction(false, ImmutableSet.of(), Optional.empty(), "TheRegistrar");
|
||||
action =
|
||||
new DeleteProberDataAction(
|
||||
false, ImmutableSet.of(), Optional.empty(), "TheRegistrar", clock);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -123,7 +129,7 @@ class DeleteProberDataActionTest {
|
||||
Set<ImmutableObject> oaEntities = persistLotsOfDomains("oa-canary.test");
|
||||
// Create action with batch size of 3
|
||||
DeleteProberDataAction batchedAction =
|
||||
new DeleteProberDataAction(false, ImmutableSet.of(), Optional.of(3), "TheRegistrar");
|
||||
new DeleteProberDataAction(false, ImmutableSet.of(), Optional.of(3), "TheRegistrar", clock);
|
||||
batchedAction.run();
|
||||
assertAllAbsent(ibEntities);
|
||||
assertAllAbsent(oaEntities);
|
||||
@@ -201,7 +207,7 @@ class DeleteProberDataActionTest {
|
||||
.setCreationTimeForTest(DateTime.now(UTC).minusYears(1))
|
||||
.build());
|
||||
action.run();
|
||||
DateTime timeAfterDeletion = DateTime.now(UTC);
|
||||
Instant timeAfterDeletion = Instant.now();
|
||||
assertThat(ForeignKeyUtils.loadResource(Domain.class, "blah.ib-any.test", timeAfterDeletion))
|
||||
.isEmpty();
|
||||
assertThat(loadByEntity(domain).getDeletionTime()).isLessThan(timeAfterDeletion);
|
||||
@@ -217,7 +223,7 @@ class DeleteProberDataActionTest {
|
||||
.setCreationTimeForTest(DateTime.now(UTC).minusYears(1))
|
||||
.build());
|
||||
action.run();
|
||||
DateTime timeAfterDeletion = DateTime.now(UTC);
|
||||
Instant timeAfterDeletion = Instant.now();
|
||||
resetAction();
|
||||
action.run();
|
||||
assertThat(ForeignKeyUtils.loadResource(Domain.class, "blah.ib-any.test", timeAfterDeletion))
|
||||
@@ -237,7 +243,7 @@ class DeleteProberDataActionTest {
|
||||
Optional<Domain> domain =
|
||||
ForeignKeyUtils.loadResource(Domain.class, "blah.ib-any.test", DateTime.now(UTC));
|
||||
assertThat(domain).isPresent();
|
||||
assertThat(domain.get().getDeletionTime()).isEqualTo(END_OF_TIME);
|
||||
assertThat(domain.get().getDeletionTime()).isEqualTo(END_INSTANT);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -250,7 +256,7 @@ class DeleteProberDataActionTest {
|
||||
.build());
|
||||
action.isDryRun = true;
|
||||
action.run();
|
||||
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(END_OF_TIME);
|
||||
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(END_INSTANT);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+2
-1
@@ -97,7 +97,8 @@ class SendExpiringCertificateNotificationEmailActionTest {
|
||||
EXPIRATION_WARNING_EMAIL_SUBJECT_TEXT,
|
||||
sendEmailService,
|
||||
certificateChecker,
|
||||
response);
|
||||
response,
|
||||
clock);
|
||||
|
||||
sampleRegistrar =
|
||||
persistResource(createRegistrar("clientId", "sampleRegistrar", null, null).build());
|
||||
|
||||
+5
-2
@@ -25,6 +25,8 @@ import static google.registry.testing.DatabaseHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources;
|
||||
import static google.registry.testing.DatabaseHelper.persistDomainWithPendingTransfer;
|
||||
import static google.registry.testing.DatabaseHelper.persistNewRegistrars;
|
||||
import static google.registry.util.DateTimeUtils.plusYears;
|
||||
import static google.registry.util.DateTimeUtils.toInstant;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -113,11 +115,12 @@ public class ResaveAllEppResourcesPipelineTest {
|
||||
DateTime now = fakeClock.nowUtc();
|
||||
Domain domain =
|
||||
persistDomainWithDependentResources("domain", "tld", now, now, now.plusYears(1));
|
||||
assertThat(domain.getRegistrationExpirationTime()).isEqualTo(now.plusYears(1));
|
||||
assertThat(domain.getRegistrationExpirationTime()).isEqualTo(plusYears(toInstant(now), 1));
|
||||
fakeClock.advanceBy(Duration.standardDays(500));
|
||||
runPipeline();
|
||||
Domain postPipeline = loadByEntity(domain);
|
||||
assertThat(postPipeline.getRegistrationExpirationTime()).isEqualTo(now.plusYears(2));
|
||||
assertThat(postPipeline.getRegistrationExpirationTime())
|
||||
.isEqualTo(plusYears(toInstant(now), 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -85,10 +85,13 @@ class SafeBrowsingTransformsTest {
|
||||
private final CloseableHttpClient mockHttpClient =
|
||||
mock(CloseableHttpClient.class, withSettings().serializable());
|
||||
|
||||
private final FakeClock clock = new FakeClock();
|
||||
|
||||
private final EvaluateSafeBrowsingFn safeBrowsingFn =
|
||||
new EvaluateSafeBrowsingFn(
|
||||
"API_KEY",
|
||||
new Retrier(new FakeSleeper(new FakeClock()), 1),
|
||||
new Retrier(new FakeSleeper(clock), 1),
|
||||
clock,
|
||||
Suppliers.ofInstance(mockHttpClient));
|
||||
|
||||
@RegisterExtension
|
||||
|
||||
@@ -187,7 +187,8 @@ class Spec11PipelineTest {
|
||||
EvaluateSafeBrowsingFn safeBrowsingFn =
|
||||
new EvaluateSafeBrowsingFn(
|
||||
SAFE_BROWSING_API_KEY,
|
||||
new Retrier(new FakeSleeper(new FakeClock()), 1),
|
||||
new Retrier(new FakeSleeper(fakeClock), 1),
|
||||
fakeClock,
|
||||
Suppliers.ofInstance(mockHttpClient));
|
||||
when(mockHttpClient.execute(any(HttpPost.class))).thenAnswer(new HttpResponder());
|
||||
Spec11Pipeline spec11Pipeline = new Spec11Pipeline(options, safeBrowsingFn);
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.export;
|
||||
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.export.ExportPremiumTermsAction.EXPORT_MIME_TYPE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.deleteTld;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
@@ -75,7 +76,7 @@ public class ExportPremiumTermsActionTest {
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
createTld("tld");
|
||||
PremiumList pl = PremiumListDao.save("pl-name", USD, PREMIUM_NAMES);
|
||||
PremiumList pl = tm().transact(() -> PremiumListDao.save("pl-name", USD, PREMIUM_NAMES));
|
||||
persistResource(
|
||||
Tld.get("tld").asBuilder().setPremiumList(pl).setDriveFolderId("folder_id").build());
|
||||
when(driveConnection.createOrUpdateFile(
|
||||
|
||||
@@ -488,7 +488,7 @@ class EppLifecycleDomainTest extends EppTestCase {
|
||||
|
||||
// Make sure that in the future, the domain expiration is unchanged after deletion
|
||||
Domain clonedDomain = domain.cloneProjectedAtTime(deleteTime.plusYears(5));
|
||||
assertThat(clonedDomain.getRegistrationExpirationTime()).isEqualTo(createTime.plusYears(2));
|
||||
assertThat(clonedDomain.getRegistrationExpirationDateTime()).isEqualTo(createTime.plusYears(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -182,7 +182,7 @@ public abstract class FlowTestCase<F extends Flow> {
|
||||
GracePeriod.create(
|
||||
entry.getKey().getType(),
|
||||
entry.getKey().getDomainRepoId(),
|
||||
entry.getKey().getExpirationTime(),
|
||||
entry.getKey().getExpirationDateTime(),
|
||||
entry.getKey().getRegistrarId(),
|
||||
null,
|
||||
1L),
|
||||
|
||||
@@ -361,7 +361,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId(getUniqueIdFromCommand())
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.setDomainHistory(historyEntry)
|
||||
.setRenewalPriceBehavior(expectedRenewalPriceBehavior)
|
||||
@@ -397,7 +397,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setTargetId(domain.getDomainName())
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setHistoryEntry(historyEntry)
|
||||
.build());
|
||||
@@ -1720,7 +1720,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setTargetId(domain.getDomainName())
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setHistoryEntry(historyEntry)
|
||||
.build(),
|
||||
@@ -1853,7 +1853,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setTargetId(domain.getDomainName())
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setHistoryEntry(historyEntry)
|
||||
.build(),
|
||||
|
||||
@@ -376,7 +376,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||
runFlowAssertResponse(loadFile("domain_delete_response_pending.xml"));
|
||||
|
||||
Domain domain = reloadResourceByForeignKey();
|
||||
DateTime redemptionEndTime = domain.getLastEppUpdateTime().plusDays(3);
|
||||
DateTime redemptionEndTime = domain.getLastEppUpdateDateTime().plusDays(3);
|
||||
Domain domainAtRedemptionTime = domain.cloneProjectedAtTime(redemptionEndTime);
|
||||
assertAboutDomains()
|
||||
.that(domainAtRedemptionTime)
|
||||
@@ -418,7 +418,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||
null));
|
||||
// We should see exactly one poll message, which is for the autorenew 1 month in the future.
|
||||
assertPollMessages(createAutorenewPollMessage("TheRegistrar").build());
|
||||
DateTime expectedExpirationTime = domain.getRegistrationExpirationTime().minusYears(2);
|
||||
DateTime expectedExpirationTime = domain.getRegistrationExpirationDateTime().minusYears(2);
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(loadFile(responseFilename, substitutions));
|
||||
Domain resource = reloadResourceByForeignKey();
|
||||
@@ -462,7 +462,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||
// There should be a future poll message at the deletion time. The previous autorenew poll
|
||||
// message should now be deleted.
|
||||
assertAboutDomains().that(domain).hasDeletePollMessage();
|
||||
DateTime deletionTime = domain.getDeletionTime();
|
||||
DateTime deletionTime = domain.getDeletionDateTime();
|
||||
assertThat(getPollMessages("TheRegistrar", deletionTime.minusMinutes(1))).isEmpty();
|
||||
assertThat(getPollMessages("TheRegistrar", deletionTime)).hasSize(1);
|
||||
assertThat(domain.getDeletePollMessage())
|
||||
@@ -496,7 +496,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||
runFlowAssertResponse(loadFile("domain_delete_response_pending.xml"));
|
||||
// There should now be two poll messages; one for the delete of the domain (in the future), and
|
||||
// another for the unacked autorenew messages.
|
||||
DateTime deletionTime = reloadResourceByForeignKey().getDeletionTime();
|
||||
DateTime deletionTime = reloadResourceByForeignKey().getDeletionDateTime();
|
||||
assertThat(getPollMessages("TheRegistrar", deletionTime.minusMinutes(1))).hasSize(1);
|
||||
assertThat(getPollMessages("TheRegistrar", deletionTime)).hasSize(2);
|
||||
}
|
||||
@@ -613,7 +613,7 @@ class DomainDeleteFlowTest extends ResourceFlowTestCase<DomainDeleteFlow, Domain
|
||||
.isEqualTo(Trid.create("transferClient-trid", "transferServer-trid"));
|
||||
assertThat(panData.getActionResult()).isFalse();
|
||||
// There should be a future poll message to the losing registrar at the deletion time.
|
||||
DateTime deletionTime = domain.getDeletionTime();
|
||||
DateTime deletionTime = domain.getDeletionDateTime();
|
||||
assertThat(getPollMessages("TheRegistrar", deletionTime.minusMinutes(1))).isEmpty();
|
||||
assertThat(getPollMessages("TheRegistrar", deletionTime)).hasSize(1);
|
||||
assertOnlyBillingEventIsClosedAutorenew("TheRegistrar");
|
||||
|
||||
@@ -247,7 +247,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||
@Nullable Money renewalPrice)
|
||||
throws Exception {
|
||||
assertMutatingFlow(true);
|
||||
DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationTime();
|
||||
DateTime currentExpiration = reloadResourceByForeignKey().getRegistrationExpirationDateTime();
|
||||
DateTime newExpiration = currentExpiration.plusYears(renewalYears);
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, userPrivileges, loadFile(responseFilename, substitutions));
|
||||
@@ -303,7 +303,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
.setTargetId(getUniqueIdFromCommand())
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.setDomainHistory(historyEntryDomainRenew)
|
||||
.build());
|
||||
@@ -313,7 +313,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setTargetId(getUniqueIdFromCommand())
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setAutorenewEndTime(END_OF_TIME)
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setHistoryEntry(historyEntryDomainRenew)
|
||||
@@ -817,7 +817,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setTargetId(getUniqueIdFromCommand())
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(reloadResourceByForeignKey().getRegistrationExpirationTime())
|
||||
.setEventTime(reloadResourceByForeignKey().getRegistrationExpirationDateTime())
|
||||
.setAutorenewEndTime(END_OF_TIME)
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setHistoryEntry(historyEntryDomainRenew)
|
||||
|
||||
@@ -201,7 +201,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setTargetId("example.tld")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setAutorenewEndTime(END_OF_TIME)
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setHistoryEntry(historyEntryDomainRestore)
|
||||
@@ -269,7 +269,7 @@ class DomainRestoreRequestFlowTest extends ResourceFlowTestCase<DomainRestoreReq
|
||||
new PollMessage.Autorenew.Builder()
|
||||
.setTargetId("example.tld")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setAutorenewEndTime(END_OF_TIME)
|
||||
.setMsg("Domain was auto-renewed.")
|
||||
.setHistoryEntry(historyEntryDomainRestore)
|
||||
|
||||
+30
-24
@@ -24,6 +24,7 @@ import static google.registry.model.reporting.DomainTransactionRecord.Transactio
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_CREATE;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_APPROVE;
|
||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_TRANSFER_REQUEST;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.assertBillingEventsForResource;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.deleteTestDomain;
|
||||
@@ -148,7 +149,8 @@ class DomainTransferApproveFlowTest
|
||||
.copyConstantFieldsToBuilder()
|
||||
.setTransferStatus(TransferStatus.CLIENT_APPROVED)
|
||||
.setPendingTransferExpirationTime(clock.nowUtc())
|
||||
.setTransferredRegistrationExpirationTime(domain.getRegistrationExpirationTime())
|
||||
.setTransferredRegistrationExpirationTime(
|
||||
domain.getRegistrationExpirationDateTime())
|
||||
.build());
|
||||
}
|
||||
|
||||
@@ -216,7 +218,7 @@ class DomainTransferApproveFlowTest
|
||||
// should be one at the current time to the gaining registrar, as well as one at the domain's
|
||||
// autorenew time.
|
||||
assertThat(getPollMessages(domain, "NewRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1);
|
||||
assertThat(getPollMessages(domain, "NewRegistrar", domain.getRegistrationExpirationTime()))
|
||||
assertThat(getPollMessages(domain, "NewRegistrar", domain.getRegistrationExpirationDateTime()))
|
||||
.hasSize(2);
|
||||
|
||||
PollMessage gainingTransferPollMessage =
|
||||
@@ -225,11 +227,11 @@ class DomainTransferApproveFlowTest
|
||||
getOnlyPollMessage(
|
||||
domain,
|
||||
"NewRegistrar",
|
||||
domain.getRegistrationExpirationTime(),
|
||||
domain.getRegistrationExpirationDateTime(),
|
||||
PollMessage.Autorenew.class);
|
||||
assertThat(gainingTransferPollMessage.getEventTime()).isEqualTo(clock.nowUtc());
|
||||
assertThat(gainingAutorenewPollMessage.getEventTime())
|
||||
.isEqualTo(domain.getRegistrationExpirationTime());
|
||||
.isEqualTo(domain.getRegistrationExpirationDateTime());
|
||||
DomainTransferResponse transferResponse =
|
||||
gainingTransferPollMessage
|
||||
.getResponseData()
|
||||
@@ -239,7 +241,7 @@ class DomainTransferApproveFlowTest
|
||||
.collect(onlyElement());
|
||||
assertThat(transferResponse.getTransferStatus()).isEqualTo(TransferStatus.CLIENT_APPROVED);
|
||||
assertThat(transferResponse.getExtendedRegistrationExpirationTime())
|
||||
.isEqualTo(domain.getRegistrationExpirationTime());
|
||||
.isEqualTo(domain.getRegistrationExpirationDateTime());
|
||||
PendingActionNotificationResponse panData =
|
||||
gainingTransferPollMessage
|
||||
.getResponseData()
|
||||
@@ -294,9 +296,9 @@ class DomainTransferApproveFlowTest
|
||||
.build(),
|
||||
getGainingClientAutorenewEvent()
|
||||
.asBuilder()
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setRecurrenceLastExpansion(
|
||||
domain.getRegistrationExpirationTime().minusYears(1))
|
||||
domain.getRegistrationExpirationDateTime().minusYears(1))
|
||||
.setDomainHistory(historyEntryTransferApproved)
|
||||
.build()))
|
||||
.toArray(BillingBase[]::new));
|
||||
@@ -332,9 +334,9 @@ class DomainTransferApproveFlowTest
|
||||
.build(),
|
||||
getGainingClientAutorenewEvent()
|
||||
.asBuilder()
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setEventTime(domain.getRegistrationExpirationDateTime())
|
||||
.setRecurrenceLastExpansion(
|
||||
domain.getRegistrationExpirationTime().minusYears(1))
|
||||
domain.getRegistrationExpirationDateTime().minusYears(1))
|
||||
.setDomainHistory(historyEntryTransferApproved)
|
||||
.build()))
|
||||
.toArray(BillingBase[]::new));
|
||||
@@ -349,7 +351,7 @@ class DomainTransferApproveFlowTest
|
||||
tld,
|
||||
commandFilename,
|
||||
expectedXmlFilename,
|
||||
domain.getRegistrationExpirationTime().plusYears(1),
|
||||
domain.getRegistrationExpirationDateTime().plusYears(1),
|
||||
1);
|
||||
}
|
||||
|
||||
@@ -511,12 +513,14 @@ class DomainTransferApproveFlowTest
|
||||
@Test
|
||||
void testSuccess_nonpremiumPriceRenewalBehavior_carriesOver() throws Exception {
|
||||
PremiumList pl =
|
||||
PremiumListDao.save(
|
||||
new PremiumList.Builder()
|
||||
.setCurrency(USD)
|
||||
.setName("tld")
|
||||
.setLabelsToPrices(ImmutableMap.of("example", new BigDecimal("67.89")))
|
||||
.build());
|
||||
tm().transact(
|
||||
() ->
|
||||
PremiumListDao.save(
|
||||
new PremiumList.Builder()
|
||||
.setCurrency(USD)
|
||||
.setName("tld")
|
||||
.setLabelsToPrices(ImmutableMap.of("example", new BigDecimal("67.89")))
|
||||
.build()));
|
||||
persistResource(Tld.get("tld").asBuilder().setPremiumList(pl).build());
|
||||
domain = loadByEntity(domain);
|
||||
persistResource(
|
||||
@@ -557,12 +561,14 @@ class DomainTransferApproveFlowTest
|
||||
@Test
|
||||
void testSuccess_specifiedPriceRenewalBehavior_carriesOver() throws Exception {
|
||||
PremiumList pl =
|
||||
PremiumListDao.save(
|
||||
new PremiumList.Builder()
|
||||
.setCurrency(USD)
|
||||
.setName("tld")
|
||||
.setLabelsToPrices(ImmutableMap.of("example", new BigDecimal("67.89")))
|
||||
.build());
|
||||
tm().transact(
|
||||
() ->
|
||||
PremiumListDao.save(
|
||||
new PremiumList.Builder()
|
||||
.setCurrency(USD)
|
||||
.setName("tld")
|
||||
.setLabelsToPrices(ImmutableMap.of("example", new BigDecimal("67.89")))
|
||||
.build()));
|
||||
persistResource(Tld.get("tld").asBuilder().setPremiumList(pl).build());
|
||||
domain = loadByEntity(domain);
|
||||
persistResource(
|
||||
@@ -821,7 +827,7 @@ class DomainTransferApproveFlowTest
|
||||
"tld",
|
||||
"domain_transfer_approve.xml",
|
||||
"domain_transfer_approve_response_zero_period.xml",
|
||||
domain.getRegistrationExpirationTime());
|
||||
domain.getRegistrationExpirationDateTime());
|
||||
assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods();
|
||||
}
|
||||
|
||||
@@ -854,7 +860,7 @@ class DomainTransferApproveFlowTest
|
||||
"tld",
|
||||
"domain_transfer_approve.xml",
|
||||
"domain_transfer_approve_response_zero_period_autorenew_grace.xml",
|
||||
domain.getRegistrationExpirationTime());
|
||||
domain.getRegistrationExpirationDateTime());
|
||||
assertHistoryEntriesDoNotContainTransferBillingEventsOrGracePeriods();
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ class DomainTransferCancelFlowTest
|
||||
|
||||
// Setup done; run the test.
|
||||
assertMutatingFlow(true);
|
||||
DateTime originalExpirationTime = domain.getRegistrationExpirationTime();
|
||||
DateTime originalExpirationTime = domain.getRegistrationExpirationDateTime();
|
||||
ImmutableSet<GracePeriod> originalGracePeriods = domain.getGracePeriods();
|
||||
DomainTransferData originalTransferData = domain.getTransferData();
|
||||
runFlowAssertResponse(loadFile("domain_transfer_cancel_response.xml"));
|
||||
|
||||
@@ -143,7 +143,8 @@ class DomainTransferQueryFlowTest
|
||||
persistResource(
|
||||
domain
|
||||
.asBuilder()
|
||||
.setRegistrationExpirationTime(domain.getRegistrationExpirationTime().plusYears(9))
|
||||
.setRegistrationExpirationTime(
|
||||
domain.getRegistrationExpirationDateTime().plusYears(9))
|
||||
.build());
|
||||
doSuccessfulTest("domain_transfer_query.xml", "domain_transfer_query_response_10_years.xml", 1);
|
||||
}
|
||||
@@ -233,7 +234,7 @@ class DomainTransferQueryFlowTest
|
||||
// Set the clock to just past the extended registration time. We'd expect the domain to have
|
||||
// auto-renewed once, but the transfer query response should be the same.
|
||||
clock.setTo(EXTENDED_REGISTRATION_EXPIRATION_TIME.plusMillis(1));
|
||||
assertThat(domain.cloneProjectedAtTime(clock.nowUtc()).getRegistrationExpirationTime())
|
||||
assertThat(domain.cloneProjectedAtTime(clock.nowUtc()).getRegistrationExpirationDateTime())
|
||||
.isEqualTo(EXTENDED_REGISTRATION_EXPIRATION_TIME.plusYears(1));
|
||||
doSuccessfulTest(
|
||||
"domain_transfer_query.xml", "domain_transfer_query_response_server_approved.xml", 2);
|
||||
|
||||
@@ -88,7 +88,7 @@ class DomainTransferRejectFlowTest
|
||||
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1);
|
||||
// Setup done; run the test.
|
||||
assertMutatingFlow(true);
|
||||
DateTime originalExpirationTime = domain.getRegistrationExpirationTime();
|
||||
DateTime originalExpirationTime = domain.getRegistrationExpirationDateTime();
|
||||
ImmutableSet<GracePeriod> originalGracePeriods = domain.getGracePeriods();
|
||||
DomainTransferData originalTransferData = domain.getTransferData();
|
||||
runFlowAssertResponse(loadFile(expectedXmlFilename));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user